[llvm] r322582 - [GlobalISel][TableGen] Add support for SDNodeXForm
Volkan Keles via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 16 10:44:05 PST 2018
Author: volkan
Date: Tue Jan 16 10:44:05 2018
New Revision: 322582
URL: http://llvm.org/viewvc/llvm-project?rev=322582&view=rev
Log:
[GlobalISel][TableGen] Add support for SDNodeXForm
Summary:
This patch adds CustomRenderer which renders the matched
operands to the specified instruction.
Targets can enable the matching of SDNodeXForm by adding
a definition that inherits from GICustomOperandRenderer and
GISDNodeXFormEquiv as follows.
def gi_imm8 : GICustomOperandRenderer<"renderImm8”>,
GISDNodeXFormEquiv<imm8_xform>;
Custom renderer functions should be of the form:
void render(MachineInstrBuilder &MIB, const MachineInstr &I);
Reviewers: dsanders, ab, rovka
Reviewed By: dsanders
Subscribers: kristof.beyls, javed.absar, llvm-commits, mgrang, qcolombet
Differential Revision: https://reviews.llvm.org/D42012
Added:
llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-mul.mir
Modified:
llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
llvm/trunk/include/llvm/Target/GlobalISel/Target.td
llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
llvm/trunk/test/TableGen/GlobalISelEmitter.td
llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h Tue Jan 16 10:44:05 2018
@@ -235,6 +235,11 @@ enum {
/// - RendererID - The renderer to call
/// - RenderOpID - The suboperand to render.
GIR_ComplexSubOperandRenderer,
+ /// Render operands to the specified instruction using a custom function
+ /// - InsnID - Instruction ID to modify
+ /// - OldInsnID - Instruction ID to get the matched operand from
+ /// - RendererFnID - Custom renderer function to call
+ GIR_CustomRenderer,
/// Render a G_CONSTANT operator as a sign-extended immediate.
/// - NewInsnID - Instruction ID to modify
@@ -311,11 +316,13 @@ protected:
};
public:
- template <class PredicateBitset, class ComplexMatcherMemFn>
- struct MatcherInfoTy {
+ template <class PredicateBitset, class ComplexMatcherMemFn,
+ class CustomRendererFn>
+ struct ISelInfoTy {
const LLT *TypeObjects;
const PredicateBitset *FeatureBitsets;
const ComplexMatcherMemFn *ComplexPredicates;
+ const CustomRendererFn *CustomRenderers;
};
protected:
@@ -324,10 +331,11 @@ protected:
/// Execute a given matcher table and return true if the match was successful
/// and false otherwise.
template <class TgtInstructionSelector, class PredicateBitset,
- class ComplexMatcherMemFn>
+ class ComplexMatcherMemFn, class CustomRendererFn>
bool executeMatchTable(
TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
- const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> &MatcherInfo,
+ const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
+ &ISelInfo,
const int64_t *MatchTable, const TargetInstrInfo &TII,
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h Tue Jan 16 10:44:05 2018
@@ -43,10 +43,11 @@ enum {
};
template <class TgtInstructionSelector, class PredicateBitset,
- class ComplexMatcherMemFn>
+ class ComplexMatcherMemFn, class CustomRendererFn>
bool InstructionSelector::executeMatchTable(
TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
- const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> &MatcherInfo,
+ const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
+ &ISelInfo,
const int64_t *MatchTable, const TargetInstrInfo &TII,
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
@@ -124,8 +125,8 @@ bool InstructionSelector::executeMatchTa
dbgs() << CurrentIdx
<< ": GIM_CheckFeatures(ExpectedBitsetID="
<< ExpectedBitsetID << ")\n");
- if ((AvailableFeatures & MatcherInfo.FeatureBitsets[ExpectedBitsetID]) !=
- MatcherInfo.FeatureBitsets[ExpectedBitsetID]) {
+ if ((AvailableFeatures & ISelInfo.FeatureBitsets[ExpectedBitsetID]) !=
+ ISelInfo.FeatureBitsets[ExpectedBitsetID]) {
if (handleReject() == RejectAndGiveUp)
return false;
}
@@ -292,7 +293,7 @@ bool InstructionSelector::executeMatchTa
<< "), TypeID=" << TypeID << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
if (MRI.getType(State.MIs[InsnID]->getOperand(OpIdx).getReg()) !=
- MatcherInfo.TypeObjects[TypeID]) {
+ ISelInfo.TypeObjects[TypeID]) {
if (handleReject() == RejectAndGiveUp)
return false;
}
@@ -356,7 +357,7 @@ bool InstructionSelector::executeMatchTa
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
// FIXME: Use std::invoke() when it's available.
ComplexRendererFns Renderer =
- (ISel.*MatcherInfo.ComplexPredicates[ComplexPredicateID])(
+ (ISel.*ISelInfo.ComplexPredicates[ComplexPredicateID])(
State.MIs[InsnID]->getOperand(OpIdx));
if (Renderer.hasValue())
State.Renderers[RendererID] = Renderer.getValue();
@@ -649,6 +650,19 @@ bool InstructionSelector::executeMatchTa
break;
}
+ case GIR_CustomRenderer: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ int64_t OldInsnID = MatchTable[CurrentIdx++];
+ int64_t RendererFnID = MatchTable[CurrentIdx++];
+ assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
+ DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
+ dbgs() << CurrentIdx << ": GIR_CustomRenderer(OutMIs["
+ << InsnID << "], MIs[" << OldInsnID << "], "
+ << RendererFnID << ")\n");
+ (ISel.*ISelInfo.CustomRenderers[RendererFnID])(OutMIs[InsnID],
+ *State.MIs[OldInsnID]);
+ break;
+ }
case GIR_ConstrainOperandRC: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
@@ -710,7 +724,7 @@ bool InstructionSelector::executeMatchTa
int64_t TypeID = MatchTable[CurrentIdx++];
State.TempRegisters[TempRegID] =
- MRI.createGenericVirtualRegister(MatcherInfo.TypeObjects[TypeID]);
+ MRI.createGenericVirtualRegister(ISelInfo.TypeObjects[TypeID]);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": TempRegs[" << TempRegID
<< "] = GIR_MakeTempReg(" << TypeID << ")\n");
Modified: llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td (original)
+++ llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td Tue Jan 16 10:44:05 2018
@@ -112,3 +112,9 @@ def : GINodeEquiv<G_ATOMICRMW_UMAX, atom
class GIComplexPatternEquiv<ComplexPattern seldag> {
ComplexPattern SelDAGEquivalent = seldag;
}
+
+// Specifies the GlobalISel equivalents for SelectionDAG's SDNodeXForm.
+// Should be used on defs that subclass GICustomOperandRenderer<>.
+class GISDNodeXFormEquiv<SDNodeXForm seldag> {
+ SDNodeXForm SelDAGEquivalent = seldag;
+}
Modified: llvm/trunk/include/llvm/Target/GlobalISel/Target.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/GlobalISel/Target.td?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/GlobalISel/Target.td (original)
+++ llvm/trunk/include/llvm/Target/GlobalISel/Target.td Tue Jan 16 10:44:05 2018
@@ -46,3 +46,16 @@ class GIComplexOperandMatcher<LLT type,
// overwritten.
string MatcherFn = matcherfn;
}
+
+// Defines a custom renderer. This is analogous to SDNodeXForm from
+// SelectionDAG. Unlike SDNodeXForm, this matches a MachineInstr and
+// renders directly to the result instruction without an intermediate node.
+//
+// Definitions that inherit from this may also inherit from GISDNodeXFormEquiv
+// to enable the import of SelectionDAG patterns involving those SDNodeXForms.
+class GICustomOperandRenderer<string rendererfn> {
+ // The function renders the operand(s) of the matched instruction to
+ // the specified instruction. It should be of the form:
+ // void render(MachineInstrBuilder &MIB, const MachineInstr &MI)
+ string RendererFn = rendererfn;
+}
Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td Tue Jan 16 10:44:05 2018
@@ -678,6 +678,9 @@ def trunc_imm : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(N->getZExtValue(), SDLoc(N), MVT::i32);
}]>;
+def gi_trunc_imm : GICustomOperandRenderer<"renderTruncImm">,
+ GISDNodeXFormEquiv<trunc_imm>;
+
def : Pat<(i64 i64imm_32bit:$src),
(SUBREG_TO_REG (i64 0), (MOVi32imm (trunc_imm imm:$src)), sub_32)>;
Modified: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp Tue Jan 16 10:44:05 2018
@@ -92,6 +92,8 @@ private:
return selectAddrModeIndexed(Root, Width / 8);
}
+ void renderTruncImm(MachineInstrBuilder &MIB, const MachineInstr &MI) const;
+
const AArch64TargetMachine &TM;
const AArch64Subtarget &STI;
const AArch64InstrInfo &TII;
@@ -1522,6 +1524,15 @@ AArch64InstructionSelector::selectAddrMo
}};
}
+void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
+ const MachineInstr &MI) const {
+ const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
+ assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && "Expected G_CONSTANT");
+ Optional<int64_t> CstVal = getConstantVRegVal(MI.getOperand(0).getReg(), MRI);
+ assert(CstVal && "Expected constant value");
+ MIB.addImm(CstVal.getValue());
+}
+
namespace llvm {
InstructionSelector *
createAArch64InstructionSelector(const AArch64TargetMachine &TM,
Added: llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-mul.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-mul.mir?rev=322582&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-mul.mir (added)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-mul.mir Tue Jan 16 10:44:05 2018
@@ -0,0 +1,34 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -O0 -mtriple=aarch64-- -run-pass=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s
+---
+name: mul_i64_sext_imm32
+legalized: true
+regBankSelected: true
+
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+
+body: |
+ bb.0:
+ liveins: %w0
+
+ ; Make sure InstructionSelector is able to match a pattern
+ ; with an SDNodeXForm, trunc_imm.
+ ; def : Pat<(i64 (mul (sext GPR32:$Rn), (s64imm_32bit:$C))),
+ ; (SMADDLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), XZR)>;
+ ; CHECK-LABEL: name: mul_i64_sext_imm32
+ ; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY %w0
+ ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 3
+ ; CHECK: [[SMADDLrrr:%[0-9]+]]:gpr64 = SMADDLrrr [[COPY]], [[MOVi32imm]], %xzr
+ ; CHECK: %x0 = COPY [[SMADDLrrr]]
+ %0:gpr(s32) = COPY %w0
+ %1:gpr(s64) = G_SEXT %0(s32)
+ %2:gpr(s64) = G_CONSTANT i64 3
+ %3:gpr(s64) = G_MUL %1, %2
+ %x0 = COPY %3(s64)
+...
+
+
Modified: llvm/trunk/test/TableGen/GlobalISelEmitter.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/GlobalISelEmitter.td (original)
+++ llvm/trunk/test/TableGen/GlobalISelEmitter.td Tue Jan 16 10:44:05 2018
@@ -45,6 +45,16 @@ def gi_complex_rr :
GIComplexOperandMatcher<s32, "selectComplexPatternRR">,
GIComplexPatternEquiv<complex_rr>;
+def cimm8_xform : SDNodeXForm<imm, [{
+ uint64_t Val = N->getZExtValue() << 1;
+ return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i64);
+ }]>;
+
+def cimm8 : Operand<i32>, ImmLeaf<i32, [{return isInt<8>(Imm);}], cimm8_xform>;
+
+def gi_cimm8 : GICustomOperandRenderer<"renderImm8">,
+ GISDNodeXFormEquiv<cimm8_xform>;
+
def m1 : OperandWithDefaultOps <i32, (ops (i32 -1))>;
def Z : OperandWithDefaultOps <i32, (ops R0)>;
def m1Z : OperandWithDefaultOps <i32, (ops (i32 -1), R0)>;
@@ -61,8 +71,10 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_DECL
// CHECK-NEXT: mutable MatcherState State;
// CHECK-NEXT: typedef ComplexRendererFns(MyTargetInstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;
-// CHECK-NEXT: const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> MatcherInfo;
+// CHECK-NEXT: typedef void(MyTargetInstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const MachineInstr&) const;
+// CHECK-NEXT: const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn> ISelInfo;
// CHECK-NEXT: static MyTargetInstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];
+// CHECK-NEXT: static MyTargetInstructionSelector::CustomRendererFn CustomRenderers[];
// CHECK-NEXT: bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const override;
// CHECK-NEXT: bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) const override;
// CHECK-NEXT: bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat &Imm) const override;
@@ -70,7 +82,7 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
// CHECK-NEXT: , State(2),
-// CHECK-NEXT: MatcherInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns})
+// CHECK-NEXT: ISelInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers})
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
@@ -128,19 +140,27 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
-// CHECK-NEXT: GIPFP_I64_Predicate_simm8 = GIPFP_I64_Invalid + 1,
+// CHECK-NEXT: GIPFP_I64_Predicate_cimm8 = GIPFP_I64_Invalid + 1,
+// CHECK-NEXT: GIPFP_I64_Predicate_simm8,
// CHECK-NEXT: };
-// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const {
-// CHECK-NEXT: switch (PredicateID) {
-// CHECK-NEXT: case GIPFP_I64_Predicate_simm8: {
+
+
+// CHECK-NEXT: bool MyTargetInstructionSelector::testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const {
+// CHECK-NEXT: switch (PredicateID) {
+// CHECK-NEXT: case GIPFP_I64_Predicate_cimm8: {
+// CHECK-NEXT: return isInt<8>(Imm);
+// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }
+// CHECK-NEXT: case GIPFP_I64_Predicate_simm8: {
// CHECK-NEXT: return isInt<8>(Imm);
-// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
-// CHECK-NEXT: return false;
-// CHECK-NEXT: }
-// CHECK-NEXT: }
-// CHECK-NEXT: llvm_unreachable("Unknown predicate");
-// CHECK-NEXT: return false;
-// CHECK-NEXT: }
+// CHECK-NEXT: llvm_unreachable("ImmediateCode should have returned");
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: llvm_unreachable("Unknown predicate");
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
@@ -181,6 +201,17 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPatternRR, // gi_complex_rr
// CHECK-NEXT: }
+// CHECK-LABEL: // Custom renderers.
+// CHECK-NEXT: enum {
+// CHECK-NEXT: GICR_Invalid,
+// CHECK-NEXT: GICR_renderImm8,
+// CHECK-NEXT: };
+// CHECK-NEXT: MyTargetInstructionSelector::CustomRendererFn
+// CHECK-NEXT: MyTargetInstructionSelector::CustomRenderers[] = {
+// CHECK-NEXT: nullptr, // GICP_Invalid
+// CHECK-NEXT: &MyTargetInstructionSelector::renderImm8, // gi_cimm8
+// CHECK-NEXT: };
+
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
// CHECK-NEXT: MachineFunction &MF = *I.getParent()->getParent();
// CHECK-NEXT: MachineRegisterInfo &MRI = MF.getRegInfo();
@@ -892,12 +923,33 @@ def MOVimm9 : I<(outs GPR32:$dst), (ins
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+
+def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)]>;
+
+
+//===- Test a pattern with a custom renderer. -----------------------------===//
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
+// CHECK-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_cimm8,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 1
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // (imm:{ *:[i32] })<<P:Predicate_cimm8>><<X:cimm8_xform>>:$imm => (MOVcimm8:{ *:[i32] } (cimm8_xform:{ *:[i32] } (imm:{ *:[i32] }):$imm))
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVcimm8,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_CustomRenderer, /*InsnID*/0, /*OldInsnID*/0, /*Renderer*/GICR_renderImm8, // imm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
// Closing the G_CONSTANT group.
// OPT-NEXT: GIM_Reject,
// OPT-NEXT: GIR_Done,
// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
-
-def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)]>;
+def MOVcimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, cimm8:$imm)]>;
//===- Test a simple pattern with a FP immediate and a predicate. ---------===//
@@ -1020,6 +1072,6 @@ def BR : I<(outs), (ins unknown:$target)
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: };
-// CHECK-NEXT: if (executeMatchTable(*this, OutMIs, State, MatcherInfo, MatchTable0, TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {
+// CHECK-NEXT: if (executeMatchTable(*this, OutMIs, State, ISelInfo, MatchTable0, TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {
// CHECK-NEXT: return true;
// CHECK-NEXT: }
Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=322582&r1=322581&r2=322582&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Tue Jan 16 10:44:05 2018
@@ -260,6 +260,11 @@ std::string explainOperator(Record *Oper
")")
.str();
+ if (Operator->isSubClassOf("SDNodeXForm"))
+ return (" (Operator is an unmapped SDNodeXForm, " + Operator->getName() +
+ ")")
+ .str();
+
return (" (Operator " + Operator->getName() + " not understood)").str();
}
@@ -315,12 +320,7 @@ static Error isTrivialOperatorNode(const
break;
}
- if (N->getTransformFn()) {
- Explanation += Separator + "Has a transform function";
- Separator = ", ";
- }
-
- if (!HasUnsupportedPredicate && !N->getTransformFn())
+ if (!HasUnsupportedPredicate)
return Error::success();
return failedImport(Explanation);
@@ -1706,7 +1706,8 @@ public:
OR_Imm,
OR_Register,
OR_TempRegister,
- OR_ComplexPattern
+ OR_ComplexPattern,
+ OR_Custom
};
protected:
@@ -2018,6 +2019,38 @@ public:
}
};
+class CustomRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const Record &Renderer;
+ /// The name of the operand.
+ const std::string SymbolicName;
+
+public:
+ CustomRenderer(unsigned InsnID, const Record &Renderer,
+ StringRef SymbolicName)
+ : OperandRenderer(OR_Custom), InsnID(InsnID), Renderer(Renderer),
+ SymbolicName(SymbolicName) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_Custom;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ const InstructionMatcher &InsnMatcher =
+ Rule.getInstructionMatcher(SymbolicName);
+ unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
+ Table << MatchTable::Opcode("GIR_CustomRenderer")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OldInsnVarID)
+ << MatchTable::Comment("Renderer")
+ << MatchTable::NamedValue(
+ "GICR_" + Renderer.getValueAsString("RendererFn").str())
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+ }
+};
+
/// An action taken when all Matcher predicates succeeded for a parent rule.
///
/// Typical actions include:
@@ -2541,6 +2574,11 @@ private:
/// GIComplexPatternEquiv.
DenseMap<const Record *, const Record *> ComplexPatternEquivs;
+ /// Keep track of the equivalence between SDNodeXForm's and
+ /// GICustomOperandRenderer. Map entries are specified by subclassing
+ /// GISDNodeXFormEquiv.
+ DenseMap<const Record *, const Record *> SDNodeXFormEquivs;
+
// Map of predicates to their subtarget features.
SubtargetFeatureInfoMap SubtargetFeatures;
@@ -2645,6 +2683,14 @@ void GlobalISelEmitter::gatherNodeEquivs
continue;
ComplexPatternEquivs[SelDAGEquiv] = Equiv;
}
+
+ assert(SDNodeXFormEquivs.empty());
+ for (Record *Equiv : RK.getAllDerivedDefinitions("GISDNodeXFormEquiv")) {
+ Record *SelDAGEquiv = Equiv->getValueAsDef("SelDAGEquivalent");
+ if (!SelDAGEquiv)
+ continue;
+ SDNodeXFormEquivs[SelDAGEquiv] = Equiv;
+ }
}
Record *GlobalISelEmitter::findNodeEquiv(Record *N) const {
@@ -2986,10 +3032,6 @@ Error GlobalISelEmitter::importChildMatc
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
TreePatternNode *DstChild) {
- if (DstChild->getTransformFn() != nullptr) {
- return failedImport("Dst pattern child has transform fn " +
- DstChild->getTransformFn()->getName());
- }
const auto &SubOperand = Rule.getComplexSubOperand(DstChild->getName());
if (SubOperand.hasValue()) {
@@ -3000,6 +3042,18 @@ Expected<action_iterator> GlobalISelEmit
}
if (!DstChild->isLeaf()) {
+
+ if (DstChild->getOperator()->isSubClassOf("SDNodeXForm")) {
+ auto Child = DstChild->getChild(0);
+ auto I = SDNodeXFormEquivs.find(DstChild->getOperator());
+ if (I != SDNodeXFormEquivs.end()) {
+ DstMIBuilder.addRenderer<CustomRenderer>(*I->second, Child->getName());
+ return InsertPt;
+ }
+ return failedImport("SDNodeXForm " + Child->getName() +
+ " has no custom renderer");
+ }
+
// We accept 'bb' here. It's an operator because BasicBlockSDNode isn't
// inline, but in MI it's just another operand.
if (DstChild->getOperator()->isSubClassOf("SDNode")) {
@@ -3104,10 +3158,6 @@ Expected<action_iterator> GlobalISelEmit
return InsertPt;
}
- if (ChildRec->isSubClassOf("SDNodeXForm"))
- return failedImport("Dst pattern child def is an unsupported tablegen "
- "class (SDNodeXForm)");
-
return failedImport(
"Dst pattern child def is an unsupported tablegen class");
}
@@ -3652,14 +3702,19 @@ void GlobalISelEmitter::run(raw_ostream
Rules.push_back(std::move(MatcherOrErr.get()));
}
+ // Comparison function to order records by name.
+ auto orderByName = [](const Record *A, const Record *B) {
+ return A->getName() < B->getName();
+ };
+
std::vector<Record *> ComplexPredicates =
RK.getAllDerivedDefinitions("GIComplexOperandMatcher");
- std::sort(ComplexPredicates.begin(), ComplexPredicates.end(),
- [](const Record *A, const Record *B) {
- if (A->getName() < B->getName())
- return true;
- return false;
- });
+ std::sort(ComplexPredicates.begin(), ComplexPredicates.end(), orderByName);
+
+ std::vector<Record *> CustomRendererFns =
+ RK.getAllDerivedDefinitions("GICustomOperandRenderer");
+ std::sort(CustomRendererFns.begin(), CustomRendererFns.end(), orderByName);
+
unsigned MaxTemporaries = 0;
for (const auto &Rule : Rules)
MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
@@ -3677,10 +3732,18 @@ void GlobalISelEmitter::run(raw_ostream
"ComplexRendererFns("
<< Target.getName()
<< "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n"
- << " const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> "
- "MatcherInfo;\n"
- << " static " << Target.getName()
+
+ << " typedef void(" << Target.getName()
+ << "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const "
+ "MachineInstr&) "
+ "const;\n"
+ << " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, "
+ "CustomRendererFn> "
+ "ISelInfo;\n";
+ OS << " static " << Target.getName()
<< "InstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];\n"
+ << " static " << Target.getName()
+ << "InstructionSelector::CustomRendererFn CustomRenderers[];\n"
<< "bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const "
"override;\n"
<< "bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) "
@@ -3691,7 +3754,8 @@ void GlobalISelEmitter::run(raw_ostream
OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
<< ", State(" << MaxTemporaries << "),\n"
- << "MatcherInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns})\n"
+ << "ISelInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns, "
+ "CustomRenderers})\n"
<< "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
OS << "#ifdef GET_GLOBALISEL_IMPL\n";
@@ -3821,6 +3885,22 @@ void GlobalISelEmitter::run(raw_ostream
<< ", // " << Record->getName() << "\n";
OS << "};\n\n";
+ OS << "// Custom renderers.\n"
+ << "enum {\n"
+ << " GICR_Invalid,\n";
+ for (const auto &Record : CustomRendererFns)
+ OS << " GICR_" << Record->getValueAsString("RendererFn") << ", \n";
+ OS << "};\n";
+
+ OS << Target.getName() << "InstructionSelector::CustomRendererFn\n"
+ << Target.getName() << "InstructionSelector::CustomRenderers[] = {\n"
+ << " nullptr, // GICP_Invalid\n";
+ for (const auto &Record : CustomRendererFns)
+ OS << " &" << Target.getName()
+ << "InstructionSelector::" << Record->getValueAsString("RendererFn")
+ << ", // " << Record->getName() << "\n";
+ OS << "};\n\n";
+
OS << "bool " << Target.getName()
<< "InstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage "
"&CoverageInfo) const {\n"
@@ -3862,7 +3942,7 @@ void GlobalISelEmitter::run(raw_ostream
}
Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
Table.emitDeclaration(OS);
- OS << " if (executeMatchTable(*this, OutMIs, State, MatcherInfo, ";
+ OS << " if (executeMatchTable(*this, OutMIs, State, ISelInfo, ";
Table.emitUse(OS);
OS << ", TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {\n"
<< " return true;\n"
More information about the llvm-commits
mailing list