xref: /llvm-project/llvm/test/Transforms/GuardWidening/profile-based-profitability-intrinsics.ll (revision 0b5bb6923f09ebc257ebed4ace1d8b6b113b2bf5)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2; RUN: opt -S -passes=guard-widening < %s | FileCheck %s
3
4; Function Attrs: nocallback nofree nosync willreturn
5declare void @llvm.experimental.guard(i1, ...) #0
6
7; Hot loop, frequently entered, should widen.
8define i32 @test_intrinsic_very_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
9; CHECK-LABEL: define i32 @test_intrinsic_very_profitable
10; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
11; CHECK-NEXT:  entry:
12; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
13; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
14; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
15; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
16; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF0:![0-9]+]]
17; CHECK:       loop:
18; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
19; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
20; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100
21; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1:![0-9]+]]
22; CHECK:       exit:
23; CHECK-NEXT:    ret i32 0
24; CHECK:       failed:
25; CHECK-NEXT:    ret i32 -1
26;
27entry:
28  call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ]
29  %loop.precondition = icmp uge i32 %n, 100
30  br i1 %loop.precondition, label %loop, label %failed, !prof !0
31
32loop:                                             ; preds = %loop, %entry
33  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
34  call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ]
35  %iv.next = add nuw nsw i32 %iv, 1
36  %loop.cond = icmp ult i32 %iv.next, 100
37  br i1 %loop.cond, label %loop, label %exit, !prof !1
38
39exit:                                             ; preds = %loop
40  ret i32 0
41
42failed:                                           ; preds = %entry
43  ret i32 -1
44}
45
46; Even though the loop is rarely entered, it has so many iterations that the widening
47; is still profitable.
48define i32 @test_intrinsic_profitable(i32 %n, i1 %cond.1, i1 %cond.2) {
49; CHECK-LABEL: define i32 @test_intrinsic_profitable
50; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
53; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
54; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
55; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
56; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF2:![0-9]+]]
57; CHECK:       loop:
58; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
59; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
60; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100
61; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]]
62; CHECK:       exit:
63; CHECK-NEXT:    ret i32 0
64; CHECK:       failed:
65; CHECK-NEXT:    ret i32 -1
66;
67entry:
68  call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ]
69  %loop.precondition = icmp uge i32 %n, 100
70  br i1 %loop.precondition, label %loop, label %failed, !prof !2
71
72loop:                                             ; preds = %loop, %entry
73  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
74  call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ]
75  %iv.next = add nuw nsw i32 %iv, 1
76  %loop.cond = icmp ult i32 %iv.next, 100
77  br i1 %loop.cond, label %loop, label %exit, !prof !1
78
79exit:                                             ; preds = %loop
80  ret i32 0
81
82failed:                                           ; preds = %entry
83  ret i32 -1
84}
85
86; Loop's hotness compensates rareness of its entrance. We still want to widen, because
87; it may open up some optimization opportunities.
88define i32 @test_intrinsic_neutral(i32 %n, i1 %cond.1, i1 %cond.2) {
89; CHECK-LABEL: define i32 @test_intrinsic_neutral
90; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
91; CHECK-NEXT:  entry:
92; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
93; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
94; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
95; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
96; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF3:![0-9]+]]
97; CHECK:       loop:
98; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
99; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
100; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100
101; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]]
102; CHECK:       exit:
103; CHECK-NEXT:    ret i32 0
104; CHECK:       failed:
105; CHECK-NEXT:    ret i32 -1
106;
107entry:
108  call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ]
109  %loop.precondition = icmp uge i32 %n, 100
110  br i1 %loop.precondition, label %loop, label %failed, !prof !3
111
112loop:                                             ; preds = %loop, %entry
113  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
114  call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ]
115  %iv.next = add nuw nsw i32 %iv, 1
116  %loop.cond = icmp ult i32 %iv.next, 100
117  br i1 %loop.cond, label %loop, label %exit, !prof !1
118
119exit:                                             ; preds = %loop
120  ret i32 0
121
122failed:                                           ; preds = %entry
123  ret i32 -1
124}
125
126; FIXME: This loop is so rarely entered, that we don't want to widen here.
127define i32 @test_intrinsic_very_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
128; CHECK-LABEL: define i32 @test_intrinsic_very_unprofitable
129; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
130; CHECK-NEXT:  entry:
131; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
132; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
133; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
134; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
135; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF4:![0-9]+]]
136; CHECK:       loop:
137; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
138; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
139; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100
140; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]]
141; CHECK:       exit:
142; CHECK-NEXT:    ret i32 0
143; CHECK:       failed:
144; CHECK-NEXT:    ret i32 -1
145;
146entry:
147  call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ]
148  %loop.precondition = icmp uge i32 %n, 100
149  br i1 %loop.precondition, label %loop, label %failed, !prof !4
150
151loop:                                             ; preds = %loop, %entry
152  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
153  call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ]
154  %iv.next = add nuw nsw i32 %iv, 1
155  %loop.cond = icmp ult i32 %iv.next, 100
156  br i1 %loop.cond, label %loop, label %exit, !prof !1
157
158exit:                                             ; preds = %loop
159  ret i32 0
160
161failed:                                           ; preds = %entry
162  ret i32 -1
163}
164
165; FIXME: This loop is so rarely entered, that we don't want to widen here.
166define i32 @test_intrinsic_unprofitable(i32 %n, i1 %cond.1, i1 %cond.2) {
167; CHECK-LABEL: define i32 @test_intrinsic_unprofitable
168; CHECK-SAME: (i32 [[N:%.*]], i1 [[COND_1:%.*]], i1 [[COND_2:%.*]]) {
169; CHECK-NEXT:  entry:
170; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2]]
171; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_2_GW_FR]]
172; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
173; CHECK-NEXT:    [[LOOP_PRECONDITION:%.*]] = icmp uge i32 [[N]], 100
174; CHECK-NEXT:    br i1 [[LOOP_PRECONDITION]], label [[LOOP:%.*]], label [[FAILED:%.*]], !prof [[PROF5:![0-9]+]]
175; CHECK:       loop:
176; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
177; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
178; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ult i32 [[IV_NEXT]], 100
179; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]], !prof [[PROF1]]
180; CHECK:       exit:
181; CHECK-NEXT:    ret i32 0
182; CHECK:       failed:
183; CHECK-NEXT:    ret i32 -1
184;
185entry:
186  call void (i1, ...) @llvm.experimental.guard(i1 %cond.1) [ "deopt"() ]
187  %loop.precondition = icmp uge i32 %n, 100
188  br i1 %loop.precondition, label %loop, label %failed, !prof !5
189
190loop:                                             ; preds = %loop, %entry
191  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
192  call void (i1, ...) @llvm.experimental.guard(i1 %cond.2) [ "deopt"() ]
193  %iv.next = add nuw nsw i32 %iv, 1
194  %loop.cond = icmp ult i32 %iv.next, 100
195  br i1 %loop.cond, label %loop, label %exit, !prof !1
196
197exit:                                             ; preds = %loop
198  ret i32 0
199
200failed:                                           ; preds = %entry
201  ret i32 -1
202}
203
204attributes #0 = { nocallback nofree nosync willreturn }
205
206!0 = !{!"branch_weights", i32 1048576, i32 1}
207!1 = !{!"branch_weights", i32 99, i32 1}
208!2 = !{!"branch_weights", i32 1, i32 10}
209!3 = !{!"branch_weights", i32 1, i32 99}
210!4 = !{!"branch_weights", i32 1, i32 1048576}
211!5 = !{!"branch_weights", i32 1, i32 1000}
212