Properly handle 'm' inline asm constraints. If a GV is being selected for the address...
authorEvan Cheng <evan.cheng@apple.com>
Wed, 24 Sep 2008 00:05:32 +0000 (00:05 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Wed, 24 Sep 2008 00:05:32 +0000 (00:05 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@56526 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Target/TargetLowering.h
lib/CodeGen/SelectionDAG/SelectionDAGBuild.cpp
lib/CodeGen/SelectionDAG/TargetLowering.cpp
lib/Target/CellSPU/SPUISelLowering.cpp
lib/Target/CellSPU/SPUISelLowering.h
lib/Target/PowerPC/PPCISelLowering.cpp
lib/Target/PowerPC/PPCISelLowering.h
lib/Target/X86/X86ISelDAGToDAG.cpp
lib/Target/X86/X86ISelLowering.cpp
lib/Target/X86/X86ISelLowering.h
test/CodeGen/X86/inline-asm-pic.ll [new file with mode: 0644]

index 0a25f59db6af193f3aa15c8a02665bf9c6b1de1b..7c25c6d3acbbc33776e7f9edc7c640411bd4b22e 100644 (file)
@@ -1169,9 +1169,11 @@ public:
   /// type to use for the specific AsmOperandInfo, setting
   /// OpInfo.ConstraintCode and OpInfo.ConstraintType.  If the actual operand
   /// being passed in is available, it can be passed in as Op, otherwise an
-  /// empty SDValue can be passed.
+  /// empty SDValue can be passed. If hasMemory is true it means one of the asm
+  /// constraint of the inline asm instruction being processed is 'm'.
   virtual void ComputeConstraintToUse(AsmOperandInfo &OpInfo,
                                       SDValue Op,
+                                      bool hasMemory,
                                       SelectionDAG *DAG = 0) const;
   
   /// getConstraintType - Given a constraint, return the type of constraint it
@@ -1206,8 +1208,11 @@ public:
   virtual const char *LowerXConstraint(MVT ConstraintVT) const;
   
   /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
-  /// vector.  If it is invalid, don't add anything to Ops.
+  /// vector.  If it is invalid, don't add anything to Ops. If hasMemory is true
+  /// it means one of the asm constraint of the inline asm instruction being
+  /// processed is 'm'.
   virtual void LowerAsmOperandForConstraint(SDValue Op, char ConstraintLetter,
+                                            bool hasMemory,
                                             std::vector<SDValue> &Ops,
                                             SelectionDAG &DAG) const;
   
index 416d3395688dd9093c3a1bfc0d30e32f2a79096e..9768021b19645d90daf0e7bb47e2d09e6d39f4ab 100644 (file)
@@ -4629,6 +4629,22 @@ GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, bool HasEarlyClobber,
   // Otherwise, we couldn't allocate enough registers for this.
 }
 
+/// hasInlineAsmMemConstraint - Return true if the inline asm instruction being
+/// processed uses a memory 'm' constraint.
+static bool
+hasInlineAsmMemConstraint(std::vector<InlineAsm::ConstraintInfo> &CInfos,
+                          TargetLowering &TLI) {
+  for (unsigned i = 0, e = CInfos.size(); i != e; ++i) {
+    InlineAsm::ConstraintInfo &CI = CInfos[i];
+    for (unsigned j = 0, ee = CI.Codes.size(); j != ee; ++j) {
+      TargetLowering::ConstraintType CType = TLI.getConstraintType(CI.Codes[j]);
+      if (CType == TargetLowering::C_Memory)
+        return true;
+    }
+  }
+
+  return false;
+}
 
 /// visitInlineAsm - Handle a call to an InlineAsm object.
 ///
@@ -4652,6 +4668,8 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
   // constraint.  If so, we can't let the register allocator allocate any input
   // registers, because it will not know to avoid the earlyclobbered output reg.
   bool SawEarlyClobber = false;
+
+  bool hasMemory = hasInlineAsmMemConstraint(ConstraintInfos, TLI);
   
   unsigned ArgNo = 0;   // ArgNo - The argument of the CallInst.
   unsigned ResNo = 0;   // ResNo - The result number of the next output.
@@ -4724,7 +4742,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
     OpInfo.ConstraintVT = OpVT;
     
     // Compute the constraint code and ConstraintType to use.
-    TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG);
+    TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, hasMemory, &DAG);
 
     // Keep track of whether we see an earlyclobber.
     SawEarlyClobber |= OpInfo.isEarlyClobber;
@@ -4927,7 +4945,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
         
         std::vector<SDValue> Ops;
         TLI.LowerAsmOperandForConstraint(InOperandVal, OpInfo.ConstraintCode[0],
-                                         Ops, DAG);
+                                         hasMemory, Ops, DAG);
         if (Ops.empty()) {
           cerr << "Invalid operand for inline asm constraint '"
                << OpInfo.ConstraintCode << "'!\n";
index a85890a433faaffe296dd618ded0323efa9e8350..a9078b1e513bda6d963e6abce8c981ed0597a78a 100644 (file)
@@ -1855,6 +1855,7 @@ const char *TargetLowering::LowerXConstraint(MVT ConstraintVT) const{
 /// vector.  If it is invalid, don't add anything to Ops.
 void TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
                                                   char ConstraintLetter,
+                                                  bool hasMemory,
                                                   std::vector<SDValue> &Ops,
                                                   SelectionDAG &DAG) const {
   switch (ConstraintLetter) {
@@ -1997,7 +1998,7 @@ static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) {
 ///     'm' over 'r', for example.
 ///
 static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
-                             const TargetLowering &TLI,
+                             bool hasMemory,  const TargetLowering &TLI,
                              SDValue Op, SelectionDAG *DAG) {
   assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options");
   unsigned BestIdx = 0;
@@ -2017,7 +2018,7 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
       assert(OpInfo.Codes[i].size() == 1 &&
              "Unhandled multi-letter 'other' constraint");
       std::vector<SDValue> ResultOps;
-      TLI.LowerAsmOperandForConstraint(Op, OpInfo.Codes[i][0],
+      TLI.LowerAsmOperandForConstraint(Op, OpInfo.Codes[i][0], hasMemory,
                                        ResultOps, *DAG);
       if (!ResultOps.empty()) {
         BestType = CType;
@@ -2044,6 +2045,7 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
 /// OpInfo.ConstraintCode and OpInfo.ConstraintType.
 void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo,
                                             SDValue Op, 
+                                            bool hasMemory,
                                             SelectionDAG *DAG) const {
   assert(!OpInfo.Codes.empty() && "Must have at least one constraint");
   
@@ -2052,7 +2054,7 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo,
     OpInfo.ConstraintCode = OpInfo.Codes[0];
     OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode);
   } else {
-    ChooseConstraint(OpInfo, *this, Op, DAG);
+    ChooseConstraint(OpInfo, hasMemory, *this, Op, DAG);
   }
   
   // 'X' matches anything.
index ab64aae9262dd680ddec5f8c1e5ebc2bbcec0c0c..285c5b6f1e6a47649bd252772c6bf58bb234b56c 100644 (file)
@@ -3040,10 +3040,12 @@ SPUTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op,
 void
 SPUTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
                                                 char ConstraintLetter,
+                                                bool hasMemory,
                                                 std::vector<SDValue> &Ops,
                                                 SelectionDAG &DAG) const {
   // Default, for the time being, to the base class handler
-  TargetLowering::LowerAsmOperandForConstraint(Op, ConstraintLetter, Ops, DAG);
+  TargetLowering::LowerAsmOperandForConstraint(Op, ConstraintLetter, hasMemory,
+                                               Ops, DAG);
 }
 
 /// isLegalAddressImmediate - Return true if the integer value can be used
index 3c09d9f467ea8adae7893ecd9502f25b91fcee8e..e79b1363f21ab8a1fff52befd3790fef033dea43 100644 (file)
@@ -131,6 +131,7 @@ namespace llvm {
                                    MVT VT) const;
 
     void LowerAsmOperandForConstraint(SDValue Op, char ConstraintLetter,
+                                      bool hasMemory, 
                                       std::vector<SDValue> &Ops,
                                       SelectionDAG &DAG) const;
 
index cfffa8610466bf9b84aa479560b6ebdad2431683..30beb93e052eaea06866d046cf5b31ce447c8673 100644 (file)
@@ -4763,8 +4763,11 @@ PPCTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
 
 
 /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
-/// vector.  If it is invalid, don't add anything to Ops.
+/// vector.  If it is invalid, don't add anything to Ops. If hasMemory is true
+/// it means one of the asm constraint of the inline asm instruction being
+/// processed is 'm'.
 void PPCTargetLowering::LowerAsmOperandForConstraint(SDValue Op, char Letter,
+                                                     bool hasMemory,
                                                      std::vector<SDValue>&Ops,
                                                      SelectionDAG &DAG) const {
   SDValue Result(0,0);
@@ -4823,7 +4826,7 @@ void PPCTargetLowering::LowerAsmOperandForConstraint(SDValue Op, char Letter,
   }
   
   // Handle standard constraint letters.
-  TargetLowering::LowerAsmOperandForConstraint(Op, Letter, Ops, DAG);
+  TargetLowering::LowerAsmOperandForConstraint(Op, Letter, hasMemory, Ops, DAG);
 }
 
 // isLegalAddressingMode - Return true if the addressing mode represented
index c0c22247ed76b48cbb19ce9a86ed404cc601bdfe..fa689de058ca23250d46ff4c7c3b1926f5d4487d 100644 (file)
@@ -300,9 +300,12 @@ namespace llvm {
     unsigned getByValTypeAlignment(const Type *Ty) const;
 
     /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
-    /// vector.  If it is invalid, don't add anything to Ops.
+    /// vector.  If it is invalid, don't add anything to Ops. If hasMemory is
+    /// true it means one of the asm constraint of the inline asm instruction
+    /// being processed is 'm'.
     virtual void LowerAsmOperandForConstraint(SDValue Op,
                                               char ConstraintLetter,
+                                              bool hasMemory,
                                               std::vector<SDValue> &Ops,
                                               SelectionDAG &DAG) const;
     
index f9a682894c79462aee792f90bcc991fc868df362..f72392df836179353adc3b3bbebe8a23863e71f3 100644 (file)
@@ -767,7 +767,7 @@ void X86DAGToDAGISel::EmitFunctionEntryCode(Function &Fn, MachineFunction &MF) {
 /// addressing mode.
 bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM,
                                    bool isRoot, unsigned Depth) {
-DOUT << "MatchAddress: "; DEBUG(AM.dump());
+  DOUT << "MatchAddress: "; DEBUG(AM.dump());
   // Limit recursion.
   if (Depth > 5)
     return MatchAddressBase(N, AM, isRoot, Depth);
index 18d0f6c78cab79ac92351a0a3b3b25c33dfc3317..76d3ba8c86a823a2e369bd3e8b26f83e2ab63031 100644 (file)
@@ -1593,7 +1593,7 @@ SDValue X86TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
   if (CallRequiresFnAddressInReg(Is64Bit, IsTailCall)) {
     // Note: The actual moving to ecx is done further down.
     GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee);
-    if (G &&  !G->getGlobal()->hasHiddenVisibility() &&
+    if (G && !G->getGlobal()->hasHiddenVisibility() &&
         !G->getGlobal()->hasProtectedVisibility())
       Callee =  LowerGlobalAddress(Callee, DAG);
     else if (isa<ExternalSymbolSDNode>(Callee))
@@ -4300,8 +4300,8 @@ X86TargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) {
 }
 
 SDValue
-X86TargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) {
-  GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+X86TargetLowering::LowerGlobalAddress(const GlobalValue *GV,
+                                      SelectionDAG &DAG) const {
   SDValue Result = DAG.getTargetGlobalAddress(GV, getPointerTy());
   Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(), Result);
   // With PIC, the address is actually $g + Offset.
@@ -4324,6 +4324,12 @@ X86TargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) {
   return Result;
 }
 
+SDValue
+X86TargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) {
+  const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+  return LowerGlobalAddress(GV, DAG);
+}
+
 // Lower ISD::GlobalTLSAddress using the "general dynamic" model, 32 bit
 static SDValue
 LowerToTLSGeneralDynamicModel32(GlobalAddressSDNode *GA, SelectionDAG &DAG,
@@ -7067,6 +7073,7 @@ LowerXConstraint(MVT ConstraintVT) const {
 /// vector.  If it is invalid, don't add anything to Ops.
 void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
                                                      char Constraint,
+                                                     bool hasMemory,
                                                      std::vector<SDValue>&Ops,
                                                      SelectionDAG &DAG) const {
   SDValue Result(0, 0);
@@ -7128,14 +7135,11 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
     }
     
     if (GA) {
-      // If addressing this global requires a load (e.g. in PIC mode), we can't
-      // match.
-      if (Subtarget->GVRequiresExtraLoad(GA->getGlobal(), getTargetMachine(),
-                                         false))
-        return;
-
-      Op = DAG.getTargetGlobalAddress(GA->getGlobal(), GA->getValueType(0),
-                                      Offset);
+      if (hasMemory) 
+        Op = LowerGlobalAddress(GA->getGlobal(), DAG);
+      else
+        Op = DAG.getTargetGlobalAddress(GA->getGlobal(), GA->getValueType(0),
+                                        Offset);
       Result = Op;
       break;
     }
@@ -7149,7 +7153,8 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
     Ops.push_back(Result);
     return;
   }
-  return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+  return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, hasMemory,
+                                                      Ops, DAG);
 }
 
 std::vector<unsigned> X86TargetLowering::
index 875787a53aac32a16535acfb0b2840c2d4dd2a89..a2d8a11dc3f60383f9612bfd84a83b0b0acb2c2d 100644 (file)
@@ -403,9 +403,12 @@ namespace llvm {
     virtual const char *LowerXConstraint(MVT ConstraintVT) const;
 
     /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
-    /// vector.  If it is invalid, don't add anything to Ops.
+    /// vector.  If it is invalid, don't add anything to Ops. If hasMemory is
+    /// true it means one of the asm constraint of the inline asm instruction
+    /// being processed is 'm'.
     virtual void LowerAsmOperandForConstraint(SDValue Op,
                                               char ConstraintLetter,
+                                              bool hasMemory,
                                               std::vector<SDValue> &Ops,
                                               SelectionDAG &DAG) const;
     
@@ -529,6 +532,7 @@ namespace llvm {
     SDValue LowerINSERT_VECTOR_ELT_SSE4(SDValue Op, SelectionDAG &DAG);
     SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG);
     SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG);
+    SDValue LowerGlobalAddress(const GlobalValue *GV, SelectionDAG &DAG) const;
     SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG);
     SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG);
     SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG);
diff --git a/test/CodeGen/X86/inline-asm-pic.ll b/test/CodeGen/X86/inline-asm-pic.ll
new file mode 100644 (file)
index 0000000..04ad48d
--- /dev/null
@@ -0,0 +1,10 @@
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin -relocation-model=pic | grep lea
+; RUN: llvm-as < %s | llc -mtriple=i386-apple-darwin -relocation-model=pic | grep call
+
+@main_q = internal global i8* null             ; <i8**> [#uses=1]
+
+define void @func2() nounwind {
+entry:
+       tail call void asm "mov $1,%gs:$0", "=*m,ri,~{dirflag},~{fpsr},~{flags}"(i8** inttoptr (i32 152 to i8**), i8* bitcast (i8** @main_q to i8*)) nounwind
+       ret void
+}