xref: /llvm-project/llvm/test/Transforms/InstSimplify/po2-shift-add-and-to-zero.ll (revision 4028dd2e93fa1697b68339b04b89f5ddbf7f9aea)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2; RUN: opt -passes=instsimplify -S < %s | FileCheck %s
3
4;; The and X, (add Y, -1) pattern is from an earlier instcombine pass which
5;; converted
6
7;; define i64 @f1() #0 {
8;; entry:
9;;   %0 = call i64 @llvm.aarch64.sve.cntb(i32 31)
10;;   %1 = call i64 @llvm.aarch64.sve.cnth(i32 31)
11;;   %rem = urem i64 %0, %1
12;;   ret i64 %rem
13;; }
14
15;; into
16
17;; define i64 @f1() #0 {
18;; entry:
19;;   %0 = call i64 @llvm.vscale.i64()
20;;   %1 = shl nuw nsw i64 %0, 4
21;;   %2 = call i64 @llvm.vscale.i64()
22;;   %3 = shl nuw nsw i64 %2, 3
23;;   %4 = add nsw i64 %3, -1
24;;   %rem = and i64 %1, %4
25;;   ret i64 %rem
26;; }
27
28;; InstCombine would have folded the original to returning 0 if the vscale
29;; calls were the same Value*, but since there's two of them it doesn't
30;; work and we convert the urem to add/and. CSE then gets rid of the extra
31;; vscale, leaving us with a new pattern to match. This only works because
32;; vscale is known to be a power of 2 (assuming there's a defined range for it).
33
34define i64 @f1() #0 {
35; CHECK-LABEL: define i64 @f1
36; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
37; CHECK-NEXT:  entry:
38; CHECK-NEXT:    ret i64 0
39;
40entry:
41  %0 = call i64 @llvm.vscale.i64()
42  %1 = shl i64 %0, 4
43  %2 = shl i64 %0, 3
44  %3 = add i64 %2, -1
45  %rem = and i64 %1, %3
46  ret i64 %rem
47}
48
49;; Make sure it works if the value could also be zero.
50define i64 @test_pow2_or_zero(i64 %arg) {
51; CHECK-LABEL: define i64 @test_pow2_or_zero
52; CHECK-SAME: (i64 [[ARG:%.*]]) {
53; CHECK-NEXT:    ret i64 0
54;
55  %neg = sub i64 0, %arg
56  %x = and i64 %neg, %arg
57  %shl1 = shl i64 %x, 4
58  %shl2 = shl i64 %x, 3
59  %mask = add i64 %shl2, -1
60  %rem = and i64 %mask, %shl1
61  ret i64 %rem
62}
63
64;; Make sure it doesn't work if the value isn't known to be a power of 2.
65;; In this case a vscale without a `vscale_range` attribute on the function.
66define i64 @no_pow2() {
67; CHECK-LABEL: define i64 @no_pow2() {
68; CHECK-NEXT:  entry:
69; CHECK-NEXT:    [[TMP0:%.*]] = call i64 @llvm.vscale.i64()
70; CHECK-NEXT:    [[TMP1:%.*]] = shl i64 [[TMP0]], 4
71; CHECK-NEXT:    [[TMP2:%.*]] = shl i64 [[TMP0]], 3
72; CHECK-NEXT:    [[TMP3:%.*]] = add i64 [[TMP2]], -1
73; CHECK-NEXT:    [[REM:%.*]] = and i64 [[TMP1]], [[TMP3]]
74; CHECK-NEXT:    ret i64 [[REM]]
75;
76entry:
77  %0 = call i64 @llvm.vscale.i64()
78  %1 = shl i64 %0, 4
79  %2 = shl i64 %0, 3
80  %3 = add i64 %2, -1
81  %rem = and i64 %1, %3
82  ret i64 %rem
83}
84
85;; Make sure it doesn't work if the shift on the -1 side is greater
86define i64 @minus_shift_greater(i64 %arg) {
87; CHECK-LABEL: define i64 @minus_shift_greater
88; CHECK-SAME: (i64 [[ARG:%.*]]) {
89; CHECK-NEXT:    [[NEG:%.*]] = sub i64 0, [[ARG]]
90; CHECK-NEXT:    [[X:%.*]] = and i64 [[NEG]], [[ARG]]
91; CHECK-NEXT:    [[SHL1:%.*]] = shl i64 [[X]], 3
92; CHECK-NEXT:    [[SHL2:%.*]] = shl i64 [[X]], 4
93; CHECK-NEXT:    [[MASK:%.*]] = add i64 [[SHL2]], -1
94; CHECK-NEXT:    [[REM:%.*]] = and i64 [[SHL1]], [[MASK]]
95; CHECK-NEXT:    ret i64 [[REM]]
96;
97  %neg = sub i64 0, %arg
98  %x = and i64 %neg, %arg
99  %shl1 = shl i64 %x, 3
100  %shl2 = shl i64 %x, 4
101  %mask = add i64 %shl2, -1
102  %rem = and i64 %shl1, %mask
103  ret i64 %rem
104}
105
106;; Make sure it doesn't work if the subtract isn't one.
107define i64 @sub2(i64 %arg) {
108; CHECK-LABEL: define i64 @sub2
109; CHECK-SAME: (i64 [[ARG:%.*]]) {
110; CHECK-NEXT:    [[NEG:%.*]] = sub i64 0, [[ARG]]
111; CHECK-NEXT:    [[X:%.*]] = and i64 [[NEG]], [[ARG]]
112; CHECK-NEXT:    [[SHL1:%.*]] = shl i64 [[X]], 4
113; CHECK-NEXT:    [[SHL2:%.*]] = shl i64 [[X]], 3
114; CHECK-NEXT:    [[MASK:%.*]] = add i64 [[SHL2]], -2
115; CHECK-NEXT:    [[REM:%.*]] = and i64 [[SHL1]], [[MASK]]
116; CHECK-NEXT:    ret i64 [[REM]]
117;
118  %neg = sub i64 0, %arg
119  %x = and i64 %neg, %arg
120  %shl1 = shl i64 %x, 4
121  %shl2 = shl i64 %x, 3
122  %mask = add i64 %shl2, -2
123  %rem = and i64 %shl1, %mask
124  ret i64 %rem
125}
126
127;; Make sure it doesn't work with a right shift
128;; Make sure it doesn't work if the subtract isn't one.
129define i64 @rightshift(i64 %arg) {
130; CHECK-LABEL: define i64 @rightshift
131; CHECK-SAME: (i64 [[ARG:%.*]]) {
132; CHECK-NEXT:    [[NEG:%.*]] = sub i64 0, [[ARG]]
133; CHECK-NEXT:    [[X:%.*]] = and i64 [[NEG]], [[ARG]]
134; CHECK-NEXT:    [[SHL1:%.*]] = shl i64 [[X]], 4
135; CHECK-NEXT:    [[SHL2:%.*]] = lshr i64 [[X]], 3
136; CHECK-NEXT:    [[MASK:%.*]] = add i64 [[SHL2]], -1
137; CHECK-NEXT:    [[REM:%.*]] = and i64 [[SHL1]], [[MASK]]
138; CHECK-NEXT:    ret i64 [[REM]]
139;
140  %neg = sub i64 0, %arg
141  %x = and i64 %neg, %arg
142  %shl1 = shl i64 %x, 4
143  %shl2 = lshr i64 %x, 3
144  %mask = add i64 %shl2, -1
145  %rem = and i64 %shl1, %mask
146  ret i64 %rem
147}
148
149declare i64 @llvm.vscale.i64()
150
151attributes #0 = { vscale_range(1,16) }
152