From 2456fe5da3a527bf7ed52de7539a75e1f9720b03 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Fri, 9 Aug 2019 09:45:06 +0000 Subject: [PATCH] Merging r367750: ------------------------------------------------------------------------ r367750 | void | 2019-08-03 07:52:47 +0200 (Sat, 03 Aug 2019) | 15 lines 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 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_90@368421 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/TargetLowering.h | 1 + .../SelectionDAG/SelectionDAGBuilder.cpp | 35 +++++++++++++++---- lib/CodeGen/SelectionDAG/TargetLowering.cpp | 18 ++++++---- lib/Target/AArch64/AArch64ISelLowering.cpp | 12 +++++-- lib/Target/ARM/ARMISelLowering.cpp | 11 +++--- lib/Target/AVR/AVRISelLowering.cpp | 6 ++-- lib/Target/RISCV/RISCVISelLowering.cpp | 4 +++ lib/Target/Sparc/SparcISelLowering.cpp | 2 +- lib/Target/SystemZ/SystemZISelLowering.cpp | 2 +- lib/Target/X86/X86ISelLowering.cpp | 5 +-- .../AArch64/arm64-inline-asm-error-I.ll | 2 +- .../AArch64/arm64-inline-asm-error-J.ll | 2 +- .../AArch64/arm64-inline-asm-error-K.ll | 2 +- .../AArch64/arm64-inline-asm-error-L.ll | 2 +- .../AArch64/arm64-inline-asm-error-M.ll | 2 +- .../AArch64/arm64-inline-asm-error-N.ll | 2 +- test/CodeGen/RISCV/inline-asm-invalid.ll | 10 +++--- .../X86/inline-asm-bad-constraint-n.ll | 2 +- test/CodeGen/X86/inline-asm-e-constraint.ll | 17 +++++++++ .../X86/inline-asm-imm-out-of-range.ll | 7 ++++ test/CodeGen/X86/inline-asm-n-constraint.ll | 13 +++++++ 21 files changed, 117 insertions(+), 40 deletions(-) create mode 100644 test/CodeGen/X86/inline-asm-e-constraint.ll create mode 100644 test/CodeGen/X86/inline-asm-imm-out-of-range.ll create mode 100644 test/CodeGen/X86/inline-asm-n-constraint.ll diff --git a/include/llvm/CodeGen/TargetLowering.h b/include/llvm/CodeGen/TargetLowering.h index d5cca60bb1b..ca7548cd8d6 100644 --- a/include/llvm/CodeGen/TargetLowering.h +++ b/include/llvm/CodeGen/TargetLowering.h @@ -3665,6 +3665,7 @@ public: C_Register, // Constraint represents specific register(s). C_RegisterClass, // Constraint represents any of register(s) in class. C_Memory, // Memory constraint. + C_Immediate, // Requires an immediate. C_Other, // Something else. C_Unknown // Unsupported constraint. }; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index e818dd27c05..3c02c36a7d2 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8021,6 +8021,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(T, SDValue()); + if (T.ConstraintType == TargetLowering::C_Immediate && + OpInfo.CallOperand && !isa(OpInfo.CallOperand)) + // We've delayed emitting a diagnostic like the "n" constraint because + // inlining could cause an integer showing up. + return emitInlineAsmError( + CS, "constraint '" + Twine(T.ConstraintCode) + "' expects an " + "integer constant expression"); + ExtraInfo.update(T); } @@ -8105,7 +8113,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { switch (OpInfo.Type) { case InlineAsm::isOutput: if (OpInfo.ConstraintType == TargetLowering::C_Memory || - (OpInfo.ConstraintType == TargetLowering::C_Other && + ((OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) && OpInfo.isIndirect)) { unsigned ConstraintID = TLI.getInlineAsmMemConstraint(OpInfo.ConstraintCode); @@ -8119,13 +8128,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { MVT::i32)); AsmNodeOperands.push_back(OpInfo.CallOperand); break; - } else if ((OpInfo.ConstraintType == TargetLowering::C_Other && + } else if (((OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) && !OpInfo.isIndirect) || OpInfo.ConstraintType == TargetLowering::C_Register || OpInfo.ConstraintType == TargetLowering::C_RegisterClass) { // Otherwise, this outputs to a register (directly for C_Register / - // C_RegisterClass, and a target-defined fashion for C_Other). Find a - // register that we can use. + // C_RegisterClass, and a target-defined fashion for + // C_Immediate/C_Other). Find a register that we can use. if (OpInfo.AssignedRegs.Regs.empty()) { emitInlineAsmError( CS, "couldn't allocate output register for constraint '" + @@ -8205,15 +8215,24 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } // Treat indirect 'X' constraint as memory. - if (OpInfo.ConstraintType == TargetLowering::C_Other && + if ((OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) && OpInfo.isIndirect) OpInfo.ConstraintType = TargetLowering::C_Memory; - if (OpInfo.ConstraintType == TargetLowering::C_Other) { + if (OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) { std::vector Ops; TLI.LowerAsmOperandForConstraint(InOperandVal, OpInfo.ConstraintCode, Ops, DAG); if (Ops.empty()) { + if (OpInfo.ConstraintType == TargetLowering::C_Immediate) + if (isa(InOperandVal)) { + emitInlineAsmError(CS, "value out of range for constraint '" + + Twine(OpInfo.ConstraintCode) + "'"); + return; + } + emitInlineAsmError(CS, "invalid operand for inline asm constraint '" + Twine(OpInfo.ConstraintCode) + "'"); return; @@ -8250,7 +8269,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass || - OpInfo.ConstraintType == TargetLowering::C_Register) && + OpInfo.ConstraintType == TargetLowering::C_Register || + OpInfo.ConstraintType == TargetLowering::C_Immediate) && "Unknown constraint type!"); // TODO: Support this. @@ -8356,6 +8376,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { Val = OpInfo.AssignedRegs.getCopyFromRegs( DAG, FuncInfo, getCurSDLoc(), Chain, &Flag, CS.getInstruction()); break; + case TargetLowering::C_Immediate: case TargetLowering::C_Other: Val = TLI.LowerAsmOutputForConstraint(Chain, Flag, getCurSDLoc(), OpInfo, DAG); diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index b260cd91d46..2d90dcba12b 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3567,15 +3567,17 @@ TargetLowering::getConstraintType(StringRef Constraint) const { if (S == 1) { switch (Constraint[0]) { default: break; - case 'r': return C_RegisterClass; + case 'r': + return C_RegisterClass; case 'm': // memory case 'o': // offsetable case 'V': // not offsetable return C_Memory; - case 'i': // Simple Integer or Relocatable Constant case 'n': // Simple Integer case 'E': // Floating Point Constant case 'F': // Floating Point Constant + return C_Immediate; + case 'i': // Simple Integer or Relocatable Constant case 's': // Relocatable Constant case 'p': // Address. case 'X': // Allow ANY value. @@ -3950,6 +3952,7 @@ TargetLowering::ParseConstraints(const DataLayout &DL, /// Return an integer indicating how general CT is. static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { switch (CT) { + case TargetLowering::C_Immediate: case TargetLowering::C_Other: case TargetLowering::C_Unknown: return 0; @@ -4069,11 +4072,12 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, TargetLowering::ConstraintType CType = TLI.getConstraintType(OpInfo.Codes[i]); - // If this is an 'other' constraint, see if the operand is valid for it. - // For example, on X86 we might have an 'rI' constraint. If the operand - // is an integer in the range [0..31] we want to use I (saving a load - // of a register), otherwise we must use 'r'. - if (CType == TargetLowering::C_Other && Op.getNode()) { + // If this is an 'other' or 'immediate' constraint, see if the operand is + // valid for it. For example, on X86 we might have an 'rI' constraint. If + // the operand is an integer in the range [0..31] we want to use I (saving a + // load of a register), otherwise we must use 'r'. + if ((CType == TargetLowering::C_Other || + CType == TargetLowering::C_Immediate) && Op.getNode()) { assert(OpInfo.Codes[i].size() == 1 && "Unhandled multi-letter 'other' constraint"); std::vector ResultOps; diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index 816db6f919b..6c250aea39f 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -5665,8 +5665,6 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { switch (Constraint[0]) { default: break; - case 'z': - return C_Other; case 'x': case 'w': return C_RegisterClass; @@ -5674,6 +5672,16 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { // currently handle addresses it is the same as 'r'. case 'Q': return C_Memory; + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'Y': + case 'Z': + return C_Immediate; + case 'z': case 'S': // A symbolic address return C_Other; } diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 18bb9bf3ecc..d390c9e237e 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -14369,7 +14369,8 @@ const char *ARMTargetLowering::LowerXConstraint(EVT ConstraintVT) const { /// constraint it is for this target. ARMTargetLowering::ConstraintType ARMTargetLowering::getConstraintType(StringRef Constraint) const { - if (Constraint.size() == 1) { + unsigned S = Constraint.size(); + if (S == 1) { switch (Constraint[0]) { default: break; case 'l': return C_RegisterClass; @@ -14377,12 +14378,12 @@ ARMTargetLowering::getConstraintType(StringRef Constraint) const { case 'h': return C_RegisterClass; case 'x': return C_RegisterClass; case 't': return C_RegisterClass; - case 'j': return C_Other; // Constant for movw. - // An address with a single base register. Due to the way we - // currently handle addresses it is the same as an 'r' memory constraint. + case 'j': return C_Immediate; // Constant for movw. + // An address with a single base register. Due to the way we + // currently handle addresses it is the same as an 'r' memory constraint. case 'Q': return C_Memory; } - } else if (Constraint.size() == 2) { + } else if (S == 2) { switch (Constraint[0]) { default: break; case 'T': return C_RegisterClass; diff --git a/lib/Target/AVR/AVRISelLowering.cpp b/lib/Target/AVR/AVRISelLowering.cpp index b6ba5f22faf..f159beee973 100644 --- a/lib/Target/AVR/AVRISelLowering.cpp +++ b/lib/Target/AVR/AVRISelLowering.cpp @@ -1689,6 +1689,8 @@ AVRTargetLowering::getConstraintType(StringRef Constraint) const { if (Constraint.size() == 1) { // See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html switch (Constraint[0]) { + default: + break; case 'a': // Simple upper registers case 'b': // Base pointer registers pairs case 'd': // Upper register @@ -1715,9 +1717,7 @@ AVRTargetLowering::getConstraintType(StringRef Constraint) const { case 'O': // Integer constant (Range: 8, 16, 24) case 'P': // Integer constant (Range: 1) case 'R': // Integer constant (Range: -6 to 5)x - return C_Other; - default: - break; + return C_Immediate; } } diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp index b2dbff38530..cdad4d461f1 100644 --- a/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2407,6 +2407,10 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const { break; case 'f': return C_RegisterClass; + case 'I': + case 'J': + case 'K': + return C_Immediate; } } return TargetLowering::getConstraintType(Constraint); diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index a6d440fa8aa..804f7ba74ed 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -3183,7 +3183,7 @@ SparcTargetLowering::getConstraintType(StringRef Constraint) const { case 'e': return C_RegisterClass; case 'I': // SIMM13 - return C_Other; + return C_Immediate; } } diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 78820f511ab..e7b7a5b0cd5 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -956,7 +956,7 @@ SystemZTargetLowering::getConstraintType(StringRef Constraint) const { case 'K': // Signed 16-bit constant case 'L': // Signed 20-bit displacement (on all targets we support) case 'M': // 0x7fffffff - return C_Other; + return C_Immediate; default: break; diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index a03ce798858..598fa9240f5 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -44656,10 +44656,11 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const { case 'I': case 'J': case 'K': - case 'L': - case 'M': case 'N': case 'G': + case 'L': + case 'M': + return C_Immediate; case 'C': case 'e': case 'Z': diff --git a/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll b/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll index 7dc9f726003..7784c9b2442 100644 --- a/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll +++ b/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'I' +; CHECK-ERRORS: error: value out of range for constraint 'I' define i32 @constraint_I(i32 %i, i32 %j) nounwind ssp { entry: diff --git a/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll b/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll index 592875b0cb0..c90178513d2 100644 --- a/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll +++ b/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'J' +; CHECK-ERRORS: error: value out of range for constraint 'J' define i32 @constraint_J(i32 %i, i32 %j) nounwind ssp { entry: diff --git a/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll b/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll index 893e8d29e65..e5baf85e954 100644 --- a/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll +++ b/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'K' +; CHECK-ERRORS: error: value out of range for constraint 'K' define i32 @constraint_K(i32 %i, i32 %j) nounwind { entry: diff --git a/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll b/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll index b2fb822aa29..cdba0562755 100644 --- a/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll +++ b/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'L' +; CHECK-ERRORS: error: value out of range for constraint 'L' define i32 @constraint_L(i32 %i, i32 %j) nounwind { entry: diff --git a/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll b/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll index aaee933fd6d..c7a786b26bb 100644 --- a/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll +++ b/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'M' +; CHECK-ERRORS: error: value out of range for constraint 'M' define i32 @constraint_M(i32 %i, i32 %j) nounwind { entry: diff --git a/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll b/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll index d1d2e03548e..38b0ab8fa29 100644 --- a/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll +++ b/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'N' +; CHECK-ERRORS: error: value out of range for constraint 'N' define i32 @constraint_N(i32 %i, i32 %j) nounwind { entry: diff --git a/test/CodeGen/RISCV/inline-asm-invalid.ll b/test/CodeGen/RISCV/inline-asm-invalid.ll index 06b0f2c2bfe..20ac5ef1111 100644 --- a/test/CodeGen/RISCV/inline-asm-invalid.ll +++ b/test/CodeGen/RISCV/inline-asm-invalid.ll @@ -2,23 +2,23 @@ ; RUN: not llc -mtriple=riscv64 < %s 2>&1 | FileCheck %s define void @constraint_I() { -; CHECK: error: invalid operand for inline asm constraint 'I' +; CHECK: error: value out of range for constraint 'I' tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2048) -; CHECK: error: invalid operand for inline asm constraint 'I' +; CHECK: error: value out of range for constraint 'I' tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2049) ret void } define void @constraint_J() { -; CHECK: error: invalid operand for inline asm constraint 'J' +; CHECK: error: value out of range for constraint 'J' tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 1) ret void } define void @constraint_K() { -; CHECK: error: invalid operand for inline asm constraint 'K' +; CHECK: error: value out of range for constraint 'K' tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 32) -; CHECK: error: invalid operand for inline asm constraint 'K' +; CHECK: error: value out of range for constraint 'K' tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 -1) ret void } diff --git a/test/CodeGen/X86/inline-asm-bad-constraint-n.ll b/test/CodeGen/X86/inline-asm-bad-constraint-n.ll index 967477d076d..a3099ab3679 100644 --- a/test/CodeGen/X86/inline-asm-bad-constraint-n.ll +++ b/test/CodeGen/X86/inline-asm-bad-constraint-n.ll @@ -2,7 +2,7 @@ @x = global i32 0, align 4 -;CHECK: error: invalid operand for inline asm constraint 'n' +; CHECK: error: constraint 'n' expects an integer constant expression define void @foo() { %a = getelementptr i32, i32* @x, i32 1 call void asm sideeffect "foo $0", "n"(i32* %a) nounwind diff --git a/test/CodeGen/X86/inline-asm-e-constraint.ll b/test/CodeGen/X86/inline-asm-e-constraint.ll new file mode 100644 index 00000000000..fd10ba42408 --- /dev/null +++ b/test/CodeGen/X86/inline-asm-e-constraint.ll @@ -0,0 +1,17 @@ +; RUN: not llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s + +%struct.s = type { i32, i32 } + +@pr40890.s = internal global %struct.s zeroinitializer, align 4 + +; CHECK: error: invalid operand for inline asm constraint 'e' +; CHECK: error: invalid operand for inline asm constraint 'e' + +define void @pr40890() { +entry: + ; This pointer cannot be used as an integer constant expression. + 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)) + ; Floating-point is also not okay. + tail call void asm sideeffect "\0A#define PI abcd$0\0A", "e,~{dirflag},~{fpsr},~{flags}"(float 0x40091EB860000000) + ret void +} diff --git a/test/CodeGen/X86/inline-asm-imm-out-of-range.ll b/test/CodeGen/X86/inline-asm-imm-out-of-range.ll new file mode 100644 index 00000000000..9c5177d02a1 --- /dev/null +++ b/test/CodeGen/X86/inline-asm-imm-out-of-range.ll @@ -0,0 +1,7 @@ +; RUN: not llc -mtriple=i686-- -no-integrated-as < %s 2>&1 | FileCheck %s + +; CHECK: error: value out of range for constraint 'I' +define void @foo() { + call void asm sideeffect "foo $0", "I"(i32 42) + ret void +} diff --git a/test/CodeGen/X86/inline-asm-n-constraint.ll b/test/CodeGen/X86/inline-asm-n-constraint.ll new file mode 100644 index 00000000000..669e464f1f6 --- /dev/null +++ b/test/CodeGen/X86/inline-asm-n-constraint.ll @@ -0,0 +1,13 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s + +@x = global i32 0, align 4 + +define void @foo() { +; CHECK-LABEL: foo: + call void asm sideeffect "foo $0", "n"(i32 42) nounwind +; CHECK: #APP +; CHECK-NEXT: foo $42 +; CHECK-NEXT: #NO_APP + ret void +; CHECK-NEXT: retq +} -- 2.40.0