[llvm] [CodeGen] Enhance inline asm constraint diagnostics (PR #101354)

Evgenii Kudriashov via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 31 09:04:48 PDT 2024


https://github.com/e-kud created https://github.com/llvm/llvm-project/pull/101354

None

>From 2dce3e99fb63f3d5ba8ae4ffffbcce756e635960 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *> 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<unsigned, const TargetRegisterClass *> MatchRC =
       TLI.getRegForInlineAsmConstraint(TRI, OpInfo.ConstraintCode,
-                                       OpInfo.ConstraintVT);
+                                       OpInfo.ConstraintVT, ErrMsg);
   std::pair<unsigned, const TargetRegisterClass *> 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<unsigned>
+static std::optional<std::string>
 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<unsigned, const TargetRegisterClass *>
 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<TargetRegisterClass *>(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<unsigned, const TargetRegisterClass *> MatchRC =
             getRegForInlineAsmConstraint(TRI, OpInfo.ConstraintCode,
-                                         OpInfo.ConstraintVT);
+                                         OpInfo.ConstraintVT, ErrMsg);
         std::pair<unsigned, const TargetRegisterClass *> 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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<SDValue> &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<unsigned, const TargetRegisterClass *>
     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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<SDValue> &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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
     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<unsigned, const TargetRegisterClass *>
     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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
     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<unsigned, const TargetRegisterClass *>
   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<SDValue> &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<unsigned, const TargetRegisterClass *>
   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<MVT> 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<unsigned, const TargetRegisterClass *>
     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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
   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<unsigned, const TargetRegisterClass *>
 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<Register, const TargetRegisterClass*> 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<unsigned, const TargetRegisterClass *>
     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<unsigned, const TargetRegisterClass *>
     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> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8>) #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



More information about the llvm-commits mailing list