diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h | 20 | ||||
| -rw-r--r-- | llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h | 49 | ||||
| -rw-r--r-- | llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td | 2 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp | 5 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86InstrFPStack.td | 16 | ||||
| -rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/select-constant.mir | 36 | ||||
| -rw-r--r-- | llvm/test/TableGen/GlobalISelEmitter.td | 82 | ||||
| -rw-r--r-- | llvm/utils/TableGen/CodeGenDAGPatterns.cpp | 8 | ||||
| -rw-r--r-- | llvm/utils/TableGen/CodeGenDAGPatterns.h | 4 | ||||
| -rw-r--r-- | llvm/utils/TableGen/GlobalISelEmitter.cpp | 102 |
10 files changed, 279 insertions, 45 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h index 9f7b9da8735..08c813a79c2 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -26,6 +26,8 @@ namespace llvm { +class APInt; +class APFloat; class LLT; class MachineInstr; class MachineInstrBuilder; @@ -96,7 +98,15 @@ enum { /// Check an immediate predicate on the specified instruction /// - InsnID - Instruction ID /// - The predicate to test - GIM_CheckImmPredicate, + GIM_CheckI64ImmPredicate, + /// Check an immediate predicate on the specified instruction via an APInt. + /// - InsnID - Instruction ID + /// - The predicate to test + GIM_CheckAPIntImmPredicate, + /// Check a floating point immediate predicate on the specified instruction. + /// - InsnID - Instruction ID + /// - The predicate to test + GIM_CheckAPFloatImmPredicate, /// Check the type for the specified operand /// - InsnID - Instruction ID @@ -226,7 +236,9 @@ enum { /// Provides the logic to select generic machine instructions. class InstructionSelector { public: - using ImmediatePredicateFn = bool (*)(int64_t); + using I64ImmediatePredicateFn = bool (*)(int64_t); + using APIntImmediatePredicateFn = bool (*)(const APInt &); + using APFloatImmediatePredicateFn = bool (*)(const APFloat &); virtual ~InstructionSelector() = default; @@ -259,7 +271,9 @@ public: struct MatcherInfoTy { const LLT *TypeObjects; const PredicateBitset *FeatureBitsets; - const ImmediatePredicateFn *ImmPredicateFns; + const I64ImmediatePredicateFn *I64ImmPredicateFns; + const APIntImmediatePredicateFn *APIntImmPredicateFns; + const APFloatImmediatePredicateFn *APFloatImmPredicateFns; const std::vector<ComplexMatcherMemFn> ComplexPredicates; }; diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h index a43c663bd6e..6bab06dca2c 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -36,7 +36,9 @@ namespace llvm { /// GlobalISel PatFrag Predicates enum { - GIPFP_Invalid, + GIPFP_I64_Invalid = 0, + GIPFP_APInt_Invalid = 0, + GIPFP_APFloat_Invalid = 0, }; template <class TgtInstructionSelector, class PredicateBitset, @@ -149,16 +151,15 @@ bool InstructionSelector::executeMatchTable( } break; } - - case GIM_CheckImmPredicate: { + case GIM_CheckI64ImmPredicate: { int64_t InsnID = MatchTable[CurrentIdx++]; int64_t Predicate = MatchTable[CurrentIdx++]; - DEBUG(dbgs() << CurrentIdx << ": GIM_CheckImmPredicate(MIs[" << InsnID + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckI64ImmPredicate(MIs[" << InsnID << "], Predicate=" << Predicate << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT && "Expected G_CONSTANT"); - assert(Predicate > GIPFP_Invalid && "Expected a valid predicate"); + assert(Predicate > GIPFP_I64_Invalid && "Expected a valid predicate"); int64_t Value = 0; if (State.MIs[InsnID]->getOperand(1).isCImm()) Value = State.MIs[InsnID]->getOperand(1).getCImm()->getSExtValue(); @@ -167,7 +168,43 @@ bool InstructionSelector::executeMatchTable( else llvm_unreachable("Expected Imm or CImm operand"); - if (!MatcherInfo.ImmPredicateFns[Predicate](Value)) + if (!MatcherInfo.I64ImmPredicateFns[Predicate](Value)) + if (handleReject() == RejectAndGiveUp) + return false; + break; + } + case GIM_CheckAPIntImmPredicate: { + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t Predicate = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckAPIntImmPredicate(MIs[" + << InsnID << "], Predicate=" << Predicate << ")\n"); + assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); + assert(State.MIs[InsnID]->getOpcode() && "Expected G_CONSTANT"); + assert(Predicate > GIPFP_APInt_Invalid && "Expected a valid predicate"); + APInt Value; + if (State.MIs[InsnID]->getOperand(1).isCImm()) + Value = State.MIs[InsnID]->getOperand(1).getCImm()->getValue(); + else + llvm_unreachable("Expected Imm or CImm operand"); + + if (!MatcherInfo.APIntImmPredicateFns[Predicate](Value)) + if (handleReject() == RejectAndGiveUp) + return false; + break; + } + case GIM_CheckAPFloatImmPredicate: { + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t Predicate = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckAPFloatImmPredicate(MIs[" << InsnID + << "], Predicate=" << Predicate << ")\n"); + assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); + assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_FCONSTANT && + "Expected G_FCONSTANT"); + assert(State.MIs[InsnID]->getOperand(1).isFPImm() && "Expected FPImm operand"); + assert(Predicate > GIPFP_APFloat_Invalid && "Expected a valid predicate"); + APFloat Value = State.MIs[InsnID]->getOperand(1).getFPImm()->getValueAPF(); + + if (!MatcherInfo.APFloatImmPredicateFns[Predicate](Value)) if (handleReject() == RejectAndGiveUp) return false; break; diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td index f6da58ba796..96245b251f9 100644 --- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -34,7 +34,7 @@ def : GINodeEquiv<G_BITCAST, bitconvert>; // G_INTTOPTR - SelectionDAG has no equivalent. // G_PTRTOINT - SelectionDAG has no equivalent. def : GINodeEquiv<G_CONSTANT, imm>; -// G_FCONSTANT - Not needed since constants aren't operators. +def : GINodeEquiv<G_FCONSTANT, fpimm>; def : GINodeEquiv<G_ADD, add>; def : GINodeEquiv<G_SUB, sub>; def : GINodeEquiv<G_MUL, mul>; diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 58624f24ec0..88259ffdf00 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -705,6 +705,11 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const { << " constant on bank: " << RB << ", expected: FPR\n"); return false; } + + // The case when we have 0.0 is covered by tablegen. Reject it here so we + // can be sure tablegen works correctly and isn't rescued by this code. + if (I.getOperand(1).getFPImm()->getValueAPF().isExactlyValue(0.0)) + return false; } else { // s32 and s64 are covered by tablegen. if (Ty != p0) { diff --git a/llvm/lib/Target/X86/X86InstrFPStack.td b/llvm/lib/Target/X86/X86InstrFPStack.td index 78608c43028..f096f51d6be 100644 --- a/llvm/lib/Target/X86/X86InstrFPStack.td +++ b/llvm/lib/Target/X86/X86InstrFPStack.td @@ -57,20 +57,20 @@ def X86fp_cwd_get16 : SDNode<"X86ISD::FNSTCW16m", SDTX86CwdStore, // FPStack pattern fragments //===----------------------------------------------------------------------===// -def fpimm0 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(+0.0); +def fpimm0 : FPImmLeaf<fAny, [{ + return Imm.isExactlyValue(+0.0); }]>; -def fpimmneg0 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(-0.0); +def fpimmneg0 : FPImmLeaf<fAny, [{ + return Imm.isExactlyValue(-0.0); }]>; -def fpimm1 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(+1.0); +def fpimm1 : FPImmLeaf<fAny, [{ + return Imm.isExactlyValue(+1.0); }]>; -def fpimmneg1 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(-1.0); +def fpimmneg1 : FPImmLeaf<fAny, [{ + return Imm.isExactlyValue(-1.0); }]>; // Some 'special' instructions diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-constant.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-constant.mir index 1a5bac9fb7d..8e3dbb4c416 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/select-constant.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-constant.mir @@ -8,6 +8,8 @@ define i32 @fconst_s32() { ret i32 42 } define i64 @fconst_s64() { ret i64 1234567890123 } + define float @fconst_s32_0() { ret float 0.0 } + define double @fconst_s64_0() { ret double 0.0 } ... --- @@ -75,3 +77,37 @@ body: | %0(s64) = G_FCONSTANT double 1.0 %d0 = COPY %0(s64) ... + +--- +# CHECK-LABEL: name: fconst_s32_0 +name: fconst_s32_0 +legalized: true +regBankSelected: true +registers: + - { id: 0, class: fpr } + +# CHECK: body: +# CHECK: [[TMP:%[0-9]+]] = FMOVS0 +# CHECK: %s0 = COPY [[TMP]] +body: | + bb.0: + %0(s32) = G_FCONSTANT float 0.0 + %s0 = COPY %0(s32) +... + +--- +# CHECK-LABEL: name: fconst_s64_0 +name: fconst_s64_0 +legalized: true +regBankSelected: true +registers: + - { id: 0, class: fpr } + +# CHECK: body: +# CHECK: [[TMP:%[0-9]+]] = FMOVD0 +# CHECK: %s0 = COPY [[TMP]] +body: | + bb.0: + %0(s64) = G_FCONSTANT double 0.0 + %s0 = COPY %0(s64) +... diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td index d08134034ad..be9bc3b9b8f 100644 --- a/llvm/test/TableGen/GlobalISelEmitter.td +++ b/llvm/test/TableGen/GlobalISelEmitter.td @@ -53,7 +53,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; } // CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT // CHECK-NEXT: , State(2), -// CHECK-NEXT: MatcherInfo({TypeObjects, FeatureBitsets, ImmPredicateFns, { +// CHECK-NEXT: MatcherInfo({TypeObjects, FeatureBitsets, I64ImmPredicateFns, APIntImmPredicateFns, APFloatImmPredicateFns, { // CHECK-NEXT: nullptr, // GICP_Invalid // CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPattern, // gi_complex // CHECK-NEXT: }}) @@ -111,14 +111,34 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; } // CHECK-LABEL: // PatFrag predicates. // CHECK-NEXT: enum { -// CHECK-NEXT: GIPFP_Predicate_simm8 = GIPFP_Invalid + 1, +// CHECK-NEXT: GIPFP_I64_Predicate_simm8 = GIPFP_I64_Invalid + 1, // CHECK-NEXT: }; // CHECK-NEXT: static bool Predicate_simm8(int64_t Imm) { return isInt<8>(Imm); } -// CHECK-NEXT: static InstructionSelector::ImmediatePredicateFn ImmPredicateFns[] = { +// CHECK-NEXT: static InstructionSelector::I64ImmediatePredicateFn I64ImmPredicateFns[] = { // CHECK-NEXT: nullptr, // CHECK-NEXT: Predicate_simm8, // CHECK-NEXT: }; +// CHECK-LABEL: // PatFrag predicates. +// CHECK-NEXT: enum { +// CHECK-NEXT: GIPFP_APFloat_Predicate_fpimmz = GIPFP_APFloat_Invalid + 1, +// CHECK-NEXT: }; +// CHECK-NEXT: static bool Predicate_fpimmz(const APFloat & Imm) { return Imm->isExactlyValue(0.0); } +// CHECK-NEXT: static InstructionSelector::APFloatImmediatePredicateFn APFloatImmPredicateFns[] = { +// CHECK-NEXT: nullptr, +// CHECK-NEXT: Predicate_fpimmz, +// CHECK-NEXT: }; + +// CHECK-LABEL: // PatFrag predicates. +// CHECK-NEXT: enum { +// CHECK-NEXT: GIPFP_APInt_Predicate_simm9 = GIPFP_APInt_Invalid + 1, +// CHECK-NEXT: }; +// CHECK-NEXT: static bool Predicate_simm9(const APInt & Imm) { return isInt<9>(Imm->getSExtValue()); } +// CHECK-NEXT: static InstructionSelector::APIntImmediatePredicateFn APIntImmPredicateFns[] = { +// CHECK-NEXT: nullptr, +// CHECK-NEXT: Predicate_simm9, +// CHECK-NEXT: }; + // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const { // CHECK-NEXT: MachineFunction &MF = *I.getParent()->getParent(); // CHECK-NEXT: MachineRegisterInfo &MRI = MF.getRegInfo(); @@ -671,7 +691,7 @@ def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>; // CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 17*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, -// CHECK-NEXT: GIM_CheckImmPredicate, /*MI*/0, /*Predicate*/GIPFP_Predicate_simm8, +// CHECK-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_simm8, // 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, @@ -689,11 +709,34 @@ def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>; def simm8 : ImmLeaf<i32, [{ return isInt<8>(Imm); }]>; def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$imm)]>; -//===- Test a simple pattern with just a leaf immediate. ------------------===// +//===- Same again but use an IntImmLeaf. ----------------------------------===// // CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 18*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, +// CHECK-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APInt_Predicate_simm9, +// 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_simm9>>:$imm => (MOVimm9:{ *:[i32] } (imm:{ *:[i32] }):$imm) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm9, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 18: @[[LABEL]] + +def simm9 : IntImmLeaf<i32, [{ return isInt<9>(Imm->getSExtValue()); }]>; +def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$imm)]>; + +//===- Test a simple pattern with just a leaf immediate. ------------------===// + +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 19*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, // 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, @@ -706,13 +749,36 @@ def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$i // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 18: @[[LABEL]] +// CHECK-NEXT: // Label 19: @[[LABEL]] def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)]>; +//===- Test a simple pattern with a FP immediate and a predicate. ---------===// + +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 20*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT, +// CHECK-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APFloat_Predicate_fpimmz, +// 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::FPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 1 +// CHECK-NEXT: // No operand predicates +// CHECK-NEXT: // (fpimm:{ *:[f32] })<<P:Predicate_fpimmz>>:$imm => (MOVfpimmz:{ *:[f32] } (fpimm:{ *:[f32] }):$imm) +// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVfpimmz, +// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst +// CHECK-NEXT: GIR_CopyFConstantAsFPImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm +// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, +// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, +// CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 20: @[[LABEL]] + +def fpimmz : FPImmLeaf<f32, [{ return Imm->isExactlyValue(0.0); }]>; +def MOVfpimmz : I<(outs FPR32:$dst), (ins f32imm:$imm), [(set FPR32:$dst, fpimmz:$imm)]>; + //===- Test a pattern with an MBB operand. --------------------------------===// -// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 19*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 21*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR, // CHECK-NEXT: // MIs[0] target @@ -721,7 +787,7 @@ def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm) // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 19: @[[LABEL]] +// CHECK-NEXT: // Label 21: @[[LABEL]] def BR : I<(outs), (ins unknown:$target), [(br bb:$target)]>; diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index a9f1b0be816..ced3e979c04 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -881,6 +881,14 @@ std::string TreePredicateFn::getImmType() const { return "int64_t"; } +std::string TreePredicateFn::getImmTypeIdentifier() const { + if (immCodeUsesAPInt()) + return "APInt"; + else if (immCodeUsesAPFloat()) + return "APFloat"; + return "I64"; +} + /// isAlwaysTrue - Return true if this is a noop predicate. bool TreePredicateFn::isAlwaysTrue() const { return getPredCode().empty() && getImmCode().empty(); diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h index 3033986fdd4..5918e901a3d 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -478,6 +478,10 @@ public: /// Get the data type of the argument to getImmediatePredicateCode(). std::string getImmType() const; + /// Get a string that describes the type returned by getImmType() but is + /// usable as part of an identifier. + std::string getImmTypeIdentifier() const; + private: std::string getPredCode() const; std::string getImmCode() const; diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 18eb271d4ef..2e86b17d0b9 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -65,6 +65,18 @@ static cl::opt<bool> WarnOnSkippedPatterns( namespace { //===- Helper functions ---------------------------------------------------===// + +/// Get the name of the enum value used to number the predicate function. +std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) { + return "GIPFP_" + Predicate.getImmTypeIdentifier() + "_" + + Predicate.getFnName(); +} + +/// Get the opcode used to check this predicate. +std::string getMatchOpcodeForPredicate(const TreePredicateFn &Predicate) { + return "GIM_Check" + Predicate.getImmTypeIdentifier() + "ImmPredicate"; +} + /// This class stands in for LLT wherever we want to tablegen-erate an /// equivalent at compiler run-time. class LLTCodeGen { @@ -1057,10 +1069,10 @@ public: void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const override { - Table << MatchTable::Opcode("GIM_CheckImmPredicate") + Table << MatchTable::Opcode(getMatchOpcodeForPredicate(Predicate)) << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Predicate") - << MatchTable::NamedValue("GIPFP_" + Predicate.getFnName()) + << MatchTable::NamedValue(getEnumNameForPredicate(Predicate)) << MatchTable::LineBreak; } }; @@ -1258,6 +1270,7 @@ public: OR_Copy, OR_CopySubReg, OR_CopyConstantAsImm, + OR_CopyFConstantAsFPImm, OR_Imm, OR_Register, OR_ComplexPattern @@ -1345,6 +1358,36 @@ public: } }; +/// A CopyFConstantAsFPImmRenderer emits code to render a G_FCONSTANT +/// instruction to an extended immediate operand. +class CopyFConstantAsFPImmRenderer : public OperandRenderer { +protected: + unsigned NewInsnID; + /// The name of the operand. + const std::string SymbolicName; + +public: + CopyFConstantAsFPImmRenderer(unsigned NewInsnID, StringRef SymbolicName) + : OperandRenderer(OR_CopyFConstantAsFPImm), NewInsnID(NewInsnID), + SymbolicName(SymbolicName) {} + + static bool classof(const OperandRenderer *R) { + return R->getKind() == OR_CopyFConstantAsFPImm; + } + + const StringRef getSymbolicName() const { return SymbolicName; } + + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { + const InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName); + unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher); + Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm") + << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID) + << MatchTable::Comment("OldInsnID") + << MatchTable::IntValue(OldInsnVarID) + << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; + } +}; + /// A CopySubRegRenderer emits code to copy a single register operand from an /// existing instruction to the one being built and indicate that only a /// subregister should be copied. @@ -1913,7 +1956,8 @@ private: importImplicitDefRenderers(BuildMIAction &DstMIBuilder, const std::vector<Record *> &ImplicitDefs) const; - void emitImmPredicates(raw_ostream &OS, + void emitImmPredicates(raw_ostream &OS, StringRef TypeIdentifier, + StringRef Type, std::function<bool(const Record *R)> Filter); /// Analyze pattern \p P, returning a matcher for it if possible. @@ -2029,8 +2073,9 @@ GlobalISelEmitter::createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher, } else { assert(SrcGIOrNull && "Expected to have already found an equivalent Instruction"); - if (SrcGIOrNull->TheDef->getName() == "G_CONSTANT") { - // imm still has an operand but we don't need to do anything with it + if (SrcGIOrNull->TheDef->getName() == "G_CONSTANT" || + SrcGIOrNull->TheDef->getName() == "G_FCONSTANT") { + // imm/fpimm still have operands but we don't need to do anything with it // here since we don't support ImmLeaf predicates yet. However, we still // need to note the hidden operand to get GIM_CheckNumOperands correct. InsnMatcher.addOperand(OpIdx++, "", TempOpIdx); @@ -2185,6 +2230,10 @@ Error GlobalISelEmitter::importExplicitUseRenderer( DstMIBuilder.addRenderer<CopyConstantAsImmRenderer>(0, DstChild->getName()); return Error::success(); + } else if (DstChild->getOperator()->getName() == "fpimm") { + DstMIBuilder.addRenderer<CopyFConstantAsFPImmRenderer>( + 0, DstChild->getName()); + return Error::success(); } return failedImport("Dst pattern child isn't a leaf node or an MBB" + llvm::to_string(*DstChild)); @@ -2566,7 +2615,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { // The 'Predicate_' part of the name is redundant but eliminating it is more // trouble than it's worth. void GlobalISelEmitter::emitImmPredicates( - raw_ostream &OS, std::function<bool(const Record *R)> Filter) { + raw_ostream &OS, StringRef TypeIdentifier, StringRef Type, + std::function<bool(const Record *R)> Filter) { std::vector<const Record *> MatchedRecords; const auto &Defs = RK.getAllDerivedDefinitions("PatFrag"); std::copy_if(Defs.begin(), Defs.end(), std::back_inserter(MatchedRecords), @@ -2575,19 +2625,25 @@ void GlobalISelEmitter::emitImmPredicates( Filter(Record); }); - OS << "// PatFrag predicates.\n" - << "enum {\n"; - StringRef EnumeratorSeparator = " = GIPFP_Invalid + 1,\n"; - for (const auto *Record : MatchedRecords) { - OS << " GIPFP_Predicate_" << Record->getName() << EnumeratorSeparator; - EnumeratorSeparator = ",\n"; + if (!MatchedRecords.empty()) { + OS << "// PatFrag predicates.\n" + << "enum {\n"; + StringRef EnumeratorSeparator = + (" = GIPFP_" + TypeIdentifier + "_Invalid + 1,\n").str(); + for (const auto *Record : MatchedRecords) { + OS << " GIPFP_" << TypeIdentifier << "_Predicate_" << Record->getName() + << EnumeratorSeparator; + EnumeratorSeparator = ",\n"; + } + OS << "};\n"; } - OS << "};\n"; + for (const auto *Record : MatchedRecords) - OS << " static bool Predicate_" << Record->getName() << "(int64_t Imm) {" - << Record->getValueAsString("ImmediateCode") << " }\n"; - OS << "static InstructionSelector::ImmediatePredicateFn ImmPredicateFns[] = " - "{\n" + OS << "static bool Predicate_" << Record->getName() << "(" << Type + << " Imm) {" << Record->getValueAsString("ImmediateCode") << "}\n"; + + OS << "static InstructionSelector::" << TypeIdentifier + << "ImmediatePredicateFn " << TypeIdentifier << "ImmPredicateFns[] = {\n" << " nullptr,\n"; for (const auto *Record : MatchedRecords) OS << " Predicate_" << Record->getName() << ",\n"; @@ -2664,7 +2720,8 @@ void GlobalISelEmitter::run(raw_ostream &OS) { OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n" << ", State(" << MaxTemporaries << "),\n" - << "MatcherInfo({TypeObjects, FeatureBitsets, ImmPredicateFns, {\n" + << "MatcherInfo({TypeObjects, FeatureBitsets, I64ImmPredicateFns, " + "APIntImmPredicateFns, APFloatImmPredicateFns, {\n" << " nullptr, // GICP_Invalid\n"; for (const auto &Record : ComplexPredicates) OS << " &" << Target.getName() @@ -2777,11 +2834,18 @@ void GlobalISelEmitter::run(raw_ostream &OS) { OS << "};\n" << "// See constructor for table contents\n\n"; - emitImmPredicates(OS, [](const Record *R) { + emitImmPredicates(OS, "I64", "int64_t", [](const Record *R) { bool Unset; return !R->getValueAsBitOrUnset("IsAPFloat", Unset) && !R->getValueAsBit("IsAPInt"); }); + emitImmPredicates(OS, "APFloat", "const APFloat &", [](const Record *R) { + bool Unset; + return R->getValueAsBitOrUnset("IsAPFloat", Unset); + }); + emitImmPredicates(OS, "APInt", "const APInt &", [](const Record *R) { + return R->getValueAsBit("IsAPInt"); + }); OS << "bool " << Target.getName() << "InstructionSelector::selectImpl(MachineInstr &I) const {\n" |

