xref: /llvm-project/llvm/test/Transforms/IROutliner/outlining-commutative.ll (revision f4b925ee7078f058602fd323e25f45f1ae91ca34)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
3
4; This test checks that commutative instructions where the operands are
5; swapped are outlined as the same function.
6
7; It also checks that non-commutative instructions outlined as different
8; functions when the operands are swapped;
9
10; These are identical functions, except that in the flipped functions,
11; the operands in the adds are commuted.  However, since add instructions
12; are commutative, we should still outline from all four as the same
13; instruction.
14
15define void @outline_from_add1() {
16; CHECK-LABEL: @outline_from_add1(
17; CHECK-NEXT:  entry:
18; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
19; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
20; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
21; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
22; CHECK-NEXT:    ret void
23;
24entry:
25  %a = alloca i32, align 4
26  %b = alloca i32, align 4
27  %c = alloca i32, align 4
28  store i32 2, ptr %a, align 4
29  store i32 3, ptr %b, align 4
30  store i32 4, ptr %c, align 4
31  %al = load i32, ptr %a
32  %bl = load i32, ptr %b
33  %cl = load i32, ptr %c
34  %0 = add i32 %al, %bl
35  %1 = add i32 %al, %cl
36  %2 = add i32 %bl, %cl
37  ret void
38}
39
40define void @outline_from_add2() {
41; CHECK-LABEL: @outline_from_add2(
42; CHECK-NEXT:  entry:
43; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
44; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
45; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
46; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
47; CHECK-NEXT:    ret void
48;
49entry:
50  %a = alloca i32, align 4
51  %b = alloca i32, align 4
52  %c = alloca i32, align 4
53  store i32 2, ptr %a, align 4
54  store i32 3, ptr %b, align 4
55  store i32 4, ptr %c, align 4
56  %al = load i32, ptr %a
57  %bl = load i32, ptr %b
58  %cl = load i32, ptr %c
59  %0 = add i32 %al, %bl
60  %1 = add i32 %al, %cl
61  %2 = add i32 %bl, %cl
62  ret void
63}
64
65define void @outline_from_flipped_add3() {
66; CHECK-LABEL: @outline_from_flipped_add3(
67; CHECK-NEXT:  entry:
68; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
69; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
70; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
71; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
72; CHECK-NEXT:    ret void
73;
74entry:
75  %a = alloca i32, align 4
76  %b = alloca i32, align 4
77  %c = alloca i32, align 4
78  store i32 2, ptr %a, align 4
79  store i32 3, ptr %b, align 4
80  store i32 4, ptr %c, align 4
81  %al = load i32, ptr %a
82  %bl = load i32, ptr %b
83  %cl = load i32, ptr %c
84  %0 = add i32 %bl, %al
85  %1 = add i32 %cl, %al
86  %2 = add i32 %cl, %bl
87  ret void
88}
89
90define void @outline_from_flipped_add4() {
91; CHECK-LABEL: @outline_from_flipped_add4(
92; CHECK-NEXT:  entry:
93; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
94; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
95; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
96; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
97; CHECK-NEXT:    ret void
98;
99entry:
100  %a = alloca i32, align 4
101  %b = alloca i32, align 4
102  %c = alloca i32, align 4
103  store i32 2, ptr %a, align 4
104  store i32 3, ptr %b, align 4
105  store i32 4, ptr %c, align 4
106  %al = load i32, ptr %a
107  %bl = load i32, ptr %b
108  %cl = load i32, ptr %c
109  %0 = add i32 %bl, %al
110  %1 = add i32 %cl, %al
111  %2 = add i32 %cl, %bl
112  ret void
113}
114
115; These are identical functions, except that in the flipped functions,
116; the operands in the subtractions are commuted.  Since subtraction
117; instructions are not commutative, we should outline the first two functions
118; differently than the second two functions.
119
120define void @outline_from_sub1() {
121; CHECK-LABEL: @outline_from_sub1(
122; CHECK-NEXT:  entry:
123; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
124; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
125; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
126; CHECK-NEXT:    call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
127; CHECK-NEXT:    ret void
128;
129entry:
130  %a = alloca i32, align 4
131  %b = alloca i32, align 4
132  %c = alloca i32, align 4
133  store i32 2, ptr %a, align 4
134  store i32 3, ptr %b, align 4
135  store i32 4, ptr %c, align 4
136  %al = load i32, ptr %a
137  %bl = load i32, ptr %b
138  %cl = load i32, ptr %c
139  %0 = sub i32 %al, %bl
140  %1 = sub i32 %al, %cl
141  %2 = sub i32 %bl, %cl
142  ret void
143}
144
145define void @outline_from_sub2() {
146; CHECK-LABEL: @outline_from_sub2(
147; CHECK-NEXT:  entry:
148; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
149; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
150; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
151; CHECK-NEXT:    call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
152; CHECK-NEXT:    ret void
153;
154entry:
155  %a = alloca i32, align 4
156  %b = alloca i32, align 4
157  %c = alloca i32, align 4
158  store i32 2, ptr %a, align 4
159  store i32 3, ptr %b, align 4
160  store i32 4, ptr %c, align 4
161  %al = load i32, ptr %a
162  %bl = load i32, ptr %b
163  %cl = load i32, ptr %c
164  %0 = sub i32 %al, %bl
165  %1 = sub i32 %al, %cl
166  %2 = sub i32 %bl, %cl
167  ret void
168}
169
170define void @dontoutline_from_flipped_sub3() {
171; CHECK-LABEL: @dontoutline_from_flipped_sub3(
172; CHECK-NEXT:  entry:
173; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
174; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
175; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
176; CHECK-NEXT:    call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
177; CHECK-NEXT:    ret void
178;
179entry:
180  %a = alloca i32, align 4
181  %b = alloca i32, align 4
182  %c = alloca i32, align 4
183  store i32 2, ptr %a, align 4
184  store i32 3, ptr %b, align 4
185  store i32 4, ptr %c, align 4
186  %al = load i32, ptr %a
187  %bl = load i32, ptr %b
188  %cl = load i32, ptr %c
189  %0 = sub i32 %bl, %al
190  %1 = sub i32 %cl, %al
191  %2 = sub i32 %cl, %bl
192  ret void
193}
194
195define void @dontoutline_from_flipped_sub4() {
196; CHECK-LABEL: @dontoutline_from_flipped_sub4(
197; CHECK-NEXT:  entry:
198; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
199; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
200; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
201; CHECK-NEXT:    call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
202; CHECK-NEXT:    ret void
203;
204entry:
205  %a = alloca i32, align 4
206  %b = alloca i32, align 4
207  %c = alloca i32, align 4
208  store i32 2, ptr %a, align 4
209  store i32 3, ptr %b, align 4
210  store i32 4, ptr %c, align 4
211  %al = load i32, ptr %a
212  %bl = load i32, ptr %b
213  %cl = load i32, ptr %c
214  %0 = sub i32 %bl, %al
215  %1 = sub i32 %cl, %al
216  %2 = sub i32 %cl, %bl
217  ret void
218}
219
220; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
221; CHECK: entry_to_outline:
222; CHECK-NEXT:    store i32 2, ptr [[ARG0]], align 4
223; CHECK-NEXT:    store i32 3, ptr [[ARG1]], align 4
224; CHECK-NEXT:    store i32 4, ptr [[ARG2]], align 4
225; CHECK-NEXT:    [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
226; CHECK-NEXT:    [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
227; CHECK-NEXT:    [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
228; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[AL]], [[BL]]
229; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[AL]], [[CL]]
230; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[BL]], [[CL]]
231
232; CHECK: define internal void @outlined_ir_func_1(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
233; CHECK: entry_to_outline:
234; CHECK-NEXT:    store i32 2, ptr [[ARG0]], align 4
235; CHECK-NEXT:    store i32 3, ptr [[ARG1]], align 4
236; CHECK-NEXT:    store i32 4, ptr [[ARG2]], align 4
237; CHECK-NEXT:    [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
238; CHECK-NEXT:    [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
239; CHECK-NEXT:    [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
240; CHECK-NEXT:    [[TMP0:%.*]] = sub i32 [[BL]], [[AL]]
241; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 [[CL]], [[AL]]
242; CHECK-NEXT:    [[TMP2:%.*]] = sub i32 [[CL]], [[BL]]
243
244; CHECK: define internal void @outlined_ir_func_2(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
245; CHECK: entry_to_outline:
246; CHECK-NEXT:    store i32 2, ptr [[ARG0]], align 4
247; CHECK-NEXT:    store i32 3, ptr [[ARG1]], align 4
248; CHECK-NEXT:    store i32 4, ptr [[ARG2]], align 4
249; CHECK-NEXT:    [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
250; CHECK-NEXT:    [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
251; CHECK-NEXT:    [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
252; CHECK-NEXT:    [[TMP0:%.*]] = sub i32 [[AL]], [[BL]]
253; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 [[AL]], [[CL]]
254; CHECK-NEXT:    [[TMP2:%.*]] = sub i32 [[BL]], [[CL]]
255