namespace llvm {
+class APInt;
+class APFloat;
class LLT;
class MachineInstr;
class MachineInstrBuilder;
/// 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
/// 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;
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;
};
/// GlobalISel PatFrag Predicates
enum {
- GIPFP_Invalid,
+ GIPFP_I64_Invalid = 0,
+ GIPFP_APInt_Invalid = 0,
+ GIPFP_APFloat_Invalid = 0,
};
template <class TgtInstructionSelector, class PredicateBitset,
}
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();
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;
// 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>;
<< " 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) {
// 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
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 }
...
---
%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)
+...
// 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: }})
// 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();
// 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,
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,
// 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
// 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)]>;
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();
/// 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;
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 {
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;
}
};
OR_Copy,
OR_CopySubReg,
OR_CopyConstantAsImm,
+ OR_CopyFConstantAsFPImm,
OR_Imm,
OR_Register,
OR_ComplexPattern
}
};
+/// 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.
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.
} 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);
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));
// 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),
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";
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()
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"