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