xref: /llvm-project/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-nested-loops.ll (revision 56a3e49a00161f6ac71316e3c1f4d5069c916590)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
2; RUN: opt -p constraint-elimination -S %s | FileCheck %s
3
4declare void @use(i1)
5
6define void @start_value_of_inner_add_rec_is_add_rec_condition_can_be_simplified(i32 noundef %len) {
7; CHECK-LABEL: define void @start_value_of_inner_add_rec_is_add_rec_condition_can_be_simplified(
8; CHECK-SAME: i32 noundef [[LEN:%.*]]) {
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
11; CHECK:       outer.header:
12; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_LATCH:%.*]] ]
13; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[I_0]], [[LEN]]
14; CHECK-NEXT:    br i1 [[CMP]], label [[INNER_HEADER:%.*]], label [[EXIT:%.*]]
15; CHECK:       inner.header:
16; CHECK-NEXT:    [[K_0:%.*]] = phi i32 [ [[I_0]], [[OUTER_HEADER]] ], [ [[K_INC:%.*]], [[INNER_LATCH:%.*]] ]
17; CHECK-NEXT:    [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], [[LEN]]
18; CHECK-NEXT:    br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]]
19; CHECK:       inner.latch:
20; CHECK-NEXT:    call void @use(i1 true)
21; CHECK-NEXT:    [[K_INC]] = add i32 [[K_0]], 1
22; CHECK-NEXT:    br label [[INNER_HEADER]]
23; CHECK:       outer.latch:
24; CHECK-NEXT:    [[I_INC]] = add i32 [[I_0]], 1
25; CHECK-NEXT:    br label [[OUTER_HEADER]]
26; CHECK:       exit:
27; CHECK-NEXT:    ret void
28;
29entry:
30  br label %outer.header
31
32outer.header:
33  %i.0 = phi i32 [ 1, %entry ], [ %i.inc, %outer.latch ]
34  %cmp = icmp ult i32 %i.0, %len
35  br i1 %cmp, label %inner.header, label %exit
36
37inner.header:
38  %k.0 = phi i32 [ %i.0, %outer.header ], [ %k.inc, %inner.latch ]
39  %cmp2.not = icmp eq i32 %k.0, %len
40  br i1 %cmp2.not, label %outer.latch, label %inner.latch
41
42inner.latch:
43  %cmp.not.i = icmp ult i32 %k.0, %len
44  call void @use(i1 %cmp.not.i)
45  %k.inc = add i32 %k.0, 1
46  br label %inner.header
47
48outer.latch:
49  %i.inc = add i32 %i.0, 1
50  br label %outer.header
51
52exit:
53  ret void
54}
55
56define void @start_value_of_inner_add_rec_is_add_rec_condition_cannot_be_simplified(i32 noundef %len) {
57; CHECK-LABEL: define void @start_value_of_inner_add_rec_is_add_rec_condition_cannot_be_simplified(
58; CHECK-SAME: i32 noundef [[LEN:%.*]]) {
59; CHECK-NEXT:  entry:
60; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
61; CHECK:       outer.header:
62; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_LATCH:%.*]] ]
63; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[I_0]], [[LEN]]
64; CHECK-NEXT:    br i1 [[CMP]], label [[INNER_HEADER:%.*]], label [[EXIT:%.*]]
65; CHECK:       inner.header:
66; CHECK-NEXT:    [[K_0:%.*]] = phi i32 [ [[I_0]], [[OUTER_HEADER]] ], [ [[K_INC:%.*]], [[INNER_LATCH:%.*]] ]
67; CHECK-NEXT:    [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], [[LEN]]
68; CHECK-NEXT:    br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]]
69; CHECK:       inner.latch:
70; CHECK-NEXT:    [[CMP_NOT_I:%.*]] = icmp ult i32 [[K_0]], 3
71; CHECK-NEXT:    call void @use(i1 [[CMP_NOT_I]])
72; CHECK-NEXT:    [[K_INC]] = add i32 [[K_0]], 1
73; CHECK-NEXT:    br label [[INNER_HEADER]]
74; CHECK:       outer.latch:
75; CHECK-NEXT:    [[I_INC]] = add i32 [[I_0]], 1
76; CHECK-NEXT:    br label [[OUTER_HEADER]]
77; CHECK:       exit:
78; CHECK-NEXT:    ret void
79;
80entry:
81  br label %outer.header
82
83outer.header:
84  %i.0 = phi i32 [ 1, %entry ], [ %i.inc, %outer.latch ]
85  %cmp = icmp ult i32 %i.0, %len
86  br i1 %cmp, label %inner.header, label %exit
87
88inner.header:
89  %k.0 = phi i32 [ %i.0, %outer.header ], [ %k.inc, %inner.latch ]
90  %cmp2.not = icmp eq i32 %k.0, %len
91  br i1 %cmp2.not, label %outer.latch, label %inner.latch
92
93inner.latch:
94  %cmp.not.i = icmp ult i32 %k.0, 3
95  call void @use(i1 %cmp.not.i)
96  %k.inc = add i32 %k.0, 1
97  br label %inner.header
98
99outer.latch:
100  %i.inc = add i32 %i.0, 1
101  br label %outer.header
102
103exit:
104  ret void
105}
106define void @inner_add_rec_decreasing(i32 noundef %len) {
107; CHECK-LABEL: define void @inner_add_rec_decreasing(
108; CHECK-SAME: i32 noundef [[LEN:%.*]]) {
109; CHECK-NEXT:  entry:
110; CHECK-NEXT:    br label [[OUTER_HEADER:%.*]]
111; CHECK:       outer.header:
112; CHECK-NEXT:    [[I_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_LATCH:%.*]] ]
113; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[I_0]], [[LEN]]
114; CHECK-NEXT:    br i1 [[CMP]], label [[INNER_HEADER:%.*]], label [[EXIT:%.*]]
115; CHECK:       inner.header:
116; CHECK-NEXT:    [[K_0:%.*]] = phi i32 [ [[I_0]], [[OUTER_HEADER]] ], [ [[K_DEC:%.*]], [[INNER_LATCH:%.*]] ]
117; CHECK-NEXT:    [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], 0
118; CHECK-NEXT:    br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]]
119; CHECK:       inner.latch:
120; CHECK-NEXT:    call void @use(i1 true)
121; CHECK-NEXT:    [[K_DEC]] = add i32 [[K_0]], -1
122; CHECK-NEXT:    br label [[INNER_HEADER]]
123; CHECK:       outer.latch:
124; CHECK-NEXT:    [[I_INC]] = add i32 [[I_0]], 1
125; CHECK-NEXT:    br label [[OUTER_HEADER]]
126; CHECK:       exit:
127; CHECK-NEXT:    ret void
128;
129entry:
130  br label %outer.header
131
132outer.header:
133  %i.0 = phi i32 [ 1, %entry ], [ %i.inc, %outer.latch ]
134  %cmp = icmp ult i32 %i.0, %len
135  br i1 %cmp, label %inner.header, label %exit
136
137inner.header:
138  %k.0 = phi i32 [ %i.0, %outer.header ], [ %k.dec, %inner.latch ]
139  %cmp2.not = icmp eq i32 %k.0, 0
140  br i1 %cmp2.not, label %outer.latch, label %inner.latch
141
142inner.latch:
143  %cmp.not.i = icmp ult i32 %k.0, %len
144  call void @use(i1 %cmp.not.i)
145  %k.dec = add i32 %k.0, -1
146  br label %inner.header
147
148outer.latch:
149  %i.inc = add i32 %i.0, 1
150  br label %outer.header
151
152exit:
153  ret void
154}
155