[TableGen][GlobalISel] Allow duplicate RendererFns

Allow different GICustomOperandRenderers to use the same RendererFn.
This avoids the need for targets to define a bunch of identical C++
renderer functions with different names.

Without this fix TableGen would have emitted code that tried to define
the GICR enumeration with duplicate enumerators.

Differential Revision: https://reviews.llvm.org/D96587
This commit is contained in:
Jay Foad 2020-08-27 16:15:33 +01:00
parent cea9f05432
commit 7e9ceed9a2
4 changed files with 25 additions and 37 deletions

View File

@ -305,16 +305,16 @@ foreach Ty = [i64, p0, p1, p4] in {
defm : SMRD_Pattern <"S_LOAD_DWORDX2", Ty>;
}
def gi_as_i32timm : GICustomOperandRenderer<"renderTruncTImm32">,
def gi_as_i32timm : GICustomOperandRenderer<"renderTruncTImm">,
GISDNodeXFormEquiv<as_i32timm>;
def gi_as_i16timm : GICustomOperandRenderer<"renderTruncTImm16">,
def gi_as_i16timm : GICustomOperandRenderer<"renderTruncTImm">,
GISDNodeXFormEquiv<as_i16timm>;
def gi_as_i8timm : GICustomOperandRenderer<"renderTruncTImm8">,
def gi_as_i8timm : GICustomOperandRenderer<"renderTruncTImm">,
GISDNodeXFormEquiv<as_i8timm>;
def gi_as_i1timm : GICustomOperandRenderer<"renderTruncTImm1">,
def gi_as_i1timm : GICustomOperandRenderer<"renderTruncTImm">,
GISDNodeXFormEquiv<as_i1timm>;
def gi_NegateImm : GICustomOperandRenderer<"renderNegateImm">,

View File

@ -275,26 +275,6 @@ private:
void renderTruncTImm(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const;
void renderTruncTImm1(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const {
renderTruncTImm(MIB, MI, OpIdx);
}
void renderTruncTImm8(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const {
renderTruncTImm(MIB, MI, OpIdx);
}
void renderTruncTImm16(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const {
renderTruncTImm(MIB, MI, OpIdx);
}
void renderTruncTImm32(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const {
renderTruncTImm(MIB, MI, OpIdx);
}
void renderNegateImm(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const;

View File

@ -51,9 +51,11 @@ def cimm8_xform : SDNodeXForm<imm, [{
def cimm8 : Operand<i32>, ImmLeaf<i32, [{return isInt<8>(Imm);}], cimm8_xform>;
def gi_cimm8 : GICustomOperandRenderer<"renderImm8">,
def gi_cimm8 : GICustomOperandRenderer<"renderImm">,
GISDNodeXFormEquiv<cimm8_xform>;
def gi_cimm9 : GICustomOperandRenderer<"renderImm">;
def m1 : OperandWithDefaultOps <i32, (ops (i32 -1))>;
def Z : OperandWithDefaultOps <i32, (ops R0)>;
def m1Z : OperandWithDefaultOps <i32, (ops (i32 -1), R0)>;
@ -206,12 +208,12 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-LABEL: // Custom renderers.
// CHECK-NEXT: enum {
// CHECK-NEXT: GICR_Invalid,
// CHECK-NEXT: GICR_renderImm8,
// CHECK-NEXT: GICR_renderImm,
// CHECK-NEXT: };
// CHECK-NEXT: MyTargetInstructionSelector::CustomRendererFn
// CHECK-NEXT: MyTargetInstructionSelector::CustomRenderers[] = {
// CHECK-NEXT: nullptr, // GICR_Invalid
// CHECK-NEXT: &MyTargetInstructionSelector::renderImm8, // gi_cimm8
// CHECK-NEXT: &MyTargetInstructionSelector::renderImm,
// CHECK-NEXT: };
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
@ -906,7 +908,7 @@ def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$i
// NOOPT-NEXT: // (imm:{ *:[i32] })<<P:Predicate_cimm8>><<X:cimm8_xform>>:$imm => (MOVcimm8:{ *:[i32] } (cimm8_xform:{ *:[i32] } (imm:{ *:[i32] }):$imm))
// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVcimm8,
// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// NOOPT-NEXT: GIR_CustomRenderer, /*InsnID*/0, /*OldInsnID*/0, /*Renderer*/GICR_renderImm8, // imm
// NOOPT-NEXT: GIR_CustomRenderer, /*InsnID*/0, /*OldInsnID*/0, /*Renderer*/GICR_renderImm, // imm
// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// NOOPT-NEXT: // GIR_Coverage, 10,

View File

@ -5595,9 +5595,17 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
RK.getAllDerivedDefinitions("GIComplexOperandMatcher");
llvm::sort(ComplexPredicates, orderByName);
std::vector<Record *> CustomRendererFns =
RK.getAllDerivedDefinitions("GICustomOperandRenderer");
llvm::sort(CustomRendererFns, orderByName);
std::vector<StringRef> CustomRendererFns;
transform(RK.getAllDerivedDefinitions("GICustomOperandRenderer"),
std::back_inserter(CustomRendererFns), [](const auto &Record) {
return Record->getValueAsString("RendererFn");
});
// Sort and remove duplicates to get a list of unique renderer functions, in
// case some were mentioned more than once.
llvm::sort(CustomRendererFns);
CustomRendererFns.erase(
std::unique(CustomRendererFns.begin(), CustomRendererFns.end()),
CustomRendererFns.end());
unsigned MaxTemporaries = 0;
for (const auto &Rule : Rules)
@ -5791,17 +5799,15 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
OS << "// Custom renderers.\n"
<< "enum {\n"
<< " GICR_Invalid,\n";
for (const auto &Record : CustomRendererFns)
OS << " GICR_" << Record->getValueAsString("RendererFn") << ",\n";
for (const auto &Fn : CustomRendererFns)
OS << " GICR_" << Fn << ",\n";
OS << "};\n";
OS << Target.getName() << "InstructionSelector::CustomRendererFn\n"
<< Target.getName() << "InstructionSelector::CustomRenderers[] = {\n"
<< " nullptr, // GICR_Invalid\n";
for (const auto &Record : CustomRendererFns)
OS << " &" << Target.getName()
<< "InstructionSelector::" << Record->getValueAsString("RendererFn")
<< ", // " << Record->getName() << "\n";
for (const auto &Fn : CustomRendererFns)
OS << " &" << Target.getName() << "InstructionSelector::" << Fn << ",\n";
OS << "};\n\n";
llvm::stable_sort(Rules, [&](const RuleMatcher &A, const RuleMatcher &B) {