Skip to content

Commit 1d94fb2

Browse files
committed
[gicombiner] Add GIMatchTree and use it for the code generation
Summary: GIMatchTree's job is to build a decision tree by zipping all the GIMatchDag's together. Each DAG is added to the tree builder as a leaf and partitioners are used to subdivide each node until there are no more partitioners to apply. At this point, the code generator is responsible for testing any untested predicates and following any unvisited traversals (there shouldn't be any of the latter as the getVRegDef partitioner handles them all). Note that the leaves don't always fit into partitions cleanly and the partitions may overlap as a result. This is resolved by cloning the leaf into every partition it belongs to. One example of this is a rule that can match one of N opcodes. The leaf for this rule would end up in N partitions when processed by the opcode partitioner. A similar example is the getVRegDef partitioner where having rules (add $a, $b), and (add ($a, $b), $c) will result in the former being in the partition for successfully following the vreg-def and failing to do so as it doesn't care which happens. Depends on D69151 Fixed the issues with the windows bots which were caused by stdout/stderr interleaving. Reviewers: bogner, volkan Reviewed By: volkan Subscribers: lkail, mgorny, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D69152
1 parent 75eacbf commit 1d94fb2

File tree

13 files changed

+1928
-17
lines changed

13 files changed

+1928
-17
lines changed

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ def match;
8989
class GIMatchKind;
9090
class GIMatchKindWithArgs;
9191

92+
/// In lieu of having proper macro support. Trivial one-off opcode checks can be
93+
/// performed with this.
94+
def wip_match_opcode : GIMatchKindWithArgs;
95+
9296
/// The operator at the root of a GICombineRule.Apply dag.
9397
def apply;
9498
/// All arguments of the apply operator must be subclasses of GIApplyKind, or
@@ -99,26 +103,30 @@ class GIApplyKindWithArgs;
99103

100104
def copy_prop : GICombineRule<
101105
(defs root:$d),
102-
(match [{ return Helper.matchCombineCopy(${d}); }]),
103-
(apply [{ Helper.applyCombineCopy(${d}); }])>;
106+
(match (COPY $d, $s):$mi,
107+
[{ return Helper.matchCombineCopy(*${mi}); }]),
108+
(apply [{ Helper.applyCombineCopy(*${mi}); }])>;
104109
def trivial_combines : GICombineGroup<[copy_prop]>;
105110

106111
def extending_loads : GICombineRule<
107112
(defs root:$root, extending_load_matchdata:$matchinfo),
108-
(match [{ return Helper.matchCombineExtendingLoads(${root}, ${matchinfo}); }]),
109-
(apply [{ Helper.applyCombineExtendingLoads(${root}, ${matchinfo}); }])>;
113+
(match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD):$root,
114+
[{ return Helper.matchCombineExtendingLoads(*${root}, ${matchinfo}); }]),
115+
(apply [{ Helper.applyCombineExtendingLoads(*${root}, ${matchinfo}); }])>;
110116
def combines_for_extload: GICombineGroup<[extending_loads]>;
111117

112118
def combine_indexed_load_store : GICombineRule<
113119
(defs root:$root, indexed_load_store_matchdata:$matchinfo),
114-
(match [{ return Helper.matchCombineIndexedLoadStore(${root}, ${matchinfo}); }]),
115-
(apply [{ Helper.applyCombineIndexedLoadStore(${root}, ${matchinfo}); }])>;
120+
(match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD, G_STORE):$root,
121+
[{ return Helper.matchCombineIndexedLoadStore(*${root}, ${matchinfo}); }]),
122+
(apply [{ Helper.applyCombineIndexedLoadStore(*${root}, ${matchinfo}); }])>;
116123

117124
// FIXME: Is there a reason this wasn't in tryCombine? I've left it out of
118125
// all_combines because it wasn't there.
119126
def elide_br_by_inverting_cond : GICombineRule<
120-
(defs root:$d),
121-
(match [{ return Helper.matchElideBrByInvertingCond(${d}); }]),
122-
(apply [{ Helper.applyElideBrByInvertingCond(${d}); }])>;
127+
(defs root:$root),
128+
(match (wip_match_opcode G_BR):$root,
129+
[{ return Helper.matchElideBrByInvertingCond(*${root}); }]),
130+
(apply [{ Helper.applyElideBrByInvertingCond(*${root}); }])>;
123131

124132
def all_combines : GICombineGroup<[trivial_combines, combines_for_extload, combine_indexed_load_store]>;
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
2+
// RUN: -combiners=MyCombinerHelper -gicombiner-stop-after-build %s \
3+
// RUN: -o %t.inc | FileCheck %s
4+
5+
include "llvm/Target/Target.td"
6+
include "llvm/Target/GlobalISel/Combine.td"
7+
8+
def MyTargetISA : InstrInfo;
9+
def MyTarget : Target { let InstructionSet = MyTargetISA; }
10+
11+
def dummy;
12+
13+
def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
14+
def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0)>;
15+
class I<dag OOps, dag IOps, list<dag> Pat>
16+
: Instruction {
17+
let Namespace = "MyTarget";
18+
let OutOperandList = OOps;
19+
let InOperandList = IOps;
20+
let Pattern = Pat;
21+
}
22+
def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
23+
def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
24+
def SUB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
25+
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
26+
def TRUNC : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
27+
def SEXT : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
28+
def ZEXT : I<(outs GPR32:$dst), (ins GPR32:$src1), []>;
29+
30+
def Rule0 : GICombineRule<
31+
(defs root:$d),
32+
(match (MUL $t, $s1, $s2),
33+
(SUB $d, $t, $s3)),
34+
(apply [{ APPLY }])>;
35+
36+
def Rule1 : GICombineRule<
37+
(defs root:$d),
38+
(match (MOV $s1, $s2),
39+
(MOV $d, $s1)),
40+
(apply [{ APPLY }])>;
41+
42+
def Rule2 : GICombineRule<
43+
(defs root:$d),
44+
(match (MOV $d, $s)),
45+
(apply [{ APPLY }])>;
46+
47+
def Rule3 : GICombineRule<
48+
(defs root:$d),
49+
(match (MUL $t, $s1, $s2),
50+
(ADD $d, $t, $s3), [{ A }]),
51+
(apply [{ APPLY }])>;
52+
53+
def Rule4 : GICombineRule<
54+
(defs root:$d),
55+
(match (ADD $d, $s1, $s2)),
56+
(apply [{ APPLY }])>;
57+
58+
def Rule5 : GICombineRule<
59+
(defs root:$d),
60+
(match (SUB $d, $s1, $s2)),
61+
(apply [{ APPLY }])>;
62+
63+
def Rule6 : GICombineRule<
64+
(defs root:$d),
65+
(match (SEXT $t, $s1),
66+
(TRUNC $d, $t)),
67+
(apply [{ APPLY }])>;
68+
69+
def Rule7 : GICombineRule<
70+
(defs root:$d),
71+
(match (ZEXT $t, $s1),
72+
(TRUNC $d, $t)),
73+
(apply [{ APPLY }])>;
74+
75+
def MyCombinerHelper: GICombinerHelper<"GenMyCombinerHelper", [
76+
Rule0,
77+
Rule1,
78+
Rule2,
79+
Rule3,
80+
Rule4,
81+
Rule5,
82+
Rule6,
83+
Rule7
84+
]>;
85+
86+
// CHECK-LABEL: digraph "matchtree" {
87+
// CHECK-DAG: Node[[N0:0x[0-9a-f]+]] [shape=record,label="{MI[0].getOpcode()|4 partitions|Rule0,Rule1,Rule2,Rule3,Rule4,Rule5,Rule6,Rule7}"]
88+
// CHECK-DAG: Node[[N1:0x[0-9a-f]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|2 partitions|Rule0,Rule5}"]
89+
// CHECK-DAG: Node[[N2:0x[0-9a-f]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule0,Rule5}"]
90+
// CHECK-DAG: Node[[N3:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule0}"]
91+
// CHECK-DAG: Node[[N4:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule5}"]
92+
// CHECK-DAG: Node[[N5:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule5}"]
93+
// CHECK-DAG: Node[[N6:0x[0-9a-f]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|2 partitions|Rule1,Rule2}"]
94+
// CHECK-DAG: Node[[N7:0x[0-9a-f]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule1,Rule2}"]
95+
// CHECK-DAG: Node[[N8:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule1}"]
96+
// CHECK-DAG: Node[[N9:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule2}"]
97+
// CHECK-DAG: Node[[N10:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule2}"]
98+
// CHECK-DAG: Node[[N11:0x[0-9a-f]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|2 partitions|Rule3,Rule4}"]
99+
// CHECK-DAG: Node[[N12:0x[0-9a-f]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule3,Rule4}"]
100+
// CHECK-DAG: Node[[N13:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule3,Rule4}",color=red]
101+
// CHECK-DAG: Node[[N14:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule4}"]
102+
// CHECK-DAG: Node[[N15:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule4}"]
103+
// CHECK-DAG: Node[[N16:0x[0-9a-f]+]] [shape=record,label="{MI[1] = getVRegDef(MI[0].getOperand(1))|1 partitions|Rule6,Rule7}"]
104+
// CHECK-DAG: Node[[N17:0x[0-9a-f]+]] [shape=record,label="{MI[1].getOpcode()|2 partitions|Rule6,Rule7}"]
105+
// CHECK-DAG: Node[[N18:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule6}"]
106+
// CHECK-DAG: Node[[N19:0x[0-9a-f]+]] [shape=record,label="{No partitioner|Rule7}"]
107+
108+
// The most important partitioner is on the first opcode:
109+
// CHECK-DAG: Node[[N0]] -> Node[[N1]] [label="#0 MyTarget::SUB"]
110+
// CHECK-DAG: Node[[N0]] -> Node[[N6]] [label="#1 MyTarget::MOV"]
111+
// CHECK-DAG: Node[[N0]] -> Node[[N11]] [label="#2 MyTarget::ADD"]
112+
// CHECK-DAG: Node[[N0]] -> Node[[N16]] [label="#3 MyTarget::TRUNC"]
113+
114+
// For, MI[0].getOpcode() == SUB, then has to determine whether it has a reg
115+
// operand and follow that link. If it can't then Rule5 is the only choice as
116+
// that rule is not constrained to a reg.
117+
// CHECK-DAG: Node[[N1]] -> Node[[N2]] [label="#0 true"]
118+
// CHECK-DAG: Node[[N1]] -> Node[[N5]] [label="#1 false"]
119+
120+
// For, MI[0].getOpcode() == SUB && MI[0].getOperand(1).isReg(), if MI[1] is a
121+
// MUL then it must be either Rule0 or Rule5. Rule0 is fully tested so Rule5 is
122+
// unreachable. If it's not MUL then it must be Rule5.
123+
// CHECK-DAG: Node[[N2]] -> Node[[N3]] [label="#0 MyTarget::MUL"]
124+
// CHECK-DAG: Node[[N2]] -> Node[[N4]] [label="#1 * or nullptr"]
125+
126+
// CHECK-DAG: Node[[N6]] -> Node[[N7]] [label="#0 true"]
127+
// CHECK-DAG: Node[[N6]] -> Node[[N10]] [label="#1 false"]
128+
129+
// CHECK-DAG: Node[[N7]] -> Node[[N8]] [label="#0 MyTarget::MOV"]
130+
// CHECK-DAG: Node[[N7]] -> Node[[N9]] [label="#1 * or nullptr"]
131+
132+
// CHECK-DAG: Node[[N11]] -> Node[[N12]] [label="#0 true"]
133+
// CHECK-DAG: Node[[N11]] -> Node[[N15]] [label="#1 false"]
134+
135+
// CHECK-DAG: Node[[N12]] -> Node[[N13]] [label="#0 MyTarget::MUL"]
136+
// CHECK-DAG: Node[[N12]] -> Node[[N14]] [label="#1 * or nullptr"]
137+
138+
// CHECK-DAG: Node[[N16]] -> Node[[N17]] [label="#0 true"]
139+
140+
// CHECK-DAG: Node[[N17]] -> Node[[N18]] [label="#0 MyTarget::SEXT"]
141+
// CHECK-DAG: Node[[N17]] -> Node[[N19]] [label="#1 MyTarget::ZEXT"]
142+
// CHECK-LABEL: {{^}$}}

0 commit comments

Comments
 (0)