[llvm-commits] [llvm] r68218 - in /llvm/trunk: lib/Target/ARM/ARMISelLowering.cpp lib/Target/ARM/ARMISelLowering.h test/CodeGen/ARM/inlineasm-imm-arm.ll test/CodeGen/ARM/inlineasm-imm-thumb.ll

Bob Wilson bob.wilson at apple.com
Wed Apr 1 10:58:54 PDT 2009


Author: bwilson
Date: Wed Apr  1 12:58:54 2009
New Revision: 68218

URL: http://llvm.org/viewvc/llvm-project?rev=68218&view=rev
Log:
Fix PR3862: Recognize some ARM-specific constraints for immediates in inline
assembly.

Added:
    llvm/trunk/test/CodeGen/ARM/inlineasm-imm-arm.ll
    llvm/trunk/test/CodeGen/ARM/inlineasm-imm-thumb.ll
Modified:
    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
    llvm/trunk/lib/Target/ARM/ARMISelLowering.h

Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=68218&r1=68217&r2=68218&view=diff

==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Wed Apr  1 12:58:54 2009
@@ -2014,3 +2014,138 @@
 
   return std::vector<unsigned>();
 }
+
+/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
+/// vector.  If it is invalid, don't add anything to Ops.
+void ARMTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
+                                                     char Constraint,
+                                                     bool hasMemory,
+                                                     std::vector<SDValue>&Ops,
+                                                     SelectionDAG &DAG) const {
+  SDValue Result(0, 0);
+
+  switch (Constraint) {
+  default: break;
+  case 'I': case 'J': case 'K': case 'L':
+  case 'M': case 'N': case 'O':
+    ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
+    if (!C)
+      return;
+
+    int64_t CVal64 = C->getSExtValue();
+    int CVal = (int) CVal64;
+    // None of these constraints allow values larger than 32 bits.  Check
+    // that the value fits in an int.
+    if (CVal != CVal64)
+      return;
+
+    switch (Constraint) {
+      case 'I':
+        if (Subtarget->isThumb()) {
+          // This must be a constant between 0 and 255, for ADD immediates.
+          if (CVal >= 0 && CVal <= 255)
+            break;
+        } else {
+          // A constant that can be used as an immediate value in a
+          // data-processing instruction.
+          if (ARM_AM::getSOImmVal(CVal) != -1)
+            break;
+        }
+        return;
+
+      case 'J':
+        if (Subtarget->isThumb()) {
+          // This must be a constant between -255 and -1, for negated ADD
+          // immediates. This can be used in GCC with an "n" modifier that
+          // prints the negated value, for use with SUB instructions. It is
+          // not useful otherwise but is implemented for compatibility.
+          if (CVal >= -255 && CVal <= -1)
+            break;
+        } else {
+          // This must be a constant between -4095 and 4095. It is not clear
+          // what this constraint is intended for. Implemented for
+          // compatibility with GCC.
+          if (CVal >= -4095 && CVal <= 4095)
+            break;
+        }
+        return;
+
+      case 'K':
+        if (Subtarget->isThumb()) {
+          // A 32-bit value where only one byte has a nonzero value. Exclude
+          // zero to match GCC. This constraint is used by GCC internally for
+          // constants that can be loaded with a move/shift combination.
+          // It is not useful otherwise but is implemented for compatibility.
+          if (CVal != 0 && ARM_AM::isThumbImmShiftedVal(CVal))
+            break;
+        } else {
+          // A constant whose bitwise inverse can be used as an immediate
+          // value in a data-processing instruction. This can be used in GCC
+          // with a "B" modifier that prints the inverted value, for use with
+          // BIC and MVN instructions. It is not useful otherwise but is
+          // implemented for compatibility.
+          if (ARM_AM::getSOImmVal(~CVal) != -1)
+            break;
+        }
+        return;
+
+      case 'L':
+        if (Subtarget->isThumb()) {
+          // This must be a constant between -7 and 7,
+          // for 3-operand ADD/SUB immediate instructions.
+          if (CVal >= -7 && CVal < 7)
+            break;
+        } else {
+          // A constant whose negation can be used as an immediate value in a
+          // data-processing instruction. This can be used in GCC with an "n"
+          // modifier that prints the negated value, for use with SUB
+          // instructions. It is not useful otherwise but is implemented for
+          // compatibility.
+          if (ARM_AM::getSOImmVal(-CVal) != -1)
+            break;
+        }
+        return;
+
+      case 'M':
+        if (Subtarget->isThumb()) {
+          // This must be a multiple of 4 between 0 and 1020, for
+          // ADD sp + immediate.
+          if ((CVal >= 0 && CVal <= 1020) && ((CVal & 3) == 0))
+            break;
+        } else {
+          // A power of two or a constant between 0 and 32.  This is used in
+          // GCC for the shift amount on shifted register operands, but it is
+          // useful in general for any shift amounts.
+          if ((CVal >= 0 && CVal <= 32) || ((CVal & (CVal - 1)) == 0))
+            break;
+        }
+        return;
+
+      case 'N':
+        if (Subtarget->isThumb()) {
+          // This must be a constant between 0 and 31, for shift amounts.
+          if (CVal >= 0 && CVal <= 31)
+            break;
+        }
+        return;
+
+      case 'O':
+        if (Subtarget->isThumb()) {
+          // This must be a multiple of 4 between -508 and 508, for
+          // ADD/SUB sp = sp + immediate.
+          if ((CVal >= -508 && CVal <= 508) && ((CVal & 3) == 0))
+            break;
+        }
+        return;
+    }
+    Result = DAG.getTargetConstant(CVal, Op.getValueType());
+    break;
+  }
+
+  if (Result.getNode()) {
+    Ops.push_back(Result);
+    return;
+  }
+  return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, hasMemory,
+                                                      Ops, DAG);
+}

Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.h?rev=68218&r1=68217&r2=68218&view=diff

==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.h (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.h Wed Apr  1 12:58:54 2009
@@ -124,6 +124,16 @@
     getRegClassForInlineAsmConstraint(const std::string &Constraint,
                                       MVT VT) const;
 
+    /// LowerAsmOperandForConstraint - Lower the specified operand into the 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;
+    
     virtual const ARMSubtarget* getSubtarget() {
       return Subtarget;
     }

Added: llvm/trunk/test/CodeGen/ARM/inlineasm-imm-arm.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/inlineasm-imm-arm.ll?rev=68218&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/ARM/inlineasm-imm-arm.ll (added)
+++ llvm/trunk/test/CodeGen/ARM/inlineasm-imm-arm.ll Wed Apr  1 12:58:54 2009
@@ -0,0 +1,31 @@
+; RUN: llvm-as < %s | llc -march=arm
+
+; Test ARM-mode "I" constraint, for any Data Processing immediate.
+define i32 @testI(i32 %x) {
+	%y = call i32 asm "add $0, $1, $2", "=r,r,I"( i32 %x, i32 65280 ) nounwind
+	ret i32 %y
+}
+
+; Test ARM-mode "J" constraint, for compatibility with unknown use in GCC.
+define void @testJ() {
+	tail call void asm sideeffect ".word $0", "J"( i32 4080 ) nounwind
+	ret void
+}
+
+; Test ARM-mode "K" constraint, for bitwise inverted Data Processing immediates.
+define void @testK() {
+	tail call void asm sideeffect ".word $0", "K"( i32 16777215 ) nounwind
+	ret void
+}
+
+; Test ARM-mode "L" constraint, for negated Data Processing immediates.
+define void @testL() {
+	tail call void asm sideeffect ".word $0", "L"( i32 -65280 ) nounwind
+	ret void
+}
+
+; Test ARM-mode "M" constraint, for value between 0 and 32.
+define i32 @testM(i32 %x) {
+	%y = call i32 asm "lsl $0, $1, $2", "=r,r,M"( i32 %x, i32 31 ) nounwind
+	ret i32 %y
+}

Added: llvm/trunk/test/CodeGen/ARM/inlineasm-imm-thumb.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/inlineasm-imm-thumb.ll?rev=68218&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/ARM/inlineasm-imm-thumb.ll (added)
+++ llvm/trunk/test/CodeGen/ARM/inlineasm-imm-thumb.ll Wed Apr  1 12:58:54 2009
@@ -0,0 +1,43 @@
+; RUN: llvm-as < %s | llc -march=thumb
+
+; Test Thumb-mode "I" constraint, for ADD immediate.
+define i32 @testI(i32 %x) {
+	%y = call i32 asm "add $0, $1, $2", "=r,r,I"( i32 %x, i32 255 ) nounwind
+	ret i32 %y
+}
+
+; Test Thumb-mode "J" constraint, for negated ADD immediates.
+define void @testJ() {
+	tail call void asm sideeffect ".word $0", "J"( i32 -255 ) nounwind
+	ret void
+}
+
+; Test Thumb-mode "K" constraint, for compatibility with GCC's internal use.
+define void @testK() {
+	tail call void asm sideeffect ".word $0", "K"( i32 65280 ) nounwind
+	ret void
+}
+
+; Test Thumb-mode "L" constraint, for 3-operand ADD immediates.
+define i32 @testL(i32 %x) {
+	%y = call i32 asm "add $0, $1, $2", "=r,r,L"( i32 %x, i32 -7 ) nounwind
+	ret i32 %y
+}
+
+; Test Thumb-mode "M" constraint, for "ADD r = sp + imm".
+define i32 @testM() {
+	%y = call i32 asm "add $0, sp, $1", "=r,M"( i32 1020 ) nounwind
+	ret i32 %y
+}
+
+; Test Thumb-mode "N" constraint, for values between 0 and 31.
+define i32 @testN(i32 %x) {
+	%y = call i32 asm "lsl $0, $1, $2", "=r,r,N"( i32 %x, i32 31 ) nounwind
+	ret i32 %y
+}
+
+; Test Thumb-mode "O" constraint, for "ADD sp = sp + imm".
+define void @testO() {
+	tail call void asm sideeffect "add sp, sp, $0; add sp, sp, $1", "O,O"( i32 -508, i32 508 ) nounwind
+        ret void
+}





More information about the llvm-commits mailing list