From 2dce3e99fb63f3d5ba8ae4ffffbcce756e635960 Mon Sep 17 00:00:00 2001 From: Evgenii Kudriashov Date: Wed, 17 Jul 2024 08:36:54 -0700 Subject: [PATCH] [CodeGen] Enhance inline asm constraint diagnostics --- llvm/include/llvm/CodeGen/TargetLowering.h | 3 +- .../CodeGen/GlobalISel/InlineAsmLowering.cpp | 3 +- .../SelectionDAG/FunctionLoweringInfo.cpp | 3 +- .../SelectionDAG/SelectionDAGBuilder.cpp | 56 ++++++++++--------- .../CodeGen/SelectionDAG/TargetLowering.cpp | 11 ++-- llvm/lib/Target/AArch64/AArch64ISelLowering.h | 3 +- llvm/lib/Target/AMDGPU/SIISelLowering.h | 3 +- llvm/lib/Target/ARM/ARMISelLowering.h | 3 +- llvm/lib/Target/AVR/AVRISelLowering.h | 3 +- llvm/lib/Target/BPF/BPFISelLowering.h | 3 +- llvm/lib/Target/CSKY/CSKYISelLowering.h | 3 +- llvm/lib/Target/Hexagon/HexagonISelLowering.h | 3 +- llvm/lib/Target/Lanai/LanaiISelLowering.h | 3 +- .../Target/LoongArch/LoongArchISelLowering.h | 3 +- llvm/lib/Target/M68k/M68kISelLowering.h | 3 +- llvm/lib/Target/MSP430/MSP430ISelLowering.h | 3 +- llvm/lib/Target/Mips/MipsISelLowering.h | 3 +- llvm/lib/Target/NVPTX/NVPTXISelLowering.h | 3 +- llvm/lib/Target/PowerPC/PPCISelLowering.h | 3 +- llvm/lib/Target/RISCV/RISCVISelLowering.h | 3 +- llvm/lib/Target/SPIRV/SPIRVISelLowering.h | 3 +- llvm/lib/Target/Sparc/SparcISelLowering.h | 3 +- llvm/lib/Target/SystemZ/SystemZISelLowering.h | 3 +- llvm/lib/Target/VE/VEISelLowering.h | 3 +- .../WebAssembly/WebAssemblyISelLowering.h | 3 +- llvm/lib/Target/X86/X86ISelLowering.cpp | 50 +++++++++++------ llvm/lib/Target/X86/X86ISelLowering.h | 3 +- llvm/lib/Target/XCore/XCoreISelLowering.h | 3 +- .../X86/asm-reject-reg-type-mismatch-avx.ll | 2 +- .../X86/asm-reject-reg-type-mismatch.ll | 6 +- llvm/test/CodeGen/X86/asm-reject-rex.ll | 6 +- llvm/test/CodeGen/X86/asm-reject-vk32-vk64.ll | 8 +-- llvm/test/CodeGen/X86/asm-reject-x87-int.ll | 2 +- llvm/test/CodeGen/X86/asm-reject-xmm16.ll | 7 ++- .../X86/inline-asm-avx512f-x-constraint.ll | 4 +- llvm/test/CodeGen/X86/inline-asm-x-i128.ll | 2 +- llvm/test/CodeGen/X86/pr37359.ll | 2 +- llvm/test/CodeGen/X86/pr50907.ll | 2 +- 38 files changed, 142 insertions(+), 91 deletions(-) diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 9d9886f4920a2..7e0f7a269ed59 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -5034,7 +5034,8 @@ class TargetLowering : public TargetLoweringBase { /// returns a register number of 0 and a null register class pointer. virtual std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const; virtual InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const { diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp index 81f25b21a0409..20c6713c17b0d 100644 --- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp @@ -93,8 +93,9 @@ static void getRegistersForValue(MachineFunction &MF, // register class, find it. Register AssignedReg; const TargetRegisterClass *RC; + std::string ErrMsg; std::tie(AssignedReg, RC) = TLI.getRegForInlineAsmConstraint( - &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT); + &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT, ErrMsg); // RC is unset only on failure. Return immediately. if (!RC) return; diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 8f5b05b662b33..0bb7fe438ad8e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -192,9 +192,10 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, if (Op.Type == InlineAsm::isClobber) { // Clobbers don't have SDValue operands, hence SDValue(). TLI->ComputeConstraintToUse(Op, SDValue(), DAG); + std::string ErrMsg; std::pair PhysReg = TLI->getRegForInlineAsmConstraint(TRI, Op.ConstraintCode, - Op.ConstraintVT); + Op.ConstraintVT, ErrMsg); if (PhysReg.first == SP) MF->getFrameInfo().setHasOpaqueSPAdjustment(true); } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 9f5e6466309e9..a22fb64cdf94f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9516,13 +9516,14 @@ static void patchMatchingInput(const SDISelAsmOperandInfo &OpInfo, const TargetRegisterInfo *TRI = DAG.getSubtarget().getRegisterInfo(); const auto &TLI = DAG.getTargetLoweringInfo(); + std::string ErrMsg; std::pair MatchRC = TLI.getRegForInlineAsmConstraint(TRI, OpInfo.ConstraintCode, - OpInfo.ConstraintVT); + OpInfo.ConstraintVT, ErrMsg); std::pair InputRC = TLI.getRegForInlineAsmConstraint(TRI, MatchingOpInfo.ConstraintCode, - MatchingOpInfo.ConstraintVT); + MatchingOpInfo.ConstraintVT, ErrMsg); if ((OpInfo.ConstraintVT.isInteger() != MatchingOpInfo.ConstraintVT.isInteger()) || (MatchRC.second != InputRC.second)) { @@ -9588,7 +9589,7 @@ static SDValue getAddressForMemoryInput(SDValue Chain, const SDLoc &Location, /// /// OpInfo describes the operand /// RefOpInfo describes the matching operand if any, the operand otherwise -static std::optional +static std::optional getRegistersForValue(SelectionDAG &DAG, const SDLoc &DL, SDISelAsmOperandInfo &OpInfo, SDISelAsmOperandInfo &RefOpInfo) { @@ -9608,11 +9609,12 @@ getRegistersForValue(SelectionDAG &DAG, const SDLoc &DL, // register class, find it. unsigned AssignedReg; const TargetRegisterClass *RC; + std::string ErrMsg; std::tie(AssignedReg, RC) = TLI.getRegForInlineAsmConstraint( - &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT); + &TRI, RefOpInfo.ConstraintCode, RefOpInfo.ConstraintVT, ErrMsg); // RC is unset only on failure. Return immediately. if (!RC) - return std::nullopt; + return ErrMsg; // Get the actual register value type. This is important, because the user // may have asked for (e.g.) the AX register in i32 type. We need to @@ -9684,7 +9686,9 @@ getRegistersForValue(SelectionDAG &DAG, const SDLoc &DL, if (I == RC->end()) { // RC does not contain the selected register, which indicates a // mismatch between the register and the required type/bitwidth. - return {AssignedReg}; + return "register '" + std::string(TRI.getName(AssignedReg)) + + "' allocated for constraint '" + OpInfo.ConstraintCode + + "' does not match required type " + ValueVT.getEVTString(); } } @@ -9933,18 +9937,6 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call, OpInfo.isMatchingInputConstraint() ? ConstraintOperands[OpInfo.getMatchedOperand()] : OpInfo; - const auto RegError = - getRegistersForValue(DAG, getCurSDLoc(), OpInfo, RefOpInfo); - if (RegError) { - const MachineFunction &MF = DAG.getMachineFunction(); - const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); - const char *RegName = TRI.getName(*RegError); - emitInlineAsmError(Call, "register '" + Twine(RegName) + - "' allocated for constraint '" + - Twine(OpInfo.ConstraintCode) + - "' does not match required type"); - return; - } auto DetectWriteToReservedRegister = [&]() { const MachineFunction &MF = DAG.getMachineFunction(); @@ -9983,12 +9975,17 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call, // Otherwise, this outputs to a register (directly for C_Register / // C_RegisterClass, and a target-defined fashion for // C_Immediate/C_Other). Find a register that we can use. - if (OpInfo.AssignedRegs.Regs.empty()) { + const auto RegError = + getRegistersForValue(DAG, getCurSDLoc(), OpInfo, RefOpInfo); + if (RegError) { emitInlineAsmError( Call, "couldn't allocate output register for constraint '" + - Twine(OpInfo.ConstraintCode) + "'"); + Twine(OpInfo.ConstraintCode) + + (RegError->empty() ? "'" : ("': " + Twine(*RegError)))); return; } + assert(!OpInfo.AssignedRegs.Regs.empty() && + "register must be allocated or an error emitted"); if (DetectWriteToReservedRegister()) return; @@ -10157,13 +10154,17 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call, return; } - // Copy the input into the appropriate registers. - if (OpInfo.AssignedRegs.Regs.empty()) { - emitInlineAsmError(Call, - "couldn't allocate input reg for constraint '" + - Twine(OpInfo.ConstraintCode) + "'"); + const auto RegError = + getRegistersForValue(DAG, getCurSDLoc(), OpInfo, RefOpInfo); + if (RegError) { + emitInlineAsmError( + Call, "couldn't allocate input reg for constraint '" + + Twine(OpInfo.ConstraintCode) + + (RegError->empty() ? "'" : ("': " + Twine(*RegError)))); return; } + assert(!OpInfo.AssignedRegs.Regs.empty() && + "register must be allocated or an error emitted"); if (DetectWriteToReservedRegister()) return; @@ -10177,15 +10178,18 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call, 0, dl, DAG, AsmNodeOperands); break; } - case InlineAsm::isClobber: + case InlineAsm::isClobber: { // Add the clobbered value to the operand list, so that the register // allocator is aware that the physreg got clobbered. + const auto RegError = + getRegistersForValue(DAG, getCurSDLoc(), OpInfo, RefOpInfo); if (!OpInfo.AssignedRegs.Regs.empty()) OpInfo.AssignedRegs.AddInlineAsmOperands(InlineAsm::Kind::Clobber, false, 0, getCurSDLoc(), DAG, AsmNodeOperands); break; } + } } // Finish up input operands. Set the input chain and add the flag last. diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 7fa83a5999dfe..04391dcfd4bb7 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5620,8 +5620,8 @@ void TargetLowering::CollectTargetIntrinsicOperands( std::pair TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *RI, - StringRef Constraint, - MVT VT) const { + StringRef Constraint, MVT VT, + std::string &ErrMsg) const { if (!Constraint.starts_with("{")) return std::make_pair(0u, static_cast(nullptr)); assert(*(Constraint.end() - 1) == '}' && "Not a brace enclosed constraint?"); @@ -5654,6 +5654,8 @@ TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *RI, } } } + if (!R.second) + ErrMsg = "register is unavailable"; return R; } @@ -5842,12 +5844,13 @@ TargetLowering::ParseConstraints(const DataLayout &DL, AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; if (OpInfo.ConstraintVT != Input.ConstraintVT) { + std::string ErrMsg; std::pair MatchRC = getRegForInlineAsmConstraint(TRI, OpInfo.ConstraintCode, - OpInfo.ConstraintVT); + OpInfo.ConstraintVT, ErrMsg); std::pair InputRC = getRegForInlineAsmConstraint(TRI, Input.ConstraintCode, - Input.ConstraintVT); + Input.ConstraintVT, ErrMsg); if ((OpInfo.ConstraintVT.isInteger() != Input.ConstraintVT.isInteger()) || (MatchRC.second != InputRC.second)) { diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 81e15185f985d..704c899328a18 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -1270,7 +1270,8 @@ class AArch64TargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; const char *LowerXConstraint(EVT ConstraintVT) const override; diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h index 1f198a92c0fa6..9a1a3d0cf795e 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.h +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h @@ -481,7 +481,8 @@ class SITargetLowering final : public AMDGPUTargetLowering { uint32_t RsrcDword1, uint64_t RsrcDword2And3) const; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; ConstraintType getConstraintType(StringRef Constraint) const override; void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector &Ops, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h index a255e9b6fc365..591e515c17943 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -529,7 +529,8 @@ class VectorType; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; const char *LowerXConstraint(EVT ConstraintVT) const override; diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h index f605795934532..5f7004b5fbb1f 100644 --- a/llvm/lib/Target/AVR/AVRISelLowering.h +++ b/llvm/lib/Target/AVR/AVRISelLowering.h @@ -131,7 +131,8 @@ class AVRTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; InlineAsm::ConstraintCode getInlineAsmMemConstraint(StringRef ConstraintCode) const override; diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h index 42707949e864c..c04545a7fa2a9 100644 --- a/llvm/lib/Target/BPF/BPFISelLowering.h +++ b/llvm/lib/Target/BPF/BPFISelLowering.h @@ -51,7 +51,8 @@ class BPFTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, diff --git a/llvm/lib/Target/CSKY/CSKYISelLowering.h b/llvm/lib/Target/CSKY/CSKYISelLowering.h index d59481af3c5ba..18ac4536ad640 100644 --- a/llvm/lib/Target/CSKY/CSKYISelLowering.h +++ b/llvm/lib/Target/CSKY/CSKYISelLowering.h @@ -92,7 +92,8 @@ class CSKYTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h index 3fd961f5a7462..8ab2fd26b7c64 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h @@ -299,7 +299,8 @@ class HexagonTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; // Intrinsics SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Lanai/LanaiISelLowering.h b/llvm/lib/Target/Lanai/LanaiISelLowering.h index 5fa5444b51618..d00321dfdb849 100644 --- a/llvm/lib/Target/Lanai/LanaiISelLowering.h +++ b/llvm/lib/Target/Lanai/LanaiISelLowering.h @@ -99,7 +99,8 @@ class LanaiTargetLowering : public TargetLowering { const MachineFunction &MF) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; ConstraintWeight getSingleConstraintMatchWeight(AsmOperandInfo &Info, const char *Constraint) const override; diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index fc5b36c2124e0..63ca6a7d32c3c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -323,7 +323,8 @@ class LoongArchTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector &Ops, diff --git a/llvm/lib/Target/M68k/M68kISelLowering.h b/llvm/lib/Target/M68k/M68kISelLowering.h index d00907775f928..69b48713bb1e2 100644 --- a/llvm/lib/Target/M68k/M68kISelLowering.h +++ b/llvm/lib/Target/M68k/M68kISelLowering.h @@ -160,7 +160,8 @@ class M68kTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; // Lower operand with C_Immediate and C_Other constraint type void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.h b/llvm/lib/Target/MSP430/MSP430ISelLowering.h index 667ad60338619..8c75b60915147 100644 --- a/llvm/lib/Target/MSP430/MSP430ISelLowering.h +++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.h @@ -108,7 +108,8 @@ namespace llvm { getConstraintType(StringRef Constraint) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; /// isTruncateFree - Return true if it's free to truncate a value of type /// Ty1 to type Ty2. e.g. On msp430 it's free to truncate a i16 value in diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h index 84ad40d6bbbe2..bd7ffea5d0ad6 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.h +++ b/llvm/lib/Target/Mips/MipsISelLowering.h @@ -637,7 +637,8 @@ class TargetRegisterClass; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops /// vector. If it is invalid, don't add anything to Ops. If hasMemory is diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.h b/llvm/lib/Target/NVPTX/NVPTXISelLowering.h index 63262961b363e..1c4d7f64cdd4f 100644 --- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.h +++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.h @@ -512,7 +512,8 @@ class NVPTXTargetLowering : public TargetLowering { ConstraintType getConstraintType(StringRef Constraint) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h index 0bdfdcd15441f..7fdddc1d2dff1 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -976,7 +976,8 @@ namespace llvm { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; /// getByValTypeAlignment - Return the desired alignment for ByVal aggregate /// function arguments in the caller parameter area. This is the actual diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index d1d0760d8ffd1..f9470ff0e65a6 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -638,7 +638,8 @@ class RISCVTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector &Ops, diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.h b/llvm/lib/Target/SPIRV/SPIRVISelLowering.h index 77356b7512a73..492225046391f 100644 --- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.h +++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.h @@ -57,7 +57,8 @@ class SPIRVTargetLowering : public TargetLowering { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; unsigned getNumRegisters(LLVMContext &Context, EVT VT, std::optional RegisterVT = std::nullopt) const override { diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h index 15d09bc930975..d95dae6514c45 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.h +++ b/llvm/lib/Target/Sparc/SparcISelLowering.h @@ -94,7 +94,8 @@ namespace llvm { std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override { diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index 1e7285e3e0fc5..f713c66e0f064 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -512,7 +512,8 @@ class SystemZTargetLowering : public TargetLowering { const char *getTargetNodeName(unsigned Opcode) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; TargetLowering::ConstraintType getConstraintType(StringRef Constraint) const override; TargetLowering::ConstraintWeight diff --git a/llvm/lib/Target/VE/VEISelLowering.h b/llvm/lib/Target/VE/VEISelLowering.h index 8b9412d786625..9e603ce058290 100644 --- a/llvm/lib/Target/VE/VEISelLowering.h +++ b/llvm/lib/Target/VE/VEISelLowering.h @@ -319,7 +319,8 @@ class VETargetLowering : public TargetLowering { ConstraintType getConstraintType(StringRef Constraint) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; /// } Inline Assembly diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h index 7d9cfb7739e43..e2a0d4bcc1c4e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -64,7 +64,8 @@ class WebAssemblyTargetLowering final : public TargetLowering { const char *getTargetNodeName(unsigned Opcode) const override; std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; bool isCheapToSpeculateCttz(Type *Ty) const override; bool isCheapToSpeculateCtlz(Type *Ty) const override; bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 73405397aa6e8..aaf9507eebb9a 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -58854,8 +58854,8 @@ static bool useEGPRInlineAsm(const X86Subtarget &Subtarget) { std::pair X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, - MVT VT) const { + StringRef Constraint, MVT VT, + std::string &ErrMsg) const { // First, see if this is a constraint that directly corresponds to an LLVM // register class. if (Constraint.size() == 1) { @@ -58888,6 +58888,7 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, if (VT == MVT::v64i1 || VT == MVT::i64) return std::make_pair(0U, &X86::VK64RegClass); } + ErrMsg = "register is unavailable without AVX512 or AVX512BW"; break; case 'q': // GENERAL_REGS in 64-bit mode, Q_REGS in 32-bit mode. if (Subtarget.is64Bit()) { @@ -58941,6 +58942,7 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return std::make_pair(0U, useEGPRInlineAsm(Subtarget) ? &X86::GR64RegClass : &X86::GR64_NOREX2RegClass); + ErrMsg = "couldn't allocate for type " + EVT(VT).getEVTString(); break; case 'R': // LEGACY_REGS if (VT == MVT::i8 || VT == MVT::i1) @@ -58962,17 +58964,23 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return std::make_pair(0U, &X86::RFP64RegClass); if (VT == MVT::f32 || VT == MVT::f64 || VT == MVT::f80) return std::make_pair(0U, &X86::RFP80RegClass); + ErrMsg = "couldn't allocate for type " + EVT(VT).getEVTString(); break; case 'y': // MMX_REGS if MMX allowed. if (!Subtarget.hasMMX()) break; return std::make_pair(0U, &X86::VR64RegClass); case 'v': case 'x': // SSE_REGS if SSE1 allowed or AVX_REGS if AVX allowed - if (!Subtarget.hasSSE1()) break; + if (!Subtarget.hasSSE1()) { + ErrMsg = "register is unavailable without SSE1"; + break; + } bool VConstraint = (Constraint[0] == 'v'); switch (VT.SimpleTy) { - default: break; + default: + ErrMsg = "couldn't allocate for type " + EVT(VT).getEVTString(); + break; // Scalar SSE types. case MVT::f16: if (VConstraint && Subtarget.hasFP16()) @@ -59043,14 +59051,18 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return std::make_pair(0U, &X86::VR256RegClass); break; case MVT::v32f16: - if (!Subtarget.hasFP16()) + if (!Subtarget.hasFP16()) { + ErrMsg = "register is unavailable without AVX512FP16"; break; + } if (VConstraint) return std::make_pair(0U, &X86::VR512RegClass); return std::make_pair(0U, &X86::VR512_0_15RegClass); case MVT::v32bf16: - if (!Subtarget.hasBF16()) + if (!Subtarget.hasBF16()) { + ErrMsg = "register is unavailable without AVX512BF16"; break; + } if (VConstraint) return std::make_pair(0U, &X86::VR512RegClass); return std::make_pair(0U, &X86::VR512_0_15RegClass); @@ -59074,7 +59086,7 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, case 'i': case 't': case '2': - return getRegForInlineAsmConstraint(TRI, "x", VT); + return getRegForInlineAsmConstraint(TRI, "x", VT, ErrMsg); case 'm': if (!Subtarget.hasMMX()) break; return std::make_pair(0U, &X86::VR64RegClass); @@ -59162,6 +59174,7 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, if (VT == MVT::v64i1 || VT == MVT::i64) return std::make_pair(0U, &X86::VK64WMRegClass); } + ErrMsg = "register is unavailable without AVX512 or AVX512BW"; break; } } else if (Constraint.size() == 2 && Constraint[0] == 'j') { @@ -59197,7 +59210,8 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, // Use the default implementation in TargetLowering to convert the register // constraint into a member of a register class. std::pair Res; - Res = TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); + Res = + TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT, ErrMsg); // Not found as a standard register? if (!Res.second) { @@ -59241,18 +59255,20 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return Res; } + // Make sure it isn't a register that requires AVX512. + if (!Subtarget.hasAVX512() && isFRClass(*Res.second) && + TRI->getEncodingValue(Res.first) & 0x10) { + // Register requires EVEX prefix. + ErrMsg = "register is unavailable without AVX512F"; + return std::make_pair(0, nullptr); + } + // Make sure it isn't a register that requires 64-bit mode. if (!Subtarget.is64Bit() && (isFRClass(*Res.second) || isGRClass(*Res.second)) && TRI->getEncodingValue(Res.first) >= 8) { // Register requires REX prefix, but we're in 32-bit mode. - return std::make_pair(0, nullptr); - } - - // Make sure it isn't a register that requires AVX512. - if (!Subtarget.hasAVX512() && isFRClass(*Res.second) && - TRI->getEncodingValue(Res.first) & 0x10) { - // Register requires EVEX prefix. + ErrMsg = "register is unavailable in 32-bit mode"; return std::make_pair(0, nullptr); } @@ -59274,8 +59290,10 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, if (isGRClass(*Class)) { unsigned Size = VT.getSizeInBits(); if (Size == 1) Size = 8; - if (Size != 8 && Size != 16 && Size != 32 && Size != 64) + if (Size != 8 && Size != 16 && Size != 32 && Size != 64) { + ErrMsg = "couldn't allocate for type " + EVT(VT).getEVTString(); return std::make_pair(0, nullptr); + } Register DestReg = getX86SubSuperRegister(Res.first, Size); if (DestReg.isValid()) { bool is64Bit = Subtarget.is64Bit(); diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h index 362daa98e1f8e..8e61c49b9a33b 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -1311,7 +1311,8 @@ namespace llvm { /// error, this returns a register number of 0. std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; /// Return true if the addressing mode represented /// by AM is legal for this target, for a load/store of the specified type. diff --git a/llvm/lib/Target/XCore/XCoreISelLowering.h b/llvm/lib/Target/XCore/XCoreISelLowering.h index eaa36d40cba92..9a0a7b4c43b8d 100644 --- a/llvm/lib/Target/XCore/XCoreISelLowering.h +++ b/llvm/lib/Target/XCore/XCoreISelLowering.h @@ -185,7 +185,8 @@ namespace llvm { // Inline asm support std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, - StringRef Constraint, MVT VT) const override; + StringRef Constraint, MVT VT, + std::string &ErrMsg) const override; // Expand specifics SDValue TryExpandADDWithMul(SDNode *Op, SelectionDAG &DAG) const; diff --git a/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch-avx.ll b/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch-avx.ll index 887de29e7e672..02189734af4f8 100644 --- a/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch-avx.ll +++ b/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch-avx.ll @@ -1,7 +1,7 @@ ; RUN: not llc -o /dev/null -mattr=avx %s 2>&1 | FileCheck %s target triple = "x86_64--" -; CHECK: error: register 'XMM15' allocated for constraint '{xmm15}' does not match required type +; CHECK: error: couldn't allocate input reg for constraint '{xmm15}': register 'XMM15' allocated for constraint '{xmm15}' does not match required type v8i32 define void @test1() nounwind { entry: tail call void asm sideeffect "call dummy", "{xmm15},~{dirflag},~{fpsr},~{flags}"(<8 x i32> ) #1 diff --git a/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll b/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll index 513f88b05dd9b..ac79435b6136f 100644 --- a/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll +++ b/llvm/test/CodeGen/X86/asm-reject-reg-type-mismatch.ll @@ -1,19 +1,19 @@ ; RUN: not llc -o /dev/null %s 2>&1 | FileCheck %s target triple = "x86_64--" -; CHECK: error: couldn't allocate output register for constraint '{ax}' +; CHECK: error: couldn't allocate output register for constraint '{ax}': couldn't allocate for type i128 define i128 @blup() { %v = tail call i128 asm "", "={ax},0"(i128 0) ret i128 %v } -; CHECK: error: couldn't allocate input reg for constraint 'r' +; CHECK: error: couldn't allocate input reg for constraint 'r': couldn't allocate for type f80 define void @fp80(x86_fp80) { tail call void asm sideeffect "", "r"(x86_fp80 %0) ret void } -; CHECK: error: couldn't allocate input reg for constraint 'f' +; CHECK: error: couldn't allocate input reg for constraint 'f': couldn't allocate for type i128 define void @f_constraint_i128(ptr %0) { %2 = load i128, ptr %0, align 16 tail call void asm sideeffect "", "f"(i128 %2) diff --git a/llvm/test/CodeGen/X86/asm-reject-rex.ll b/llvm/test/CodeGen/X86/asm-reject-rex.ll index f9719b84816a6..7456f5a354d60 100644 --- a/llvm/test/CodeGen/X86/asm-reject-rex.ll +++ b/llvm/test/CodeGen/X86/asm-reject-rex.ll @@ -2,19 +2,19 @@ ; Make sure X32 still works. ; RUN: llc -o /dev/null %s -mtriple=x86_64-linux-gnux32 -; CHECK: error: couldn't allocate output register for constraint '{xmm8}' +; CHECK: error: couldn't allocate output register for constraint '{xmm8}': register is unavailable in 32-bit mode define i64 @blup() { %v = tail call i64 asm "", "={xmm8},0"(i64 0) ret i64 %v } -; CHECK: error: couldn't allocate output register for constraint '{r8d}' +; CHECK: error: couldn't allocate output register for constraint '{r8d}': register is unavailable in 32-bit mode define i32 @foo() { %v = tail call i32 asm "", "={r8d},0"(i32 0) ret i32 %v } -; CHECK: error: couldn't allocate output register for constraint '{rax}' +; CHECK: error: couldn't allocate output register for constraint '{rax}': register is unavailable define i64 @bar() { %v = tail call i64 asm "", "={rax},0"(i64 0) ret i64 %v diff --git a/llvm/test/CodeGen/X86/asm-reject-vk32-vk64.ll b/llvm/test/CodeGen/X86/asm-reject-vk32-vk64.ll index 12d148a3a74b6..2392745dddea8 100644 --- a/llvm/test/CodeGen/X86/asm-reject-vk32-vk64.ll +++ b/llvm/test/CodeGen/X86/asm-reject-vk32-vk64.ll @@ -1,28 +1,28 @@ ; RUN: not llc -o /dev/null %s -mtriple=x86_64-unknown-unknown -mattr=avx512f 2>&1 | FileCheck %s ; RUN: not llc -o /dev/null %s -mtriple=i386-unknown-unknown -mattr=avx512f 2>&1 | FileCheck %s -; CHECK: error: couldn't allocate input reg for constraint 'Yk' +; CHECK: error: couldn't allocate input reg for constraint 'Yk': register is unavailable without AVX512 or AVX512BW define <8 x i64> @mask_Yk_i32(i32 %msk, <8 x i64> %x, <8 x i64> %y) { entry: %0 = tail call <8 x i64> asm "vpaddw\09$3, $2, $0 {$1}", "=x,^Yk,x,x,~{dirflag},~{fpsr},~{flags}"(i32 %msk, <8 x i64> %x, <8 x i64> %y) ret <8 x i64> %0 } -; CHECK: error: couldn't allocate input reg for constraint 'Yk' +; CHECK: error: couldn't allocate input reg for constraint 'Yk': register is unavailable without AVX512 or AVX512BW define <8 x i64> @mask_Yk_i64(i64 %msk, <8 x i64> %x, <8 x i64> %y) { entry: %0 = tail call <8 x i64> asm "vpaddb\09$3, $2, $0 {$1}", "=x,^Yk,x,x,~{dirflag},~{fpsr},~{flags}"(i64 %msk, <8 x i64> %x, <8 x i64> %y) ret <8 x i64> %0 } -; CHECK: error: couldn't allocate output register for constraint 'k' +; CHECK: error: couldn't allocate output register for constraint 'k': register is unavailable without AVX512 or AVX512BW define i32 @k_wise_op_i32(i32 %msk_src1, i32 %msk_src2) { entry: %0 = tail call i32 asm "kandd\09$2, $1, $0", "=k,k,k,~{dirflag},~{fpsr},~{flags}"(i32 %msk_src1, i32 %msk_src2) ret i32 %0 } -; CHECK: error: couldn't allocate output register for constraint 'k' +; CHECK: error: couldn't allocate output register for constraint 'k': register is unavailable without AVX512 or AVX512BW define i64 @k_wise_op_i64(i64 %msk_src1, i64 %msk_src2) { entry: %0 = tail call i64 asm "kandq\09$2, $1, $0", "=k,k,k,~{dirflag},~{fpsr},~{flags}"(i64 %msk_src1, i64 %msk_src2) diff --git a/llvm/test/CodeGen/X86/asm-reject-x87-int.ll b/llvm/test/CodeGen/X86/asm-reject-x87-int.ll index 233a0df5ba46b..e79d358aa3075 100644 --- a/llvm/test/CodeGen/X86/asm-reject-x87-int.ll +++ b/llvm/test/CodeGen/X86/asm-reject-x87-int.ll @@ -22,7 +22,7 @@ %struct.float4 = type { float } -; CHECK: error: couldn't allocate output register for constraint '{st}' +; CHECK: error: couldn't allocate output register for constraint '{st}': register is unavailable define dso_local i32 @foo() { entry: %retval = alloca i32, align 4 diff --git a/llvm/test/CodeGen/X86/asm-reject-xmm16.ll b/llvm/test/CodeGen/X86/asm-reject-xmm16.ll index 52915d9558b9c..b898d16dcd45f 100644 --- a/llvm/test/CodeGen/X86/asm-reject-xmm16.ll +++ b/llvm/test/CodeGen/X86/asm-reject-xmm16.ll @@ -1,7 +1,8 @@ -; RUN: not llc -o /dev/null %s -mtriple=x86_64-unknown-unknown 2>&1 | FileCheck %s -; RUN: not llc -o /dev/null %s -mtriple=i386-unknown-unknown -mattr=avx512vl 2>&1 | FileCheck %s +; RUN: not llc -o /dev/null %s -mtriple=x86_64-unknown-unknown 2>&1 | FileCheck %s -check-prefix X64 +; RUN: not llc -o /dev/null %s -mtriple=i386-unknown-unknown -mattr=avx512vl 2>&1 | FileCheck %s -check-prefix X86 -; CHECK: error: couldn't allocate output register for constraint '{xmm16}' +; X64: error: couldn't allocate output register for constraint '{xmm16}': register is unavailable without AVX512F +; X86: error: couldn't allocate output register for constraint '{xmm16}': register is unavailable in 32-bit mode define i64 @blup() { %v = tail call i64 asm "", "={xmm16},0"(i64 0) ret i64 %v diff --git a/llvm/test/CodeGen/X86/inline-asm-avx512f-x-constraint.ll b/llvm/test/CodeGen/X86/inline-asm-avx512f-x-constraint.ll index e153387d16e72..d355a5ca5bad9 100644 --- a/llvm/test/CodeGen/X86/inline-asm-avx512f-x-constraint.ll +++ b/llvm/test/CodeGen/X86/inline-asm-avx512f-x-constraint.ll @@ -18,7 +18,7 @@ entry: ; FP16: %[[REG1:.*]]:vr512_0_15 = COPY %1 ; FP16: %[[REG2:.*]]:vr512_0_15 = COPY %2 ; FP16: INLINEASM &"vaddph\09$3, $2, $0 {$1}", 0 /* attdialect */, {{.*}}, def %{{.*}}, {{.*}}, %{{.*}}, {{.*}}, %[[REG1]], {{.*}}, %[[REG2]], 12 /* clobber */, implicit-def early-clobber $df, 12 /* clobber */, implicit-def early-clobber $fpsw, 12 /* clobber */, implicit-def early-clobber $eflags -; CHECK-STDERR: couldn't allocate output register for constraint 'x' +; CHECK-STDERR: couldn't allocate output register for constraint 'x': register is unavailable without AVX512FP16 define <32 x half> @mask_Yk_f16(i8 signext %msk, <32 x half> %x, <32 x half> %y) { entry: %0 = tail call <32 x half> asm "vaddph\09$3, $2, $0 {$1}", "=x,^Yk,x,x,~{dirflag},~{fpsr},~{flags}"(i8 %msk, <32 x half> %x, <32 x half> %y) @@ -29,7 +29,7 @@ entry: ; FP16: %[[REG1:.*]]:vr512_0_15 = COPY %1 ; FP16: %[[REG2:.*]]:vr512_0_15 = COPY %2 ; FP16: INLINEASM &"vaddph\09$3, $2, $0 {$1}", 0 /* attdialect */, {{.*}}, def %{{.*}}, {{.*}}, %{{.*}}, {{.*}}, %[[REG1]], {{.*}}, %[[REG2]], 12 /* clobber */, implicit-def early-clobber $df, 12 /* clobber */, implicit-def early-clobber $fpsw, 12 /* clobber */, implicit-def early-clobber $eflags -; CHECK-STDERR: couldn't allocate output register for constraint 'x' +; CHECK-STDERR: couldn't allocate output register for constraint 'x': register is unavailable without AVX512BF16 define <32 x bfloat> @mask_Yk_bf16(i8 signext %msk, <32 x bfloat> %x, <32 x bfloat> %y) { entry: %0 = tail call <32 x bfloat> asm "vaddph\09$3, $2, $0 {$1}", "=x,^Yk,x,x,~{dirflag},~{fpsr},~{flags}"(i8 %msk, <32 x bfloat> %x, <32 x bfloat> %y) diff --git a/llvm/test/CodeGen/X86/inline-asm-x-i128.ll b/llvm/test/CodeGen/X86/inline-asm-x-i128.ll index 7aee1d175494e..281921ff570a8 100644 --- a/llvm/test/CodeGen/X86/inline-asm-x-i128.ll +++ b/llvm/test/CodeGen/X86/inline-asm-x-i128.ll @@ -4,7 +4,7 @@ ; RUN: not llc < %s -mtriple=i386-unknown-linux-gnu 2>&1 | FileCheck %s --check-prefix=ERROR ; For 32-bit we still error since __int128 isn't supported in the frontend. -; ERROR: error: couldn't allocate output register for constraint 'x' +; ERROR: error: couldn't allocate output register for constraint 'x': register is unavailable without SSE1 define { i64, i64 } @foo(i64 %0, i64 %1) { ; CHECK-LABEL: foo: diff --git a/llvm/test/CodeGen/X86/pr37359.ll b/llvm/test/CodeGen/X86/pr37359.ll index 5032855ff3e9d..3a272e315f8f6 100644 --- a/llvm/test/CodeGen/X86/pr37359.ll +++ b/llvm/test/CodeGen/X86/pr37359.ll @@ -3,7 +3,7 @@ target triple = "x86_64--" @a = global i32 0, align 4 -; CHECK: error: couldn't allocate input reg for constraint 'x' +; CHECK: error: couldn't allocate input reg for constraint 'x': couldn't allocate for type i1 define i32 @main() { entry: %0 = load i32, ptr @a, align 4 diff --git a/llvm/test/CodeGen/X86/pr50907.ll b/llvm/test/CodeGen/X86/pr50907.ll index c6af54d5ab8b4..95de1b1fdddf4 100644 --- a/llvm/test/CodeGen/X86/pr50907.ll +++ b/llvm/test/CodeGen/X86/pr50907.ll @@ -2,7 +2,7 @@ ; RUN: not llc -o /dev/null %s 2>&1 | FileCheck %s target triple = "x86_64-unknown-linux-gnu" -; CHECK: error: couldn't allocate input reg for constraint 'r' +; CHECK: error: couldn't allocate input reg for constraint 'r': couldn't allocate for type v8i16 define i32 @f2() #0 { entry: %retval = alloca i32, align 4