xref: /llvm-project/llvm/test/Transforms/GuardWidening/basic-loop.ll (revision 0b5bb6923f09ebc257ebed4ace1d8b6b113b2bf5)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes="loop-mssa(guard-widening)" -verify-memoryssa < %s | FileCheck %s
3
4declare void @llvm.experimental.guard(i1,...)
5
6@G = external global i32
7
8; Show that we can widen into early checks within a loop, and in the process
9; expose optimization oppurtunities.
10define void @widen_within_loop(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
11; CHECK-LABEL: @widen_within_loop(
12; CHECK-NEXT:  entry:
13; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]]
14; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
15; CHECK-NEXT:    br label [[LOOP:%.*]]
16; CHECK:       loop:
17; CHECK-NEXT:    store i32 0, ptr @G, align 4
18; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
19; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2_GW_FR]]
20; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
21; CHECK-NEXT:    store i32 1, ptr @G, align 4
22; CHECK-NEXT:    store i32 2, ptr @G, align 4
23; CHECK-NEXT:    store i32 3, ptr @G, align 4
24; CHECK-NEXT:    br label [[LOOP]]
25;
26entry:
27  br label %loop
28
29loop:
30  store i32 0, ptr @G
31  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
32  store i32 1, ptr @G
33  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
34  store i32 2, ptr @G
35  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
36  store i32 3, ptr @G
37  br label %loop
38}
39
40define void @widen_into_preheader(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
41; CHECK-LABEL: @widen_into_preheader(
42; CHECK-NEXT:  entry:
43; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]]
44; CHECK-NEXT:    [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
45; CHECK-NEXT:    store i32 0, ptr @G, align 4
46; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
47; CHECK-NEXT:    [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_2_GW_FR]]
48; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"(i32 0) ]
49; CHECK-NEXT:    br label [[LOOP:%.*]]
50; CHECK:       loop:
51; CHECK-NEXT:    store i32 1, ptr @G, align 4
52; CHECK-NEXT:    store i32 2, ptr @G, align 4
53; CHECK-NEXT:    store i32 3, ptr @G, align 4
54; CHECK-NEXT:    br label [[LOOP]]
55;
56entry:
57  store i32 0, ptr @G
58  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
59  br label %loop
60
61loop:
62  store i32 1, ptr @G
63  call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"(i32 1) ]
64  store i32 2, ptr @G
65  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
66  store i32 3, ptr @G
67  br label %loop
68}
69
70define void @dont_widen_over_common_exit(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
71; CHECK-LABEL: @dont_widen_over_common_exit(
72; CHECK-NEXT:  entry:
73; CHECK-NEXT:    br label [[LOOP:%.*]]
74; CHECK:       loop:
75; CHECK-NEXT:    store i32 0, ptr @G, align 4
76; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"(i32 0) ]
77; CHECK-NEXT:    store i32 1, ptr @G, align 4
78; CHECK-NEXT:    br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
79; CHECK:       backedge:
80; CHECK-NEXT:    store i32 2, ptr @G, align 4
81; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2:%.*]]) [ "deopt"(i32 2) ]
82; CHECK-NEXT:    store i32 3, ptr @G, align 4
83; CHECK-NEXT:    br label [[LOOP]]
84; CHECK:       exit:
85; CHECK-NEXT:    ret void
86;
87entry:
88  br label %loop
89
90loop:
91  store i32 0, ptr @G
92  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
93  store i32 1, ptr @G
94  br i1 %cond_1, label %backedge, label %exit
95
96backedge:
97  store i32 2, ptr @G
98  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
99  store i32 3, ptr @G
100  br label %loop
101
102exit:
103  ret void
104}
105
106define void @widen_over_common_exit_to_ph(i1 %cond_0, i1 %cond_1, i1 %cond_2) {
107; CHECK-LABEL: @widen_over_common_exit_to_ph(
108; CHECK-NEXT:  entry:
109; CHECK-NEXT:    [[COND_2_GW_FR:%.*]] = freeze i1 [[COND_2:%.*]]
110; CHECK-NEXT:    store i32 0, ptr @G, align 4
111; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2_GW_FR]]
112; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"(i32 0) ]
113; CHECK-NEXT:    br label [[LOOP:%.*]]
114; CHECK:       loop:
115; CHECK-NEXT:    store i32 1, ptr @G, align 4
116; CHECK-NEXT:    br i1 [[COND_1:%.*]], label [[BACKEDGE:%.*]], label [[EXIT:%.*]]
117; CHECK:       backedge:
118; CHECK-NEXT:    store i32 2, ptr @G, align 4
119; CHECK-NEXT:    store i32 3, ptr @G, align 4
120; CHECK-NEXT:    br label [[LOOP]]
121; CHECK:       exit:
122; CHECK-NEXT:    ret void
123;
124entry:
125  store i32 0, ptr @G
126  call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"(i32 0) ]
127  br label %loop
128
129loop:
130  store i32 1, ptr @G
131  br i1 %cond_1, label %backedge, label %exit
132
133backedge:
134  store i32 2, ptr @G
135  call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"(i32 2) ]
136  store i32 3, ptr @G
137  br label %loop
138
139exit:
140  ret void
141}
142
143