mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Fix PR3862: Recognize some ARM-specific constraints for immediates in inline
assembly. llvm-svn: 68218
This commit is contained in:
parent
a134448980
commit
5b42ebe6a9
@ -2014,3 +2014,138 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint,
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -124,6 +124,16 @@ namespace llvm {
|
||||
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;
|
||||
}
|
||||
|
31
test/CodeGen/ARM/inlineasm-imm-arm.ll
Normal file
31
test/CodeGen/ARM/inlineasm-imm-arm.ll
Normal file
@ -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
|
||||
}
|
43
test/CodeGen/ARM/inlineasm-imm-thumb.ll
Normal file
43
test/CodeGen/ARM/inlineasm-imm-thumb.ll
Normal file
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user