llvm.org GIT mirror llvm / b5378b6
Re-commit with some instrumentation: [globalisel][tablegen] Support zero-instruction emission. Summary: Support the case where an operand of a pattern is also the whole of the result pattern. In this case the original result and all its uses must be replaced by the operand. However, register class restrictions can require a COPY. This patch handles both cases by always emitting the copy and leaving it for the register allocator to optimize. The previous commit failed on the windows bots and this one is likely to fail on those same bots. However, the added instrumentation should reveal a particular isHigherPriorityThan() evaluation which I'm expecting to expose that these machines are weighing priority of two rules differently from the non-windows machines. Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits Differential Revision: https://reviews.llvm.org/D36084 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310919 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Sanders 2 years ago
4 changed file(s) with 175 addition(s) and 66 deletion(s). Raw diff Collapse all Expand all
11621162
11631163
11641164 case TargetOpcode::G_INTTOPTR:
1165 // The importer is currently unable to import pointer types since they
1166 // didn't exist in SelectionDAG.
1167 return selectCopy(I, TII, MRI, TRI, RBI);
1168
11651169 case TargetOpcode::G_BITCAST:
1166 return selectCopy(I, TII, MRI, TRI, RBI);
1170 // Imported SelectionDAG rules can handle every bitcast except those that
1171 // bitcast from a type to the same type. Ideally, these shouldn't occur
1172 // but we might not run an optimizer that deletes them.
1173 if (MRI.getType(I.getOperand(0).getReg()) ==
1174 MRI.getType(I.getOperand(1).getReg()))
1175 return selectCopy(I, TII, MRI, TRI, RBI);
1176 return false;
11671177
11681178 case TargetOpcode::G_FPEXT: {
11691179 if (MRI.getType(I.getOperand(0).getReg()) != LLT::scalar(64)) {
1010 define void @bitcast_s64_fpr() { ret void }
1111 define void @bitcast_s64_gpr_fpr() { ret void }
1212 define void @bitcast_s64_fpr_gpr() { ret void }
13 define void @bitcast_s64_v2f32_fpr() { ret void }
14 define void @bitcast_s64_v8i8_fpr() { ret void }
1315 ...
1416
1517 ---
209211 %1(s64) = G_BITCAST %0
210212 %x0 = COPY %1(s64)
211213 ...
214
215 ---
216 # CHECK-LABEL: name: bitcast_s64_v2f32_fpr
217 name: bitcast_s64_v2f32_fpr
218 legalized: true
219 regBankSelected: true
220
221 # CHECK: registers:
222 # CHECK-NEXT: - { id: 0, class: fpr64, preferred-register: '' }
223 # CHECK-NEXT: - { id: 1, class: fpr64, preferred-register: '' }
224 registers:
225 - { id: 0, class: fpr }
226 - { id: 1, class: fpr }
227
228 # CHECK: body:
229 # CHECK: %0 = COPY %d0
230 # CHECK: %1 = COPY %0
231 body: |
232 bb.0:
233 liveins: %d0
234
235 %0(s64) = COPY %d0
236 %1(<2 x s32>) = G_BITCAST %0
237 %x0 = COPY %1(<2 x s32>)
238 ...
239
240 ---
241 # CHECK-LABEL: name: bitcast_s64_v8i8_fpr
242 name: bitcast_s64_v8i8_fpr
243 legalized: true
244 regBankSelected: true
245
246 # CHECK: registers:
247 # CHECK-NEXT: - { id: 0, class: fpr64, preferred-register: '' }
248 # CHECK-NEXT: - { id: 1, class: fpr64, preferred-register: '' }
249 registers:
250 - { id: 0, class: fpr }
251 - { id: 1, class: fpr }
252
253 # CHECK: body:
254 # CHECK: %0 = COPY %d0
255 # CHECK: %1 = COPY %0
256 body: |
257 bb.0:
258 liveins: %d0
259
260 %0(s64) = COPY %d0
261 %1(<8 x s8>) = G_BITCAST %0
262 %x0 = COPY %1(<8 x s8>)
263 ...
8181 // CHECK-NEXT: Features[Feature_HasCBit] = 1;
8282 // CHECK-NEXT: return Features;
8383 // CHECK-NEXT: }
84
85 // CHECK-LABEL: enum {
86 // CHECK-NEXT: GILLT_s32,
87 // CHECK-NEXT: }
88 // CHECK-NEXT: const static LLT TypeObjects[] = {
89 // CHECK-NEXT: LLT::scalar(32),
90 // CHECK-NEXT: };
8491
8592 // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const {
8693 // CHECK-NEXT: MachineFunction &MF = *I.getParent()->getParent();
109109 const LLT &get() const { return Ty; }
110110
111111 /// This ordering is used for std::unique() and std::sort(). There's no
112 /// particular logic behind the order.
112 /// particular logic behind the order but either A < B or B < A must be
113 /// true if A != B.
113114 bool operator<(const LLTCodeGen &Other) const {
115 if (Ty.isValid() != Other.Ty.isValid())
116 return Ty.isValid() < Other.Ty.isValid();
114117 if (!Ty.isValid())
115 return Other.Ty.isValid();
116 if (Ty.isScalar()) {
117 if (!Other.Ty.isValid())
118 return false;
119 if (Other.Ty.isScalar())
120 return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
121118 return false;
122 }
123 if (Ty.isVector()) {
124 if (!Other.Ty.isValid() || Other.Ty.isScalar())
125 return false;
126 if (Other.Ty.isVector()) {
127 if (Ty.getNumElements() < Other.Ty.getNumElements())
128 return true;
129 if (Ty.getNumElements() > Other.Ty.getNumElements())
130 return false;
131 return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
132 }
133 return false;
134 }
135 llvm_unreachable("Unhandled LLT");
119
120 if (Ty.isVector() != Other.Ty.isVector())
121 return Ty.isVector() < Other.Ty.isVector();
122 if (Ty.isScalar() != Other.Ty.isScalar())
123 return Ty.isScalar() < Other.Ty.isScalar();
124 if (Ty.isPointer() != Other.Ty.isPointer())
125 return Ty.isPointer() < Other.Ty.isPointer();
126
127 if (Ty.isPointer() && Ty.getAddressSpace() != Other.Ty.getAddressSpace())
128 return Ty.getAddressSpace() < Other.Ty.getAddressSpace();
129
130 if (Ty.isVector() && Ty.getNumElements() != Other.Ty.getNumElements())
131 return Ty.getNumElements() < Other.Ty.getNumElements();
132
133 return Ty.getSizeInBits() < Other.Ty.getSizeInBits();
136134 }
137135 };
138136
181179 static Error isTrivialOperatorNode(const TreePatternNode *N) {
182180 std::string Explanation = "";
183181 std::string Separator = "";
184 if (N->isLeaf()) {
185 if (isa(N->getLeafValue()))
186 return Error::success();
187
188 Explanation = "Is a leaf";
189 Separator = ", ";
190 }
191
192182 if (N->hasAnyPredicate()) {
193183 Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")";
194184 Separator = ", ";
199189 Separator = ", ";
200190 }
201191
202 if (!N->isLeaf() && !N->hasAnyPredicate() && !N->getTransformFn())
192 if (!N->hasAnyPredicate() && !N->getTransformFn())
203193 return Error::success();
204194
205195 return failedImport(Explanation);
457447
458448 /// A list of actions that need to be taken when all predicates in this rule
459449 /// have succeeded.
450 public:
460451 std::vector> Actions;
452 protected:
461453
462454 typedef std::map
463455 DefinedInsnVariablesMap;
633625 LLTCodeGen Ty;
634626
635627 public:
628 static std::set KnownTypes;
629
636630 LLTOperandMatcher(const LLTCodeGen &Ty)
637 : OperandPredicateMatcher(OPM_LLT), Ty(Ty) {}
631 : OperandPredicateMatcher(OPM_LLT), Ty(Ty) {
632 KnownTypes.insert(Ty);
633 }
638634
639635 static bool classof(const OperandPredicateMatcher *P) {
640636 return P->getKind() == OPM_LLT;
649645 << MatchTable::LineBreak;
650646 }
651647 };
648
649 std::set LLTOperandMatcher::KnownTypes;
652650
653651 /// Generates code to check that an operand is a particular target constant.
654652 class ComplexPatternOperandMatcher : public OperandPredicateMatcher {
14351433 class BuildMIAction : public MatchAction {
14361434 private:
14371435 unsigned InsnID;
1436 public:
14381437 const CodeGenInstruction *I;
1438 private:
14391439 const InstructionMatcher &Matched;
14401440 std::vector> OperandRenderers;
14411441
22862286 return failedImport("Src pattern root isn't a trivial operator (" +
22872287 toString(std::move(Err)) + ")");
22882288
2289 if (Dst->isLeaf())
2290 return failedImport("Dst pattern root isn't a known leaf");
2291
2292 // Start with the defined operands (i.e., the results of the root operator).
2293 Record *DstOp = Dst->getOperator();
2294 if (!DstOp->isSubClassOf("Instruction"))
2295 return failedImport("Pattern operator isn't an instruction");
2296
2297 auto &DstI = Target.getInstruction(DstOp);
2298 if (DstI.Operands.NumDefs != Src->getExtTypes().size())
2299 return failedImport("Src pattern results and dst MI defs are different (" +
2300 to_string(Src->getExtTypes().size()) + " def(s) vs " +
2301 to_string(DstI.Operands.NumDefs) + " def(s))");
2302
23032289 InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName());
23042290 unsigned TempOpIdx = 0;
23052291 auto InsnMatcherOrError =
23072293 if (auto Error = InsnMatcherOrError.takeError())
23082294 return std::move(Error);
23092295 InstructionMatcher &InsnMatcher = InsnMatcherOrError.get();
2296
2297 if (Dst->isLeaf()) {
2298 Record *RCDef = getInitValueAsRegClass(Dst->getLeafValue());
2299
2300 const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef);
2301 if (RCDef) {
2302 // We need to replace the def and all its uses with the specified
2303 // operand. However, we must also insert COPY's wherever needed.
2304 // For now, emit a copy and let the register allocator clean up.
2305 auto &DstI = Target.getInstruction(RK.getDef("COPY"));
2306 const auto &DstIOperand = DstI.Operands[0];
2307
2308 OperandMatcher &OM0 = InsnMatcher.getOperand(0);
2309 OM0.setSymbolicName(DstIOperand.Name);
2310 OM0.addPredicate(RC);
2311
2312 auto &DstMIBuilder = M.addAction(0, &DstI, InsnMatcher);
2313 DstMIBuilder.addRenderer(0, InsnMatcher, DstIOperand.Name);
2314 DstMIBuilder.addRenderer(0, InsnMatcher, Dst->getName());
2315 M.addAction(0, 0, RC);
2316
2317 // We're done with this pattern! It's eligible for GISel emission; return
2318 // it.
2319 ++NumPatternImported;
2320 return std::move(M);
2321 }
2322
2323 return failedImport("Dst pattern root isn't a known leaf");
2324 }
2325
2326 // Start with the defined operands (i.e., the results of the root operator).
2327 Record *DstOp = Dst->getOperator();
2328 if (!DstOp->isSubClassOf("Instruction"))
2329 return failedImport("Pattern operator isn't an instruction");
2330
2331 auto &DstI = Target.getInstruction(DstOp);
2332 if (DstI.Operands.NumDefs != Src->getExtTypes().size())
2333 return failedImport("Src pattern results and dst MI defs are different (" +
2334 to_string(Src->getExtTypes().size()) + " def(s) vs " +
2335 to_string(DstI.Operands.NumDefs) + " def(s))");
23102336
23112337 // The root of the match also has constraints on the register bank so that it
23122338 // matches the result instruction.
24552481 Rules.push_back(std::move(MatcherOrErr.get()));
24562482 }
24572483
2458 std::stable_sort(Rules.begin(), Rules.end(),
2459 [&](const RuleMatcher &A, const RuleMatcher &B) {
2460 if (A.isHigherPriorityThan(B)) {
2461 assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
2462 "and less important at "
2463 "the same time");
2464 return true;
2465 }
2466 return false;
2467 });
2484 const auto &IsRuleEmittingOpcode = [](const RuleMatcher &A, StringRef I) -> bool {
2485 const BuildMIAction &BMI = (const BuildMIAction &)*A.Actions[1];
2486 if (BMI.I->TheDef->getName() == I)
2487 return true;
2488 return false;
2489 };
2490
2491 std::stable_sort(Rules.begin(), Rules.end(), [&](const RuleMatcher &A,
2492 const RuleMatcher &B) {
2493 bool EmitResult = false;
2494 bool AIsADD8ri = false;
2495 if (IsRuleEmittingOpcode(A, "ADD8ri") && IsRuleEmittingOpcode(B, "INC8r")) {
2496 EmitResult = true;
2497 AIsADD8ri = true;
2498 }
2499 if (IsRuleEmittingOpcode(B, "ADD8ri") && IsRuleEmittingOpcode(A, "INC8r"))
2500 EmitResult = true;
2501
2502 if (EmitResult)
2503 errs() << "A=" << (AIsADD8ri ? "ADD8ri" : "INC8r") << ", B=" << (!AIsADD8ri ? "ADD8ri" : "INC8r") << "\n";
2504 if (A.isHigherPriorityThan(B)) {
2505 if (EmitResult)
2506 errs() << "A higher priority than B\n";
2507 assert(!B.isHigherPriorityThan(A) && "Cannot be more important "
2508 "and less important at "
2509 "the same time");
2510 return true;
2511 } else if (EmitResult)
2512 errs() << "A lower priority than B\n";
2513 return false;
2514 });
24682515
24692516 std::vector ComplexPredicates =
24702517 RK.getAllDerivedDefinitions("GIComplexOperandMatcher");
25342581
25352582 // Emit a table containing the LLT objects needed by the matcher and an enum
25362583 // for the matcher to reference them with.
2537 std::vector TypeObjects = {
2538 LLT::scalar(8), LLT::scalar(16), LLT::scalar(32),
2539 LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1),
2540 LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1),
2541 LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8),
2542 LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16),
2543 LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32),
2544 LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32),
2545 LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64),
2546 };
2584 std::vector TypeObjects;
2585 for (const auto &Ty : LLTOperandMatcher::KnownTypes)
2586 TypeObjects.push_back(Ty);
25472587 std::sort(TypeObjects.begin(), TypeObjects.end());
25482588 OS << "enum {\n";
25492589 for (const auto &TypeObject : TypeObjects) {