Skip to content

(reland) [GlobalISel] Diagnose inline assembly constraint lowering errors #139049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 41 additions & 33 deletions llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Module.h"

#define DEBUG_TYPE "inline-asm-lowering"
Expand Down Expand Up @@ -231,6 +232,19 @@ bool InlineAsmLowering::lowerInlineAsm(
TargetLowering::AsmOperandInfoVector TargetConstraints =
TLI->ParseConstraints(DL, TRI, Call);

const auto ConstraintError = [&](const GISelAsmOperandInfo &Info, Twine Msg) {
// Use warnings in combination with a "return false" to trigger the fallback
// path. If fallback isn't enabled, then another error will be emitted later
// and the warnings will provide context as to why the error occured.
LLVMContext &Ctx = MIRBuilder.getContext();
Ctx.diagnose(DiagnosticInfoInlineAsm(
Call, "invalid constraint '" + Info.ConstraintCode + "': " + Msg,
DS_Warning));
// TODO: If we could detect that the fallback isn't enabled, we could
// recover here by defining all result registers as G_IMPLICIT_DEF.
return false;
};

ExtraFlags ExtraInfo(Call);
unsigned ArgNo = 0; // ArgNo - The argument of the CallInst.
unsigned ResNo = 0; // ResNo - The result number of the next output.
Expand All @@ -243,8 +257,8 @@ bool InlineAsmLowering::lowerInlineAsm(
OpInfo.CallOperandVal = const_cast<Value *>(Call.getArgOperand(ArgNo));

if (isa<BasicBlock>(OpInfo.CallOperandVal)) {
LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n");
return false;
return ConstraintError(OpInfo,
"basic block input operands not supported yet");
}

Type *OpTy = OpInfo.CallOperandVal->getType();
Expand All @@ -258,9 +272,8 @@ bool InlineAsmLowering::lowerInlineAsm(

// FIXME: Support aggregate input operands
if (!OpTy->isSingleValueType()) {
LLVM_DEBUG(
dbgs() << "Aggregate input operands are not supported yet\n");
return false;
return ConstraintError(OpInfo,
"aggregate input operands not supported yet");
}

OpInfo.ConstraintVT =
Expand Down Expand Up @@ -344,9 +357,8 @@ bool InlineAsmLowering::lowerInlineAsm(

// Find a register that we can use.
if (OpInfo.Regs.empty()) {
LLVM_DEBUG(dbgs()
<< "Couldn't allocate output register for constraint\n");
return false;
return ConstraintError(
OpInfo, "could not allocate output register for constraint");
}

// Add information to the INLINEASM instruction to know that this
Expand Down Expand Up @@ -389,13 +401,13 @@ bool InlineAsmLowering::lowerInlineAsm(

const InlineAsm::Flag MatchedOperandFlag(Inst->getOperand(InstFlagIdx).getImm());
if (MatchedOperandFlag.isMemKind()) {
LLVM_DEBUG(dbgs() << "Matching input constraint to mem operand not "
"supported. This should be target specific.\n");
return false;
return ConstraintError(
OpInfo,
"matching input constraint to mem operand not supported; this "
"should be target specific");
}
if (!MatchedOperandFlag.isRegDefKind() && !MatchedOperandFlag.isRegDefEarlyClobberKind()) {
LLVM_DEBUG(dbgs() << "Unknown matching constraint\n");
return false;
return ConstraintError(OpInfo, "unknown matching constraint");
}

// We want to tie input to register in next operand.
Expand Down Expand Up @@ -425,9 +437,10 @@ bool InlineAsmLowering::lowerInlineAsm(

if (OpInfo.ConstraintType == TargetLowering::C_Other &&
OpInfo.isIndirect) {
LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "
"not supported yet\n");
return false;
return ConstraintError(
OpInfo,
"indirect input operands with unknown constraint not supported "
"yet");
}

if (OpInfo.ConstraintType == TargetLowering::C_Immediate ||
Expand All @@ -437,9 +450,7 @@ bool InlineAsmLowering::lowerInlineAsm(
if (!lowerAsmOperandForConstraint(OpInfo.CallOperandVal,
OpInfo.ConstraintCode, Ops,
MIRBuilder)) {
LLVM_DEBUG(dbgs() << "Don't support constraint: "
<< OpInfo.ConstraintCode << " yet\n");
return false;
return ConstraintError(OpInfo, "unsupported constraint");
}

assert(Ops.size() > 0 &&
Expand All @@ -456,9 +467,8 @@ bool InlineAsmLowering::lowerInlineAsm(
if (OpInfo.ConstraintType == TargetLowering::C_Memory) {

if (!OpInfo.isIndirect) {
LLVM_DEBUG(dbgs()
<< "Cannot indirectify memory input operands yet\n");
return false;
return ConstraintError(
OpInfo, "indirect memory input operands are not supported yet");
}

assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!");
Expand All @@ -482,18 +492,15 @@ bool InlineAsmLowering::lowerInlineAsm(
"Unknown constraint type!");

if (OpInfo.isIndirect) {
LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "
"for constraint '"
<< OpInfo.ConstraintCode << "'\n");
return false;
return ConstraintError(
OpInfo, "indirect register inputs are not supported yet");
}

// Copy the input into the appropriate registers.
if (OpInfo.Regs.empty()) {
LLVM_DEBUG(
dbgs()
<< "Couldn't allocate input register for register constraint\n");
return false;
return ConstraintError(
OpInfo,
"could not allocate input register for register constraint");
}

unsigned NumRegs = OpInfo.Regs.size();
Expand All @@ -503,9 +510,10 @@ bool InlineAsmLowering::lowerInlineAsm(
"source registers");

if (NumRegs > 1) {
LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are "
"not supported yet\n");
return false;
return ConstraintError(
OpInfo,
"input operands with multiple input registers are not supported "
"yet");
}

InlineAsm::Flag Flag(InlineAsm::Kind::RegUse, NumRegs);
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/CodeGen/AMDGPU/GlobalISel/inline-asm-lowering-diags.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; RUN: not llc -mtriple=amdgcn -mcpu=fiji -O0 -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' %s -o - 2>&1 | FileCheck %s

; CHECK: warning: invalid constraint '': aggregate input operands not supported yet
define amdgpu_kernel void @aggregates([4 x i8] %val) {
tail call void asm sideeffect "s_nop", "r"([4 x i8] %val)
ret void
}

; CHECK: warning: invalid constraint '{s999}': could not allocate output register for constraint
define amdgpu_kernel void @bad_output() {
tail call i32 asm sideeffect "s_nop", "={s999}"()
ret void
}

; CHECK: warning: invalid constraint '{s998}': could not allocate input register for register constraint
define amdgpu_kernel void @bad_input() {
tail call void asm sideeffect "s_nop", "{s998}"(i32 poison)
ret void
}
; CHECK: warning: invalid constraint '{s997}': indirect register inputs are not supported yet
define amdgpu_kernel void @indirect_input() {
tail call void asm sideeffect "s_nop", "*{s997}"(ptr elementtype(i32) poison)
ret void
}

; CHECK: warning: invalid constraint 'i': unsupported constraint
define amdgpu_kernel void @badimm() {
tail call void asm sideeffect "s_nop", "i"(i32 poison)
ret void
}
Loading