1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -slsr -gvn -S | FileCheck %s
3; RUN: opt < %s -passes='slsr,gvn' -S | FileCheck %s
4
5target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64"
6
7define void @shl(i32 %b, i32 %s) {
8; CHECK-LABEL: @shl(
9; CHECK-NEXT:    [[T1:%.*]] = add i32 [[B:%.*]], [[S:%.*]]
10; CHECK-NEXT:    call void @foo(i32 [[T1]])
11; CHECK-NEXT:    [[T2:%.*]] = add i32 [[T1]], [[S]]
12; CHECK-NEXT:    call void @foo(i32 [[T2]])
13; CHECK-NEXT:    ret void
14;
15  %t1 = add i32 %b, %s
16  call void @foo(i32 %t1)
17  %s2 = shl i32 %s, 1
18  %t2 = add i32 %b, %s2
19  call void @foo(i32 %t2)
20  ret void
21}
22
23define void @stride_is_2s(i32 %b, i32 %s) {
24; CHECK-LABEL: @stride_is_2s(
25; CHECK-NEXT:    [[S2:%.*]] = shl i32 [[S:%.*]], 1
26; CHECK-NEXT:    [[T1:%.*]] = add i32 [[B:%.*]], [[S2]]
27; CHECK-NEXT:    call void @foo(i32 [[T1]])
28; CHECK-NEXT:    [[T2:%.*]] = add i32 [[T1]], [[S2]]
29; CHECK-NEXT:    call void @foo(i32 [[T2]])
30; CHECK-NEXT:    [[T3:%.*]] = add i32 [[T2]], [[S2]]
31; CHECK-NEXT:    call void @foo(i32 [[T3]])
32; CHECK-NEXT:    ret void
33;
34  %s2 = shl i32 %s, 1
35  %t1 = add i32 %b, %s2
36  call void @foo(i32 %t1)
37  %s4 = shl i32 %s, 2
38  %t2 = add i32 %b, %s4
39  call void @foo(i32 %t2)
40  %s6 = mul i32 %s, 6
41  %t3 = add i32 %b, %s6
42  call void @foo(i32 %t3)
43  ret void
44}
45
46define void @stride_is_3s(i32 %b, i32 %s) {
47; CHECK-LABEL: @stride_is_3s(
48; CHECK-NEXT:    [[T1:%.*]] = add i32 [[S:%.*]], [[B:%.*]]
49; CHECK-NEXT:    call void @foo(i32 [[T1]])
50; CHECK-NEXT:    [[TMP1:%.*]] = mul i32 [[S]], 3
51; CHECK-NEXT:    [[T2:%.*]] = add i32 [[T1]], [[TMP1]]
52; CHECK-NEXT:    call void @foo(i32 [[T2]])
53; CHECK-NEXT:    [[T3:%.*]] = add i32 [[T2]], [[TMP1]]
54; CHECK-NEXT:    call void @foo(i32 [[T3]])
55; CHECK-NEXT:    ret void
56;
57  %t1 = add i32 %s, %b
58  call void @foo(i32 %t1)
59  %s4 = shl i32 %s, 2
60  %t2 = add i32 %s4, %b
61  call void @foo(i32 %t2)
62  %s7 = mul i32 %s, 7
63  %t3 = add i32 %s7, %b
64  call void @foo(i32 %t3)
65  ret void
66}
67
68; foo(b + 6 * s);
69; foo(b + 4 * s);
70; foo(b + 2 * s);
71;   =>
72; t1 = b + 6 * s;
73; foo(t1);
74; s2 = 2 * s;
75; t2 = t1 - s2;
76; foo(t2);
77; t3 = t2 - s2;
78; foo(t3);
79define void @stride_is_minus_2s(i32 %b, i32 %s) {
80; CHECK-LABEL: @stride_is_minus_2s(
81; CHECK-NEXT:    [[S6:%.*]] = mul i32 [[S:%.*]], 6
82; CHECK-NEXT:    [[T1:%.*]] = add i32 [[B:%.*]], [[S6]]
83; CHECK-NEXT:    call void @foo(i32 [[T1]])
84; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[S]], 1
85; CHECK-NEXT:    [[T2:%.*]] = sub i32 [[T1]], [[TMP1]]
86; CHECK-NEXT:    call void @foo(i32 [[T2]])
87; CHECK-NEXT:    [[T3:%.*]] = sub i32 [[T2]], [[TMP1]]
88; CHECK-NEXT:    call void @foo(i32 [[T3]])
89; CHECK-NEXT:    ret void
90;
91  %s6 = mul i32 %s, 6
92  %t1 = add i32 %b, %s6
93  call void @foo(i32 %t1)
94  %s4 = shl i32 %s, 2
95  %t2 = add i32 %b, %s4
96  call void @foo(i32 %t2)
97  %s2 = shl i32 %s, 1
98  %t3 = add i32 %b, %s2
99  call void @foo(i32 %t3)
100  ret void
101}
102
103; TODO: This pass is targeted at simple address-calcs, so it is artificially limited to
104; match scalar values. The code could be modified to handle vector types too.
105
106define void @stride_is_minus_2s_vec(<2 x i32> %b, <2 x i32> %s) {
107; CHECK-LABEL: @stride_is_minus_2s_vec(
108; CHECK-NEXT:    [[S6:%.*]] = mul <2 x i32> [[S:%.*]], <i32 6, i32 6>
109; CHECK-NEXT:    [[T1:%.*]] = add <2 x i32> [[B:%.*]], [[S6]]
110; CHECK-NEXT:    call void @voo(<2 x i32> [[T1]])
111; CHECK-NEXT:    [[S4:%.*]] = shl <2 x i32> [[S]], <i32 2, i32 2>
112; CHECK-NEXT:    [[T2:%.*]] = add <2 x i32> [[B]], [[S4]]
113; CHECK-NEXT:    call void @voo(<2 x i32> [[T2]])
114; CHECK-NEXT:    [[S2:%.*]] = shl <2 x i32> [[S]], <i32 1, i32 1>
115; CHECK-NEXT:    [[T3:%.*]] = add <2 x i32> [[B]], [[S2]]
116; CHECK-NEXT:    call void @voo(<2 x i32> [[T3]])
117; CHECK-NEXT:    ret void
118;
119  %s6 = mul <2 x i32> %s, <i32 6, i32 6>
120  %t1 = add <2 x i32> %b, %s6
121  call void @voo(<2 x i32> %t1)
122  %s4 = shl <2 x i32> %s, <i32 2, i32 2>
123  %t2 = add <2 x i32> %b, %s4
124  call void @voo(<2 x i32> %t2)
125  %s2 = shl <2 x i32> %s, <i32 1, i32 1>
126  %t3 = add <2 x i32> %b, %s2
127  call void @voo(<2 x i32> %t3)
128  ret void
129}
130
131; t = b + (s << 3);
132; foo(t);
133; foo(b + s);
134;
135; do not rewrite b + s to t - 7 * s because the latter is more complicated.
136define void @simple_enough(i32 %b, i32 %s) {
137; CHECK-LABEL: @simple_enough(
138; CHECK-NEXT:    [[S8:%.*]] = shl i32 [[S:%.*]], 3
139; CHECK-NEXT:    [[T1:%.*]] = add i32 [[B:%.*]], [[S8]]
140; CHECK-NEXT:    call void @foo(i32 [[T1]])
141; CHECK-NEXT:    [[T2:%.*]] = add i32 [[B]], [[S]]
142; CHECK-NEXT:    call void @foo(i32 [[T2]])
143; CHECK-NEXT:    ret void
144;
145  %s8 = shl i32 %s, 3
146  %t1 = add i32 %b, %s8
147  call void @foo(i32 %t1)
148  %t2 = add i32 %b, %s
149  call void @foo(i32 %t2)
150  ret void
151}
152
153define void @slsr_strided_add_128bit(i128 %b, i128 %s) {
154; CHECK-LABEL: @slsr_strided_add_128bit(
155; CHECK-NEXT:    [[S125:%.*]] = shl i128 [[S:%.*]], 125
156; CHECK-NEXT:    [[T1:%.*]] = add i128 [[B:%.*]], [[S125]]
157; CHECK-NEXT:    call void @bar(i128 [[T1]])
158; CHECK-NEXT:    [[T2:%.*]] = add i128 [[T1]], [[S125]]
159; CHECK-NEXT:    call void @bar(i128 [[T2]])
160; CHECK-NEXT:    ret void
161;
162  %s125 = shl i128 %s, 125
163  %s126 = shl i128 %s, 126
164  %t1 = add i128 %b, %s125
165  call void @bar(i128 %t1)
166  %t2 = add i128 %b, %s126
167  call void @bar(i128 %t2)
168  ret void
169}
170
171declare void @foo(i32)
172declare void @voo(<2 x i32>)
173declare void @bar(i128)
174