Skip to content

Commit c22081c

Browse files
authored
[GlobalISel] Diagnose inline assembly constraint lowering errors (#135782)
Instead of printing something to dbgs (which is not visible to all users), emit a diagnostic like the DAG does. We still crash later because we fail to select the inline assembly, but at least now users will know why it's crashing. In a future patch we could also recover from the error like the DAG does, so the lowering can keep going until it either crashes or gives a different error later.
1 parent c3a638c commit c22081c

File tree

6 files changed

+75
-37
lines changed

6 files changed

+75
-37
lines changed

llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/CodeGen/MachineOperand.h"
1717
#include "llvm/CodeGen/MachineRegisterInfo.h"
1818
#include "llvm/CodeGen/TargetLowering.h"
19+
#include "llvm/IR/DiagnosticInfo.h"
1920
#include "llvm/IR/Module.h"
2021

2122
#define DEBUG_TYPE "inline-asm-lowering"
@@ -231,6 +232,15 @@ bool InlineAsmLowering::lowerInlineAsm(
231232
TargetLowering::AsmOperandInfoVector TargetConstraints =
232233
TLI->ParseConstraints(DL, TRI, Call);
233234

235+
const auto ConstraintError = [&](const GISelAsmOperandInfo &Info, Twine Msg) {
236+
LLVMContext &Ctx = MIRBuilder.getContext();
237+
Ctx.diagnose(DiagnosticInfoInlineAsm(
238+
Call, "invalid constraint '" + Info.ConstraintCode + "': " + Msg));
239+
// TODO: Recover if fallback isn't used. Otherwise let the fallback to DAG
240+
// kick in.
241+
return false;
242+
};
243+
234244
ExtraFlags ExtraInfo(Call);
235245
unsigned ArgNo = 0; // ArgNo - The argument of the CallInst.
236246
unsigned ResNo = 0; // ResNo - The result number of the next output.
@@ -243,8 +253,8 @@ bool InlineAsmLowering::lowerInlineAsm(
243253
OpInfo.CallOperandVal = const_cast<Value *>(Call.getArgOperand(ArgNo));
244254

245255
if (isa<BasicBlock>(OpInfo.CallOperandVal)) {
246-
LLVM_DEBUG(dbgs() << "Basic block input operands not supported yet\n");
247-
return false;
256+
return ConstraintError(OpInfo,
257+
"basic block input operands not supported yet");
248258
}
249259

250260
Type *OpTy = OpInfo.CallOperandVal->getType();
@@ -258,9 +268,8 @@ bool InlineAsmLowering::lowerInlineAsm(
258268

259269
// FIXME: Support aggregate input operands
260270
if (!OpTy->isSingleValueType()) {
261-
LLVM_DEBUG(
262-
dbgs() << "Aggregate input operands are not supported yet\n");
263-
return false;
271+
return ConstraintError(OpInfo,
272+
"aggregate input operands not supported yet");
264273
}
265274

266275
OpInfo.ConstraintVT =
@@ -344,9 +353,8 @@ bool InlineAsmLowering::lowerInlineAsm(
344353

345354
// Find a register that we can use.
346355
if (OpInfo.Regs.empty()) {
347-
LLVM_DEBUG(dbgs()
348-
<< "Couldn't allocate output register for constraint\n");
349-
return false;
356+
return ConstraintError(
357+
OpInfo, "could not allocate output register for constraint");
350358
}
351359

352360
// Add information to the INLINEASM instruction to know that this
@@ -389,13 +397,13 @@ bool InlineAsmLowering::lowerInlineAsm(
389397

390398
const InlineAsm::Flag MatchedOperandFlag(Inst->getOperand(InstFlagIdx).getImm());
391399
if (MatchedOperandFlag.isMemKind()) {
392-
LLVM_DEBUG(dbgs() << "Matching input constraint to mem operand not "
393-
"supported. This should be target specific.\n");
394-
return false;
400+
return ConstraintError(
401+
OpInfo,
402+
"matching input constraint to mem operand not supported; this "
403+
"should be target specific");
395404
}
396405
if (!MatchedOperandFlag.isRegDefKind() && !MatchedOperandFlag.isRegDefEarlyClobberKind()) {
397-
LLVM_DEBUG(dbgs() << "Unknown matching constraint\n");
398-
return false;
406+
return ConstraintError(OpInfo, "unknown matching constraint");
399407
}
400408

401409
// We want to tie input to register in next operand.
@@ -425,9 +433,10 @@ bool InlineAsmLowering::lowerInlineAsm(
425433

426434
if (OpInfo.ConstraintType == TargetLowering::C_Other &&
427435
OpInfo.isIndirect) {
428-
LLVM_DEBUG(dbgs() << "Indirect input operands with unknown constraint "
429-
"not supported yet\n");
430-
return false;
436+
return ConstraintError(
437+
OpInfo,
438+
"indirect input operands with unknown constraint not supported "
439+
"yet");
431440
}
432441

433442
if (OpInfo.ConstraintType == TargetLowering::C_Immediate ||
@@ -437,9 +446,7 @@ bool InlineAsmLowering::lowerInlineAsm(
437446
if (!lowerAsmOperandForConstraint(OpInfo.CallOperandVal,
438447
OpInfo.ConstraintCode, Ops,
439448
MIRBuilder)) {
440-
LLVM_DEBUG(dbgs() << "Don't support constraint: "
441-
<< OpInfo.ConstraintCode << " yet\n");
442-
return false;
449+
return ConstraintError(OpInfo, "unsupported constraint");
443450
}
444451

445452
assert(Ops.size() > 0 &&
@@ -456,9 +463,8 @@ bool InlineAsmLowering::lowerInlineAsm(
456463
if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
457464

458465
if (!OpInfo.isIndirect) {
459-
LLVM_DEBUG(dbgs()
460-
<< "Cannot indirectify memory input operands yet\n");
461-
return false;
466+
return ConstraintError(
467+
OpInfo, "indirect memory input operands are not supported yet");
462468
}
463469

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

484490
if (OpInfo.isIndirect) {
485-
LLVM_DEBUG(dbgs() << "Can't handle indirect register inputs yet "
486-
"for constraint '"
487-
<< OpInfo.ConstraintCode << "'\n");
488-
return false;
491+
return ConstraintError(
492+
OpInfo, "indirect register inputs are not supported yet");
489493
}
490494

491495
// Copy the input into the appropriate registers.
492496
if (OpInfo.Regs.empty()) {
493-
LLVM_DEBUG(
494-
dbgs()
495-
<< "Couldn't allocate input register for register constraint\n");
496-
return false;
497+
return ConstraintError(
498+
OpInfo,
499+
"could not allocate input register for register constraint");
497500
}
498501

499502
unsigned NumRegs = OpInfo.Regs.size();
@@ -503,9 +506,10 @@ bool InlineAsmLowering::lowerInlineAsm(
503506
"source registers");
504507

505508
if (NumRegs > 1) {
506-
LLVM_DEBUG(dbgs() << "Input operands with multiple input registers are "
507-
"not supported yet\n");
508-
return false;
509+
return ConstraintError(
510+
OpInfo,
511+
"input operands with multiple input registers are not supported "
512+
"yet");
509513
}
510514

511515
InlineAsm::Flag Flag(InlineAsm::Kind::RegUse, NumRegs);

llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
; RUN: llc -O0 -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o %t.out 2> %t.err
1+
; RUN: not llc -O0 -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o - > %t.out 2> %t.err
22
; RUN: FileCheck %s --check-prefix=FALLBACK-WITH-REPORT-OUT < %t.out
33
; RUN: FileCheck %s --check-prefix=FALLBACK-WITH-REPORT-ERR < %t.err
44
; RUN: not --crash llc -global-isel -mtriple aarch64_be %s -o - 2>&1 | FileCheck %s --check-prefix=BIG-ENDIAN
5+
56
; This file checks that the fallback path to selection dag works.
67
; The test is fragile in the sense that it must be updated to expose
78
; something that fails with global-isel.
89
; When we cannot produce a test case anymore, that means we can remove
910
; the fallback path.
1011

12+
; -o - > %t.out is used instead of -o %t.out because llc does not write the output
13+
; file if an error is emitted, but it will still print to stdout.
14+
1115
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
1216
target triple = "aarch64--"
1317

llvm/test/CodeGen/AArch64/arm64-preserve-all.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ define preserve_allcc void @preserve_all() {
4343
define dso_local void @normal_cc_caller() {
4444
entry:
4545
%v = alloca i32, align 4
46-
call void asm sideeffect "mov x9, $0", "N,~{x9}"(i32 48879) #2
46+
call void asm sideeffect "mov x9, $0", "n,~{x9}"(i32 48879) #2
4747
call void asm sideeffect "movi v9.2d, #0","~{v9}" () #2
4848

4949

llvm/test/CodeGen/AArch64/arm64-preserve-most.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ define preserve_mostcc void @preserve_most() {
2929
define dso_local void @normal_cc_caller() {
3030
entry:
3131
%v = alloca i32, align 4
32-
call void asm sideeffect "mov x9, $0", "N,~{x9}"(i32 48879) #2
32+
call void asm sideeffect "mov x9, $0", "n,~{x9}"(i32 48879) #2
3333
call preserve_mostcc void @preserve_most()
3434
%0 = load i32, ptr %v, align 4
3535
%1 = call i32 asm sideeffect "mov ${0:w}, w9", "=r,r"(i32 %0) #2
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
; RUN: not llc -mtriple=amdgcn -mcpu=fiji -O0 -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' %s -o - 2>&1 | FileCheck %s
2+
3+
; CHECK: error: invalid constraint '': aggregate input operands not supported yet
4+
define amdgpu_kernel void @aggregates([4 x i8] %val) {
5+
tail call void asm sideeffect "s_nop", "r"([4 x i8] %val)
6+
ret void
7+
}
8+
9+
; CHECK: error: invalid constraint '{s999}': could not allocate output register for constraint
10+
define amdgpu_kernel void @bad_output() {
11+
tail call i32 asm sideeffect "s_nop", "={s999}"()
12+
ret void
13+
}
14+
15+
; CHECK: error: invalid constraint '{s998}': could not allocate input register for register constraint
16+
define amdgpu_kernel void @bad_input() {
17+
tail call void asm sideeffect "s_nop", "{s998}"(i32 poison)
18+
ret void
19+
}
20+
; CHECK: error: invalid constraint '{s997}': indirect register inputs are not supported yet
21+
define amdgpu_kernel void @indirect_input() {
22+
tail call void asm sideeffect "s_nop", "*{s997}"(ptr elementtype(i32) poison)
23+
ret void
24+
}
25+
26+
; CHECK: error: invalid constraint 'i': unsupported constraint
27+
define amdgpu_kernel void @badimm() {
28+
tail call void asm sideeffect "s_nop", "i"(i32 poison)
29+
ret void
30+
}

llvm/test/CodeGen/AMDGPU/GlobalISel/inline-asm-mismatched-size.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2-
; RUN: llc -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' -mtriple=amdgcn -mcpu=fiji -stop-after=irtranslator -verify-machineinstrs %s -o - 2>%t | FileCheck %s
2+
; RUN: not llc -global-isel -global-isel-abort=2 -pass-remarks-missed='gisel*' -mtriple=amdgcn -mcpu=fiji -stop-after=irtranslator -verify-machineinstrs %s -o - 2>%t | FileCheck %s
33
; RUN: FileCheck -check-prefix=ERR %s < %t
44

55
; ERR: remark: <unknown>:0:0: unable to translate instruction: call: ' %sgpr = call <4 x i32> asm sideeffect "; def $0", "={s[8:12]}"()' (in function: return_type_is_too_big_vector)

0 commit comments

Comments
 (0)