llvm.org GIT mirror llvm / a2824b6
[globalisel][tablegen] Add support for C++ predicates on PatFrags and use it to support BFC on ARM. So far, we've only handled special cases of PatFrag like ImmLeaf. This patch adds support for the remaining cases using similar mechanisms. Like most C++ code from SelectionDAG, GISel and DAGISel expect to operate on different types and representations and as such the code is not compatible between the two. It's therefore necessary to add an alternative implementation in the GISelPredicateCode field. The target test for this feature could easily be done with IntImmLeaf and this would save on a little boilerplate. The reason I've chosen to implement this using PatFrag.GISelPredicateCode and not IntImmLeaf is because I was unable to find a rule that was blocked solely by lack of support for PatFrag predicates. I found that the ones I investigated as being likely candidates for the test were further blocked by other things. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@334871 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Sanders 1 year, 4 months ago
8 changed file(s) with 172 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
146146 GIM_CheckMemorySizeEqualToLLT,
147147 GIM_CheckMemorySizeLessThanLLT,
148148 GIM_CheckMemorySizeGreaterThanLLT,
149 /// Check a generic C++ instruction predicate
150 /// - InsnID - Instruction ID
151 /// - PredicateID - The ID of the predicate function to call
152 GIM_CheckCxxInsnPredicate,
149153
150154 /// Check the type for the specified operand
151155 /// - InsnID - Instruction ID
412416 }
413417
414418 virtual bool testImmPredicate_I64(unsigned, int64_t) const {
415 llvm_unreachable("Subclasses must override this to use tablegen");
419 llvm_unreachable(
420 "Subclasses must override this with a tablegen-erated function");
416421 }
417422 virtual bool testImmPredicate_APInt(unsigned, const APInt &) const {
418 llvm_unreachable("Subclasses must override this to use tablegen");
423 llvm_unreachable(
424 "Subclasses must override this with a tablegen-erated function");
419425 }
420426 virtual bool testImmPredicate_APFloat(unsigned, const APFloat &) const {
421 llvm_unreachable("Subclasses must override this to use tablegen");
427 llvm_unreachable(
428 "Subclasses must override this with a tablegen-erated function");
429 }
430 virtual bool testMIPredicate_MI(unsigned, const MachineInstr &) const {
431 llvm_unreachable(
432 "Subclasses must override this with a tablegen-erated function");
422433 }
423434
424435 /// Constrain a register operand of an instruction \p I to a specified
4040 GIPFP_I64_Invalid = 0,
4141 GIPFP_APInt_Invalid = 0,
4242 GIPFP_APFloat_Invalid = 0,
43 GIPFP_MI_Invalid = 0,
4344 };
4445
4546 template
301302 return false;
302303 break;
303304 }
305 case GIM_CheckCxxInsnPredicate: {
306 int64_t InsnID = MatchTable[CurrentIdx++];
307 int64_t Predicate = MatchTable[CurrentIdx++];
308 DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
309 dbgs()
310 << CurrentIdx << ": GIM_CheckCxxPredicate(MIs["
311 << InsnID << "], Predicate=" << Predicate << ")\n");
312 assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
313 assert(Predicate > GIPFP_MI_Invalid && "Expected a valid predicate");
314
315 if (!testMIPredicate_MI(Predicate, *State.MIs[InsnID]))
316 if (handleReject() == RejectAndGiveUp)
317 return false;
318 break;
319 }
304320 case GIM_CheckAtomicOrdering: {
305321 int64_t InsnID = MatchTable[CurrentIdx++];
306322 AtomicOrdering Ordering = (AtomicOrdering)MatchTable[CurrentIdx++];
622622 dag Operands = ops;
623623 dag Fragment = frag;
624624 code PredicateCode = pred;
625 code GISelPredicateCode = [{}];
625626 code ImmediateCode = [{}];
626627 SDNodeXForm OperandTransform = xform;
627628
882882 let PrintMethod = "printBitfieldInvMaskImmOperand";
883883 let DecoderMethod = "DecodeBitfieldMaskOperand";
884884 let ParserMatchClass = BitfieldAsmOperand;
885 let GISelPredicateCode = [{
886 // There's better methods of implementing this check. IntImmLeaf<> would be
887 // equivalent and have less boilerplate but we need a test for C++
888 // predicates and this one causes new rules to be imported into GlobalISel
889 // without requiring additional features first.
890 const auto &MO = MI.getOperand(1);
891 if (!MO.isCImm())
892 return false;
893 return ARM::isBitFieldInvertedMask(MO.getCImm()->getZExtValue());
894 }];
885895 }
886896
887897 def imm1_32_XFORM: SDNodeXForm
9393 // CHECK-NEXT: bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) const override;
9494 // CHECK-NEXT: bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat &Imm) const override;
9595 // CHECK-NEXT: const int64_t *getMatchTable() const override;
96 // CHECK-NEXT: bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI) const override;
9697 // CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL
9798
9899 // CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
255256 // R19O-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
256257 // R19O-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
257258 // R19O-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
259 //
260 // R19C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
261 //
258262 // R19O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
259263 // R19O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
260 //
261 // R19C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
262 //
263264 // R19N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
264265 // R19N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
265266 // R19N-NEXT: // MIs[0] dst
344345 // R21O-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
345346 // R21O-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
346347 // R21O-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
347 // R21O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
348 // R21O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
349348 //
350349 // R21C-NEXT: GIM_Try, /*On fail goto*//*Label [[PREV_NUM:[0-9]+]]*/ [[PREV:[0-9]+]], // Rule ID 19 //
351350 // R21C-NOT: GIR_Done,
354353 // R21C-NEXT: // Label [[PREV_NUM]]: @[[PREV]]
355354 // R21C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 21 //
356355 //
356 // R21O-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_frag,
357 // R21O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
358 // R21O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
357359 // R21N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
358360 // R21N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
361 // R21N-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIPFP_MI_Predicate_frag,
359362 // R21N-NEXT: // MIs[0] dst
360363 // R21N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
361364 // R21N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
369372 // R21N-NEXT: // MIs[0] src3
370373 // R21N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
371374 // R21C-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/3, /*Renderer*/1, GICP_gi_complex,
372 // R21C-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, complex:{ *:[i32] }:$src3) => (INSN2:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src2)
375 // R21C-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, complex:{ *:[i32] }:$src3)<> => (INSN2:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src2)
376
373377 // R21C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN2,
374378 // R21C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
375379 // R21C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
446450 let mayLoad = 1 in {
447451 def INSN2 : I<(outs GPR32:$dst), (ins GPR32Op:$src1, complex:$src2, complex:$src3), []>;
448452 }
449 def : Pat<(select GPR32:$src1, complex:$src2, complex:$src3),
453 def frag : PatFrag<(ops node:$a, node:$b, node:$c),
454 (select node:$a, node:$b, node:$c),
455 [{ return true; // C++ code }]> {
456 let GISelPredicateCode = [{ return true; // C++ code }];
457 }
458 def : Pat<(frag GPR32:$src1, complex:$src2, complex:$src3),
450459 (INSN2 GPR32:$src1, complex:$src3, complex:$src2)>;
451460
452461 //===- Test a more complex multi-instruction match. -----------------------===//
11321132 if (R->isValueUnset("ScalarMemoryVT"))
11331133 return nullptr;
11341134 return R->getValueAsDef("ScalarMemoryVT");
1135 }
1136 bool TreePredicateFn::hasGISelPredicateCode() const {
1137 return !PatFragRec->getRecord()
1138 ->getValueAsString("GISelPredicateCode")
1139 .empty();
1140 }
1141 std::string TreePredicateFn::getGISelPredicateCode() const {
1142 return PatFragRec->getRecord()->getValueAsString("GISelPredicateCode");
11351143 }
11361144
11371145 StringRef TreePredicateFn::getImmType() const {
542542 /// ValueType record for the memory VT.
543543 Record *getScalarMemoryVT() const;
544544
545 // If true, indicates that GlobalISel-based C++ code was supplied.
546 bool hasGISelPredicateCode() const;
547 std::string getGISelPredicateCode() const;
548
545549 private:
546550 bool hasPredCode() const;
547551 bool hasImmCode() const;
8383
8484 /// Get the name of the enum value used to number the predicate function.
8585 std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {
86 if (Predicate.hasGISelPredicateCode())
87 return "GIPFP_MI_" + Predicate.getFnName();
8688 return "GIPFP_" + Predicate.getImmTypeIdentifier().str() + "_" +
8789 Predicate.getFnName();
8890 }
316318 Predicate.isAtomicOrderingWeakerThanAcquire() ||
317319 Predicate.isAtomicOrderingReleaseOrStronger() ||
318320 Predicate.isAtomicOrderingWeakerThanRelease()))
321 continue;
322
323 if (Predicate.hasGISelPredicateCode())
319324 continue;
320325
321326 HasUnsupportedPredicate = true;
10131018 IPM_AtomicOrderingMMO,
10141019 IPM_MemoryLLTSize,
10151020 IPM_MemoryVsLLTSize,
1021 IPM_GenericPredicate,
10161022 OPM_SameOperand,
10171023 OPM_ComplexPattern,
10181024 OPM_IntrinsicID,
18121818 << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
18131819 << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
18141820 << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
1821 << MatchTable::LineBreak;
1822 }
1823 };
1824
1825 /// Generates code to check an arbitrary C++ instruction predicate.
1826 class GenericInstructionPredicateMatcher : public InstructionPredicateMatcher {
1827 protected:
1828 TreePredicateFn Predicate;
1829
1830 public:
1831 GenericInstructionPredicateMatcher(unsigned InsnVarID,
1832 TreePredicateFn Predicate)
1833 : InstructionPredicateMatcher(IPM_GenericPredicate, InsnVarID),
1834 Predicate(Predicate) {}
1835
1836 static bool classof(const InstructionPredicateMatcher *P) {
1837 return P->getKind() == IPM_GenericPredicate;
1838 }
1839 void emitPredicateOpcodes(MatchTable &Table,
1840 RuleMatcher &Rule) const override {
1841 Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate")
1842 << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
1843 << MatchTable::Comment("FnId")
1844 << MatchTable::NamedValue(getEnumNameForPredicate(Predicate))
18151845 << MatchTable::LineBreak;
18161846 }
18171847 };
29532983 void gatherOpcodeValues();
29542984 void gatherTypeIDValues();
29552985 void gatherNodeEquivs();
2986 // Instruction predicate code that will be emitted in generated functions.
2987 SmallVector InstructionPredicateCodes;
2988 unsigned getOrCreateInstructionPredicateFnId(StringRef Code);
2989
29562990 Record *findNodeEquiv(Record *N) const;
29572991 const CodeGenInstruction *getEquivNode(Record &Equiv,
29582992 const TreePatternNode *N) const;
29592993
29602994 Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates);
2961 Expected createAndImportSelDAGMatcher(
2962 RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
2963 const TreePatternNode *Src, unsigned &TempOpIdx) const;
2995 Expected
2996 createAndImportSelDAGMatcher(RuleMatcher &Rule,
2997 InstructionMatcher &InsnMatcher,
2998 const TreePatternNode *Src, unsigned &TempOpIdx);
29642999 Error importComplexPatternOperandMatcher(OperandMatcher &OM, Record *R,
29653000 unsigned &TempOpIdx) const;
29663001 Error importChildMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
29673002 const TreePatternNode *SrcChild,
29683003 bool OperandIsAPointer, unsigned OpIdx,
2969 unsigned &TempOpIdx) const;
3004 unsigned &TempOpIdx);
29703005
29713006 Expected
29723007 createAndImportInstructionRenderer(RuleMatcher &M,
29923027 importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
29933028 const std::vector &ImplicitDefs) const;
29943029
2995 void emitImmPredicates(raw_ostream &OS, StringRef TypeIdentifier,
2996 StringRef Type,
2997 std::function Filter);
3030 void emitCxxPredicateFns(raw_ostream &OS, StringRef CodeFieldName,
3031 StringRef TypeIdentifier, StringRef ArgType,
3032 StringRef ArgName, StringRef AdditionalDeclarations,
3033 std::function Filter);
3034 void emitImmPredicateFns(raw_ostream &OS, StringRef TypeIdentifier,
3035 StringRef ArgType,
3036 std::function Filter);
3037 void emitMIPredicateFns(raw_ostream &OS);
29983038
29993039 /// Analyze pattern \p P, returning a matcher for it if possible.
30003040 /// Otherwise, return an Error explaining why we don't support it.
30443084 void GlobalISelEmitter::gatherTypeIDValues() {
30453085 LLTOperandMatcher::initTypeIDValuesMap();
30463086 }
3087 unsigned GlobalISelEmitter::getOrCreateInstructionPredicateFnId(StringRef Code) {
3088 // There's not very many predicates that need to be here at the moment so we
3089 // just maintain a simple set-like vector. If it grows then we'll need to do
3090 // something more efficient.
3091 const auto &I = std::find(InstructionPredicateCodes.begin(),
3092 InstructionPredicateCodes.end(),
3093 Code);
3094 if (I == InstructionPredicateCodes.end()) {
3095 unsigned ID = InstructionPredicateCodes.size();
3096 InstructionPredicateCodes.push_back(Code);
3097 return ID;
3098 }
3099 return std::distance(InstructionPredicateCodes.begin(), I);
3100 }
30473101
30483102 void GlobalISelEmitter::gatherNodeEquivs() {
30493103 assert(NodeEquivs.empty());
31053159
31063160 Expected GlobalISelEmitter::createAndImportSelDAGMatcher(
31073161 RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
3108 const TreePatternNode *Src, unsigned &TempOpIdx) const {
3162 const TreePatternNode *Src, unsigned &TempOpIdx) {
31093163 Record *SrcGIEquivOrNull = nullptr;
31103164 const CodeGenInstruction *SrcGIOrNull = nullptr;
31113165
32503304 }
32513305 }
32523306
3307 if (Predicate.hasGISelPredicateCode()) {
3308 InsnMatcher.addPredicate(Predicate);
3309 continue;
3310 }
3311
32533312 return failedImport("Src pattern child has predicate (" +
32543313 explainPredicates(Src) + ")");
32553314 }
33283387 const TreePatternNode *SrcChild,
33293388 bool OperandIsAPointer,
33303389 unsigned OpIdx,
3331 unsigned &TempOpIdx) const {
3390 unsigned &TempOpIdx) {
33323391 OperandMatcher &OM =
33333392 InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx);
33343393 if (OM.isSameAsAnotherOperand())
39904049 // Emit imm predicate table and an enum to reference them with.
39914050 // The 'Predicate_' part of the name is redundant but eliminating it is more
39924051 // trouble than it's worth.
3993 void GlobalISelEmitter::emitImmPredicates(
3994 raw_ostream &OS, StringRef TypeIdentifier, StringRef Type,
4052 void GlobalISelEmitter::emitCxxPredicateFns(
4053 raw_ostream &OS, StringRef CodeFieldName, StringRef TypeIdentifier,
4054 StringRef ArgType, StringRef ArgName, StringRef AdditionalDeclarations,
39954055 std::function Filter) {
39964056 std::vector MatchedRecords;
39974057 const auto &Defs = RK.getAllDerivedDefinitions("PatFrag");
39984058 std::copy_if(Defs.begin(), Defs.end(), std::back_inserter(MatchedRecords),
39994059 [&](Record *Record) {
4000 return !Record->getValueAsString("ImmediateCode").empty() &&
4060 return !Record->getValueAsString(CodeFieldName).empty() &&
40014061 Filter(Record);
40024062 });
40034063
40144074 OS << "};\n";
40154075 }
40164076
4017 OS << "bool " << Target.getName() << "InstructionSelector::testImmPredicate_"
4018 << TypeIdentifier << "(unsigned PredicateID, " << Type
4019 << " Imm) const {\n";
4077 OS << "bool " << Target.getName() << "InstructionSelector::test" << ArgName
4078 << "Predicate_" << TypeIdentifier << "(unsigned PredicateID, " << ArgType << " "
4079 << ArgName << ") const {\n"
4080 << AdditionalDeclarations;
4081 if (!AdditionalDeclarations.empty())
4082 OS << "\n";
40204083 if (!MatchedRecords.empty())
40214084 OS << " switch (PredicateID) {\n";
40224085 for (const auto *Record : MatchedRecords) {
40234086 OS << " case GIPFP_" << TypeIdentifier << "_Predicate_"
40244087 << Record->getName() << ": {\n"
4025 << " " << Record->getValueAsString("ImmediateCode") << "\n"
4026 << " llvm_unreachable(\"ImmediateCode should have returned\");\n"
4088 << " " << Record->getValueAsString(CodeFieldName) << "\n"
4089 << " llvm_unreachable(\"" << CodeFieldName
4090 << " should have returned\");\n"
40274091 << " return false;\n"
40284092 << " }\n";
40294093 }
40324096 OS << " llvm_unreachable(\"Unknown predicate\");\n"
40334097 << " return false;\n"
40344098 << "}\n";
4099 }
4100
4101 void GlobalISelEmitter::emitImmPredicateFns(
4102 raw_ostream &OS, StringRef TypeIdentifier, StringRef ArgType,
4103 std::function Filter) {
4104 return emitCxxPredicateFns(OS, "ImmediateCode", TypeIdentifier, ArgType,
4105 "Imm", "", Filter);
4106 }
4107
4108 void GlobalISelEmitter::emitMIPredicateFns(raw_ostream &OS) {
4109 return emitCxxPredicateFns(
4110 OS, "GISelPredicateCode", "MI", "const MachineInstr &", "MI",
4111 " const MachineFunction &MF = *MI.getParent()->getParent();\n"
4112 " const LLVM_ATTRIBUTE_UNUSED MachineRegisterInfo &MRI = "
4113 "MF.getRegInfo();",
4114 [](const Record *R) { return true; });
40354115 }
40364116
40374117 template
42604340 << " bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat "
42614341 "&Imm) const override;\n"
42624342 << " const int64_t *getMatchTable() const override;\n"
4343 << " bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI) "
4344 "const override;\n"
42634345 << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
42644346
42654347 OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
43734455 OS << "};\n"
43744456 << "// See constructor for table contents\n\n";
43754457
4376 emitImmPredicates(OS, "I64", "int64_t", [](const Record *R) {
4458 emitImmPredicateFns(OS, "I64", "int64_t", [](const Record *R) {
43774459 bool Unset;
43784460 return !R->getValueAsBitOrUnset("IsAPFloat", Unset) &&
43794461 !R->getValueAsBit("IsAPInt");
43804462 });
4381 emitImmPredicates(OS, "APFloat", "const APFloat &", [](const Record *R) {
4463 emitImmPredicateFns(OS, "APFloat", "const APFloat &", [](const Record *R) {
43824464 bool Unset;
43834465 return R->getValueAsBitOrUnset("IsAPFloat", Unset);
43844466 });
4385 emitImmPredicates(OS, "APInt", "const APInt &", [](const Record *R) {
4467 emitImmPredicateFns(OS, "APInt", "const APInt &", [](const Record *R) {
43864468 return R->getValueAsBit("IsAPInt");
43874469 });
4470 emitMIPredicateFns(OS);
43884471 OS << "\n";
43894472
43904473 OS << Target.getName() << "InstructionSelector::ComplexMatcherMemFn\n"