xref: /llvm-project/llvm/test/CodeGen/AArch64/align-down.ll (revision 1ee315ae7964c8433b772e0b5d667834994ba753)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=aarch64-unknown-linux-gnu --aarch64-enable-sink-fold=true < %s | FileCheck %s
3
4; Fold
5;   ptr - (ptr & (alignment-1))
6; To
7;   ptr & (0 - alignment)
8;
9; This needs to be a backend-level fold because only by now pointers
10; are just registers; in middle-end IR this can only be done via @llvm.ptrmask()
11; intrinsic which is not sufficiently widely-spread yet.
12;
13; https://bugs.llvm.org/show_bug.cgi?id=44448
14
15; The basic positive tests
16
17define i32 @t0_32(i32 %ptr, i32 %alignment) nounwind {
18; CHECK-LABEL: t0_32:
19; CHECK:       // %bb.0:
20; CHECK-NEXT:    neg w8, w1
21; CHECK-NEXT:    and w0, w0, w8
22; CHECK-NEXT:    ret
23  %mask = add i32 %alignment, -1
24  %bias = and i32 %ptr, %mask
25  %r = sub i32 %ptr, %bias
26  ret i32 %r
27}
28define i64 @t1_64(i64 %ptr, i64 %alignment) nounwind {
29; CHECK-LABEL: t1_64:
30; CHECK:       // %bb.0:
31; CHECK-NEXT:    neg x8, x1
32; CHECK-NEXT:    and x0, x0, x8
33; CHECK-NEXT:    ret
34  %mask = add i64 %alignment, -1
35  %bias = and i64 %ptr, %mask
36  %r = sub i64 %ptr, %bias
37  ret i64 %r
38}
39
40define i32 @t2_commutative(i32 %ptr, i32 %alignment) nounwind {
41; CHECK-LABEL: t2_commutative:
42; CHECK:       // %bb.0:
43; CHECK-NEXT:    neg w8, w1
44; CHECK-NEXT:    and w0, w0, w8
45; CHECK-NEXT:    ret
46  %mask = add i32 %alignment, -1
47  %bias = and i32 %mask, %ptr ; swapped
48  %r = sub i32 %ptr, %bias
49  ret i32 %r
50}
51
52; Extra use tests
53
54define i32 @t3_extrause0(i32 %ptr, i32 %alignment, ptr %mask_storage) nounwind {
55; CHECK-LABEL: t3_extrause0:
56; CHECK:       // %bb.0:
57; CHECK-NEXT:    neg w8, w1
58; CHECK-NEXT:    sub w9, w1, #1
59; CHECK-NEXT:    and w0, w0, w8
60; CHECK-NEXT:    str w9, [x2]
61; CHECK-NEXT:    ret
62  %mask = add i32 %alignment, -1
63  store i32 %mask, ptr %mask_storage
64  %bias = and i32 %ptr, %mask
65  %r = sub i32 %ptr, %bias
66  ret i32 %r
67}
68define i32 @n4_extrause1(i32 %ptr, i32 %alignment, ptr %bias_storage) nounwind {
69; CHECK-LABEL: n4_extrause1:
70; CHECK:       // %bb.0:
71; CHECK-NEXT:    sub w8, w1, #1
72; CHECK-NEXT:    and w8, w0, w8
73; CHECK-NEXT:    sub w0, w0, w8
74; CHECK-NEXT:    str w8, [x2]
75; CHECK-NEXT:    ret
76  %mask = add i32 %alignment, -1
77  %bias = and i32 %ptr, %mask ; has extra uses, can't fold
78  store i32 %bias, ptr %bias_storage
79  %r = sub i32 %ptr, %bias
80  ret i32 %r
81}
82define i32 @n5_extrause2(i32 %ptr, i32 %alignment, ptr %mask_storage, ptr %bias_storage) nounwind {
83; CHECK-LABEL: n5_extrause2:
84; CHECK:       // %bb.0:
85; CHECK-NEXT:    sub w8, w1, #1
86; CHECK-NEXT:    and w9, w0, w8
87; CHECK-NEXT:    str w8, [x2]
88; CHECK-NEXT:    sub w0, w0, w9
89; CHECK-NEXT:    str w9, [x3]
90; CHECK-NEXT:    ret
91  %mask = add i32 %alignment, -1
92  store i32 %mask, ptr %mask_storage
93  %bias = and i32 %ptr, %mask ; has extra uses, can't fold
94  store i32 %bias, ptr %bias_storage
95  %r = sub i32 %ptr, %bias
96  ret i32 %r
97}
98
99; Negative tests
100
101define i32 @n6_different_ptrs(i32 %ptr0, i32 %ptr1, i32 %alignment) nounwind {
102; CHECK-LABEL: n6_different_ptrs:
103; CHECK:       // %bb.0:
104; CHECK-NEXT:    sub w8, w2, #1
105; CHECK-NEXT:    and w8, w1, w8
106; CHECK-NEXT:    sub w0, w0, w8
107; CHECK-NEXT:    ret
108  %mask = add i32 %alignment, -1
109  %bias = and i32 %ptr1, %mask ; not %ptr0
110  %r = sub i32 %ptr0, %bias ; not %ptr1
111  ret i32 %r
112}
113define i32 @n7_different_ptrs_commutative(i32 %ptr0, i32 %ptr1, i32 %alignment) nounwind {
114; CHECK-LABEL: n7_different_ptrs_commutative:
115; CHECK:       // %bb.0:
116; CHECK-NEXT:    sub w8, w2, #1
117; CHECK-NEXT:    and w8, w8, w1
118; CHECK-NEXT:    sub w0, w0, w8
119; CHECK-NEXT:    ret
120  %mask = add i32 %alignment, -1
121  %bias = and i32 %mask, %ptr1 ; swapped, not %ptr0
122  %r = sub i32 %ptr0, %bias ; not %ptr1
123  ret i32 %r
124}
125
126define i32 @n8_not_lowbit_mask(i32 %ptr, i32 %alignment) nounwind {
127; CHECK-LABEL: n8_not_lowbit_mask:
128; CHECK:       // %bb.0:
129; CHECK-NEXT:    add w8, w1, #1
130; CHECK-NEXT:    bic w0, w0, w8
131; CHECK-NEXT:    ret
132  %mask = add i32 %alignment, 1 ; not -1
133  %bias = and i32 %ptr, %mask
134  %r = sub i32 %ptr, %bias
135  ret i32 %r
136}
137
138define i32 @n9_sub_is_not_commutative(i32 %ptr, i32 %alignment) nounwind {
139; CHECK-LABEL: n9_sub_is_not_commutative:
140; CHECK:       // %bb.0:
141; CHECK-NEXT:    sub w8, w1, #1
142; CHECK-NEXT:    and w8, w0, w8
143; CHECK-NEXT:    sub w0, w8, w0
144; CHECK-NEXT:    ret
145  %mask = add i32 %alignment, -1
146  %bias = and i32 %ptr, %mask
147  %r = sub i32 %bias, %ptr ; wrong order
148  ret i32 %r
149}
150