[mips] Distinguish 'R', 'ZC', and 'm' inline assembly memory constraint.
authorDaniel Sanders <daniel.sanders@imgtec.com>
Tue, 24 Mar 2015 11:26:34 +0000 (11:26 +0000)
committerDaniel Sanders <daniel.sanders@imgtec.com>
Tue, 24 Mar 2015 11:26:34 +0000 (11:26 +0000)
Summary:
Previous behaviour of 'R' and 'm' has been preserved for now. They will be
improved in subsequent commits.

The offset permitted by ZC varies according to the subtarget since it is
intended to match the restrictions of the pref, ll, and sc instructions.

The restrictions on these instructions are:
* For microMIPS: 12-bit signed offset.
* For Mips32r6/Mips64r6: 9-bit signed offset.
* Otherwise: 16-bit signed offset.

Reviewers: vkalintiris

Reviewed By: vkalintiris

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D8414

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233063 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/IR/InlineAsm.h
lib/Target/Mips/MipsAsmPrinter.cpp
lib/Target/Mips/MipsISelDAGToDAG.cpp
lib/Target/Mips/MipsISelLowering.cpp
lib/Target/Mips/MipsISelLowering.h
lib/Target/Mips/MipsSEISelDAGToDAG.cpp
lib/Target/Mips/MipsSEISelDAGToDAG.h
test/CodeGen/Mips/inlineasm_constraint_ZC.ll [new file with mode: 0644]

index 46367c1ad7b0f5eaa556af5ff9c2c3f09d4a83b7..6ae4122d936e71a3e9f7da86b3463247a9e6d7fa 100644 (file)
@@ -249,6 +249,7 @@ public:
     Constraint_S,
     Constraint_T,
     Constraint_Z,
+    Constraint_ZC,
     Constraint_Zy,
     Constraints_Max = Constraint_Zy,
     Constraints_ShiftAmount = 16,
index c6572402e95428e93b688b81593e4bcbf29f55b1..1eb3b2c6568ca7ce8d373f7d969a69fee324a891 100644 (file)
@@ -437,7 +437,7 @@ bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock*
 
 // Print out an operand for an inline asm expression.
 bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
-                                     unsigned AsmVariant,const char *ExtraCode,
+                                     unsigned AsmVariant, const char *ExtraCode,
                                      raw_ostream &O) {
   // Does this asm operand have a single letter operand modifier?
   if (ExtraCode && ExtraCode[0]) {
@@ -539,18 +539,24 @@ bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
                                            unsigned OpNum, unsigned AsmVariant,
                                            const char *ExtraCode,
                                            raw_ostream &O) {
-  int Offset = 0;
+  assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
+  const MachineOperand &BaseMO = MI->getOperand(OpNum);
+  const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
+  assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand.");
+  assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand.");
+  int Offset = OffsetMO.getImm();
+
   // Currently we are expecting either no ExtraCode or 'D'
   if (ExtraCode) {
     if (ExtraCode[0] == 'D')
-      Offset = 4;
+      Offset += 4;
     else
       return true; // Unknown modifier.
+    // FIXME: M = high order bits
+    // FIXME: L = low order bits
   }
 
-  const MachineOperand &MO = MI->getOperand(OpNum);
-  assert(MO.isReg() && "unexpected inline asm memory operand");
-  O << Offset << "($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")";
+  O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg()) << ")";
 
   return false;
 }
index 50776f9015b0c2861875b5bd3cc44a6fe7f4a02f..c78c3296762088a30abc384d5c3596d7d33b9bd4 100644 (file)
@@ -232,8 +232,16 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
 bool MipsDAGToDAGISel::
 SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
                              std::vector<SDValue> &OutOps) {
-  assert(ConstraintID == InlineAsm::Constraint_m &&
-         "unexpected asm memory constraint");
-  OutOps.push_back(Op);
-  return false;
+  // All memory constraints can at least accept raw pointers.
+  switch(ConstraintID) {
+  default:
+    llvm_unreachable("Unexpected asm memory constraint");
+  case InlineAsm::Constraint_i:
+  case InlineAsm::Constraint_m:
+  case InlineAsm::Constraint_R:
+  case InlineAsm::Constraint_ZC:
+    OutOps.push_back(Op);
+    return false;
+  }
+  return true;
 }
index 2eebd76ce246289f2e5c9b536a5d7ad576dfc55a..e4bae03ebd4fc4a60ae8c4de0851128a57c5daff 100644 (file)
@@ -3173,6 +3173,10 @@ getConstraintType(const std::string &Constraint) const
         return C_Memory;
     }
   }
+
+  if (Constraint == "ZC")
+    return C_Memory;
+
   return TargetLowering::getConstraintType(Constraint);
 }
 
index 02efba84fcfeb1c8a4821a7c2c519c1fc2b90553..40b6661b537aee7bae7004d99abf514668374a44 100644 (file)
@@ -507,8 +507,11 @@ namespace llvm {
 
     unsigned getInlineAsmMemConstraint(
         const std::string &ConstraintCode) const override {
-      // FIXME: Map different constraints differently.
-      return InlineAsm::Constraint_m;
+      if (ConstraintCode == "R")
+        return InlineAsm::Constraint_R;
+      else if (ConstraintCode == "ZC")
+        return InlineAsm::Constraint_ZC;
+      return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
     }
 
     bool isLegalAddressingMode(const AddrMode &AM, Type *Ty) const override;
index 4da30bece9e7f646c3b45b13eade509549194af9..252f9b68c1d64e122c9c2b22792f09b83b9e5e95 100644 (file)
@@ -382,6 +382,17 @@ bool MipsSEDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base,
     selectAddrDefault(Addr, Base, Offset);
 }
 
+bool MipsSEDAGToDAGISel::selectAddrRegImm9(SDValue Addr, SDValue &Base,
+                                           SDValue &Offset) const {
+  if (selectAddrFrameIndex(Addr, Base, Offset))
+    return true;
+
+  if (selectAddrFrameIndexOffset(Addr, Base, Offset, 9))
+    return true;
+
+  return false;
+}
+
 bool MipsSEDAGToDAGISel::selectAddrRegImm10(SDValue Addr, SDValue &Base,
                                             SDValue &Offset) const {
   if (selectAddrFrameIndex(Addr, Base, Offset))
@@ -405,6 +416,17 @@ bool MipsSEDAGToDAGISel::selectAddrRegImm12(SDValue Addr, SDValue &Base,
   return false;
 }
 
+bool MipsSEDAGToDAGISel::selectAddrRegImm16(SDValue Addr, SDValue &Base,
+                                            SDValue &Offset) const {
+  if (selectAddrFrameIndex(Addr, Base, Offset))
+    return true;
+
+  if (selectAddrFrameIndexOffset(Addr, Base, Offset, 16))
+    return true;
+
+  return false;
+}
+
 bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base,
                                          SDValue &Offset) const {
   return selectAddrRegImm12(Addr, Base, Offset) ||
@@ -916,6 +938,52 @@ std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) {
   return std::make_pair(false, nullptr);
 }
 
+bool MipsSEDAGToDAGISel::
+SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
+                             std::vector<SDValue> &OutOps) {
+  SDValue Base, Offset;
+
+  switch(ConstraintID) {
+  default:
+    llvm_unreachable("Unexpected asm memory constraint");
+  // All memory constraints can at least accept raw pointers.
+  case InlineAsm::Constraint_i:
+  case InlineAsm::Constraint_m:
+  case InlineAsm::Constraint_R:
+    OutOps.push_back(Op);
+    OutOps.push_back(CurDAG->getTargetConstant(0, MVT::i32));
+    return false;
+  case InlineAsm::Constraint_ZC:
+    // ZC matches whatever the pref, ll, and sc instructions can handle for the
+    // given subtarget.
+    if (Subtarget->inMicroMipsMode()) {
+      // On microMIPS, they can handle 12-bit offsets.
+      if (selectAddrRegImm12(Op, Base, Offset)) {
+        OutOps.push_back(Base);
+        OutOps.push_back(Offset);
+        return false;
+      }
+    } else if (Subtarget->hasMips32r6()) {
+      // On MIPS32r6/MIPS64r6, they can only handle 9-bit offsets.
+      if (selectAddrRegImm9(Op, Base, Offset)) {
+        OutOps.push_back(Base);
+        OutOps.push_back(Offset);
+        return false;
+      }
+    } else if (selectAddrRegImm16(Op, Base, Offset)) {
+      // Prior to MIPS32r6/MIPS64r6, they can handle 16-bit offsets.
+      OutOps.push_back(Base);
+      OutOps.push_back(Offset);
+      return false;
+    }
+    // In all cases, 0-bit offsets are acceptable.
+    OutOps.push_back(Op);
+    OutOps.push_back(CurDAG->getTargetConstant(0, MVT::i32));
+    return false;
+  }
+  return true;
+}
+
 FunctionPass *llvm::createMipsSEISelDag(MipsTargetMachine &TM) {
   return new MipsSEDAGToDAGISel(TM);
 }
index 2d24eb43e303ef62e532573d0b454376d740c97f..a11fcf4e2e028f815f1871610ba9c158e04ec917 100644 (file)
@@ -56,12 +56,18 @@ private:
   bool selectIntAddr(SDValue Addr, SDValue &Base,
                      SDValue &Offset) const override;
 
+  bool selectAddrRegImm9(SDValue Addr, SDValue &Base,
+                         SDValue &Offset) const;
+
   bool selectAddrRegImm10(SDValue Addr, SDValue &Base,
                           SDValue &Offset) const;
 
   bool selectAddrRegImm12(SDValue Addr, SDValue &Base,
                           SDValue &Offset) const;
 
+  bool selectAddrRegImm16(SDValue Addr, SDValue &Base,
+                          SDValue &Offset) const;
+
   bool selectIntAddrMM(SDValue Addr, SDValue &Base,
                        SDValue &Offset) const override;
 
@@ -111,6 +117,10 @@ private:
   // Insert instructions to initialize the global base register in the
   // first MBB of the function.
   void initGlobalBaseReg(MachineFunction &MF);
+
+  bool SelectInlineAsmMemoryOperand(const SDValue &Op,
+                                    unsigned ConstraintID,
+                                    std::vector<SDValue> &OutOps) override;
 };
 
 FunctionPass *createMipsSEISelDag(MipsTargetMachine &TM);
diff --git a/test/CodeGen/Mips/inlineasm_constraint_ZC.ll b/test/CodeGen/Mips/inlineasm_constraint_ZC.ll
new file mode 100644 (file)
index 0000000..c1746a6
--- /dev/null
@@ -0,0 +1,167 @@
+; RUN: llc -march=mipsel -mcpu=mips32r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=09BIT
+; RUN: llc -march=mipsel -mattr=+micromips < %s | FileCheck %s -check-prefix=ALL -check-prefix=12BIT
+; RUN: llc -march=mipsel < %s | FileCheck %s -check-prefix=ALL -check-prefix=16BIT
+
+@data = global [8193 x i32] zeroinitializer
+
+define void @ZC(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 0))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+  ; ALL: #APP
+  ; ALL: lw $1, 0($[[BASEPTR]])
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_n4(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_n4:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 -1))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+  ; ALL: #APP
+  ; ALL: lw $1, -4($[[BASEPTR]])
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_4(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_4:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 1))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+  ; ALL: #APP
+  ; ALL: lw $1, 4($[[BASEPTR]])
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_252(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_252:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 63))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+  ; ALL: #APP
+  ; ALL: lw $1, 252($[[BASEPTR]])
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_256(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_256:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 64))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+
+  ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 256
+
+  ; ALL: #APP
+
+  ; 09BIT: lw $1, 0($[[BASEPTR2]])
+  ; 12BIT: lw $1, 256($[[BASEPTR]])
+  ; 16BIT: lw $1, 256($[[BASEPTR]])
+
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_2044(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_2044:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 511))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+
+  ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 2044
+
+  ; ALL: #APP
+
+  ; 09BIT: lw $1, 0($[[BASEPTR2]])
+  ; 12BIT: lw $1, 2044($[[BASEPTR]])
+  ; 16BIT: lw $1, 2044($[[BASEPTR]])
+
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_2048(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_2048:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 512))
+
+  ; ALL: lw $[[BASEPTR:[0-9]+]], %got(data)(
+
+  ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 2048
+  ; 12BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 2048
+
+  ; ALL: #APP
+
+  ; 09BIT: lw $1, 0($[[BASEPTR2]])
+  ; 12BIT: lw $1, 0($[[BASEPTR2]])
+  ; 16BIT: lw $1, 2048($[[BASEPTR]])
+
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_32764(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_32764:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 8191))
+
+  ; ALL-DAG: lw $[[BASEPTR:[0-9]+]], %got(data)(
+
+  ; 09BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 32764
+  ; 12BIT: addiu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], 32764
+
+  ; ALL: #APP
+
+  ; 09BIT: lw $1, 0($[[BASEPTR2]])
+  ; 12BIT: lw $1, 0($[[BASEPTR2]])
+  ; 16BIT: lw $1, 32764($[[BASEPTR]])
+
+  ; ALL: #NO_APP
+
+  ret void
+}
+
+define void @ZC_offset_32768(i32 *%p) nounwind {
+entry:
+  ; ALL-LABEL: ZC_offset_32768:
+
+  call void asm sideeffect "lw $$1, $0", "*^ZC,~{$1}"(i32* getelementptr inbounds ([8193 x i32], [8193 x i32]* @data, i32 0, i32 8192))
+
+  ; ALL-DAG: lw $[[BASEPTR:[0-9]+]], %got(data)(
+  ; ALL-DAG: ori $[[T0:[0-9]+]], $zero, 32768
+
+  ; 09BIT: addu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], $[[T0]]
+  ; 12BIT: addu16 $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], $[[T0]]
+  ; 16BIT: addu $[[BASEPTR2:[0-9]+]], $[[BASEPTR]], $[[T0]]
+
+  ; ALL: #APP
+  ; ALL: lw $1, 0($[[BASEPTR2]])
+  ; ALL: #NO_APP
+
+  ret void
+}