Fix PR4152: asm constraint validation happens before dag combine, so we
authorChris Lattner <sabre@nondot.org>
Fri, 8 May 2009 18:23:14 +0000 (18:23 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 8 May 2009 18:23:14 +0000 (18:23 +0000)
need to work a bit to combine things like (x+c1+c2) into x+c3.

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

lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/2009-05-08-InlineAsmIOffset.ll [new file with mode: 0644]

index 72aadef384fb9ad5a4f052d03cfcc7380dcda77f..9ac59df5bd9decc5691e96e42b0969299ebae81d 100644 (file)
@@ -8519,40 +8519,39 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
 
     // If we are in non-pic codegen mode, we allow the address of a global (with
     // an optional displacement) to be used with 'i'.
-    GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op);
+    GlobalAddressSDNode *GA = 0;
     int64_t Offset = 0;
 
-    // Match either (GA) or (GA+C)
-    if (GA) {
-      Offset = GA->getOffset();
-    } else if (Op.getOpcode() == ISD::ADD) {
-      ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1));
-      GA = dyn_cast<GlobalAddressSDNode>(Op.getOperand(0));
-      if (C && GA) {
-        Offset = GA->getOffset()+C->getZExtValue();
-      } else {
-        C = dyn_cast<ConstantSDNode>(Op.getOperand(1));
-        GA = dyn_cast<GlobalAddressSDNode>(Op.getOperand(0));
-        if (C && GA)
-          Offset = GA->getOffset()+C->getZExtValue();
-        else
-          C = 0, GA = 0;
+    // Match either (GA), (GA+C), (GA+C1+C2), etc.
+    while (1) {
+      if ((GA = dyn_cast<GlobalAddressSDNode>(Op))) {
+        Offset += GA->getOffset();
+        break;
+      } else if (Op.getOpcode() == ISD::ADD) {
+        if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
+          Offset += C->getZExtValue();
+          Op = Op.getOperand(0);
+          continue;
+        }
+      } else if (Op.getOpcode() == ISD::SUB) {
+        if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
+          Offset += -C->getZExtValue();
+          Op = Op.getOperand(0);
+          continue;
+        }
       }
+      
+      // Otherwise, this isn't something we can handle, reject it.
+      return;
     }
 
-    if (GA) {
-      if (hasMemory)
-        Op = LowerGlobalAddress(GA->getGlobal(), Op.getDebugLoc(),
-                                Offset, DAG);
-      else
-        Op = DAG.getTargetGlobalAddress(GA->getGlobal(), GA->getValueType(0),
-                                        Offset);
-      Result = Op;
-      break;
-    }
-
-    // Otherwise, not valid for this mode.
-    return;
+    if (hasMemory)
+      Op = LowerGlobalAddress(GA->getGlobal(), Op.getDebugLoc(), Offset, DAG);
+    else
+      Op = DAG.getTargetGlobalAddress(GA->getGlobal(), GA->getValueType(0),
+                                      Offset);
+    Result = Op;
+    break;
   }
   }
 
diff --git a/test/CodeGen/X86/2009-05-08-InlineAsmIOffset.ll b/test/CodeGen/X86/2009-05-08-InlineAsmIOffset.ll
new file mode 100644 (file)
index 0000000..284c6e2
--- /dev/null
@@ -0,0 +1,17 @@
+; RUN: llvm-as < %s | llc -relocation-model=static > %t
+; RUN: grep "1: ._pv_cpu_ops+8" %t
+; RUN: grep "2: ._G" %t
+; PR4152
+
+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-darwin9.6"
+       %struct.pv_cpu_ops = type { i32, [2 x i32] }
+@pv_cpu_ops = external global %struct.pv_cpu_ops               ; <%struct.pv_cpu_ops*> [#uses=1]
+@G = external global i32               ; <i32*> [#uses=1]
+
+define void @x() nounwind {
+entry:
+       tail call void asm sideeffect "1: $0", "i,~{dirflag},~{fpsr},~{flags}"(i32* getelementptr (%struct.pv_cpu_ops* @pv_cpu_ops, i32 0, i32 1, i32 1)) nounwind
+       tail call void asm sideeffect "2: $0", "i,~{dirflag},~{fpsr},~{flags}"(i32* @G) nounwind
+       ret void
+}