Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ 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 @@ /// 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 @@ /// Provides the logic to select generic machine instructions. class InstructionSelector { public: - typedef bool(*ImmediatePredicateFn)(int64_t); + typedef bool(*I64ImmediatePredicateFn)(int64_t); + typedef bool(*APIntImmediatePredicateFn)(const APInt &); + typedef bool(*APFloatImmediatePredicateFn)(const APFloat &); virtual ~InstructionSelector() = default; @@ -260,7 +272,9 @@ struct MatcherInfoTy { const LLT *TypeObjects; const PredicateBitset *FeatureBitsets; - const ImmediatePredicateFn *ImmPredicateFns; + const I64ImmediatePredicateFn *I64ImmPredicateFns; + const APIntImmediatePredicateFn *APIntImmPredicateFns; + const APFloatImmediatePredicateFn *APFloatImmPredicateFns; const std::vector ComplexPredicates; }; Index: include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -20,7 +20,9 @@ /// GlobalISel PatFrag Predicates enum { - GIPFP_Invalid, + GIPFP_I64_Invalid = 0, + GIPFP_APInt_Invalid = 0, + GIPFP_APFloat_Invalid = 0, }; template 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(); @@ -149,7 +151,43 @@ 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; Index: include/llvm/Target/GlobalISel/SelectionDAGCompat.td =================================================================== --- include/llvm/Target/GlobalISel/SelectionDAGCompat.td +++ include/llvm/Target/GlobalISel/SelectionDAGCompat.td @@ -34,7 +34,7 @@ // G_INTTOPTR - SelectionDAG has no equivalent. // G_PTRTOINT - SelectionDAG has no equivalent. def : GINodeEquiv; -// G_FCONSTANT - Not needed since constants aren't operators. +def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; Index: lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.cpp +++ lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -703,6 +703,10 @@ << " constant on bank: " << RB << ", expected: FPR\n"); return false; } + + // 0.0 is covered by tablegen. + if (I.getOperand(1).getFPImm()->getValueAPF().isExactlyValue(0.0)) + return false; } else { // s32 and s64 are covered by tablegen. if (Ty != p0) { Index: lib/Target/X86/X86InstrFPStack.td =================================================================== --- lib/Target/X86/X86InstrFPStack.td +++ lib/Target/X86/X86InstrFPStack.td @@ -57,20 +57,20 @@ // FPStack pattern fragments //===----------------------------------------------------------------------===// -def fpimm0 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(+0.0); +def fpimm0 : FPImmLeaf; -def fpimmneg0 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(-0.0); +def fpimmneg0 : FPImmLeaf; -def fpimm1 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(+1.0); +def fpimm1 : FPImmLeaf; -def fpimmneg1 : PatLeaf<(fpimm), [{ - return N->isExactlyValue(-1.0); +def fpimmneg1 : FPImmLeaf; // Some 'special' instructions Index: test/CodeGen/AArch64/GlobalISel/select-constant.mir =================================================================== --- test/CodeGen/AArch64/GlobalISel/select-constant.mir +++ 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 @@ %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) +... Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -53,7 +53,7 @@ // 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 @@ // 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(); @@ -650,7 +670,7 @@ // CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 16*/ [[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, @@ -668,11 +688,34 @@ def simm8 : ImmLeaf(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 17*/ [[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)<>:$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 17: @[[LABEL]] + +def simm9 : IntImmLeaf(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 18*/ [[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, @@ -685,13 +728,36 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 17: @[[LABEL]] +// CHECK-NEXT: // Label 18: @[[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 19*/ [[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)<>:$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 19: @[[LABEL]] + +def fpimmz : FPImmLeafisExactlyValue(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 18*/ [[LABEL:[0-9]+]], +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 20*/ [[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 @@ -700,7 +766,7 @@ // CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, -// CHECK-NEXT: // Label 18: @[[LABEL]] +// CHECK-NEXT: // Label 20: @[[LABEL]] def BR : I<(outs), (ins unknown:$target), [(br bb:$target)]>; Index: utils/TableGen/CodeGenDAGPatterns.h =================================================================== --- utils/TableGen/CodeGenDAGPatterns.h +++ utils/TableGen/CodeGenDAGPatterns.h @@ -314,11 +314,21 @@ /// Get the data type of the argument to getImmediatePredicateCode(). std::string getImmType() const; + /// Get the name of the enum value used to number the predicate function. + std::string getGlobalISelEnumName() const; + + /// Get the opcode used to check this predicate. + std::string getGlobalISelMatchOpcode() const; + private: std::string getPredCode() const; std::string getImmCode() const; bool immCodeUsesAPInt() const; bool immCodeUsesAPFloat() const; + + /// Get a string that describes the type returned by getImmType() but is + /// usable as part of an identifier. + std::string getImmTypeIdentifier() const; }; Index: utils/TableGen/CodeGenDAGPatterns.cpp =================================================================== --- utils/TableGen/CodeGenDAGPatterns.cpp +++ utils/TableGen/CodeGenDAGPatterns.cpp @@ -789,6 +789,22 @@ return "int64_t"; } +std::string TreePredicateFn::getImmTypeIdentifier() const { + if (immCodeUsesAPInt()) + return "APInt"; + else if (immCodeUsesAPFloat()) + return "APFloat"; + return "I64"; +} + +std::string TreePredicateFn::getGlobalISelEnumName() const { + return "GIPFP_" + getImmTypeIdentifier() + "_" + getFnName(); +} + +std::string TreePredicateFn::getGlobalISelMatchOpcode() const { + return "GIM_Check" + getImmTypeIdentifier() + "ImmPredicate"; +} + /// isAlwaysTrue - Return true if this is a noop predicate. bool TreePredicateFn::isAlwaysTrue() const { return getPredCode().empty() && getImmCode().empty(); Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -1057,10 +1057,10 @@ void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const override { - Table << MatchTable::Opcode("GIM_CheckImmPredicate") + Table << MatchTable::Opcode(Predicate.getGlobalISelMatchOpcode()) << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Predicate") - << MatchTable::NamedValue("GIPFP_" + Predicate.getFnName()) + << MatchTable::NamedValue(Predicate.getGlobalISelEnumName()) << MatchTable::LineBreak; } }; @@ -1258,6 +1258,7 @@ OR_Copy, OR_CopySubReg, OR_CopyConstantAsImm, + OR_CopyFConstantAsFPImm, OR_Imm, OR_Register, OR_ComplexPattern @@ -1345,6 +1346,36 @@ } }; +/// 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 +1944,8 @@ importImplicitDefRenderers(BuildMIAction &DstMIBuilder, const std::vector &ImplicitDefs) const; - void emitImmPredicates(raw_ostream &OS, + void emitImmPredicates(raw_ostream &OS, StringRef TypeIdentifier, + StringRef Type, std::function Filter); /// Analyze pattern \p P, returning a matcher for it if possible. @@ -2026,8 +2058,9 @@ } 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); @@ -2171,6 +2204,10 @@ DstMIBuilder.addRenderer(0, DstChild->getName()); return Error::success(); + } else if (DstChild->getOperator()->getName() == "fpimm") { + DstMIBuilder.addRenderer( + 0, DstChild->getName()); + return Error::success(); } return failedImport("Dst pattern child isn't a leaf node or an MBB" + llvm::to_string(*DstChild)); @@ -2549,7 +2586,8 @@ // 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 Filter) { + raw_ostream &OS, StringRef TypeIdentifier, StringRef Type, + std::function Filter) { std::vector MatchedRecords; const auto &Defs = RK.getAllDerivedDefinitions("PatFrag"); std::copy_if(Defs.begin(), Defs.end(), std::back_inserter(MatchedRecords), @@ -2558,19 +2596,25 @@ 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"; @@ -2647,7 +2691,8 @@ 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() @@ -2760,11 +2805,18 @@ 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"