Skip to content

Commit bfa9e2c

Browse files
committedOct 14, 2017
[globalisel][tablegen] Simplify named operand/operator lookups and fix a wrong-code bug this revealed.
Summary: Operand variable lookups are now performed by the RuleMatcher rather than searching the whole matcher hierarchy for a match. This revealed a wrong-code bug that currently affects ARM and X86 where patterns that use a variable more than once in the match pattern will be imported but won't check that the operands are identical. This can cause the tablegen-erated matcher to accept matches that should be rejected. Depends on D36569 Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar Subscribers: aemerson, igorb, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D36618 llvm-svn: 315780
1 parent aafbc1c commit bfa9e2c

File tree

5 files changed

+274
-108
lines changed

5 files changed

+274
-108
lines changed
 

‎llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h

+7
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ enum {
150150
/// - InsnID - Instruction ID
151151
GIM_CheckIsSafeToFold,
152152

153+
/// Check the specified operands are identical.
154+
/// - InsnID - Instruction ID
155+
/// - OpIdx - Operand index
156+
/// - OtherInsnID - Other instruction ID
157+
/// - OtherOpIdx - Other operand index
158+
GIM_CheckIsSameOperand,
159+
153160
/// Fail the current try-block, or completely fail to match if there is no
154161
/// current try-block.
155162
GIM_Reject,

‎llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h

+19-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,25 @@ bool InstructionSelector::executeMatchTable(
334334
}
335335
break;
336336
}
337-
337+
case GIM_CheckIsSameOperand: {
338+
int64_t InsnID = MatchTable[CurrentIdx++];
339+
int64_t OpIdx = MatchTable[CurrentIdx++];
340+
int64_t OtherInsnID = MatchTable[CurrentIdx++];
341+
int64_t OtherOpIdx = MatchTable[CurrentIdx++];
342+
DEBUG(dbgs() << CurrentIdx << ": GIM_CheckIsSameOperand(MIs[" << InsnID
343+
<< "][" << OpIdx << "], MIs[" << OtherInsnID << "]["
344+
<< OtherOpIdx << "])\n");
345+
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
346+
assert(State.MIs[OtherInsnID] != nullptr && "Used insn before defined");
347+
State.MIs[InsnID]->getOperand(OpIdx).dump();
348+
State.MIs[OtherInsnID]->getOperand(OtherOpIdx).dump();
349+
if (!State.MIs[InsnID]->getOperand(OpIdx).isIdenticalTo(
350+
State.MIs[OtherInsnID]->getOperand(OtherInsnID))) {
351+
if (handleReject() == RejectAndGiveUp)
352+
return false;
353+
}
354+
break;
355+
}
338356
case GIM_Reject:
339357
DEBUG(dbgs() << CurrentIdx << ": GIM_Reject");
340358
if (handleReject() == RejectAndGiveUp)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# RUN: llc -mtriple=x86_64-linux-gnu -mattr=+bmi -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
2+
#
3+
# Test that rules where multiple operands must be the same operand successfully
4+
# match. Also test that the rules do not match when they're not the same
5+
# operand.
6+
7+
---
8+
name: test_blsr32rr
9+
# CHECK-LABEL: name: test_blsr32rr
10+
alignment: 4
11+
legalized: true
12+
regBankSelected: true
13+
# CHECK: registers:
14+
# CHECK-NEXT: - { id: 0, class: gr32, preferred-register: '' }
15+
# CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' }
16+
# CHECK-NEXT: - { id: 2, class: gpr, preferred-register: '' }
17+
# CHECK-NEXT: - { id: 3, class: gr32, preferred-register: '' }
18+
registers:
19+
- { id: 0, class: gpr }
20+
- { id: 1, class: gpr }
21+
- { id: 2, class: gpr }
22+
- { id: 3, class: gpr }
23+
# G_ADD and G_AND both use %0 so we should match this.
24+
# CHECK: %3 = BLSR32rr %0
25+
body: |
26+
bb.1:
27+
liveins: %edi
28+
29+
%0(s32) = COPY %edi
30+
%1(s32) = G_CONSTANT i32 -1
31+
%2(s32) = G_ADD %0, %1
32+
%3(s32) = G_AND %2, %0
33+
%edi = COPY %3
34+
35+
...
36+
---
37+
name: test_blsr32rr_nomatch
38+
# CHECK-LABEL: name: test_blsr32rr_nomatch
39+
alignment: 4
40+
legalized: true
41+
regBankSelected: true
42+
registers:
43+
- { id: 0, class: gpr }
44+
- { id: 1, class: gpr }
45+
- { id: 2, class: gpr }
46+
- { id: 3, class: gpr }
47+
# G_ADD and G_AND use different operands so we shouldn't match this.
48+
# CHECK-NOT: BLSR32rr
49+
body: |
50+
bb.1:
51+
liveins: %edi
52+
53+
%0(s32) = COPY %edi
54+
%1(s32) = G_CONSTANT i32 -1
55+
%2(s32) = G_ADD %1, %1
56+
%3(s32) = G_AND %2, %0
57+
%edi = COPY %3
58+
...

‎llvm/test/TableGen/GlobalISelEmitter.td

+62-38
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,38 @@ def : Pat<(select GPR32:$src1, complex:$src2, complex:$src3),
259259
def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
260260
[(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>;
261261

262-
//===- Test a simple pattern with ValueType operands. ----------------------===//
262+
//===- Test a pattern with a tied operand in the matcher ------------------===//
263263

264264
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 3*/ [[LABEL:[0-9]+]],
265265
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
266266
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
267267
// CHECK-NEXT: // MIs[0] dst
268268
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
269269
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
270+
// CHECK-NEXT: // MIs[0] src{{$}}
271+
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
272+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
273+
// CHECK-NEXT: // MIs[0] src{{$}}
274+
// CHECK-NEXT: GIM_CheckIsSameOperand, /*MI*/0, /*OpIdx*/2, /*OtherMI*/0, /*OtherOpIdx*/1,
275+
// CHECK-NEXT: // (add:{ *:[i32] } GPR32:{ *:[i32] }:$src, GPR32:{ *:[i32] }:$src) => (DOUBLE:{ *:[i32] } GPR32:{ *:[i32] }:$src)
276+
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::DOUBLE,
277+
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
278+
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src
279+
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
280+
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
281+
// CHECK-NEXT: GIR_Done,
282+
// CHECK-NEXT: // Label 3: @[[LABEL]]
283+
284+
def DOUBLE : I<(outs GPR32:$dst), (ins GPR32:$src), [(set GPR32:$dst, (add GPR32:$src, GPR32:$src))]>;
285+
286+
//===- Test a simple pattern with ValueType operands. ----------------------===//
287+
288+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ [[LABEL:[0-9]+]],
289+
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
290+
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
291+
// CHECK-NEXT: // MIs[0] dst
292+
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
293+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
270294
// CHECK-NEXT: // MIs[0] src1
271295
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
272296
// CHECK-NEXT: // MIs[0] src2
@@ -275,15 +299,15 @@ def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
275299
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
276300
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
277301
// CHECK-NEXT: GIR_Done,
278-
// CHECK-NEXT: // Label 3: @[[LABEL]]
302+
// CHECK-NEXT: // Label 4: @[[LABEL]]
279303

280304
def : Pat<(add i32:$src1, i32:$src2),
281305
(ADD i32:$src1, i32:$src2)>;
282306

283307
//===- Test a simple pattern with an intrinsic. ---------------------------===//
284308
//
285309

286-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ [[LABEL:[0-9]+]],
310+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ [[LABEL:[0-9]+]],
287311
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
288312
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC,
289313
// CHECK-NEXT: // MIs[0] dst
@@ -302,14 +326,14 @@ def : Pat<(add i32:$src1, i32:$src2),
302326
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
303327
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
304328
// CHECK-NEXT: GIR_Done,
305-
// CHECK-NEXT: // Label 4: @[[LABEL]]
329+
// CHECK-NEXT: // Label 5: @[[LABEL]]
306330

307331
def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1),
308332
[(set GPR32:$dst, (int_mytarget_nop GPR32:$src1))]>;
309333

310334
//===- Test a nested instruction match. -----------------------------------===//
311335

312-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ [[LABEL:[0-9]+]],
336+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ [[LABEL:[0-9]+]],
313337
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA,
314338
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
315339
// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
@@ -342,10 +366,10 @@ def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1),
342366
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
343367
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
344368
// CHECK-NEXT: GIR_Done,
345-
// CHECK-NEXT: // Label 5: @[[LABEL]]
369+
// CHECK-NEXT: // Label 6: @[[LABEL]]
346370

347371
// We also get a second rule by commutativity.
348-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ [[LABEL:[0-9]+]],
372+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ [[LABEL:[0-9]+]],
349373
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA,
350374
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
351375
// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2,
@@ -378,7 +402,7 @@ def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1),
378402
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
379403
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
380404
// CHECK-NEXT: GIR_Done,
381-
// CHECK-NEXT: // Label 6: @[[LABEL]]
405+
// CHECK-NEXT: // Label 7: @[[LABEL]]
382406

383407
def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
384408
[(set GPR32:$dst,
@@ -387,7 +411,7 @@ def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
387411

388412
//===- Test another simple pattern with regclass operands. ----------------===//
389413

390-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ [[LABEL:[0-9]+]],
414+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ [[LABEL:[0-9]+]],
391415
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA_HasB_HasC,
392416
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
393417
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
@@ -408,15 +432,15 @@ def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
408432
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
409433
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
410434
// CHECK-NEXT: GIR_Done,
411-
// CHECK-NEXT: // Label 7: @[[LABEL]]
435+
// CHECK-NEXT: // Label 8: @[[LABEL]]
412436

413437
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
414438
[(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>,
415439
Requires<[HasA, HasB, HasC]>;
416440

417441
//===- Test a more complex multi-instruction match. -----------------------===//
418442

419-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ [[LABEL:[0-9]+]],
443+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ [[LABEL:[0-9]+]],
420444
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA,
421445
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
422446
// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
@@ -461,7 +485,7 @@ def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
461485
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
462486
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
463487
// CHECK-NEXT: GIR_Done,
464-
// CHECK-NEXT: // Label 8: @[[LABEL]]
488+
// CHECK-NEXT: // Label 9: @[[LABEL]]
465489

466490
def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4),
467491
[(set GPR32:$dst,
@@ -471,7 +495,7 @@ def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, G
471495
//===- Test a pattern with ComplexPattern operands. -----------------------===//
472496
//
473497

474-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ [[LABEL:[0-9]+]],
498+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 10*/ [[LABEL:[0-9]+]],
475499
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
476500
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
477501
// CHECK-NEXT: // MIs[0] dst
@@ -491,15 +515,15 @@ def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, G
491515
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
492516
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
493517
// CHECK-NEXT: GIR_Done,
494-
// CHECK-NEXT: // Label 9: @[[LABEL]]
518+
// CHECK-NEXT: // Label 10: @[[LABEL]]
495519

496520
def INSN1 : I<(outs GPR32:$dst), (ins GPR32:$src1, complex:$src2), []>;
497521
def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>;
498522

499523
//===- Test a simple pattern with a default operand. ----------------------===//
500524
//
501525

502-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 10*/ [[LABEL:[0-9]+]],
526+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 11*/ [[LABEL:[0-9]+]],
503527
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
504528
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
505529
// CHECK-NEXT: // MIs[0] dst
@@ -519,7 +543,7 @@ def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>;
519543
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
520544
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
521545
// CHECK-NEXT: GIR_Done,
522-
// CHECK-NEXT: // Label 10: @[[LABEL]]
546+
// CHECK-NEXT: // Label 11: @[[LABEL]]
523547

524548
// The -2 is just to distinguish it from the 'not' case below.
525549
def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1),
@@ -528,7 +552,7 @@ def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1),
528552
//===- Test a simple pattern with a default register operand. -------------===//
529553
//
530554

531-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 11*/ [[LABEL:[0-9]+]],
555+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 12*/ [[LABEL:[0-9]+]],
532556
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
533557
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
534558
// CHECK-NEXT: // MIs[0] dst
@@ -548,7 +572,7 @@ def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1),
548572
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
549573
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
550574
// CHECK-NEXT: GIR_Done,
551-
// CHECK-NEXT: // Label 11: @[[LABEL]]
575+
// CHECK-NEXT: // Label 12: @[[LABEL]]
552576

553577
// The -3 is just to distinguish it from the 'not' case below and the other default op case above.
554578
def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1),
@@ -557,7 +581,7 @@ def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1),
557581
//===- Test a simple pattern with a multiple default operands. ------------===//
558582
//
559583

560-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 12*/ [[LABEL:[0-9]+]],
584+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 13*/ [[LABEL:[0-9]+]],
561585
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
562586
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
563587
// CHECK-NEXT: // MIs[0] dst
@@ -578,7 +602,7 @@ def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1),
578602
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
579603
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
580604
// CHECK-NEXT: GIR_Done,
581-
// CHECK-NEXT: // Label 12: @[[LABEL]]
605+
// CHECK-NEXT: // Label 13: @[[LABEL]]
582606

583607
// The -4 is just to distinguish it from the other 'not' cases.
584608
def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
@@ -587,7 +611,7 @@ def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
587611
//===- Test a simple pattern with multiple operands with defaults. --------===//
588612
//
589613

590-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 13*/ [[LABEL:[0-9]+]],
614+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 14*/ [[LABEL:[0-9]+]],
591615
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
592616
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
593617
// CHECK-NEXT: // MIs[0] dst
@@ -609,7 +633,7 @@ def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
609633
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
610634
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
611635
// CHECK-NEXT: GIR_Done,
612-
// CHECK-NEXT: // Label 13: @[[LABEL]]
636+
// CHECK-NEXT: // Label 14: @[[LABEL]]
613637

614638
// The -5 is just to distinguish it from the other cases.
615639
def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1),
@@ -620,7 +644,7 @@ def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1)
620644
// This must precede the 3-register variants because constant immediates have
621645
// priority over register banks.
622646

623-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 14*/ [[LABEL:[0-9]+]],
647+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 15*/ [[LABEL:[0-9]+]],
624648
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
625649
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
626650
// CHECK-NEXT: // MIs[0] dst
@@ -640,15 +664,15 @@ def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1)
640664
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
641665
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
642666
// CHECK-NEXT: GIR_Done,
643-
// CHECK-NEXT: // Label 14: @[[LABEL]]
667+
// CHECK-NEXT: // Label 15: @[[LABEL]]
644668

645669
def ORN : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
646670
def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
647671

648672
//===- Test a COPY_TO_REGCLASS --------------------------------------------===//
649673
//
650674

651-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 15*/ [[LABEL:[0-9]+]],
675+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 16*/ [[LABEL:[0-9]+]],
652676
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
653677
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST,
654678
// CHECK-NEXT: // MIs[0] dst
@@ -661,14 +685,14 @@ def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
661685
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY,
662686
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1,
663687
// CHECK-NEXT: GIR_Done,
664-
// CHECK-NEXT: // Label 15: @[[LABEL]]
688+
// CHECK-NEXT: // Label 16: @[[LABEL]]
665689

666690
def : Pat<(i32 (bitconvert FPR32:$src1)),
667691
(COPY_TO_REGCLASS FPR32:$src1, GPR32)>;
668692

669693
//===- Test a simple pattern with just a specific leaf immediate. ---------===//
670694

671-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 16*/ [[LABEL:[0-9]+]],
695+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 17*/ [[LABEL:[0-9]+]],
672696
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
673697
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
674698
// CHECK-NEXT: // MIs[0] dst
@@ -682,13 +706,13 @@ def : Pat<(i32 (bitconvert FPR32:$src1)),
682706
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
683707
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
684708
// CHECK-NEXT: GIR_Done,
685-
// CHECK-NEXT: // Label 16: @[[LABEL]]
709+
// CHECK-NEXT: // Label 17: @[[LABEL]]
686710

687711
def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>;
688712

689713
//===- Test a simple pattern with a leaf immediate and a predicate. -------===//
690714

691-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 17*/ [[LABEL:[0-9]+]],
715+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 18*/ [[LABEL:[0-9]+]],
692716
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
693717
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
694718
// CHECK-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_simm8,
@@ -704,14 +728,14 @@ def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>;
704728
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
705729
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
706730
// CHECK-NEXT: GIR_Done,
707-
// CHECK-NEXT: // Label 17: @[[LABEL]]
731+
// CHECK-NEXT: // Label 18: @[[LABEL]]
708732

709733
def simm8 : ImmLeaf<i32, [{ return isInt<8>(Imm); }]>;
710734
def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$imm)]>;
711735

712736
//===- Same again but use an IntImmLeaf. ----------------------------------===//
713737

714-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 18*/ [[LABEL:[0-9]+]],
738+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 19*/ [[LABEL:[0-9]+]],
715739
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
716740
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
717741
// CHECK-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APInt_Predicate_simm9,
@@ -727,14 +751,14 @@ def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$i
727751
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
728752
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
729753
// CHECK-NEXT: GIR_Done,
730-
// CHECK-NEXT: // Label 18: @[[LABEL]]
754+
// CHECK-NEXT: // Label 19: @[[LABEL]]
731755

732756
def simm9 : IntImmLeaf<i32, [{ return isInt<9>(Imm->getSExtValue()); }]>;
733757
def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$imm)]>;
734758

735759
//===- Test a simple pattern with just a leaf immediate. ------------------===//
736760

737-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 19*/ [[LABEL:[0-9]+]],
761+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 20*/ [[LABEL:[0-9]+]],
738762
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
739763
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
740764
// CHECK-NEXT: // MIs[0] dst
@@ -749,13 +773,13 @@ def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$i
749773
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
750774
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
751775
// CHECK-NEXT: GIR_Done,
752-
// CHECK-NEXT: // Label 19: @[[LABEL]]
776+
// CHECK-NEXT: // Label 20: @[[LABEL]]
753777

754778
def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)]>;
755779

756780
//===- Test a simple pattern with a FP immediate and a predicate. ---------===//
757781

758-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 20*/ [[LABEL:[0-9]+]],
782+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 21*/ [[LABEL:[0-9]+]],
759783
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
760784
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT,
761785
// CHECK-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APFloat_Predicate_fpimmz,
@@ -771,14 +795,14 @@ def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)
771795
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
772796
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
773797
// CHECK-NEXT: GIR_Done,
774-
// CHECK-NEXT: // Label 20: @[[LABEL]]
798+
// CHECK-NEXT: // Label 21: @[[LABEL]]
775799

776800
def fpimmz : FPImmLeaf<f32, [{ return Imm->isExactlyValue(0.0); }]>;
777801
def MOVfpimmz : I<(outs FPR32:$dst), (ins f32imm:$imm), [(set FPR32:$dst, fpimmz:$imm)]>;
778802

779803
//===- Test a pattern with an MBB operand. --------------------------------===//
780804

781-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 21*/ [[LABEL:[0-9]+]],
805+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 22*/ [[LABEL:[0-9]+]],
782806
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1,
783807
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR,
784808
// CHECK-NEXT: // MIs[0] target
@@ -787,7 +811,7 @@ def MOVfpimmz : I<(outs FPR32:$dst), (ins f32imm:$imm), [(set FPR32:$dst, fpimmz
787811
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR,
788812
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
789813
// CHECK-NEXT: GIR_Done,
790-
// CHECK-NEXT: // Label 21: @[[LABEL]]
814+
// CHECK-NEXT: // Label 22: @[[LABEL]]
791815

792816
def BR : I<(outs), (ins unknown:$target),
793817
[(br bb:$target)]>;

‎llvm/utils/TableGen/GlobalISelEmitter.cpp

+128-69
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,21 @@ class RuleMatcher {
478478
/// emitCaptureOpcodes().
479479
DefinedInsnVariablesMap InsnVariableIDs;
480480

481+
/// A map of named operands defined by the matchers that may be referenced by
482+
/// the renderers.
483+
StringMap<OperandMatcher *> DefinedOperands;
484+
481485
/// ID for the next instruction variable defined with defineInsnVar()
482486
unsigned NextInsnVarID;
483487

484488
std::vector<Record *> RequiredFeatures;
485489

490+
ArrayRef<SMLoc> SrcLoc;
491+
486492
public:
487-
RuleMatcher()
488-
: Matchers(), Actions(), InsnVariableIDs(), NextInsnVarID(0) {}
493+
RuleMatcher(ArrayRef<SMLoc> SrcLoc)
494+
: Matchers(), Actions(), InsnVariableIDs(), DefinedOperands(),
495+
NextInsnVarID(0), SrcLoc(SrcLoc) {}
489496
RuleMatcher(RuleMatcher &&Other) = default;
490497
RuleMatcher &operator=(RuleMatcher &&Other) = default;
491498

@@ -513,7 +520,10 @@ class RuleMatcher {
513520
return make_range(defined_insn_vars_begin(), defined_insn_vars_end());
514521
}
515522

523+
void defineOperand(StringRef SymbolicName, OperandMatcher &OM);
524+
516525
const InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
526+
const OperandMatcher &getOperandMatcher(StringRef Name) const;
517527

518528
void emitCaptureOpcodes(MatchTable &Table);
519529

@@ -544,10 +554,10 @@ template <class PredicateTy> class PredicateListMatcher {
544554
public:
545555
/// Construct a new operand predicate and add it to the matcher.
546556
template <class Kind, class... Args>
547-
Kind &addPredicate(Args&&... args) {
557+
Optional<Kind *> addPredicate(Args&&... args) {
548558
Predicates.emplace_back(
549559
llvm::make_unique<Kind>(std::forward<Args>(args)...));
550-
return *static_cast<Kind *>(Predicates.back().get());
560+
return static_cast<Kind *>(Predicates.back().get());
551561
}
552562

553563
typename PredicateVec::const_iterator predicates_begin() const {
@@ -593,6 +603,7 @@ class OperandPredicateMatcher {
593603
/// but OPM_Int must have priority over OPM_RegBank since constant integers
594604
/// are represented by a virtual register defined by a G_CONSTANT instruction.
595605
enum PredicateKind {
606+
OPM_Tie,
596607
OPM_ComplexPattern,
597608
OPM_IntrinsicID,
598609
OPM_Instruction,
@@ -612,17 +623,6 @@ class OperandPredicateMatcher {
612623

613624
PredicateKind getKind() const { return Kind; }
614625

615-
/// Return the OperandMatcher for the specified operand or nullptr if there
616-
/// isn't one by that name in this operand predicate matcher.
617-
///
618-
/// InstructionOperandMatcher is the only subclass that can return non-null
619-
/// for this.
620-
virtual Optional<const OperandMatcher *>
621-
getOptionalOperand(StringRef SymbolicName) const {
622-
assert(!SymbolicName.empty() && "Cannot lookup unnamed operand");
623-
return None;
624-
}
625-
626626
/// Emit MatchTable opcodes to capture instructions into the MIs table.
627627
///
628628
/// Only InstructionOperandMatcher needs to do anything for this method the
@@ -651,6 +651,23 @@ PredicateListMatcher<OperandPredicateMatcher>::getNoPredicateComment() const {
651651
return "No operand predicates";
652652
}
653653

654+
/// Generates code to check that a register operand is defined by the same exact
655+
/// one as another.
656+
class SameOperandMatcher : public OperandPredicateMatcher {
657+
std::string TiedTo;
658+
659+
public:
660+
SameOperandMatcher(StringRef TiedTo)
661+
: OperandPredicateMatcher(OPM_Tie), TiedTo(TiedTo) {}
662+
663+
static bool classof(const OperandPredicateMatcher *P) {
664+
return P->getKind() == OPM_Tie;
665+
}
666+
667+
void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule,
668+
unsigned InsnVarID, unsigned OpIdx) const override;
669+
};
670+
654671
/// Generates code to check that an operand is a particular LLT.
655672
class LLTOperandMatcher : public OperandPredicateMatcher {
656673
protected:
@@ -857,19 +874,6 @@ class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
857874
llvm::to_string(OpIdx) + ")";
858875
}
859876

860-
Optional<const OperandMatcher *>
861-
getOptionalOperand(StringRef DesiredSymbolicName) const {
862-
assert(!DesiredSymbolicName.empty() && "Cannot lookup unnamed operand");
863-
if (DesiredSymbolicName == SymbolicName)
864-
return this;
865-
for (const auto &OP : predicates()) {
866-
const auto &MaybeOperand = OP->getOptionalOperand(DesiredSymbolicName);
867-
if (MaybeOperand.hasValue())
868-
return MaybeOperand.getValue();
869-
}
870-
return None;
871-
}
872-
873877
InstructionMatcher &getInstructionMatcher() const { return Insn; }
874878

875879
/// Emit MatchTable opcodes to capture instructions into the MIs table.
@@ -930,8 +934,27 @@ class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
930934
unsigned getAllocatedTemporariesBaseID() const {
931935
return AllocatedTemporariesBaseID;
932936
}
937+
938+
bool isSameAsAnotherOperand() const {
939+
for (const auto &Predicate : predicates())
940+
if (isa<SameOperandMatcher>(Predicate))
941+
return true;
942+
return false;
943+
}
933944
};
934945

946+
// Specialize OperandMatcher::addPredicate() to refrain from adding redundant
947+
// predicates.
948+
template <>
949+
template <class Kind, class... Args>
950+
Optional<Kind *>
951+
PredicateListMatcher<OperandPredicateMatcher>::addPredicate(Args &&... args) {
952+
if (static_cast<OperandMatcher *>(this)->isSameAsAnotherOperand())
953+
return None;
954+
Predicates.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...));
955+
return static_cast<Kind *>(Predicates.back().get());
956+
}
957+
935958
unsigned ComplexPatternOperandMatcher::getAllocatedTemporariesBaseID() const {
936959
return Operand.getAllocatedTemporariesBaseID();
937960
}
@@ -1088,20 +1111,28 @@ class InstructionMatcher
10881111
protected:
10891112
typedef std::vector<std::unique_ptr<OperandMatcher>> OperandVec;
10901113

1114+
RuleMatcher &Rule;
1115+
10911116
/// The operands to match. All rendered operands must be present even if the
10921117
/// condition is always true.
10931118
OperandVec Operands;
10941119

10951120
std::string SymbolicName;
10961121

10971122
public:
1098-
InstructionMatcher(StringRef SymbolicName) : SymbolicName(SymbolicName) {}
1123+
InstructionMatcher(RuleMatcher &Rule, StringRef SymbolicName)
1124+
: Rule(Rule), SymbolicName(SymbolicName) {}
1125+
1126+
RuleMatcher &getRuleMatcher() const { return Rule; }
10991127

11001128
/// Add an operand to the matcher.
11011129
OperandMatcher &addOperand(unsigned OpIdx, const std::string &SymbolicName,
11021130
unsigned AllocatedTemporariesBaseID) {
11031131
Operands.emplace_back(new OperandMatcher(*this, OpIdx, SymbolicName,
11041132
AllocatedTemporariesBaseID));
1133+
if (!SymbolicName.empty())
1134+
Rule.defineOperand(SymbolicName, *Operands.back());
1135+
11051136
return *Operands.back();
11061137
}
11071138

@@ -1115,24 +1146,6 @@ class InstructionMatcher
11151146
llvm_unreachable("Failed to lookup operand");
11161147
}
11171148

1118-
Optional<const OperandMatcher *>
1119-
getOptionalOperand(StringRef SymbolicName) const {
1120-
assert(!SymbolicName.empty() && "Cannot lookup unnamed operand");
1121-
for (const auto &Operand : Operands) {
1122-
const auto &OM = Operand->getOptionalOperand(SymbolicName);
1123-
if (OM.hasValue())
1124-
return OM.getValue();
1125-
}
1126-
return None;
1127-
}
1128-
1129-
const OperandMatcher &getOperand(StringRef SymbolicName) const {
1130-
Optional<const OperandMatcher *>OM = getOptionalOperand(SymbolicName);
1131-
if (OM.hasValue())
1132-
return *OM.getValue();
1133-
llvm_unreachable("Failed to lookup operand");
1134-
}
1135-
11361149
StringRef getSymbolicName() const { return SymbolicName; }
11371150
unsigned getNumOperands() const { return Operands.size(); }
11381151
OperandVec::iterator operands_begin() { return Operands.begin(); }
@@ -1233,22 +1246,16 @@ class InstructionOperandMatcher : public OperandPredicateMatcher {
12331246
std::unique_ptr<InstructionMatcher> InsnMatcher;
12341247

12351248
public:
1236-
InstructionOperandMatcher(StringRef SymbolicName)
1249+
InstructionOperandMatcher(RuleMatcher &Rule, StringRef SymbolicName)
12371250
: OperandPredicateMatcher(OPM_Instruction),
1238-
InsnMatcher(new InstructionMatcher(SymbolicName)) {}
1251+
InsnMatcher(new InstructionMatcher(Rule, SymbolicName)) {}
12391252

12401253
static bool classof(const OperandPredicateMatcher *P) {
12411254
return P->getKind() == OPM_Instruction;
12421255
}
12431256

12441257
InstructionMatcher &getInsnMatcher() const { return *InsnMatcher; }
12451258

1246-
Optional<const OperandMatcher *>
1247-
getOptionalOperand(StringRef SymbolicName) const override {
1248-
assert(!SymbolicName.empty() && "Cannot lookup unnamed operand");
1249-
return InsnMatcher->getOptionalOperand(SymbolicName);
1250-
}
1251-
12521259
void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule,
12531260
unsigned InsnID, unsigned OpIdx) const override {
12541261
unsigned InsnVarID = Rule.defineInsnVar(Table, *InsnMatcher, InsnID, OpIdx);
@@ -1316,7 +1323,7 @@ class CopyRenderer : public OperandRenderer {
13161323
const StringRef getSymbolicName() const { return SymbolicName; }
13171324

13181325
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
1319-
const OperandMatcher &Operand = Matched.getOperand(SymbolicName);
1326+
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
13201327
unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
13211328
Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
13221329
<< MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
@@ -1416,7 +1423,7 @@ class CopySubRegRenderer : public OperandRenderer {
14161423
const StringRef getSymbolicName() const { return SymbolicName; }
14171424

14181425
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
1419-
const OperandMatcher &Operand = Matched.getOperand(SymbolicName);
1426+
const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
14201427
unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
14211428
Table << MatchTable::Opcode("GIR_CopySubReg")
14221429
<< MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
@@ -1556,13 +1563,13 @@ class BuildMIAction : public MatchAction {
15561563
std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers;
15571564

15581565
/// True if the instruction can be built solely by mutating the opcode.
1559-
bool canMutate() const {
1566+
bool canMutate(RuleMatcher &Rule) const {
15601567
if (OperandRenderers.size() != Matched.getNumOperands())
15611568
return false;
15621569

15631570
for (const auto &Renderer : enumerate(OperandRenderers)) {
15641571
if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
1565-
const OperandMatcher &OM = Matched.getOperand(Copy->getSymbolicName());
1572+
const OperandMatcher &OM = Rule.getOperandMatcher(Copy->getSymbolicName());
15661573
if (&Matched != &OM.getInstructionMatcher() ||
15671574
OM.getOperandIndex() != Renderer.index())
15681575
return false;
@@ -1587,7 +1594,7 @@ class BuildMIAction : public MatchAction {
15871594

15881595
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
15891596
unsigned RecycleInsnID) const override {
1590-
if (canMutate()) {
1597+
if (canMutate(Rule)) {
15911598
Table << MatchTable::Opcode("GIR_MutateOpcode")
15921599
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
15931600
<< MatchTable::Comment("RecycleInsnID")
@@ -1695,7 +1702,7 @@ class ConstrainOperandToRegClassAction : public MatchAction {
16951702
};
16961703

16971704
InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {
1698-
Matchers.emplace_back(new InstructionMatcher(SymbolicName));
1705+
Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));
16991706
return *Matchers.back();
17001707
}
17011708

@@ -1740,6 +1747,17 @@ unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const
17401747
llvm_unreachable("Matched Insn was not captured in a local variable");
17411748
}
17421749

1750+
void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) {
1751+
if (DefinedOperands.find(SymbolicName) == DefinedOperands.end()) {
1752+
DefinedOperands[SymbolicName] = &OM;
1753+
return;
1754+
}
1755+
1756+
// If the operand is already defined, then we must ensure both references in
1757+
// the matcher have the exact same node.
1758+
OM.addPredicate<SameOperandMatcher>(OM.getSymbolicName());
1759+
}
1760+
17431761
const InstructionMatcher &
17441762
RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
17451763
for (const auto &I : InsnVariableIDs)
@@ -1749,6 +1767,16 @@ RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
17491767
("Failed to lookup instruction " + SymbolicName).str().c_str());
17501768
}
17511769

1770+
const OperandMatcher &
1771+
RuleMatcher::getOperandMatcher(StringRef Name) const {
1772+
const auto &I = DefinedOperands.find(Name);
1773+
1774+
if (I == DefinedOperands.end())
1775+
PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");
1776+
1777+
return *I->second;
1778+
}
1779+
17521780
/// Emit MatchTable opcodes to check the shape of the match and capture
17531781
/// instructions into local variables.
17541782
void RuleMatcher::emitCaptureOpcodes(MatchTable &Table) {
@@ -1908,6 +1936,23 @@ bool OperandPredicateMatcher::isHigherPriorityThan(
19081936
return Kind < B.Kind;
19091937
}
19101938

1939+
void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1940+
RuleMatcher &Rule,
1941+
unsigned InsnVarID,
1942+
unsigned OpIdx) const {
1943+
const OperandMatcher &OtherOM = Rule.getOperandMatcher(TiedTo);
1944+
unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher());
1945+
1946+
Table << MatchTable::Opcode("GIM_CheckIsSameOperand")
1947+
<< MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
1948+
<< MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
1949+
<< MatchTable::Comment("OtherMI")
1950+
<< MatchTable::IntValue(OtherInsnVarID)
1951+
<< MatchTable::Comment("OtherOpIdx")
1952+
<< MatchTable::IntValue(OtherOM.getOperandIndex())
1953+
<< MatchTable::LineBreak;
1954+
}
1955+
19111956
//===- GlobalISelEmitter class --------------------------------------------===//
19121957

19131958
class GlobalISelEmitter {
@@ -1947,7 +1992,8 @@ class GlobalISelEmitter {
19471992
Expected<BuildMIAction &>
19481993
createAndImportInstructionRenderer(RuleMatcher &M, const TreePatternNode *Dst,
19491994
const InstructionMatcher &InsnMatcher);
1950-
Error importExplicitUseRenderer(BuildMIAction &DstMIBuilder,
1995+
Error importExplicitUseRenderer(RuleMatcher &Rule,
1996+
BuildMIAction &DstMIBuilder,
19511997
TreePatternNode *DstChild,
19521998
const InstructionMatcher &InsnMatcher) const;
19531999
Error importDefaultOperandRenderers(BuildMIAction &DstMIBuilder,
@@ -2065,7 +2111,8 @@ GlobalISelEmitter::createAndImportSelDAGMatcher(InstructionMatcher &InsnMatcher,
20652111
if (Src->isLeaf()) {
20662112
Init *SrcInit = Src->getLeafValue();
20672113
if (IntInit *SrcIntInit = dyn_cast<IntInit>(SrcInit)) {
2068-
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
2114+
OperandMatcher &OM =
2115+
InsnMatcher.addOperand(OpIdx++, Src->getName(), TempOpIdx);
20692116
OM.addPredicate<LiteralIntOperandMatcher>(SrcIntInit->getValue());
20702117
} else
20712118
return failedImport(
@@ -2116,6 +2163,8 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher,
21162163
unsigned &TempOpIdx) const {
21172164
OperandMatcher &OM =
21182165
InsnMatcher.addOperand(OpIdx, SrcChild->getName(), TempOpIdx);
2166+
if (OM.isSameAsAnotherOperand())
2167+
return Error::success();
21192168

21202169
ArrayRef<TypeSetByHwMode> ChildTypes = SrcChild->getExtTypes();
21212170
if (ChildTypes.size() != 1)
@@ -2141,9 +2190,17 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher,
21412190

21422191
// Check for nested instructions.
21432192
if (!SrcChild->isLeaf()) {
2193+
auto MaybeInsnOperand = OM.addPredicate<InstructionOperandMatcher>(
2194+
InsnMatcher.getRuleMatcher(), SrcChild->getName());
2195+
if (!MaybeInsnOperand.hasValue()) {
2196+
// This isn't strictly true. If the user were to provide exactly the same
2197+
// matchers as the original operand then we could allow it. However, it's
2198+
// simpler to not permit the redundant specification.
2199+
return failedImport("Nested instruction cannot be the same as another operand");
2200+
}
2201+
21442202
// Map the node to a gMIR instruction.
2145-
InstructionOperandMatcher &InsnOperand =
2146-
OM.addPredicate<InstructionOperandMatcher>(SrcChild->getName());
2203+
InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand;
21472204
auto InsnMatcherOrError = createAndImportSelDAGMatcher(
21482205
InsnOperand.getInsnMatcher(), SrcChild, TempOpIdx);
21492206
if (auto Error = InsnMatcherOrError.takeError())
@@ -2203,7 +2260,7 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher,
22032260
}
22042261

22052262
Error GlobalISelEmitter::importExplicitUseRenderer(
2206-
BuildMIAction &DstMIBuilder, TreePatternNode *DstChild,
2263+
RuleMatcher &Rule, BuildMIAction &DstMIBuilder, TreePatternNode *DstChild,
22072264
const InstructionMatcher &InsnMatcher) const {
22082265
if (DstChild->getTransformFn() != nullptr) {
22092266
return failedImport("Dst pattern child has transform fn " +
@@ -2272,7 +2329,7 @@ Error GlobalISelEmitter::importExplicitUseRenderer(
22722329
return failedImport(
22732330
"SelectionDAG ComplexPattern not mapped to GlobalISel");
22742331

2275-
const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName());
2332+
const OperandMatcher &OM = Rule.getOperandMatcher(DstChild->getName());
22762333
DstMIBuilder.addRenderer<RenderComplexPatternOperand>(
22772334
0, *ComplexPattern->second, DstChild->getName(),
22782335
OM.getAllocatedTemporariesBaseID());
@@ -2373,7 +2430,7 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
23732430
}
23742431

23752432
if (auto Error = importExplicitUseRenderer(
2376-
DstMIBuilder, Dst->getChild(Child), InsnMatcher))
2433+
M, DstMIBuilder, Dst->getChild(Child), InsnMatcher))
23772434
return std::move(Error);
23782435
++Child;
23792436
}
@@ -2426,7 +2483,7 @@ Error GlobalISelEmitter::importImplicitDefRenderers(
24262483

24272484
Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
24282485
// Keep track of the matchers and actions to emit.
2429-
RuleMatcher M;
2486+
RuleMatcher M(P.getSrcRecord()->getLoc());
24302487
M.addAction<DebugCommentAction>(P);
24312488

24322489
if (auto Error = importRulePredicates(M, P.getPredicates()))
@@ -2465,6 +2522,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
24652522

24662523
OperandMatcher &OM0 = InsnMatcher.getOperand(0);
24672524
OM0.setSymbolicName(DstIOperand.Name);
2525+
M.defineOperand(OM0.getSymbolicName(), OM0);
24682526
OM0.addPredicate<RegisterBankOperandMatcher>(RC);
24692527

24702528
auto &DstMIBuilder = M.addAction<BuildMIAction>(0, &DstI, InsnMatcher);
@@ -2525,6 +2583,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
25252583

25262584
OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
25272585
OM.setSymbolicName(DstIOperand.Name);
2586+
M.defineOperand(OM.getSymbolicName(), OM);
25282587
OM.addPredicate<RegisterBankOperandMatcher>(
25292588
Target.getRegisterClass(DstIOpRec));
25302589
++OpIdx;

0 commit comments

Comments
 (0)
Please sign in to comment.