Skip to content

Commit fcd6421

Browse files
committed
[TableGen][GISel] Learn to import patterns with optional defs
1 parent d375041 commit fcd6421

File tree

4 files changed

+65
-11
lines changed

4 files changed

+65
-11
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common < %s | FileCheck %s
2+
3+
include "llvm/Target/Target.td"
4+
include "GlobalISelEmitterCommon.td"
5+
6+
def cc_out : OptionalDefOperand<i32, (ops GPR8), (ops (i8 zero_reg))>;
7+
def s_cc_out : OptionalDefOperand<i32, (ops GPR8, FPR32), (ops (i8 B0), F0)>;
8+
9+
// CHECK-LABEL: // (add:{ *:[i32] } i32:{ *:[i32] }:$rs1, i32:{ *:[i32] }:$rs2) => (tst2:{ *:[i32] } i32:{ *:[i32] }:$rs1, i32:{ *:[i32] }:$rs2)
10+
// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::tst2),
11+
// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[rd]
12+
// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, GIMT_Encode2(MyTarget::B0), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define | RegState::Dead),
13+
// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, GIMT_Encode2(MyTarget::F0), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define | RegState::Dead),
14+
// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/1, // rs1
15+
// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/2, // rs2
16+
// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
17+
// CHECK-NEXT: // GIR_Coverage, 1,
18+
// CHECK-NEXT: GIR_EraseRootFromParent_Done,
19+
20+
// CHECK-LABEL: // (imm:{ *:[i32] }):$imm => (tst1:{ *:[i32] } (imm:{ *:[i32] }):$imm)
21+
// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::tst1),
22+
// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[rd]
23+
// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, GIMT_Encode2(MyTarget::NoRegister), /*AddRegisterRegFlags*/GIMT_Encode2(RegState::Define | RegState::Dead),
24+
// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
25+
// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
26+
// CHECK-NEXT: // GIR_Coverage, 0,
27+
// CHECK-NEXT: GIR_EraseRootFromParent_Done,
28+
29+
def tst1 : I<(outs GPR32:$rd, cc_out:$s), (ins i32imm:$imm),
30+
[(set GPR32:$rd, imm:$imm)]>;
31+
32+
def tst2 : I<(outs GPR32:$rd, s_cc_out:$s), (ins GPR32:$rs1, GPR32:$rs2),
33+
[(set GPR32:$rd, (add i32:$rs1, i32:$rs2))]>;
34+
35+
// TODO: There should be more tests, but any attempt to write something
36+
// more complex results in tablegen crashing somewhere in
37+
// TreePatternNode::UpdateNodeType.

llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,10 +1993,13 @@ void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
19931993
// TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are
19941994
// really needed for a physical register reference. We can pack the
19951995
// register and flags in a single field.
1996-
if (IsDef)
1997-
Table << MatchTable::NamedValue(2, "RegState::Define");
1998-
else
1996+
if (IsDef) {
1997+
Table << MatchTable::NamedValue(
1998+
2, IsDead ? "RegState::Define | RegState::Dead" : "RegState::Define");
1999+
} else {
2000+
assert(!IsDead && "A use cannot be dead");
19992001
Table << MatchTable::IntValue(2, 0);
2002+
}
20002003
Table << MatchTable::LineBreak;
20012004
}
20022005

llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,13 +2091,15 @@ class AddRegisterRenderer : public OperandRenderer {
20912091
unsigned InsnID;
20922092
const Record *RegisterDef;
20932093
bool IsDef;
2094+
bool IsDead;
20942095
const CodeGenTarget &Target;
20952096

20962097
public:
20972098
AddRegisterRenderer(unsigned InsnID, const CodeGenTarget &Target,
2098-
const Record *RegisterDef, bool IsDef = false)
2099+
const Record *RegisterDef, bool IsDef = false,
2100+
bool IsDead = false)
20992101
: OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef),
2100-
IsDef(IsDef), Target(Target) {}
2102+
IsDef(IsDef), IsDead(IsDead), Target(Target) {}
21012103

21022104
static bool classof(const OperandRenderer *R) {
21032105
return R->getKind() == OR_Register;

llvm/utils/TableGen/GlobalISelEmitter.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,14 +1451,10 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
14511451
const TreePatternNode &Src, const TreePatternNode &Dst, unsigned Start) {
14521452
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
14531453

1454-
// Some instructions have multiple defs, but are missing a type entry
1455-
// (e.g. s_cc_out operands).
1456-
if (Dst.getExtTypes().size() < DstI->Operands.NumDefs)
1457-
return failedImport("unhandled discarded def");
1458-
14591454
// Process explicit defs. The caller may have already handled the first def.
14601455
for (unsigned I = Start, E = DstI->Operands.NumDefs; I != E; ++I) {
1461-
std::string OpName = getMangledRootDefName(DstI->Operands[I].Name);
1456+
const CGIOperandList::OperandInfo &OpInfo = DstI->Operands[I];
1457+
std::string OpName = getMangledRootDefName(OpInfo.Name);
14621458

14631459
// If the def is used in the source DAG, forward it.
14641460
if (M.hasOperand(OpName)) {
@@ -1469,6 +1465,22 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
14691465
continue;
14701466
}
14711467

1468+
// A discarded explicit def may be an optional physical register.
1469+
// If this is the case, add the default register and mark it as dead.
1470+
if (OpInfo.Rec->isSubClassOf("OptionalDefOperand")) {
1471+
for (const TreePatternNode &DefaultOp :
1472+
make_pointee_range(CGP.getDefaultOperand(OpInfo.Rec).DefaultOps)) {
1473+
const Record *Reg = cast<DefInit>(DefaultOp.getLeafValue())->getDef();
1474+
1475+
if (!Reg->isSubClassOf("Register") && Reg->getName() != "zero_reg")
1476+
return failedImport("optional def is not a register");
1477+
1478+
DstMIBuilder.addRenderer<AddRegisterRenderer>(
1479+
Target, Reg, /*IsDef=*/true, /*IsDead=*/true);
1480+
}
1481+
continue;
1482+
}
1483+
14721484
// The def is discarded, create a dead virtual register for it.
14731485
const TypeSetByHwMode &ExtTy = Dst.getExtType(I);
14741486
if (!ExtTy.isMachineValueType())

0 commit comments

Comments
 (0)