1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2 /// Check the code generation for the alignment builtins
3 /// To make the test case easier to read, run SROA after generating IR to remove the alloca instructions.
4 // RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_VOID_PTR \
5 // RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -passes=sroa | \
6 // RUN: FileCheck %s -check-prefixes CHECK,CHECK-VOID_PTR \
7 // RUN: -enable-var-scope '-D$PTRTYPE=i8'
8 // RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_FLOAT_PTR \
9 // RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -passes=sroa | \
10 // RUN: FileCheck %s -check-prefixes CHECK,CHECK-FLOAT_PTR \
11 // RUN: -enable-var-scope '-D$PTRTYPE=f32'
12 // RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_LONG \
13 // RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -passes=sroa | \
14 // RUN: FileCheck %s -check-prefixes CHECK,CHECK-LONG -enable-var-scope
15 /// Check that we can handle the case where the alignment parameter is wider
16 /// than the source type (generate a trunc on alignment instead of zext)
17 // RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_USHORT \
18 // RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -passes=sroa | \
19 // RUN: FileCheck %s -check-prefixes CHECK,CHECK-USHORT -enable-var-scope
24 #elif defined(TEST_FLOAT_PTR)
26 #elif defined(TEST_LONG)
28 #elif defined(TEST_USHORT)
29 #define TYPE unsigned short
34 /// Check that constant initializers work and are correct
35 _Bool aligned_true
= __builtin_is_aligned(1024, 512);
36 // CHECK: @aligned_true ={{.*}} global i8 1, align 1
37 _Bool aligned_false
= __builtin_is_aligned(123, 512);
38 // CHECK: @aligned_false ={{.*}} global i8 0, align 1
40 int down_1
= __builtin_align_down(1023, 32);
41 // CHECK: @down_1 ={{.*}} global i32 992, align 4
42 int down_2
= __builtin_align_down(256, 32);
43 // CHECK: @down_2 ={{.*}} global i32 256, align 4
45 int up_1
= __builtin_align_up(1023, 32);
46 // CHECK: @up_1 ={{.*}} global i32 1024, align 4
47 int up_2
= __builtin_align_up(256, 32);
48 // CHECK: @up_2 ={{.*}} global i32 256, align 4
50 /// Capture the IR type here to use in the remaining FileCheck captures:
51 // CHECK-VOID_PTR-LABEL: define {{[^@]+}}@get_type() #0
52 // CHECK-VOID_PTR-NEXT: entry:
53 // CHECK-VOID_PTR-NEXT: ret ptr null
55 // CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@get_type() #0
56 // CHECK-FLOAT_PTR-NEXT: entry:
57 // CHECK-FLOAT_PTR-NEXT: ret ptr null
59 // CHECK-LONG-LABEL: define {{[^@]+}}@get_type() #0
60 // CHECK-LONG-NEXT: entry:
61 // CHECK-LONG-NEXT: ret i64 0
63 // CHECK-USHORT-LABEL: define {{[^@]+}}@get_type() #0
64 // CHECK-USHORT-NEXT: entry:
65 // CHECK-USHORT-NEXT: ret i16 0
71 // CHECK-VOID_PTR-LABEL: define {{[^@]+}}@is_aligned
72 // CHECK-VOID_PTR-SAME: (ptr noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
73 // CHECK-VOID_PTR-NEXT: entry:
74 // CHECK-VOID_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
75 // CHECK-VOID_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
76 // CHECK-VOID_PTR-NEXT: [[SRC_ADDR:%.*]] = ptrtoint ptr [[PTR]] to i64
77 // CHECK-VOID_PTR-NEXT: [[SET_BITS:%.*]] = and i64 [[SRC_ADDR]], [[MASK]]
78 // CHECK-VOID_PTR-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
79 // CHECK-VOID_PTR-NEXT: ret i1 [[IS_ALIGNED]]
81 // CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@is_aligned
82 // CHECK-FLOAT_PTR-SAME: (ptr noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
83 // CHECK-FLOAT_PTR-NEXT: entry:
84 // CHECK-FLOAT_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
85 // CHECK-FLOAT_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
86 // CHECK-FLOAT_PTR-NEXT: [[SRC_ADDR:%.*]] = ptrtoint ptr [[PTR]] to i64
87 // CHECK-FLOAT_PTR-NEXT: [[SET_BITS:%.*]] = and i64 [[SRC_ADDR]], [[MASK]]
88 // CHECK-FLOAT_PTR-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
89 // CHECK-FLOAT_PTR-NEXT: ret i1 [[IS_ALIGNED]]
91 // CHECK-LONG-LABEL: define {{[^@]+}}@is_aligned
92 // CHECK-LONG-SAME: (i64 noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
93 // CHECK-LONG-NEXT: entry:
94 // CHECK-LONG-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
95 // CHECK-LONG-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
96 // CHECK-LONG-NEXT: [[SET_BITS:%.*]] = and i64 [[PTR]], [[MASK]]
97 // CHECK-LONG-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
98 // CHECK-LONG-NEXT: ret i1 [[IS_ALIGNED]]
100 // CHECK-USHORT-LABEL: define {{[^@]+}}@is_aligned
101 // CHECK-USHORT-SAME: (i16 noundef zeroext [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
102 // CHECK-USHORT-NEXT: entry:
103 // CHECK-USHORT-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to i16
104 // CHECK-USHORT-NEXT: [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
105 // CHECK-USHORT-NEXT: [[SET_BITS:%.*]] = and i16 [[PTR]], [[MASK]]
106 // CHECK-USHORT-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i16 [[SET_BITS]], 0
107 // CHECK-USHORT-NEXT: ret i1 [[IS_ALIGNED]]
109 _Bool
is_aligned(TYPE ptr
, unsigned align
) {
110 return __builtin_is_aligned(ptr
, align
);
113 // NOTYET-POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = call [[$TYPE]] @llvm.ptrmask.p0[[$PTRTYPE]].p0i8.i64(ptr [[OVER_BOUNDARY]], [[ALIGN_TYPE]] [[INVERTED_MASK]])
114 // CHECK-VOID_PTR-LABEL: define {{[^@]+}}@align_up
115 // CHECK-VOID_PTR-SAME: (ptr noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
116 // CHECK-VOID_PTR-NEXT: entry:
117 // CHECK-VOID_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
118 // CHECK-VOID_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
119 // CHECK-VOID_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
120 // CHECK-VOID_PTR-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[INTPTR]], [[MASK]]
121 // CHECK-VOID_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
122 // CHECK-VOID_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
123 // CHECK-VOID_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
124 // CHECK-VOID_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[DIFF]]
125 // CHECK-VOID_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ]
126 // CHECK-VOID_PTR-NEXT: ret ptr [[ALIGNED_RESULT]]
128 // CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@align_up
129 // CHECK-FLOAT_PTR-SAME: (ptr noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
130 // CHECK-FLOAT_PTR-NEXT: entry:
131 // CHECK-FLOAT_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
132 // CHECK-FLOAT_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
133 // CHECK-FLOAT_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
134 // CHECK-FLOAT_PTR-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[INTPTR]], [[MASK]]
135 // CHECK-FLOAT_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
136 // CHECK-FLOAT_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
137 // CHECK-FLOAT_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
138 // CHECK-FLOAT_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[DIFF]]
139 // CHECK-FLOAT_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ]
140 // CHECK-FLOAT_PTR-NEXT: ret ptr [[ALIGNED_RESULT]]
142 // CHECK-LONG-LABEL: define {{[^@]+}}@align_up
143 // CHECK-LONG-SAME: (i64 noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
144 // CHECK-LONG-NEXT: entry:
145 // CHECK-LONG-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
146 // CHECK-LONG-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
147 // CHECK-LONG-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[PTR]], [[MASK]]
148 // CHECK-LONG-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
149 // CHECK-LONG-NEXT: [[ALIGNED_RESULT:%.*]] = and i64 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
150 // CHECK-LONG-NEXT: ret i64 [[ALIGNED_RESULT]]
152 // CHECK-USHORT-LABEL: define {{[^@]+}}@align_up
153 // CHECK-USHORT-SAME: (i16 noundef zeroext [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
154 // CHECK-USHORT-NEXT: entry:
155 // CHECK-USHORT-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to i16
156 // CHECK-USHORT-NEXT: [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
157 // CHECK-USHORT-NEXT: [[OVER_BOUNDARY:%.*]] = add i16 [[PTR]], [[MASK]]
158 // CHECK-USHORT-NEXT: [[INVERTED_MASK:%.*]] = xor i16 [[MASK]], -1
159 // CHECK-USHORT-NEXT: [[ALIGNED_RESULT:%.*]] = and i16 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
160 // CHECK-USHORT-NEXT: ret i16 [[ALIGNED_RESULT]]
162 TYPE
align_up(TYPE ptr
, unsigned align
) {
163 return __builtin_align_up(ptr
, align
);
166 // NOTYET-POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = call [[$TYPE]] @llvm.ptrmask.p0[[$PTRTYPE]].p0[[$PTRTYPE]].i64([[$TYPE]] [[PTR]], [[ALIGN_TYPE]] [[INVERTED_MASK]])
167 // CHECK-VOID_PTR-LABEL: define {{[^@]+}}@align_down
168 // CHECK-VOID_PTR-SAME: (ptr noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
169 // CHECK-VOID_PTR-NEXT: entry:
170 // CHECK-VOID_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
171 // CHECK-VOID_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
172 // CHECK-VOID_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
173 // CHECK-VOID_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
174 // CHECK-VOID_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], [[INVERTED_MASK]]
175 // CHECK-VOID_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
176 // CHECK-VOID_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[DIFF]]
177 // CHECK-VOID_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ]
178 // CHECK-VOID_PTR-NEXT: ret ptr [[ALIGNED_RESULT]]
180 // CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@align_down
181 // CHECK-FLOAT_PTR-SAME: (ptr noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
182 // CHECK-FLOAT_PTR-NEXT: entry:
183 // CHECK-FLOAT_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
184 // CHECK-FLOAT_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
185 // CHECK-FLOAT_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint ptr [[PTR]] to i64
186 // CHECK-FLOAT_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
187 // CHECK-FLOAT_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], [[INVERTED_MASK]]
188 // CHECK-FLOAT_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
189 // CHECK-FLOAT_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 [[DIFF]]
190 // CHECK-FLOAT_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ]
191 // CHECK-FLOAT_PTR-NEXT: ret ptr [[ALIGNED_RESULT]]
193 // CHECK-LONG-LABEL: define {{[^@]+}}@align_down
194 // CHECK-LONG-SAME: (i64 noundef [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
195 // CHECK-LONG-NEXT: entry:
196 // CHECK-LONG-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
197 // CHECK-LONG-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
198 // CHECK-LONG-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
199 // CHECK-LONG-NEXT: [[ALIGNED_RESULT:%.*]] = and i64 [[PTR]], [[INVERTED_MASK]]
200 // CHECK-LONG-NEXT: ret i64 [[ALIGNED_RESULT]]
202 // CHECK-USHORT-LABEL: define {{[^@]+}}@align_down
203 // CHECK-USHORT-SAME: (i16 noundef zeroext [[PTR:%.*]], i32 noundef [[ALIGN:%.*]]) #0
204 // CHECK-USHORT-NEXT: entry:
205 // CHECK-USHORT-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to i16
206 // CHECK-USHORT-NEXT: [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
207 // CHECK-USHORT-NEXT: [[INVERTED_MASK:%.*]] = xor i16 [[MASK]], -1
208 // CHECK-USHORT-NEXT: [[ALIGNED_RESULT:%.*]] = and i16 [[PTR]], [[INVERTED_MASK]]
209 // CHECK-USHORT-NEXT: ret i16 [[ALIGNED_RESULT]]
211 TYPE
align_down(TYPE ptr
, unsigned align
) {
212 return __builtin_align_down(ptr
, align
);