Skip to content

Commit 41a2847

Browse files
committed
Emit diagnostic if an inline asm constraint requires an immediate
Summary: An inline asm call can result in an immediate after inlining. Therefore emit a diagnostic here if constraint requires an immediate but one isn't supplied. Reviewers: joerg, mgorny, efriedma, rsmith Reviewed By: joerg Subscribers: asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, s.egerton, MaskRay, jyknight, dylanmckay, javed.absar, fedor.sergeev, jrtc27, Jim, krytarowski, eraman, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D60942 llvm-svn: 367750
1 parent 10bf563 commit 41a2847

21 files changed

+117
-40
lines changed

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3742,6 +3742,7 @@ class TargetLowering : public TargetLoweringBase {
37423742
C_Register, // Constraint represents specific register(s).
37433743
C_RegisterClass, // Constraint represents any of register(s) in class.
37443744
C_Memory, // Memory constraint.
3745+
C_Immediate, // Requires an immediate.
37453746
C_Other, // Something else.
37463747
C_Unknown // Unsupported constraint.
37473748
};

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8049,6 +8049,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) {
80498049
// Compute the constraint code and ConstraintType to use.
80508050
TLI.ComputeConstraintToUse(T, SDValue());
80518051

8052+
if (T.ConstraintType == TargetLowering::C_Immediate &&
8053+
OpInfo.CallOperand && !isa<ConstantSDNode>(OpInfo.CallOperand))
8054+
// We've delayed emitting a diagnostic like the "n" constraint because
8055+
// inlining could cause an integer showing up.
8056+
return emitInlineAsmError(
8057+
CS, "constraint '" + Twine(T.ConstraintCode) + "' expects an "
8058+
"integer constant expression");
8059+
80528060
ExtraInfo.update(T);
80538061
}
80548062

@@ -8133,7 +8141,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) {
81338141
switch (OpInfo.Type) {
81348142
case InlineAsm::isOutput:
81358143
if (OpInfo.ConstraintType == TargetLowering::C_Memory ||
8136-
(OpInfo.ConstraintType == TargetLowering::C_Other &&
8144+
((OpInfo.ConstraintType == TargetLowering::C_Immediate ||
8145+
OpInfo.ConstraintType == TargetLowering::C_Other) &&
81378146
OpInfo.isIndirect)) {
81388147
unsigned ConstraintID =
81398148
TLI.getInlineAsmMemConstraint(OpInfo.ConstraintCode);
@@ -8147,13 +8156,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) {
81478156
MVT::i32));
81488157
AsmNodeOperands.push_back(OpInfo.CallOperand);
81498158
break;
8150-
} else if ((OpInfo.ConstraintType == TargetLowering::C_Other &&
8159+
} else if (((OpInfo.ConstraintType == TargetLowering::C_Immediate ||
8160+
OpInfo.ConstraintType == TargetLowering::C_Other) &&
81518161
!OpInfo.isIndirect) ||
81528162
OpInfo.ConstraintType == TargetLowering::C_Register ||
81538163
OpInfo.ConstraintType == TargetLowering::C_RegisterClass) {
81548164
// Otherwise, this outputs to a register (directly for C_Register /
8155-
// C_RegisterClass, and a target-defined fashion for C_Other). Find a
8156-
// register that we can use.
8165+
// C_RegisterClass, and a target-defined fashion for
8166+
// C_Immediate/C_Other). Find a register that we can use.
81578167
if (OpInfo.AssignedRegs.Regs.empty()) {
81588168
emitInlineAsmError(
81598169
CS, "couldn't allocate output register for constraint '" +
@@ -8233,15 +8243,24 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) {
82338243
}
82348244

82358245
// Treat indirect 'X' constraint as memory.
8236-
if (OpInfo.ConstraintType == TargetLowering::C_Other &&
8246+
if ((OpInfo.ConstraintType == TargetLowering::C_Immediate ||
8247+
OpInfo.ConstraintType == TargetLowering::C_Other) &&
82378248
OpInfo.isIndirect)
82388249
OpInfo.ConstraintType = TargetLowering::C_Memory;
82398250

8240-
if (OpInfo.ConstraintType == TargetLowering::C_Other) {
8251+
if (OpInfo.ConstraintType == TargetLowering::C_Immediate ||
8252+
OpInfo.ConstraintType == TargetLowering::C_Other) {
82418253
std::vector<SDValue> Ops;
82428254
TLI.LowerAsmOperandForConstraint(InOperandVal, OpInfo.ConstraintCode,
82438255
Ops, DAG);
82448256
if (Ops.empty()) {
8257+
if (OpInfo.ConstraintType == TargetLowering::C_Immediate)
8258+
if (isa<ConstantSDNode>(InOperandVal)) {
8259+
emitInlineAsmError(CS, "value out of range for constraint '" +
8260+
Twine(OpInfo.ConstraintCode) + "'");
8261+
return;
8262+
}
8263+
82458264
emitInlineAsmError(CS, "invalid operand for inline asm constraint '" +
82468265
Twine(OpInfo.ConstraintCode) + "'");
82478266
return;
@@ -8278,7 +8297,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) {
82788297
}
82798298

82808299
assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass ||
8281-
OpInfo.ConstraintType == TargetLowering::C_Register) &&
8300+
OpInfo.ConstraintType == TargetLowering::C_Register ||
8301+
OpInfo.ConstraintType == TargetLowering::C_Immediate) &&
82828302
"Unknown constraint type!");
82838303

82848304
// TODO: Support this.
@@ -8384,6 +8404,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) {
83848404
Val = OpInfo.AssignedRegs.getCopyFromRegs(
83858405
DAG, FuncInfo, getCurSDLoc(), Chain, &Flag, CS.getInstruction());
83868406
break;
8407+
case TargetLowering::C_Immediate:
83878408
case TargetLowering::C_Other:
83888409
Val = TLI.LowerAsmOutputForConstraint(Chain, Flag, getCurSDLoc(),
83898410
OpInfo, DAG);

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3873,15 +3873,17 @@ TargetLowering::getConstraintType(StringRef Constraint) const {
38733873
if (S == 1) {
38743874
switch (Constraint[0]) {
38753875
default: break;
3876-
case 'r': return C_RegisterClass;
3876+
case 'r':
3877+
return C_RegisterClass;
38773878
case 'm': // memory
38783879
case 'o': // offsetable
38793880
case 'V': // not offsetable
38803881
return C_Memory;
3881-
case 'i': // Simple Integer or Relocatable Constant
38823882
case 'n': // Simple Integer
38833883
case 'E': // Floating Point Constant
38843884
case 'F': // Floating Point Constant
3885+
return C_Immediate;
3886+
case 'i': // Simple Integer or Relocatable Constant
38853887
case 's': // Relocatable Constant
38863888
case 'p': // Address.
38873889
case 'X': // Allow ANY value.
@@ -4256,6 +4258,7 @@ TargetLowering::ParseConstraints(const DataLayout &DL,
42564258
/// Return an integer indicating how general CT is.
42574259
static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) {
42584260
switch (CT) {
4261+
case TargetLowering::C_Immediate:
42594262
case TargetLowering::C_Other:
42604263
case TargetLowering::C_Unknown:
42614264
return 0;
@@ -4375,11 +4378,12 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo,
43754378
TargetLowering::ConstraintType CType =
43764379
TLI.getConstraintType(OpInfo.Codes[i]);
43774380

4378-
// If this is an 'other' constraint, see if the operand is valid for it.
4379-
// For example, on X86 we might have an 'rI' constraint. If the operand
4380-
// is an integer in the range [0..31] we want to use I (saving a load
4381-
// of a register), otherwise we must use 'r'.
4382-
if (CType == TargetLowering::C_Other && Op.getNode()) {
4381+
// If this is an 'other' or 'immediate' constraint, see if the operand is
4382+
// valid for it. For example, on X86 we might have an 'rI' constraint. If
4383+
// the operand is an integer in the range [0..31] we want to use I (saving a
4384+
// load of a register), otherwise we must use 'r'.
4385+
if ((CType == TargetLowering::C_Other ||
4386+
CType == TargetLowering::C_Immediate) && Op.getNode()) {
43834387
assert(OpInfo.Codes[i].size() == 1 &&
43844388
"Unhandled multi-letter 'other' constraint");
43854389
std::vector<SDValue> ResultOps;

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5686,15 +5686,23 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const {
56865686
switch (Constraint[0]) {
56875687
default:
56885688
break;
5689-
case 'z':
5690-
return C_Other;
56915689
case 'x':
56925690
case 'w':
56935691
return C_RegisterClass;
56945692
// An address with a single base register. Due to the way we
56955693
// currently handle addresses it is the same as 'r'.
56965694
case 'Q':
56975695
return C_Memory;
5696+
case 'I':
5697+
case 'J':
5698+
case 'K':
5699+
case 'L':
5700+
case 'M':
5701+
case 'N':
5702+
case 'Y':
5703+
case 'Z':
5704+
return C_Immediate;
5705+
case 'z':
56985706
case 'S': // A symbolic address
56995707
return C_Other;
57005708
}

llvm/lib/Target/ARM/ARMISelLowering.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14976,20 +14976,21 @@ const char *ARMTargetLowering::LowerXConstraint(EVT ConstraintVT) const {
1497614976
/// constraint it is for this target.
1497714977
ARMTargetLowering::ConstraintType
1497814978
ARMTargetLowering::getConstraintType(StringRef Constraint) const {
14979-
if (Constraint.size() == 1) {
14979+
unsigned S = Constraint.size();
14980+
if (S == 1) {
1498014981
switch (Constraint[0]) {
1498114982
default: break;
1498214983
case 'l': return C_RegisterClass;
1498314984
case 'w': return C_RegisterClass;
1498414985
case 'h': return C_RegisterClass;
1498514986
case 'x': return C_RegisterClass;
1498614987
case 't': return C_RegisterClass;
14987-
case 'j': return C_Other; // Constant for movw.
14988-
// An address with a single base register. Due to the way we
14989-
// currently handle addresses it is the same as an 'r' memory constraint.
14988+
case 'j': return C_Immediate; // Constant for movw.
14989+
// An address with a single base register. Due to the way we
14990+
// currently handle addresses it is the same as an 'r' memory constraint.
1499014991
case 'Q': return C_Memory;
1499114992
}
14992-
} else if (Constraint.size() == 2) {
14993+
} else if (S == 2) {
1499314994
switch (Constraint[0]) {
1499414995
default: break;
1499514996
case 'T': return C_RegisterClass;

llvm/lib/Target/AVR/AVRISelLowering.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,8 @@ AVRTargetLowering::getConstraintType(StringRef Constraint) const {
16891689
if (Constraint.size() == 1) {
16901690
// See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
16911691
switch (Constraint[0]) {
1692+
default:
1693+
break;
16921694
case 'a': // Simple upper registers
16931695
case 'b': // Base pointer registers pairs
16941696
case 'd': // Upper register
@@ -1715,9 +1717,7 @@ AVRTargetLowering::getConstraintType(StringRef Constraint) const {
17151717
case 'O': // Integer constant (Range: 8, 16, 24)
17161718
case 'P': // Integer constant (Range: 1)
17171719
case 'R': // Integer constant (Range: -6 to 5)x
1718-
return C_Other;
1719-
default:
1720-
break;
1720+
return C_Immediate;
17211721
}
17221722
}
17231723

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,6 +2407,10 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const {
24072407
break;
24082408
case 'f':
24092409
return C_RegisterClass;
2410+
case 'I':
2411+
case 'J':
2412+
case 'K':
2413+
return C_Immediate;
24102414
}
24112415
}
24122416
return TargetLowering::getConstraintType(Constraint);

llvm/lib/Target/Sparc/SparcISelLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3183,7 +3183,7 @@ SparcTargetLowering::getConstraintType(StringRef Constraint) const {
31833183
case 'e':
31843184
return C_RegisterClass;
31853185
case 'I': // SIMM13
3186-
return C_Other;
3186+
return C_Immediate;
31873187
}
31883188
}
31893189

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ SystemZTargetLowering::getConstraintType(StringRef Constraint) const {
956956
case 'K': // Signed 16-bit constant
957957
case 'L': // Signed 20-bit displacement (on all targets we support)
958958
case 'M': // 0x7fffffff
959-
return C_Other;
959+
return C_Immediate;
960960

961961
default:
962962
break;

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44875,10 +44875,11 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const {
4487544875
case 'I':
4487644876
case 'J':
4487744877
case 'K':
44878-
case 'L':
44879-
case 'M':
4488044878
case 'N':
4488144879
case 'G':
44880+
case 'L':
44881+
case 'M':
44882+
return C_Immediate;
4488244883
case 'C':
4488344884
case 'e':
4488444885
case 'Z':

llvm/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
33

44
; Check for at least one invalid constant.
5-
; CHECK-ERRORS: error: invalid operand for inline asm constraint 'I'
5+
; CHECK-ERRORS: error: value out of range for constraint 'I'
66

77
define i32 @constraint_I(i32 %i, i32 %j) nounwind ssp {
88
entry:

llvm/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
33

44
; Check for at least one invalid constant.
5-
; CHECK-ERRORS: error: invalid operand for inline asm constraint 'J'
5+
; CHECK-ERRORS: error: value out of range for constraint 'J'
66

77
define i32 @constraint_J(i32 %i, i32 %j) nounwind ssp {
88
entry:

llvm/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
33

44
; Check for at least one invalid constant.
5-
; CHECK-ERRORS: error: invalid operand for inline asm constraint 'K'
5+
; CHECK-ERRORS: error: value out of range for constraint 'K'
66

77
define i32 @constraint_K(i32 %i, i32 %j) nounwind {
88
entry:

llvm/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
33

44
; Check for at least one invalid constant.
5-
; CHECK-ERRORS: error: invalid operand for inline asm constraint 'L'
5+
; CHECK-ERRORS: error: value out of range for constraint 'L'
66

77
define i32 @constraint_L(i32 %i, i32 %j) nounwind {
88
entry:

llvm/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
33

44
; Check for at least one invalid constant.
5-
; CHECK-ERRORS: error: invalid operand for inline asm constraint 'M'
5+
; CHECK-ERRORS: error: value out of range for constraint 'M'
66

77
define i32 @constraint_M(i32 %i, i32 %j) nounwind {
88
entry:

llvm/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
33

44
; Check for at least one invalid constant.
5-
; CHECK-ERRORS: error: invalid operand for inline asm constraint 'N'
5+
; CHECK-ERRORS: error: value out of range for constraint 'N'
66

77
define i32 @constraint_N(i32 %i, i32 %j) nounwind {
88
entry:

llvm/test/CodeGen/RISCV/inline-asm-invalid.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
; RUN: not llc -mtriple=riscv64 < %s 2>&1 | FileCheck %s
33

44
define void @constraint_I() {
5-
; CHECK: error: invalid operand for inline asm constraint 'I'
5+
; CHECK: error: value out of range for constraint 'I'
66
tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2048)
7-
; CHECK: error: invalid operand for inline asm constraint 'I'
7+
; CHECK: error: value out of range for constraint 'I'
88
tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2049)
99
ret void
1010
}
1111

1212
define void @constraint_J() {
13-
; CHECK: error: invalid operand for inline asm constraint 'J'
13+
; CHECK: error: value out of range for constraint 'J'
1414
tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 1)
1515
ret void
1616
}
1717

1818
define void @constraint_K() {
19-
; CHECK: error: invalid operand for inline asm constraint 'K'
19+
; CHECK: error: value out of range for constraint 'K'
2020
tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 32)
21-
; CHECK: error: invalid operand for inline asm constraint 'K'
21+
; CHECK: error: value out of range for constraint 'K'
2222
tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 -1)
2323
ret void
2424
}

llvm/test/CodeGen/X86/inline-asm-bad-constraint-n.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
@x = global i32 0, align 4
44

5-
;CHECK: error: invalid operand for inline asm constraint 'n'
5+
; CHECK: error: constraint 'n' expects an integer constant expression
66
define void @foo() {
77
%a = getelementptr i32, i32* @x, i32 1
88
call void asm sideeffect "foo $0", "n"(i32* %a) nounwind
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; RUN: not llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s
2+
3+
%struct.s = type { i32, i32 }
4+
5+
@pr40890.s = internal global %struct.s zeroinitializer, align 4
6+
7+
; CHECK: error: invalid operand for inline asm constraint 'e'
8+
; CHECK: error: invalid operand for inline asm constraint 'e'
9+
10+
define void @pr40890() {
11+
entry:
12+
; This pointer cannot be used as an integer constant expression.
13+
tail call void asm sideeffect "\0A#define GLOBAL_A abcd$0\0A", "e,~{dirflag},~{fpsr},~{flags}"(i32* getelementptr inbounds (%struct.s, %struct.s* @pr40890.s, i64 0, i32 0))
14+
; Floating-point is also not okay.
15+
tail call void asm sideeffect "\0A#define PI abcd$0\0A", "e,~{dirflag},~{fpsr},~{flags}"(float 0x40091EB860000000)
16+
ret void
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
; RUN: not llc -mtriple=i686-- -no-integrated-as < %s 2>&1 | FileCheck %s
2+
3+
; CHECK: error: value out of range for constraint 'I'
4+
define void @foo() {
5+
call void asm sideeffect "foo $0", "I"(i32 42)
6+
ret void
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; RUN: llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s
2+
3+
@x = global i32 0, align 4
4+
5+
define void @foo() {
6+
; CHECK-LABEL: foo:
7+
call void asm sideeffect "foo $0", "n"(i32 42) nounwind
8+
; CHECK: #APP
9+
; CHECK-NEXT: foo $42
10+
; CHECK-NEXT: #NO_APP
11+
ret void
12+
; CHECK-NEXT: retq
13+
}

0 commit comments

Comments
 (0)