Implement a signficant optimization for inline asm:
authorChris Lattner <sabre@nondot.org>
Sun, 27 Apr 2008 00:37:18 +0000 (00:37 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 27 Apr 2008 00:37:18 +0000 (00:37 +0000)
When choosing between constraints with multiple options,
like "ir", test to see if we can use the 'i' constraint and
go with that if possible.  This produces more optimal ASM in
all cases (sparing a register and an instruction to load it),
and fixes inline asm like this:

void test () {
  asm volatile (" %c0 %1 " : : "imr" (42), "imr"(14));
}

Previously we would dump "42" into a memory location (which
is ok for the 'm' constraint) which would cause a problem
because the 'c' modifier is not valid on memory operands.

Isn't it great how inline asm turns 'missed optimization'
into 'compile failed'??

Incidentally, this was the todo in
PowerPC/2007-04-24-InlineAsm-I-Modifier.ll

Please do NOT pull this into Tak.

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

include/llvm/Target/TargetLowering.h
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/CodeGen/SelectionDAG/TargetLowering.cpp
lib/Transforms/Scalar/CodeGenPrepare.cpp
test/CodeGen/PowerPC/2007-04-24-InlineAsm-I-Modifier.ll
test/CodeGen/X86/2008-04-26-Asm-Optimize-Imm.ll [new file with mode: 0644]

index 559f0387ace1f3781b2c7d69be0727a2dccb7d41..9b4c8af95dc3b5271066a01c9bbd6764491fecc1 100644 (file)
@@ -109,7 +109,8 @@ public:
   /// srl/add/sra.
   bool isPow2DivCheap() const { return Pow2DivIsCheap; }
 
-  /// getSetCCResultType - Return the ValueType of the result of setcc operations.
+  /// getSetCCResultType - Return the ValueType of the result of setcc
+  /// operations.
   virtual MVT::ValueType getSetCCResultType(const SDOperand &) const;
 
   /// getSetCCResultContents - For targets without boolean registers, this flag
@@ -1080,8 +1081,12 @@ public:
 
   /// ComputeConstraintToUse - Determines the constraint code and constraint
   /// type to use for the specific AsmOperandInfo, setting
-  /// OpInfo.ConstraintCode and OpInfo.ConstraintType.
-  virtual void ComputeConstraintToUse(AsmOperandInfo &OpInfo) const;
+  /// OpInfo.ConstraintCode and OpInfo.ConstraintType.  If the actual operand
+  /// being passed in is available, it can be passed in as Op, otherwise an
+  /// empty SDOperand can be passed.
+  virtual void ComputeConstraintToUse(AsmOperandInfo &OpInfo,
+                                      SDOperand Op,
+                                      SelectionDAG *DAG = 0) const;
   
   /// getConstraintType - Given a constraint, return the type of constraint it
   /// is for this target.
@@ -1130,7 +1135,7 @@ public:
   // insert.  The specified MachineInstr is created but not inserted into any
   // basic blocks, and the scheduler passes ownership of it to this method.
   virtual MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI,
-                                                         MachineBasicBlock *MBB);
+                                                        MachineBasicBlock *MBB);
 
   //===--------------------------------------------------------------------===//
   // Addressing mode description hooks (used by LSR etc).
index 7e8b61465ad42675aebc862418510f5148318890..b63470ffd12d88f7888a398d5001d82d1a485549 100644 (file)
@@ -3822,7 +3822,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
     OpInfo.ConstraintVT = OpVT;
     
     // Compute the constraint code and ConstraintType to use.
-    TLI.ComputeConstraintToUse(OpInfo);
+    TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG);
 
     // Keep track of whether we see an earlyclobber.
     SawEarlyClobber |= OpInfo.isEarlyClobber;
index cd43349411ee317327c94ad252a0f901c9738816..dd9d96cca67f605a8409b86f51e3cb82cfe8badb 100644 (file)
@@ -1688,7 +1688,8 @@ static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) {
 ///     'm' over 'r', for example.
 ///
 static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
-                             const TargetLowering &TLI) {
+                             const TargetLowering &TLI,
+                             SDOperand Op, SelectionDAG *DAG) {
   assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options");
   unsigned BestIdx = 0;
   TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown;
@@ -1699,6 +1700,23 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
     TargetLowering::ConstraintType CType =
       TLI.getConstraintType(OpInfo.Codes[i]);
     
+    // If this is an 'other' constraint, see if the operand is valid for it.
+    // For example, on X86 we might have an 'rI' constraint.  If the operand
+    // is an integer in the range [0..31] we want to use I (saving a load
+    // of a register), otherwise we must use 'r'.
+    if (CType == TargetLowering::C_Other && Op.Val) {
+      assert(OpInfo.Codes[i].size() == 1 &&
+             "Unhandled multi-letter 'other' constraint");
+      std::vector<SDOperand> ResultOps;
+      TLI.LowerAsmOperandForConstraint(Op, OpInfo.Codes[i][0],
+                                       ResultOps, *DAG);
+      if (!ResultOps.empty()) {
+        BestType = CType;
+        BestIdx = i;
+        break;
+      }
+    }
+    
     // This constraint letter is more general than the previous one, use it.
     int Generality = getConstraintGenerality(CType);
     if (Generality > BestGenerality) {
@@ -1715,7 +1733,9 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
 /// ComputeConstraintToUse - Determines the constraint code and constraint
 /// type to use for the specific AsmOperandInfo, setting
 /// OpInfo.ConstraintCode and OpInfo.ConstraintType.
-void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo) const {
+void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo,
+                                            SDOperand Op, 
+                                            SelectionDAG *DAG) const {
   assert(!OpInfo.Codes.empty() && "Must have at least one constraint");
   
   // Single-letter constraints ('r') are very common.
@@ -1723,7 +1743,7 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo) const {
     OpInfo.ConstraintCode = OpInfo.Codes[0];
     OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode);
   } else {
-    ChooseConstraint(OpInfo, *this);
+    ChooseConstraint(OpInfo, *this, Op, DAG);
   }
   
   // 'X' matches anything.
index cdabadeb36255aacff8c5607f44289129bb79494..87c9374b2ff371ba5bbdf3ff336b3e7be010ea03 100644 (file)
@@ -962,7 +962,7 @@ bool CodeGenPrepare::OptimizeInlineAsmInst(Instruction *I, CallSite CS,
     }
 
     // Compute the constraint code and ConstraintType to use.
-    TLI->ComputeConstraintToUse(OpInfo);
+    TLI->ComputeConstraintToUse(OpInfo, SDOperand());
 
     if (OpInfo.ConstraintType == TargetLowering::C_Memory &&
         OpInfo.isIndirect) {
index 8405703b0eafe17d367b331bf459271df1060b4c..656b83192e0055d7f5f73fbd95ae154028f8780e 100644 (file)
@@ -1,15 +1,14 @@
 ; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {foo r3, r4}
-; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {bar r3, r}
+; RUN: llvm-as < %s | llc -march=ppc32 -mtriple=powerpc-apple-darwin8.8.0 | grep {bari r3, 47}
 
 ; PR1351
 
-define i32 @test1(i32 %Y, i32 %X) {
+define i32 @test1(i32 %Y, i32 %X) nounwind {
        %tmp1 = tail call i32 asm "foo${1:I} $0, $1", "=r,rI"( i32 %X )
        ret i32 %tmp1
 }
 
-;; TODO: We'd actually prefer this to be 'bari r3, 47', but 'bar r3, rN' is also ok.
-define i32 @test2(i32 %Y, i32 %X) {
+define i32 @test2(i32 %Y, i32 %X) nounwind {
        %tmp1 = tail call i32 asm "bar${1:I} $0, $1", "=r,rI"( i32 47 )
        ret i32 %tmp1
 }
diff --git a/test/CodeGen/X86/2008-04-26-Asm-Optimize-Imm.ll b/test/CodeGen/X86/2008-04-26-Asm-Optimize-Imm.ll
new file mode 100644 (file)
index 0000000..82721a5
--- /dev/null
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llc | grep {1 \$2 3}
+; rdar://5720231
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+target triple = "i386-apple-darwin8"
+
+define void @test() nounwind  {
+entry:
+       tail call void asm sideeffect " ${0:c} $1 ${2:c} ", "imr,imr,i,~{dirflag},~{fpsr},~{flags}"( i32 1, i32 2, i32 3 ) nounwind 
+       ret void
+}
+