1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -simplifycfg-max-small-block-size=6 -S < %s | FileCheck %s
3; RUN: opt -passes=simplify-cfg -simplifycfg-max-small-block-size=6 -S < %s | FileCheck %s
4
5target datalayout = "e-p:64:64-p5:32:32-A5"
6
7declare void @llvm.assume(i1)
8declare i1 @llvm.type.test(i8*, metadata) nounwind readnone
9
10define void @test_01(i1 %c, i64* align 1 %ptr) local_unnamed_addr #0 {
11; CHECK-LABEL: @test_01(
12; CHECK-NEXT:    br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]]
13; CHECK:       false1:
14; CHECK-NEXT:    store volatile i64 1, i64* [[PTR:%.*]], align 4
15; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint i64* [[PTR]] to i64
16; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 7
17; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
18; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
19; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
20; CHECK-NEXT:    store volatile i64 3, i64* [[PTR]], align 8
21; CHECK-NEXT:    ret void
22; CHECK:       true2.critedge:
23; CHECK-NEXT:    [[PTRINT_C:%.*]] = ptrtoint i64* [[PTR]] to i64
24; CHECK-NEXT:    [[MASKEDPTR_C:%.*]] = and i64 [[PTRINT_C]], 7
25; CHECK-NEXT:    [[MASKCOND_C:%.*]] = icmp eq i64 [[MASKEDPTR_C]], 0
26; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND_C]])
27; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
28; CHECK-NEXT:    store volatile i64 2, i64* [[PTR]], align 8
29; CHECK-NEXT:    ret void
30;
31  br i1 %c, label %true1, label %false1
32
33true1:                                            ; preds = %false1, %0
34  %ptrint = ptrtoint i64* %ptr to i64
35  %maskedptr = and i64 %ptrint, 7
36  %maskcond = icmp eq i64 %maskedptr, 0
37  tail call void @llvm.assume(i1 %maskcond)
38  store volatile i64 0, i64* %ptr, align 8
39  br i1 %c, label %true2, label %false2
40
41false1:                                           ; preds = %0
42  store volatile i64 1, i64* %ptr, align 4
43  br label %true1
44
45true2:                                            ; preds = %true1
46  store volatile i64 2, i64* %ptr, align 8
47  ret void
48
49false2:                                           ; preds = %true1
50  store volatile i64 3, i64* %ptr, align 8
51  ret void
52}
53
54; Corner case: the block has max possible size for which we still do PRE.
55define void @test_02(i1 %c, i64* align 1 %ptr) local_unnamed_addr #0 {
56; CHECK-LABEL: @test_02(
57; CHECK-NEXT:    br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]]
58; CHECK:       false1:
59; CHECK-NEXT:    store volatile i64 1, i64* [[PTR:%.*]], align 4
60; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint i64* [[PTR]] to i64
61; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 7
62; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
63; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
64; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
65; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
66; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
67; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
68; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
69; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
70; CHECK-NEXT:    store volatile i64 3, i64* [[PTR]], align 8
71; CHECK-NEXT:    ret void
72; CHECK:       true2.critedge:
73; CHECK-NEXT:    [[PTRINT_C:%.*]] = ptrtoint i64* [[PTR]] to i64
74; CHECK-NEXT:    [[MASKEDPTR_C:%.*]] = and i64 [[PTRINT_C]], 7
75; CHECK-NEXT:    [[MASKCOND_C:%.*]] = icmp eq i64 [[MASKEDPTR_C]], 0
76; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND_C]])
77; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
78; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
79; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
80; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
81; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
82; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
83; CHECK-NEXT:    store volatile i64 2, i64* [[PTR]], align 8
84; CHECK-NEXT:    ret void
85;
86  br i1 %c, label %true1, label %false1
87
88true1:                                            ; preds = %false1, %0
89  %ptrint = ptrtoint i64* %ptr to i64
90  %maskedptr = and i64 %ptrint, 7
91  %maskcond = icmp eq i64 %maskedptr, 0
92  tail call void @llvm.assume(i1 %maskcond)
93  store volatile i64 0, i64* %ptr, align 8
94  store volatile i64 -1, i64* %ptr, align 8
95  store volatile i64 -1, i64* %ptr, align 8
96  store volatile i64 -1, i64* %ptr, align 8
97  store volatile i64 -1, i64* %ptr, align 8
98  store volatile i64 -1, i64* %ptr, align 8
99  br i1 %c, label %true2, label %false2
100
101false1:                                           ; preds = %0
102  store volatile i64 1, i64* %ptr, align 4
103  br label %true1
104
105true2:                                            ; preds = %true1
106  store volatile i64 2, i64* %ptr, align 8
107  ret void
108
109false2:                                           ; preds = %true1
110  store volatile i64 3, i64* %ptr, align 8
111  ret void
112}
113
114; This block is too huge for PRE.
115define void @test_03(i1 %c, i64* align 1 %ptr) local_unnamed_addr #0 {
116; CHECK-LABEL: @test_03(
117; CHECK-NEXT:    br i1 [[C:%.*]], label [[TRUE1:%.*]], label [[FALSE1:%.*]]
118; CHECK:       true1:
119; CHECK-NEXT:    [[PTRINT:%.*]] = ptrtoint i64* [[PTR:%.*]] to i64
120; CHECK-NEXT:    [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 7
121; CHECK-NEXT:    [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
122; CHECK-NEXT:    tail call void @llvm.assume(i1 [[MASKCOND]])
123; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
124; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
125; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
126; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
127; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
128; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
129; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
130; CHECK-NEXT:    br i1 [[C]], label [[TRUE2:%.*]], label [[FALSE2:%.*]]
131; CHECK:       false1:
132; CHECK-NEXT:    store volatile i64 1, i64* [[PTR]], align 4
133; CHECK-NEXT:    br label [[TRUE1]]
134; CHECK:       true2:
135; CHECK-NEXT:    store volatile i64 2, i64* [[PTR]], align 8
136; CHECK-NEXT:    ret void
137; CHECK:       false2:
138; CHECK-NEXT:    store volatile i64 3, i64* [[PTR]], align 8
139; CHECK-NEXT:    ret void
140;
141  br i1 %c, label %true1, label %false1
142
143true1:                                            ; preds = %false1, %0
144  %ptrint = ptrtoint i64* %ptr to i64
145  %maskedptr = and i64 %ptrint, 7
146  %maskcond = icmp eq i64 %maskedptr, 0
147  tail call void @llvm.assume(i1 %maskcond)
148  store volatile i64 0, i64* %ptr, align 8
149  store volatile i64 -1, i64* %ptr, align 8
150  store volatile i64 -1, i64* %ptr, align 8
151  store volatile i64 -1, i64* %ptr, align 8
152  store volatile i64 -1, i64* %ptr, align 8
153  store volatile i64 -1, i64* %ptr, align 8
154  store volatile i64 -1, i64* %ptr, align 8
155  br i1 %c, label %true2, label %false2
156
157false1:                                           ; preds = %0
158  store volatile i64 1, i64* %ptr, align 4
159  br label %true1
160
161true2:                                            ; preds = %true1
162  store volatile i64 2, i64* %ptr, align 8
163  ret void
164
165false2:                                           ; preds = %true1
166  store volatile i64 3, i64* %ptr, align 8
167  ret void
168}
169
170; Try the max block size for PRE again but with the bitcast/type test/assume
171; sequence used for whole program devirt.
172define void @test_04(i1 %c, i64* align 1 %ptr, [3 x i8*]* %vtable) local_unnamed_addr #0 {
173; CHECK-LABEL: @test_04(
174; CHECK-NEXT:    br i1 [[C:%.*]], label [[TRUE2_CRITEDGE:%.*]], label [[FALSE1:%.*]]
175; CHECK:       false1:
176; CHECK-NEXT:    store volatile i64 1, i64* [[PTR:%.*]], align 4
177; CHECK-NEXT:    [[VTABLE:%.*]] = bitcast [3 x i8*]* %vtable to i8*
178; CHECK-NEXT:    [[P:%.*]] = call i1 @llvm.type.test(i8* [[VTABLE]], metadata !"foo")
179; CHECK-NEXT:    tail call void @llvm.assume(i1 [[P]])
180; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
181; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
182; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
183; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
184; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
185; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
186; CHECK-NEXT:    store volatile i64 3, i64* [[PTR]], align 8
187; CHECK-NEXT:    ret void
188; CHECK:       true2.critedge:
189; CHECK-NEXT:    [[VTABLE:%.*]] = bitcast [3 x i8*]* %vtable to i8*
190; CHECK-NEXT:    [[P:%.*]] = call i1 @llvm.type.test(i8* [[VTABLE]], metadata !"foo")
191; CHECK-NEXT:    tail call void @llvm.assume(i1 [[P]])
192; CHECK-NEXT:    store volatile i64 0, i64* [[PTR]], align 8
193; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
194; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
195; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
196; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
197; CHECK-NEXT:    store volatile i64 -1, i64* [[PTR]], align 8
198; CHECK-NEXT:    store volatile i64 2, i64* [[PTR]], align 8
199; CHECK-NEXT:    ret void
200;
201  br i1 %c, label %true1, label %false1
202
203true1:                                            ; preds = %false1, %0
204  %vtablei8 = bitcast [3 x i8*]* %vtable to i8*
205  %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"foo")
206  tail call void @llvm.assume(i1 %p)
207  store volatile i64 0, i64* %ptr, align 8
208  store volatile i64 -1, i64* %ptr, align 8
209  store volatile i64 -1, i64* %ptr, align 8
210  store volatile i64 -1, i64* %ptr, align 8
211  store volatile i64 -1, i64* %ptr, align 8
212  store volatile i64 -1, i64* %ptr, align 8
213  br i1 %c, label %true2, label %false2
214
215false1:                                           ; preds = %0
216  store volatile i64 1, i64* %ptr, align 4
217  br label %true1
218
219true2:                                            ; preds = %true1
220  store volatile i64 2, i64* %ptr, align 8
221  ret void
222
223false2:                                           ; preds = %true1
224  store volatile i64 3, i64* %ptr, align 8
225  ret void
226}
227