[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