blob: 8fb51822164d0056bb194de04cad9ed22a975f3d [file] [log] [blame]
Alex Richardson8c387cb2020-01-09 20:48:06 +00001/// Check the code generation for the alignment builtins
2/// To make the test case easier to read, run SROA after generating IR to remove the alloca instructions.
3// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_VOID_PTR \
4// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
5// RUN: FileCheck %s -check-prefixes CHECK,POINTER,ALIGNMENT_EXT \
6// RUN: -enable-var-scope '-D$PTRTYPE=i8'
7// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_FLOAT_PTR \
8// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
9// RUN: FileCheck %s -check-prefixes CHECK,POINTER,NON_I8_POINTER,ALIGNMENT_EXT \
10// RUN: -enable-var-scope '-D$PTRTYPE=f32'
11// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_LONG \
12// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
13// RUN: FileCheck %s -check-prefixes CHECK,INTEGER,ALIGNMENT_EXT -enable-var-scope
14/// Check that we can handle the case where the alignment parameter is wider
15/// than the source type (generate a trunc on alignment instead of zext)
16// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_USHORT \
17// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
18// RUN: FileCheck %s -check-prefixes CHECK,INTEGER,ALIGNMENT_TRUNC -enable-var-scope
19
20
21#ifdef TEST_VOID_PTR
22#define TYPE void *
23#elif defined(TEST_FLOAT_PTR)
24#define TYPE float *
25#elif defined(TEST_LONG)
26#define TYPE long
27#elif defined(TEST_CAP)
28#define TYPE void *__capability
29#elif defined(TEST_USHORT)
30#define TYPE unsigned short
31#else
32#error MISSING TYPE
33#endif
34
35/// Check that constant initializers work and are correct
36_Bool aligned_true = __builtin_is_aligned(1024, 512);
Fangrui Songdbc96b52020-02-03 10:09:39 -080037// CHECK: @aligned_true = global i8 1, align 1
Alex Richardson8c387cb2020-01-09 20:48:06 +000038_Bool aligned_false = __builtin_is_aligned(123, 512);
Fangrui Songdbc96b52020-02-03 10:09:39 -080039// CHECK: @aligned_false = global i8 0, align 1
Alex Richardson8c387cb2020-01-09 20:48:06 +000040
41int down_1 = __builtin_align_down(1023, 32);
Fangrui Songdbc96b52020-02-03 10:09:39 -080042// CHECK: @down_1 = global i32 992, align 4
Alex Richardson8c387cb2020-01-09 20:48:06 +000043int down_2 = __builtin_align_down(256, 32);
Fangrui Songdbc96b52020-02-03 10:09:39 -080044// CHECK: @down_2 = global i32 256, align 4
Alex Richardson8c387cb2020-01-09 20:48:06 +000045
46int up_1 = __builtin_align_up(1023, 32);
Fangrui Songdbc96b52020-02-03 10:09:39 -080047// CHECK: @up_1 = global i32 1024, align 4
Alex Richardson8c387cb2020-01-09 20:48:06 +000048int up_2 = __builtin_align_up(256, 32);
Fangrui Songdbc96b52020-02-03 10:09:39 -080049// CHECK: @up_2 = global i32 256, align 4
Alex Richardson8c387cb2020-01-09 20:48:06 +000050
51/// Capture the IR type here to use in the remaining FileCheck captures:
52// CHECK: define {{[^@]+}}@get_type() #0
53// CHECK-NEXT: entry:
54// POINTER-NEXT: ret [[$TYPE:.+]] null
55// INTEGER-NEXT: ret [[$TYPE:.+]] 0
56//
57TYPE get_type(void) {
58 return (TYPE)0;
59}
60
61// CHECK-LABEL: define {{[^@]+}}@is_aligned
62// CHECK-SAME: ([[$TYPE]] {{[^%]*}}[[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
63// CHECK-NEXT: entry:
64// ALIGNMENT_EXT-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to [[ALIGN_TYPE:i64]]
65// ALIGNMENT_TRUNC-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to [[ALIGN_TYPE:i16]]
66// CHECK-NEXT: [[MASK:%.*]] = sub [[ALIGN_TYPE]] [[ALIGNMENT]], 1
67// POINTER-NEXT: [[PTR:%.*]] = ptrtoint [[$TYPE]] %ptr to i64
68// CHECK-NEXT: [[SET_BITS:%.*]] = and [[ALIGN_TYPE]] [[PTR]], [[MASK]]
69// CHECK-NEXT: [[IS_ALIGNED:%.*]] = icmp eq [[ALIGN_TYPE]] [[SET_BITS]], 0
70// CHECK-NEXT: ret i1 [[IS_ALIGNED]]
71//
72_Bool is_aligned(TYPE ptr, unsigned align) {
73 return __builtin_is_aligned(ptr, align);
74}
75
76// CHECK-LABEL: define {{[^@]+}}@align_up
77// CHECK-SAME: ([[$TYPE]] {{[^%]*}}[[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
78// CHECK-NEXT: entry:
79// ALIGNMENT_EXT-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to [[ALIGN_TYPE:i64]]
80// ALIGNMENT_TRUNC-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to [[ALIGN_TYPE:i16]]
81// CHECK-NEXT: [[MASK:%.*]] = sub [[ALIGN_TYPE]] [[ALIGNMENT]], 1
82// INTEGER-NEXT: [[OVER_BOUNDARY:%.*]] = add [[$TYPE]] [[PTR]], [[MASK]]
83// NOTYET-POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = call [[$TYPE]] @llvm.ptrmask.p0[[$PTRTYPE]].p0i8.i64(i8* [[OVER_BOUNDARY]], [[ALIGN_TYPE]] [[INVERTED_MASK]])
84// POINTER-NEXT: [[INTPTR:%.*]] = ptrtoint [[$TYPE]] [[PTR]] to [[ALIGN_TYPE]]
85// POINTER-NEXT: [[OVER_BOUNDARY:%.*]] = add [[ALIGN_TYPE]] [[INTPTR]], [[MASK]]
86// CHECK-NEXT: [[INVERTED_MASK:%.*]] = xor [[ALIGN_TYPE]] [[MASK]], -1
87// CHECK-NEXT: [[ALIGNED_RESULT:%.*]] = and [[ALIGN_TYPE]] [[OVER_BOUNDARY]], [[INVERTED_MASK]]
88// POINTER-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_RESULT]], [[INTPTR]]
89// NON_I8_POINTER-NEXT: [[PTR:%.*]] = bitcast [[$TYPE]] {{%.*}} to i8*
90// POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[DIFF]]
91// NON_I8_POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = bitcast i8* {{%.*}} to [[$TYPE]]
92// POINTER-NEXT: [[ASSUME_MASK:%.*]] = sub i64 %alignment, 1
93// POINTER-NEXT: [[ASSUME_INTPTR:%.*]]= ptrtoint [[$TYPE]] [[ALIGNED_RESULT]] to i64
94// POINTER-NEXT: [[MASKEDPTR:%.*]] = and i64 %ptrint, [[ASSUME_MASK]]
95// POINTER-NEXT: [[MASKEDCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
96// POINTER-NEXT: call void @llvm.assume(i1 [[MASKEDCOND]])
97// CHECK-NEXT: ret [[$TYPE]] [[ALIGNED_RESULT]]
98//
99TYPE align_up(TYPE ptr, unsigned align) {
100 return __builtin_align_up(ptr, align);
101}
102
103// CHECK-LABEL: define {{[^@]+}}@align_down
104// CHECK-SAME: ([[$TYPE]] {{[^%]*}}[[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
105// CHECK-NEXT: entry:
106// ALIGNMENT_EXT-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to [[ALIGN_TYPE:i64]]
107// ALIGNMENT_TRUNC-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to [[ALIGN_TYPE:i16]]
108// CHECK-NEXT: [[MASK:%.*]] = sub [[ALIGN_TYPE]] [[ALIGNMENT]], 1
109// NOTYET-POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = call [[$TYPE]] @llvm.ptrmask.p0[[$PTRTYPE]].p0[[$PTRTYPE]].i64([[$TYPE]] [[PTR]], [[ALIGN_TYPE]] [[INVERTED_MASK]])
110// POINTER-NEXT: [[INTPTR:%.*]] = ptrtoint [[$TYPE]] [[PTR]] to [[ALIGN_TYPE]]
111// CHECK-NEXT: [[INVERTED_MASK:%.*]] = xor [[ALIGN_TYPE]] [[MASK]], -1
112// POINTER-NEXT: [[ALIGNED_INTPTR:%.*]] = and [[ALIGN_TYPE]] [[INTPTR]], [[INVERTED_MASK]]
113// POINTER-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
114// NON_I8_POINTER-NEXT: [[PTR:%.*]] = bitcast [[$TYPE]] {{%.*}} to i8*
115// POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[DIFF]]
116// NON_I8_POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = bitcast i8* {{%.*}} to [[$TYPE]]
117// INTEGER-NEXT: [[ALIGNED_RESULT:%.*]] = and [[ALIGN_TYPE]] [[PTR]], [[INVERTED_MASK]]
118// POINTER-NEXT: [[ASSUME_MASK:%.*]] = sub i64 %alignment, 1
119// POINTER-NEXT: [[ASSUME_INTPTR:%.*]]= ptrtoint [[$TYPE]] [[ALIGNED_RESULT]] to i64
120// POINTER-NEXT: [[MASKEDPTR:%.*]] = and i64 %ptrint, [[ASSUME_MASK]]
121// POINTER-NEXT: [[MASKEDCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
122// POINTER-NEXT: call void @llvm.assume(i1 [[MASKEDCOND]])
123// CHECK-NEXT: ret [[$TYPE]] [[ALIGNED_RESULT]]
124//
125TYPE align_down(TYPE ptr, unsigned align) {
126 return __builtin_align_down(ptr, align);
127}