xref: /llvm-project/llvm/test/Transforms/IROutliner/outlining-multiple-exits-diff-outputs.ll (revision f4b925ee7078f058602fd323e25f45f1ae91ca34)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
2; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
3
4; Here we have multiple exits, but the different sources, different outputs are
5; needed, this checks that they are handled by separate switch statements.
6
7define void @outline_outputs1() #0 {
8entry:
9  %output = alloca i32, align 4
10  %result = alloca i32, align 4
11  %output2 = alloca i32, align 4
12  %result2 = alloca i32, align 4
13  %a = alloca i32, align 4
14  %b = alloca i32, align 4
15  br label %block_2
16block_1:
17  %a2 = alloca i32, align 4
18  %b2 = alloca i32, align 4
19  br label %block_2
20block_2:
21  %a2val = load i32, ptr %a
22  %b2val = load i32, ptr %b
23  %add2 = add i32 2, %a2val
24  %mul2 = mul i32 2, %b2val
25  br label %block_5
26block_3:
27  %aval = load i32, ptr %a
28  %bval = load i32, ptr %b
29  %add = add i32 2, %aval
30  %mul = mul i32 2, %bval
31  br label %block_4
32block_4:
33  store i32 %add, ptr %output, align 4
34  store i32 %mul, ptr %result, align 4
35  br label %block_6
36block_5:
37  store i32 %add2, ptr %output, align 4
38  store i32 %mul2, ptr %result, align 4
39  br label %block_7
40block_6:
41  %div = udiv i32 %aval, %bval
42  ret void
43block_7:
44  %sub = sub i32 %a2val, %b2val
45  ret void
46}
47
48define void @outline_outputs2() #0 {
49entry:
50  %output = alloca i32, align 4
51  %result = alloca i32, align 4
52  %output2 = alloca i32, align 4
53  %result2 = alloca i32, align 4
54  %a = alloca i32, align 4
55  %b = alloca i32, align 4
56  br label %block_2
57block_1:
58  %a2 = alloca i32, align 4
59  %b2 = alloca i32, align 4
60  br label %block_2
61block_2:
62  %a2val = load i32, ptr %a
63  %b2val = load i32, ptr %b
64  %add2 = add i32 2, %a2val
65  %mul2 = mul i32 2, %b2val
66  br label %block_5
67block_3:
68  %aval = load i32, ptr %a
69  %bval = load i32, ptr %b
70  %add = add i32 2, %aval
71  %mul = mul i32 2, %bval
72  br label %block_4
73block_4:
74  store i32 %add, ptr %output, align 4
75  store i32 %mul, ptr %result, align 4
76  br label %block_7
77block_5:
78  store i32 %add2, ptr %output, align 4
79  store i32 %mul2, ptr %result, align 4
80  br label %block_6
81block_6:
82  %diff = sub i32 %a2val, %b2val
83  ret void
84block_7:
85  %quot = udiv i32 %add, %mul
86  ret void
87}
88; CHECK-LABEL: @outline_outputs1(
89; CHECK-NEXT:  entry:
90; CHECK-NEXT:    [[BVAL_LOC:%.*]] = alloca i32, align 4
91; CHECK-NEXT:    [[AVAL_LOC:%.*]] = alloca i32, align 4
92; CHECK-NEXT:    [[B2VAL_LOC:%.*]] = alloca i32, align 4
93; CHECK-NEXT:    [[A2VAL_LOC:%.*]] = alloca i32, align 4
94; CHECK-NEXT:    [[OUTPUT:%.*]] = alloca i32, align 4
95; CHECK-NEXT:    [[RESULT:%.*]] = alloca i32, align 4
96; CHECK-NEXT:    [[OUTPUT2:%.*]] = alloca i32, align 4
97; CHECK-NEXT:    [[RESULT2:%.*]] = alloca i32, align 4
98; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
99; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
100; CHECK-NEXT:    br label [[BLOCK_2:%.*]]
101; CHECK:       block_1:
102; CHECK-NEXT:    [[A2:%.*]] = alloca i32, align 4
103; CHECK-NEXT:    [[B2:%.*]] = alloca i32, align 4
104; CHECK-NEXT:    br label [[BLOCK_2]]
105; CHECK:       block_2:
106; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[A2VAL_LOC]])
107; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[B2VAL_LOC]])
108; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[AVAL_LOC]])
109; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[BVAL_LOC]])
110; CHECK-NEXT:    [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[AVAL_LOC]], ptr [[BVAL_LOC]], i32 0)
111; CHECK-NEXT:    [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
112; CHECK-NEXT:    [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
113; CHECK-NEXT:    [[AVAL_RELOAD:%.*]] = load i32, ptr [[AVAL_LOC]], align 4
114; CHECK-NEXT:    [[BVAL_RELOAD:%.*]] = load i32, ptr [[BVAL_LOC]], align 4
115; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[A2VAL_LOC]])
116; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[B2VAL_LOC]])
117; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[AVAL_LOC]])
118; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[BVAL_LOC]])
119; CHECK-NEXT:    br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
120; CHECK:       block_6:
121; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AVAL_RELOAD]], [[BVAL_RELOAD]]
122; CHECK-NEXT:    ret void
123; CHECK:       block_7:
124; CHECK-NEXT:    [[SUB:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
125; CHECK-NEXT:    ret void
126;
127;
128; CHECK-LABEL: @outline_outputs2(
129; CHECK-NEXT:  entry:
130; CHECK-NEXT:    [[MUL_LOC:%.*]] = alloca i32, align 4
131; CHECK-NEXT:    [[ADD_LOC:%.*]] = alloca i32, align 4
132; CHECK-NEXT:    [[B2VAL_LOC:%.*]] = alloca i32, align 4
133; CHECK-NEXT:    [[A2VAL_LOC:%.*]] = alloca i32, align 4
134; CHECK-NEXT:    [[OUTPUT:%.*]] = alloca i32, align 4
135; CHECK-NEXT:    [[RESULT:%.*]] = alloca i32, align 4
136; CHECK-NEXT:    [[OUTPUT2:%.*]] = alloca i32, align 4
137; CHECK-NEXT:    [[RESULT2:%.*]] = alloca i32, align 4
138; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
139; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
140; CHECK-NEXT:    br label [[BLOCK_2:%.*]]
141; CHECK:       block_1:
142; CHECK-NEXT:    [[A2:%.*]] = alloca i32, align 4
143; CHECK-NEXT:    [[B2:%.*]] = alloca i32, align 4
144; CHECK-NEXT:    br label [[BLOCK_2]]
145; CHECK:       block_2:
146; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[A2VAL_LOC]])
147; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[B2VAL_LOC]])
148; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[ADD_LOC]])
149; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 -1, ptr [[MUL_LOC]])
150; CHECK-NEXT:    [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 1)
151; CHECK-NEXT:    [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
152; CHECK-NEXT:    [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
153; CHECK-NEXT:    [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
154; CHECK-NEXT:    [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4
155; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[A2VAL_LOC]])
156; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[B2VAL_LOC]])
157; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[ADD_LOC]])
158; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 -1, ptr [[MUL_LOC]])
159; CHECK-NEXT:    br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
160; CHECK:       block_6:
161; CHECK-NEXT:    [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
162; CHECK-NEXT:    ret void
163; CHECK:       block_7:
164; CHECK-NEXT:    [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]]
165; CHECK-NEXT:    ret void
166;
167;
168; CHECK: define internal i1 @outlined_ir_func_0(
169; CHECK-NEXT:  newFuncRoot:
170; CHECK-NEXT:    br label [[BLOCK_2_TO_OUTLINE:%.*]]
171; CHECK:       block_2_to_outline:
172; CHECK-NEXT:    [[A2VAL:%.*]] = load i32, ptr [[TMP0:%.*]], align 4
173; CHECK-NEXT:    [[B2VAL:%.*]] = load i32, ptr [[TMP1:%.*]], align 4
174; CHECK-NEXT:    [[ADD2:%.*]] = add i32 2, [[A2VAL]]
175; CHECK-NEXT:    [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
176; CHECK-NEXT:    br label [[BLOCK_5:%.*]]
177; CHECK:       block_3:
178; CHECK-NEXT:    [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
179; CHECK-NEXT:    [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
180; CHECK-NEXT:    [[ADD:%.*]] = add i32 2, [[AVAL]]
181; CHECK-NEXT:    [[MUL:%.*]] = mul i32 2, [[BVAL]]
182; CHECK-NEXT:    br label [[BLOCK_4:%.*]]
183; CHECK:       block_4:
184; CHECK-NEXT:    store i32 [[ADD]], ptr [[TMP2:%.*]], align 4
185; CHECK-NEXT:    store i32 [[MUL]], ptr [[TMP3:%.*]], align 4
186; CHECK-NEXT:    br label [[BLOCK_6_EXITSTUB:%.*]]
187; CHECK:       block_5:
188; CHECK-NEXT:    store i32 [[ADD2]], ptr [[TMP2]], align 4
189; CHECK-NEXT:    store i32 [[MUL2]], ptr [[TMP3]], align 4
190; CHECK-NEXT:    br label [[BLOCK_7_EXITSTUB:%.*]]
191; CHECK:       block_6.exitStub:
192; CHECK-NEXT:    switch i32 [[TMP8:%.*]], label [[FINAL_BLOCK_1:%.*]] [
193; CHECK-NEXT:    i32 0, label [[OUTPUT_BLOCK_0_1:%.*]]
194; CHECK-NEXT:    i32 1, label [[OUTPUT_BLOCK_1_1:%.*]]
195; CHECK-NEXT:    ]
196; CHECK:       block_7.exitStub:
197; CHECK-NEXT:    switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [
198; CHECK-NEXT:    i32 0, label [[OUTPUT_BLOCK_0_0:%.*]]
199; CHECK-NEXT:    i32 1, label [[OUTPUT_BLOCK_1_0:%.*]]
200; CHECK-NEXT:    ]
201; CHECK:       output_block_0_0:
202; CHECK-NEXT:    store i32 [[A2VAL]], ptr [[TMP4:%.*]], align 4
203; CHECK-NEXT:    store i32 [[B2VAL]], ptr [[TMP5:%.*]], align 4
204; CHECK-NEXT:    br label [[FINAL_BLOCK_0]]
205; CHECK:       output_block_0_1:
206; CHECK-NEXT:    store i32 [[AVAL]], ptr [[TMP6:%.*]], align 4
207; CHECK-NEXT:    store i32 [[BVAL]], ptr [[TMP7:%.*]], align 4
208; CHECK-NEXT:    br label [[FINAL_BLOCK_1]]
209; CHECK:       output_block_1_0:
210; CHECK-NEXT:    store i32 [[A2VAL]], ptr [[TMP4]], align 4
211; CHECK-NEXT:    store i32 [[B2VAL]], ptr [[TMP5]], align 4
212; CHECK-NEXT:    br label [[FINAL_BLOCK_0]]
213; CHECK:       output_block_1_1:
214; CHECK-NEXT:    store i32 [[ADD]], ptr [[TMP6]], align 4
215; CHECK-NEXT:    store i32 [[MUL]], ptr [[TMP7]], align 4
216; CHECK-NEXT:    br label [[FINAL_BLOCK_1]]
217; CHECK:       final_block_0:
218; CHECK-NEXT:    ret i1 false
219; CHECK:       final_block_1:
220; CHECK-NEXT:    ret i1 true
221;
222