156 changes: 108 additions & 48 deletions clang/test/CodeGen/alloc-align-attr.c
Original file line number Diff line number Diff line change
@@ -1,57 +1,74 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s

__INT32_TYPE__*m1(__INT32_TYPE__ i) __attribute__((alloc_align(1)));

// Condition where parameter to m1 is not size_t.
// CHECK-LABEL: define {{[^@]+}}@test1
// CHECK-SAME: (i32 [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[A]], i32* [[A_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
// CHECK-NEXT: [[CALL:%.*]] = call i32* @m1(i32 [[TMP0]])
// CHECK-NEXT: [[CASTED_ALIGN:%.*]] = zext i32 [[TMP0]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 [[CASTED_ALIGN]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP1]]
//
__INT32_TYPE__ test1(__INT32_TYPE__ a) {
// CHECK: define i32 @test1
return *m1(a);
// CHECK: call i32* @m1(i32 [[PARAM1:%[^\)]+]])
// CHECK: [[ALIGNCAST1:%.+]] = zext i32 [[PARAM1]] to i64
// CHECK: [[MASK1:%.+]] = sub i64 [[ALIGNCAST1]], 1
// CHECK: [[PTRINT1:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR1:%.+]] = and i64 [[PTRINT1]], [[MASK1]]
// CHECK: [[MASKCOND1:%.+]] = icmp eq i64 [[MASKEDPTR1]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND1]])
}
// Condition where test2 param needs casting.
// CHECK-LABEL: define {{[^@]+}}@test2
// CHECK-SAME: (i64 [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
// CHECK-NEXT: store i64 [[A]], i64* [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
// CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
// CHECK-NEXT: [[CALL:%.*]] = call i32* @m1(i32 [[CONV]])
// CHECK-NEXT: [[CASTED_ALIGN:%.*]] = zext i32 [[CONV]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 [[CASTED_ALIGN]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP1]]
//
__INT32_TYPE__ test2(__SIZE_TYPE__ a) {
// CHECK: define i32 @test2
return *m1(a);
// CHECK: [[CONV2:%.+]] = trunc i64 %{{.+}} to i32
// CHECK: call i32* @m1(i32 [[CONV2]])
// CHECK: [[ALIGNCAST2:%.+]] = zext i32 [[CONV2]] to i64
// CHECK: [[MASK2:%.+]] = sub i64 [[ALIGNCAST2]], 1
// CHECK: [[PTRINT2:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR2:%.+]] = and i64 [[PTRINT2]], [[MASK2]]
// CHECK: [[MASKCOND2:%.+]] = icmp eq i64 [[MASKEDPTR2]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND2]])
}
__INT32_TYPE__ *m2(__SIZE_TYPE__ i) __attribute__((alloc_align(1)));

// test3 param needs casting, but 'm2' is correct.
// CHECK-LABEL: define {{[^@]+}}@test3
// CHECK-SAME: (i32 [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[A]], i32* [[A_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A_ADDR]], align 4
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP0]] to i64
// CHECK-NEXT: [[CALL:%.*]] = call i32* @m2(i64 [[CONV]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 [[CONV]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP1]]
//
__INT32_TYPE__ test3(__INT32_TYPE__ a) {
// CHECK: define i32 @test3
return *m2(a);
// CHECK: [[CONV3:%.+]] = sext i32 %{{.+}} to i64
// CHECK: call i32* @m2(i64 [[CONV3]])
// CHECK: [[MASK3:%.+]] = sub i64 [[CONV3]], 1
// CHECK: [[PTRINT3:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR3:%.+]] = and i64 [[PTRINT3]], [[MASK3]]
// CHECK: [[MASKCOND3:%.+]] = icmp eq i64 [[MASKEDPTR3]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND3]])
}

// Every type matches, canonical example.
// CHECK-LABEL: define {{[^@]+}}@test4
// CHECK-SAME: (i64 [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i64, align 8
// CHECK-NEXT: store i64 [[A]], i64* [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[A_ADDR]], align 8
// CHECK-NEXT: [[CALL:%.*]] = call i32* @m2(i64 [[TMP0]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 [[TMP0]]) ]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP1]]
//
__INT32_TYPE__ test4(__SIZE_TYPE__ a) {
// CHECK: define i32 @test4
return *m2(a);
// CHECK: call i32* @m2(i64 [[PARAM4:%[^\)]+]])
// CHECK: [[MASK4:%.+]] = sub i64 [[PARAM4]], 1
// CHECK: [[PTRINT4:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR4:%.+]] = and i64 [[PTRINT4]], [[MASK4]]
// CHECK: [[MASKCOND4:%.+]] = icmp eq i64 [[MASKEDPTR4]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND4]])
}


Expand All @@ -60,30 +77,73 @@ struct MultiArgs { __INT64_TYPE__ a, b;};
// Struct parameter doesn't take up an IR parameter, 'i' takes up 2.
// Truncation to i64 is permissible, since alignments of greater than 2^64 are insane.
__INT32_TYPE__ *m3(struct Empty s, __int128_t i) __attribute__((alloc_align(2)));
// CHECK-LABEL: define {{[^@]+}}@test5
// CHECK-SAME: (i64 [[A_COERCE0:%.*]], i64 [[A_COERCE1:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A:%.*]] = alloca i128, align 16
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i128, align 16
// CHECK-NEXT: [[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1
// CHECK-NEXT: [[COERCE:%.*]] = alloca i128, align 16
// CHECK-NEXT: [[TMP0:%.*]] = bitcast i128* [[A]] to { i64, i64 }*
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP0]], i32 0, i32 0
// CHECK-NEXT: store i64 [[A_COERCE0]], i64* [[TMP1]], align 16
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP0]], i32 0, i32 1
// CHECK-NEXT: store i64 [[A_COERCE1]], i64* [[TMP2]], align 8
// CHECK-NEXT: [[A1:%.*]] = load i128, i128* [[A]], align 16
// CHECK-NEXT: store i128 [[A1]], i128* [[A_ADDR]], align 16
// CHECK-NEXT: [[TMP3:%.*]] = load i128, i128* [[A_ADDR]], align 16
// CHECK-NEXT: store i128 [[TMP3]], i128* [[COERCE]], align 16
// CHECK-NEXT: [[TMP4:%.*]] = bitcast i128* [[COERCE]] to { i64, i64 }*
// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP4]], i32 0, i32 0
// CHECK-NEXT: [[TMP6:%.*]] = load i64, i64* [[TMP5]], align 16
// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP4]], i32 0, i32 1
// CHECK-NEXT: [[TMP8:%.*]] = load i64, i64* [[TMP7]], align 8
// CHECK-NEXT: [[CALL:%.*]] = call i32* @m3(i64 [[TMP6]], i64 [[TMP8]])
// CHECK-NEXT: [[CASTED_ALIGN:%.*]] = trunc i128 [[TMP3]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 [[CASTED_ALIGN]]) ]
// CHECK-NEXT: [[TMP9:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP9]]
//
__INT32_TYPE__ test5(__int128_t a) {
// CHECK: define i32 @test5
struct Empty e;
return *m3(e, a);
// CHECK: call i32* @m3(i64 %{{.*}}, i64 %{{.*}})
// CHECK: [[ALIGNCAST5:%.+]] = trunc i128 %{{.*}} to i64
// CHECK: [[MASK5:%.+]] = sub i64 [[ALIGNCAST5]], 1
// CHECK: [[PTRINT5:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR5:%.+]] = and i64 [[PTRINT5]], [[MASK5]]
// CHECK: [[MASKCOND5:%.+]] = icmp eq i64 [[MASKEDPTR5]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND5]])
}
// Struct parameter takes up 2 parameters, 'i' takes up 2.
__INT32_TYPE__ *m4(struct MultiArgs s, __int128_t i) __attribute__((alloc_align(2)));
// CHECK-LABEL: define {{[^@]+}}@test6
// CHECK-SAME: (i64 [[A_COERCE0:%.*]], i64 [[A_COERCE1:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A:%.*]] = alloca i128, align 16
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i128, align 16
// CHECK-NEXT: [[E:%.*]] = alloca [[STRUCT_MULTIARGS:%.*]], align 8
// CHECK-NEXT: [[COERCE:%.*]] = alloca i128, align 16
// CHECK-NEXT: [[TMP0:%.*]] = bitcast i128* [[A]] to { i64, i64 }*
// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP0]], i32 0, i32 0
// CHECK-NEXT: store i64 [[A_COERCE0]], i64* [[TMP1]], align 16
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP0]], i32 0, i32 1
// CHECK-NEXT: store i64 [[A_COERCE1]], i64* [[TMP2]], align 8
// CHECK-NEXT: [[A1:%.*]] = load i128, i128* [[A]], align 16
// CHECK-NEXT: store i128 [[A1]], i128* [[A_ADDR]], align 16
// CHECK-NEXT: [[TMP3:%.*]] = load i128, i128* [[A_ADDR]], align 16
// CHECK-NEXT: [[TMP4:%.*]] = bitcast %struct.MultiArgs* [[E]] to { i64, i64 }*
// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP4]], i32 0, i32 0
// CHECK-NEXT: [[TMP6:%.*]] = load i64, i64* [[TMP5]], align 8
// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP4]], i32 0, i32 1
// CHECK-NEXT: [[TMP8:%.*]] = load i64, i64* [[TMP7]], align 8
// CHECK-NEXT: store i128 [[TMP3]], i128* [[COERCE]], align 16
// CHECK-NEXT: [[TMP9:%.*]] = bitcast i128* [[COERCE]] to { i64, i64 }*
// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP9]], i32 0, i32 0
// CHECK-NEXT: [[TMP11:%.*]] = load i64, i64* [[TMP10]], align 16
// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[TMP9]], i32 0, i32 1
// CHECK-NEXT: [[TMP13:%.*]] = load i64, i64* [[TMP12]], align 8
// CHECK-NEXT: [[CALL:%.*]] = call i32* @m4(i64 [[TMP6]], i64 [[TMP8]], i64 [[TMP11]], i64 [[TMP13]])
// CHECK-NEXT: [[CASTED_ALIGN:%.*]] = trunc i128 [[TMP3]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 [[CASTED_ALIGN]]) ]
// CHECK-NEXT: [[TMP14:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP14]]
//
__INT32_TYPE__ test6(__int128_t a) {
// CHECK: define i32 @test6
struct MultiArgs e;
return *m4(e, a);
// CHECK: call i32* @m4(i64 %{{.*}}, i64 %{{.*}}, i64 %{{.*}})
// CHECK: [[ALIGNCAST6:%.+]] = trunc i128 %{{.*}} to i64
// CHECK: [[MASK6:%.+]] = sub i64 [[ALIGNCAST6]], 1
// CHECK: [[PTRINT6:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR6:%.+]] = and i64 [[PTRINT6]], [[MASK6]]
// CHECK: [[MASKCOND6:%.+]] = icmp eq i64 [[MASKEDPTR6]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND6]])
}

Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,8 @@ void *t2_immediate2() {
// CHECK-NEXT: store i32 [[ALIGNMENT:%.*]], i32* [[ALIGNMENT_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ALIGNMENT_ADDR]], align 4
// CHECK-NEXT: [[CALL:%.*]] = call align 32 i8* @my_aligned_alloc(i32 320, i32 [[TMP0]])
// CHECK-NEXT: [[ALIGNMENTCAST:%.*]] = zext i32 [[TMP0]] to i64
// CHECK-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENTCAST]], 1
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], [[MASK]]
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
// CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[CALL]], i64 [[TMP1]]) ]
// CHECK-NEXT: ret i8* [[CALL]]
//
void *t3_variable(int alignment) {
Expand Down
32 changes: 10 additions & 22 deletions clang/test/CodeGen/builtin-align-array.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,26 @@

extern int func(char *c);

// CHECK-LABEL: define {{[^@]+}}@test_array() #0
// CHECK-LABEL: @test_array(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[BUF:%.*]] = alloca [1024 x i8], align 16
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BUF]], i64 0, i64 44
// CHECK-NEXT: [[INTPTR:%.*]] = ptrtoint i8* [[ARRAYIDX]] to i64
// CHECK-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], -16
// CHECK-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// CHECK-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[ARRAYIDX]], i64 [[DIFF]]
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[ALIGNED_RESULT]] to i64
// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 15
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[ALIGNED_RESULT]], i64 16) ]
// CHECK-NEXT: [[CALL:%.*]] = call i32 @func(i8* [[ALIGNED_RESULT]])
// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BUF]], i64 0, i64 22
// CHECK-NEXT: [[INTPTR2:%.*]] = ptrtoint i8* [[ARRAYIDX1]] to i64
// CHECK-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[INTPTR2]], 31
// CHECK-NEXT: [[ALIGNED_INTPTR4:%.*]] = and i64 [[OVER_BOUNDARY]], -32
// CHECK-NEXT: [[DIFF5:%.*]] = sub i64 [[ALIGNED_INTPTR4]], [[INTPTR2]]
// CHECK-NEXT: [[ALIGNED_RESULT6:%.*]] = getelementptr inbounds i8, i8* [[ARRAYIDX1]], i64 [[DIFF5]]
// CHECK-NEXT: [[PTRINT7:%.*]] = ptrtoint i8* [[ALIGNED_RESULT6]] to i64
// CHECK-NEXT: [[MASKEDPTR8:%.*]] = and i64 [[PTRINT7]], 31
// CHECK-NEXT: [[MASKCOND9:%.*]] = icmp eq i64 [[MASKEDPTR8]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND9]])
// CHECK-NEXT: [[CALL10:%.*]] = call i32 @func(i8* [[ALIGNED_RESULT6]])
// CHECK-NEXT: [[ARRAYIDX11:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BUF]], i64 0, i64 16
// CHECK-NEXT: [[SRC_ADDR:%.*]] = ptrtoint i8* [[ARRAYIDX11]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[ALIGNED_RESULT6]], i64 32) ]
// CHECK-NEXT: [[CALL7:%.*]] = call i32 @func(i8* [[ALIGNED_RESULT6]])
// CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BUF]], i64 0, i64 16
// CHECK-NEXT: [[SRC_ADDR:%.*]] = ptrtoint i8* [[ARRAYIDX8]] to i64
// CHECK-NEXT: [[SET_BITS:%.*]] = and i64 [[SRC_ADDR]], 63
// CHECK-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
// CHECK-NEXT: [[CONV:%.*]] = zext i1 [[IS_ALIGNED]] to i32
Expand All @@ -42,30 +36,24 @@ int test_array(void) {
return __builtin_is_aligned(&buf[16], 64);
}

// CHECK-LABEL: define {{[^@]+}}@test_array_should_not_mask() #0
// CHECK-LABEL: @test_array_should_not_mask(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[BUF:%.*]] = alloca [1024 x i8], align 32
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BUF]], i64 0, i64 64
// CHECK-NEXT: [[INTPTR:%.*]] = ptrtoint i8* [[ARRAYIDX]] to i64
// CHECK-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], -16
// CHECK-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// CHECK-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[ARRAYIDX]], i64 [[DIFF]]
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[ALIGNED_RESULT]] to i64
// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 15
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[ALIGNED_RESULT]], i64 16) ]
// CHECK-NEXT: [[CALL:%.*]] = call i32 @func(i8* [[ALIGNED_RESULT]])
// CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BUF]], i64 0, i64 32
// CHECK-NEXT: [[INTPTR2:%.*]] = ptrtoint i8* [[ARRAYIDX1]] to i64
// CHECK-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[INTPTR2]], 31
// CHECK-NEXT: [[ALIGNED_INTPTR4:%.*]] = and i64 [[OVER_BOUNDARY]], -32
// CHECK-NEXT: [[DIFF5:%.*]] = sub i64 [[ALIGNED_INTPTR4]], [[INTPTR2]]
// CHECK-NEXT: [[ALIGNED_RESULT6:%.*]] = getelementptr inbounds i8, i8* [[ARRAYIDX1]], i64 [[DIFF5]]
// CHECK-NEXT: [[PTRINT7:%.*]] = ptrtoint i8* [[ALIGNED_RESULT6]] to i64
// CHECK-NEXT: [[MASKEDPTR8:%.*]] = and i64 [[PTRINT7]], 31
// CHECK-NEXT: [[MASKCOND9:%.*]] = icmp eq i64 [[MASKEDPTR8]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND9]])
// CHECK-NEXT: [[CALL10:%.*]] = call i32 @func(i8* [[ALIGNED_RESULT6]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[ALIGNED_RESULT6]], i64 32) ]
// CHECK-NEXT: [[CALL7:%.*]] = call i32 @func(i8* [[ALIGNED_RESULT6]])
// CHECK-NEXT: ret i32 1
//
int test_array_should_not_mask(void) {
Expand Down
212 changes: 151 additions & 61 deletions clang/test/CodeGen/builtin-align.c
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
/// Check the code generation for the alignment builtins
/// To make the test case easier to read, run SROA after generating IR to remove the alloca instructions.
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_VOID_PTR \
// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
// RUN: FileCheck %s -check-prefixes CHECK,POINTER,ALIGNMENT_EXT \
// RUN: FileCheck %s -check-prefixes CHECK,CHECK-VOID_PTR \
// RUN: -enable-var-scope '-D$PTRTYPE=i8'
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_FLOAT_PTR \
// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
// RUN: FileCheck %s -check-prefixes CHECK,POINTER,NON_I8_POINTER,ALIGNMENT_EXT \
// RUN: FileCheck %s -check-prefixes CHECK,CHECK-FLOAT_PTR \
// RUN: -enable-var-scope '-D$PTRTYPE=f32'
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_LONG \
// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
// RUN: FileCheck %s -check-prefixes CHECK,INTEGER,ALIGNMENT_EXT -enable-var-scope
// RUN: FileCheck %s -check-prefixes CHECK,CHECK-LONG -enable-var-scope
/// Check that we can handle the case where the alignment parameter is wider
/// than the source type (generate a trunc on alignment instead of zext)
// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -DTEST_USHORT \
// RUN: -o - -emit-llvm %s -disable-O0-optnone | opt -S -sroa | \
// RUN: FileCheck %s -check-prefixes CHECK,INTEGER,ALIGNMENT_TRUNC -enable-var-scope
// RUN: FileCheck %s -check-prefixes CHECK,CHECK-USHORT -enable-var-scope


#ifdef TEST_VOID_PTR
Expand All @@ -24,8 +25,6 @@
#define TYPE float *
#elif defined(TEST_LONG)
#define TYPE long
#elif defined(TEST_CAP)
#define TYPE void *__capability
#elif defined(TEST_USHORT)
#define TYPE unsigned short
#else
Expand All @@ -49,78 +48,169 @@ int up_2 = __builtin_align_up(256, 32);
// CHECK: @up_2 = global i32 256, align 4

/// Capture the IR type here to use in the remaining FileCheck captures:
// CHECK: define {{[^@]+}}@get_type() #0
// CHECK-NEXT: entry:
// POINTER-NEXT: ret [[$TYPE:.+]] null
// INTEGER-NEXT: ret [[$TYPE:.+]] 0
// CHECK-VOID_PTR-LABEL: define {{[^@]+}}@get_type() #0
// CHECK-VOID_PTR-NEXT: entry:
// CHECK-VOID_PTR-NEXT: ret i8* null
//
// CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@get_type() #0
// CHECK-FLOAT_PTR-NEXT: entry:
// CHECK-FLOAT_PTR-NEXT: ret float* null
//
// CHECK-LONG-LABEL: define {{[^@]+}}@get_type() #0
// CHECK-LONG-NEXT: entry:
// CHECK-LONG-NEXT: ret i64 0
//
// CHECK-USHORT-LABEL: define {{[^@]+}}@get_type() #0
// CHECK-USHORT-NEXT: entry:
// CHECK-USHORT-NEXT: ret i16 0
//
TYPE get_type(void) {
return (TYPE)0;
}

// CHECK-LABEL: define {{[^@]+}}@is_aligned
// CHECK-SAME: ([[$TYPE]] {{[^%]*}}[[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-NEXT: entry:
// ALIGNMENT_EXT-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to [[ALIGN_TYPE:i64]]
// ALIGNMENT_TRUNC-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to [[ALIGN_TYPE:i16]]
// CHECK-NEXT: [[MASK:%.*]] = sub [[ALIGN_TYPE]] [[ALIGNMENT]], 1
// POINTER-NEXT: [[PTR:%.*]] = ptrtoint [[$TYPE]] %ptr to i64
// CHECK-NEXT: [[SET_BITS:%.*]] = and [[ALIGN_TYPE]] [[PTR]], [[MASK]]
// CHECK-NEXT: [[IS_ALIGNED:%.*]] = icmp eq [[ALIGN_TYPE]] [[SET_BITS]], 0
// CHECK-NEXT: ret i1 [[IS_ALIGNED]]
// CHECK-VOID_PTR-LABEL: define {{[^@]+}}@is_aligned
// CHECK-VOID_PTR-SAME: (i8* [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-VOID_PTR-NEXT: entry:
// CHECK-VOID_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-VOID_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-VOID_PTR-NEXT: [[SRC_ADDR:%.*]] = ptrtoint i8* [[PTR]] to i64
// CHECK-VOID_PTR-NEXT: [[SET_BITS:%.*]] = and i64 [[SRC_ADDR]], [[MASK]]
// CHECK-VOID_PTR-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
// CHECK-VOID_PTR-NEXT: ret i1 [[IS_ALIGNED]]
//
// CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@is_aligned
// CHECK-FLOAT_PTR-SAME: (float* [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-FLOAT_PTR-NEXT: entry:
// CHECK-FLOAT_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-FLOAT_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-FLOAT_PTR-NEXT: [[SRC_ADDR:%.*]] = ptrtoint float* [[PTR]] to i64
// CHECK-FLOAT_PTR-NEXT: [[SET_BITS:%.*]] = and i64 [[SRC_ADDR]], [[MASK]]
// CHECK-FLOAT_PTR-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
// CHECK-FLOAT_PTR-NEXT: ret i1 [[IS_ALIGNED]]
//
// CHECK-LONG-LABEL: define {{[^@]+}}@is_aligned
// CHECK-LONG-SAME: (i64 [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-LONG-NEXT: entry:
// CHECK-LONG-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-LONG-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-LONG-NEXT: [[SET_BITS:%.*]] = and i64 [[PTR]], [[MASK]]
// CHECK-LONG-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i64 [[SET_BITS]], 0
// CHECK-LONG-NEXT: ret i1 [[IS_ALIGNED]]
//
// CHECK-USHORT-LABEL: define {{[^@]+}}@is_aligned
// CHECK-USHORT-SAME: (i16 zeroext [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-USHORT-NEXT: entry:
// CHECK-USHORT-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to i16
// CHECK-USHORT-NEXT: [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
// CHECK-USHORT-NEXT: [[SET_BITS:%.*]] = and i16 [[PTR]], [[MASK]]
// CHECK-USHORT-NEXT: [[IS_ALIGNED:%.*]] = icmp eq i16 [[SET_BITS]], 0
// CHECK-USHORT-NEXT: ret i1 [[IS_ALIGNED]]
//
_Bool is_aligned(TYPE ptr, unsigned align) {
return __builtin_is_aligned(ptr, align);
}

// CHECK-LABEL: define {{[^@]+}}@align_up
// CHECK-SAME: ([[$TYPE]] {{[^%]*}}[[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-NEXT: entry:
// ALIGNMENT_EXT-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to [[ALIGN_TYPE:i64]]
// ALIGNMENT_TRUNC-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to [[ALIGN_TYPE:i16]]
// CHECK-NEXT: [[MASK:%.*]] = sub [[ALIGN_TYPE]] [[ALIGNMENT]], 1
// INTEGER-NEXT: [[OVER_BOUNDARY:%.*]] = add [[$TYPE]] [[PTR]], [[MASK]]
// NOTYET-POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = call [[$TYPE]] @llvm.ptrmask.p0[[$PTRTYPE]].p0i8.i64(i8* [[OVER_BOUNDARY]], [[ALIGN_TYPE]] [[INVERTED_MASK]])
// POINTER-NEXT: [[INTPTR:%.*]] = ptrtoint [[$TYPE]] [[PTR]] to [[ALIGN_TYPE]]
// POINTER-NEXT: [[OVER_BOUNDARY:%.*]] = add [[ALIGN_TYPE]] [[INTPTR]], [[MASK]]
// CHECK-NEXT: [[INVERTED_MASK:%.*]] = xor [[ALIGN_TYPE]] [[MASK]], -1
// CHECK-NEXT: [[ALIGNED_RESULT:%.*]] = and [[ALIGN_TYPE]] [[OVER_BOUNDARY]], [[INVERTED_MASK]]
// POINTER-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_RESULT]], [[INTPTR]]
// NON_I8_POINTER-NEXT: [[PTR:%.*]] = bitcast [[$TYPE]] {{%.*}} to i8*
// POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[DIFF]]
// NON_I8_POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = bitcast i8* {{%.*}} to [[$TYPE]]
// POINTER-NEXT: [[ASSUME_MASK:%.*]] = sub i64 %alignment, 1
// POINTER-NEXT: [[ASSUME_INTPTR:%.*]]= ptrtoint [[$TYPE]] [[ALIGNED_RESULT]] to i64
// POINTER-NEXT: [[MASKEDPTR:%.*]] = and i64 %ptrint, [[ASSUME_MASK]]
// POINTER-NEXT: [[MASKEDCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// POINTER-NEXT: call void @llvm.assume(i1 [[MASKEDCOND]])
// CHECK-NEXT: ret [[$TYPE]] [[ALIGNED_RESULT]]
// CHECK-VOID_PTR-LABEL: define {{[^@]+}}@align_up
// CHECK-VOID_PTR-SAME: (i8* [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-VOID_PTR-NEXT: entry:
// CHECK-VOID_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-VOID_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-VOID_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint i8* [[PTR]] to i64
// CHECK-VOID_PTR-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[INTPTR]], [[MASK]]
// CHECK-VOID_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
// CHECK-VOID_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
// CHECK-VOID_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// CHECK-VOID_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[DIFF]]
// CHECK-VOID_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ]
// CHECK-VOID_PTR-NEXT: ret i8* [[ALIGNED_RESULT]]
//
// CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@align_up
// CHECK-FLOAT_PTR-SAME: (float* [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-FLOAT_PTR-NEXT: entry:
// CHECK-FLOAT_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-FLOAT_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-FLOAT_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint float* [[PTR]] to i64
// CHECK-FLOAT_PTR-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[INTPTR]], [[MASK]]
// CHECK-FLOAT_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
// CHECK-FLOAT_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
// CHECK-FLOAT_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// CHECK-FLOAT_PTR-NEXT: [[TMP0:%.*]] = bitcast float* [[PTR]] to i8*
// CHECK-FLOAT_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[TMP0]], i64 [[DIFF]]
// CHECK-FLOAT_PTR-NEXT: [[TMP1:%.*]] = bitcast i8* [[ALIGNED_RESULT]] to float*
// CHECK-FLOAT_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[TMP1]], i64 [[ALIGNMENT]]) ]
// CHECK-FLOAT_PTR-NEXT: ret float* [[TMP1]]
//
// CHECK-LONG-LABEL: define {{[^@]+}}@align_up
// CHECK-LONG-SAME: (i64 [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-LONG-NEXT: entry:
// CHECK-LONG-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-LONG-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-LONG-NEXT: [[OVER_BOUNDARY:%.*]] = add i64 [[PTR]], [[MASK]]
// CHECK-LONG-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
// CHECK-LONG-NEXT: [[ALIGNED_RESULT:%.*]] = and i64 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
// CHECK-LONG-NEXT: ret i64 [[ALIGNED_RESULT]]
//
// CHECK-USHORT-LABEL: define {{[^@]+}}@align_up
// CHECK-USHORT-SAME: (i16 zeroext [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-USHORT-NEXT: entry:
// CHECK-USHORT-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to i16
// CHECK-USHORT-NEXT: [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
// CHECK-USHORT-NEXT: [[OVER_BOUNDARY:%.*]] = add i16 [[PTR]], [[MASK]]
// CHECK-USHORT-NEXT: [[INVERTED_MASK:%.*]] = xor i16 [[MASK]], -1
// CHECK-USHORT-NEXT: [[ALIGNED_RESULT:%.*]] = and i16 [[OVER_BOUNDARY]], [[INVERTED_MASK]]
// CHECK-USHORT-NEXT: ret i16 [[ALIGNED_RESULT]]
//
TYPE align_up(TYPE ptr, unsigned align) {
return __builtin_align_up(ptr, align);
}

// CHECK-LABEL: define {{[^@]+}}@align_down
// CHECK-SAME: ([[$TYPE]] {{[^%]*}}[[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-NEXT: entry:
// ALIGNMENT_EXT-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to [[ALIGN_TYPE:i64]]
// ALIGNMENT_TRUNC-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to [[ALIGN_TYPE:i16]]
// CHECK-NEXT: [[MASK:%.*]] = sub [[ALIGN_TYPE]] [[ALIGNMENT]], 1
// NOTYET-POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = call [[$TYPE]] @llvm.ptrmask.p0[[$PTRTYPE]].p0[[$PTRTYPE]].i64([[$TYPE]] [[PTR]], [[ALIGN_TYPE]] [[INVERTED_MASK]])
// POINTER-NEXT: [[INTPTR:%.*]] = ptrtoint [[$TYPE]] [[PTR]] to [[ALIGN_TYPE]]
// CHECK-NEXT: [[INVERTED_MASK:%.*]] = xor [[ALIGN_TYPE]] [[MASK]], -1
// POINTER-NEXT: [[ALIGNED_INTPTR:%.*]] = and [[ALIGN_TYPE]] [[INTPTR]], [[INVERTED_MASK]]
// POINTER-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// NON_I8_POINTER-NEXT: [[PTR:%.*]] = bitcast [[$TYPE]] {{%.*}} to i8*
// POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[DIFF]]
// NON_I8_POINTER-NEXT: [[ALIGNED_RESULT:%.*]] = bitcast i8* {{%.*}} to [[$TYPE]]
// INTEGER-NEXT: [[ALIGNED_RESULT:%.*]] = and [[ALIGN_TYPE]] [[PTR]], [[INVERTED_MASK]]
// POINTER-NEXT: [[ASSUME_MASK:%.*]] = sub i64 %alignment, 1
// POINTER-NEXT: [[ASSUME_INTPTR:%.*]]= ptrtoint [[$TYPE]] [[ALIGNED_RESULT]] to i64
// POINTER-NEXT: [[MASKEDPTR:%.*]] = and i64 %ptrint, [[ASSUME_MASK]]
// POINTER-NEXT: [[MASKEDCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// POINTER-NEXT: call void @llvm.assume(i1 [[MASKEDCOND]])
// CHECK-NEXT: ret [[$TYPE]] [[ALIGNED_RESULT]]
// CHECK-VOID_PTR-LABEL: define {{[^@]+}}@align_down
// CHECK-VOID_PTR-SAME: (i8* [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-VOID_PTR-NEXT: entry:
// CHECK-VOID_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-VOID_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-VOID_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint i8* [[PTR]] to i64
// CHECK-VOID_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
// CHECK-VOID_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], [[INVERTED_MASK]]
// CHECK-VOID_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// CHECK-VOID_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i64 [[DIFF]]
// CHECK-VOID_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[ALIGNED_RESULT]], i64 [[ALIGNMENT]]) ]
// CHECK-VOID_PTR-NEXT: ret i8* [[ALIGNED_RESULT]]
//
// CHECK-FLOAT_PTR-LABEL: define {{[^@]+}}@align_down
// CHECK-FLOAT_PTR-SAME: (float* [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-FLOAT_PTR-NEXT: entry:
// CHECK-FLOAT_PTR-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-FLOAT_PTR-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-FLOAT_PTR-NEXT: [[INTPTR:%.*]] = ptrtoint float* [[PTR]] to i64
// CHECK-FLOAT_PTR-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
// CHECK-FLOAT_PTR-NEXT: [[ALIGNED_INTPTR:%.*]] = and i64 [[INTPTR]], [[INVERTED_MASK]]
// CHECK-FLOAT_PTR-NEXT: [[DIFF:%.*]] = sub i64 [[ALIGNED_INTPTR]], [[INTPTR]]
// CHECK-FLOAT_PTR-NEXT: [[TMP0:%.*]] = bitcast float* [[PTR]] to i8*
// CHECK-FLOAT_PTR-NEXT: [[ALIGNED_RESULT:%.*]] = getelementptr inbounds i8, i8* [[TMP0]], i64 [[DIFF]]
// CHECK-FLOAT_PTR-NEXT: [[TMP1:%.*]] = bitcast i8* [[ALIGNED_RESULT]] to float*
// CHECK-FLOAT_PTR-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[TMP1]], i64 [[ALIGNMENT]]) ]
// CHECK-FLOAT_PTR-NEXT: ret float* [[TMP1]]
//
// CHECK-LONG-LABEL: define {{[^@]+}}@align_down
// CHECK-LONG-SAME: (i64 [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-LONG-NEXT: entry:
// CHECK-LONG-NEXT: [[ALIGNMENT:%.*]] = zext i32 [[ALIGN]] to i64
// CHECK-LONG-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENT]], 1
// CHECK-LONG-NEXT: [[INVERTED_MASK:%.*]] = xor i64 [[MASK]], -1
// CHECK-LONG-NEXT: [[ALIGNED_RESULT:%.*]] = and i64 [[PTR]], [[INVERTED_MASK]]
// CHECK-LONG-NEXT: ret i64 [[ALIGNED_RESULT]]
//
// CHECK-USHORT-LABEL: define {{[^@]+}}@align_down
// CHECK-USHORT-SAME: (i16 zeroext [[PTR:%.*]], i32 [[ALIGN:%.*]]) #0
// CHECK-USHORT-NEXT: entry:
// CHECK-USHORT-NEXT: [[ALIGNMENT:%.*]] = trunc i32 [[ALIGN]] to i16
// CHECK-USHORT-NEXT: [[MASK:%.*]] = sub i16 [[ALIGNMENT]], 1
// CHECK-USHORT-NEXT: [[INVERTED_MASK:%.*]] = xor i16 [[MASK]], -1
// CHECK-USHORT-NEXT: [[ALIGNED_RESULT:%.*]] = and i16 [[PTR]], [[INVERTED_MASK]]
// CHECK-USHORT-NEXT: ret i16 [[ALIGNED_RESULT]]
//
TYPE align_down(TYPE ptr, unsigned align) {
return __builtin_align_down(ptr, align);
Expand Down
122 changes: 88 additions & 34 deletions clang/test/CodeGen/builtin-assume-aligned.c
Original file line number Diff line number Diff line change
@@ -1,50 +1,93 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s

// CHECK-LABEL: @test1
// CHECK-LABEL: define {{[^@]+}}@test1
// CHECK-SAME: (i32* [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32*, align 8
// CHECK-NEXT: store i32* [[A]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP0]] to i8*
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[TMP1]], i64 32, i64 0) ]
// CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
// CHECK-NEXT: store i32* [[TMP2]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP3:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[TMP3]], i64 0
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
// CHECK-NEXT: ret i32 [[TMP4]]
//
int test1(int *a) {
// CHECK: [[PTRINT1:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR1:%.+]] = and i64 [[PTRINT1]], 31
// CHECK: [[MASKCOND1:%.+]] = icmp eq i64 [[MASKEDPTR1]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND1]])
a = __builtin_assume_aligned(a, 32, 0ull);
return a[0];
}

// CHECK-LABEL: @test2
// CHECK-LABEL: define {{[^@]+}}@test2
// CHECK-SAME: (i32* [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32*, align 8
// CHECK-NEXT: store i32* [[A]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP0]] to i8*
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[TMP1]], i64 32, i64 0) ]
// CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
// CHECK-NEXT: store i32* [[TMP2]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP3:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[TMP3]], i64 0
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
// CHECK-NEXT: ret i32 [[TMP4]]
//
int test2(int *a) {
// CHECK: [[PTRINT2:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR2:%.+]] = and i64 [[PTRINT2]], 31
// CHECK: [[MASKCOND2:%.+]] = icmp eq i64 [[MASKEDPTR2]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND2]])
a = __builtin_assume_aligned(a, 32, 0);
return a[0];
}

// CHECK-LABEL: @test3
// CHECK-LABEL: define {{[^@]+}}@test3
// CHECK-SAME: (i32* [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32*, align 8
// CHECK-NEXT: store i32* [[A]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP0]] to i8*
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[TMP1]], i64 32) ]
// CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
// CHECK-NEXT: store i32* [[TMP2]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP3:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[TMP3]], i64 0
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
// CHECK-NEXT: ret i32 [[TMP4]]
//
int test3(int *a) {
// CHECK: [[PTRINT3:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR3:%.+]] = and i64 [[PTRINT3]], 31
// CHECK: [[MASKCOND3:%.+]] = icmp eq i64 [[MASKEDPTR3]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND3]])
a = __builtin_assume_aligned(a, 32);
return a[0];
}

// CHECK-LABEL: @test4
// CHECK-LABEL: define {{[^@]+}}@test4
// CHECK-SAME: (i32* [[A:%.*]], i32 [[B:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32*, align 8
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32* [[A]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: store i32 [[B]], i32* [[B_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP0]] to i8*
// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[B_ADDR]], align 4
// CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP2]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[TMP1]], i64 32, i64 [[CONV]]) ]
// CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP1]] to i32*
// CHECK-NEXT: store i32* [[TMP3]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP4:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[TMP4]], i64 0
// CHECK-NEXT: [[TMP5:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
// CHECK-NEXT: ret i32 [[TMP5]]
//
int test4(int *a, int b) {
// CHECK-DAG: [[PTRINT4:%.+]] = ptrtoint
// CHECK-DAG: [[CONV4:%.+]] = sext i32
// CHECK: [[OFFSETPTR4:%.+]] = sub i64 [[PTRINT4]], [[CONV4]]
// CHECK: [[MASKEDPTR4:%.+]] = and i64 [[OFFSETPTR4]], 31
// CHECK: [[MASKCOND4:%.+]] = icmp eq i64 [[MASKEDPTR4]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND4]])
a = __builtin_assume_aligned(a, 32, b);
return a[0];
}

int *m1() __attribute__((assume_aligned(64)));

// CHECK-LABEL: @test5(
// CHECK-LABEL: define {{[^@]+}}@test5() #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[CALL:%.*]] = call align 64 i32* (...) @m1()
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[CALL]], align 4
Expand All @@ -56,22 +99,33 @@ int test5() {

int *m2() __attribute__((assume_aligned(64, 12)));

// CHECK-LABEL: @test6
// CHECK-LABEL: define {{[^@]+}}@test6() #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[CALL:%.*]] = call i32* (...) @m2()
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[CALL]], i64 64, i64 12) ]
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[CALL]], align 4
// CHECK-NEXT: ret i32 [[TMP0]]
//
int test6() {
return *m2();
// CHECK: [[PTRINT6:%.+]] = ptrtoint
// CHECK: [[OFFSETPTR6:%.+]] = sub i64 [[PTRINT6]], 12
// CHECK: [[MASKEDPTR6:%.+]] = and i64 [[OFFSETPTR6]], 63
// CHECK: [[MASKCOND6:%.+]] = icmp eq i64 [[MASKEDPTR6]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND6]])
}

// CHECK-LABEL: @pr43638
// CHECK-LABEL: define {{[^@]+}}@pr43638
// CHECK-SAME: (i32* [[A:%.*]]) #0
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32*, align 8
// CHECK-NEXT: store i32* [[A]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[TMP0]] to i8*
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[TMP1]], i64 536870912) ]
// CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i32*
// CHECK-NEXT: store i32* [[TMP2]], i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[TMP3:%.*]] = load i32*, i32** [[A_ADDR]], align 8
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[TMP3]], i64 0
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[ARRAYIDX]], align 4
// CHECK-NEXT: ret i32 [[TMP4]]
//
int pr43638(int *a) {
a = __builtin_assume_aligned(a, 4294967296);
return a[0];
// CHECK: [[PTRINT7:%.+]] = ptrtoint
// CHECK: [[MASKEDPTR7:%.+]] = and i64 [[PTRINT7]], 536870911
// CHECK: [[MASKCOND7:%.+]] = icmp eq i64 [[MASKEDPTR7]], 0
// CHECK: call void @llvm.assume(i1 [[MASKCOND7]])
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ char **load_from_ac_struct(struct ac_struct *x) {
// CHECK-NEXT: %[[X_RELOADED:.*]] = load %[[STRUCT_AC_STRUCT]]*, %[[STRUCT_AC_STRUCT]]** %[[STRUCT_AC_STRUCT_ADDR]], align 8
// CHECK: %[[A_ADDR:.*]] = getelementptr inbounds %[[STRUCT_AC_STRUCT]], %[[STRUCT_AC_STRUCT]]* %[[X_RELOADED]], i32 0, i32 0
// CHECK: %[[A:.*]] = load i8**, i8*** %[[A_ADDR]], align 8
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[A]] to i64
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[A]] to i64
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[A]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -32,7 +32,7 @@ char **load_from_ac_struct(struct ac_struct *x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[A]], i64 2147483648) ]
// CHECK-NEXT: ret i8** %[[A]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ char **passthrough(__attribute__((align_value(0x80000000))) char **x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[X_RELOADED]], i64 2147483648) ]
// CHECK-NEXT: ret i8** %[[X_RELOADED]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ char **caller(char **x, unsigned long alignment) {
// CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[ALIGNMENT_RELOADED:.*]] = load i64, i64* %[[ALIGNMENT_ADDR]], align 8
// CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]], i64 %[[ALIGNMENT_RELOADED]])
// CHECK-NEXT: %[[MASK:.*]] = sub i64 %[[ALIGNMENT_RELOADED]], 1
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], %[[MASK]]
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64
// CHECK-SANITIZE-NEXT: %[[MASK:.*]] = sub i64 %[[ALIGNMENT_RELOADED]], 1
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], %[[MASK]]
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -42,7 +42,7 @@ char **caller(char **x, unsigned long alignment) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[X_RETURNED]], i64 %1) ]
// CHECK-NEXT: ret i8** %[[X_RETURNED]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ char **caller(char **x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[X_RETURNED]], i64 128) ]
// CHECK-NEXT: ret i8** %[[X_RETURNED]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ char **caller(char **x) {
// CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]])
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64
// CHECK-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], 42
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 2147483647
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64
// CHECK-SANITIZE-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], 42
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 2147483647
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -36,7 +36,7 @@ char **caller(char **x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[X_RETURNED]], i64 2147483648, i64 42) ]
// CHECK-NEXT: ret i8** %[[X_RETURNED]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ char **caller(char **x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 true) [ "align"(i8** %[[X_RETURNED]], i64 128) ]
// CHECK-NEXT: ret i8** %[[X_RETURNED]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ void *caller(char **x, unsigned long offset) {
// CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[BITCAST:.*]] = bitcast i8** %[[X_RELOADED]] to i8*
// CHECK-NEXT: %[[OFFSET_RELOADED:.*]] = load i64, i64* %[[OFFSET_ADDR]], align 8
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64
// CHECK-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], %[[OFFSET_RELOADED]]
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 536870911
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64
// CHECK-SANITIZE-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], %[[OFFSET_RELOADED]]
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 536870911
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[BITCAST]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -28,7 +28,7 @@ void *caller(char **x, unsigned long offset) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* %[[BITCAST]], i64 536870912, i64 %[[OFFSET_RELOADED]]) ]
// CHECK-NEXT: ret i8* %[[BITCAST]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ void *caller(char **x) {
// CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[BITCAST:.*]] = bitcast i8** %[[X_RELOADED]] to i8*
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64
// CHECK-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], 42
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 536870911
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64
// CHECK-SANITIZE-NEXT: %[[OFFSETPTR:.*]] = sub i64 %[[PTRINT]], 42
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[OFFSETPTR]], 536870911
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[BITCAST]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -25,7 +25,7 @@ void *caller(char **x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* %[[BITCAST]], i64 536870912, i64 42) ]
// CHECK-NEXT: ret i8* %[[BITCAST]]
// CHECK-NEXT: }
#line 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ void *caller(char **x) {
// CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[BITCAST:.*]] = bitcast i8** %[[X_RELOADED]] to i8*
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 536870911
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[BITCAST]] to i64
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 536870911
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[BITCAST]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -24,7 +24,7 @@ void *caller(char **x) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* %[[BITCAST]], i64 536870912) ]
// CHECK-NEXT: ret i8* %[[BITCAST]]
// CHECK-NEXT: }
#line 100
Expand Down
8 changes: 4 additions & 4 deletions clang/test/CodeGen/catch-alignment-assumption-openmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ void func(char *data) {
// CHECK-NEXT: %[[DATA_ADDR:.*]] = alloca i8*, align 8
// CHECK: store i8* %[[DATA]], i8** %[[DATA_ADDR]], align 8
// CHECK: %[[DATA_RELOADED:.*]] = load i8*, i8** %[[DATA_ADDR]], align 8
// CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[DATA_RELOADED]] to i64
// CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 1073741823
// CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8* %[[DATA_RELOADED]] to i64
// CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 1073741823
// CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8* %[[DATA_RELOADED]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
Expand All @@ -23,7 +23,7 @@ void func(char *data) {
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
// CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* %[[DATA_RELOADED]], i64 1073741824) ]

#line 100
#pragma omp for simd aligned(data : 0x40000000)
Expand Down
13 changes: 3 additions & 10 deletions clang/test/CodeGen/non-power-of-2-alignment-assumptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ void *__attribute__((alloc_align(1))) alloc(int align);
// CHECK-NEXT: store i32 [[ALIGN:%.*]], i32* [[ALIGN_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ALIGN_ADDR]], align 4
// CHECK-NEXT: [[CALL:%.*]] = call i8* @alloc(i32 [[TMP0]])
// CHECK-NEXT: [[ALIGNMENTCAST:%.*]] = zext i32 [[TMP0]] to i64
// CHECK-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENTCAST]], 1
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], [[MASK]]
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
// CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[CALL]], i64 [[TMP1]]) ]
// CHECK-NEXT: ret void
//
void t0(int align) {
Expand All @@ -25,10 +21,7 @@ void t0(int align) {
// CHECK-NEXT: [[ALIGN_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[ALIGN:%.*]], i32* [[ALIGN_ADDR]], align 4
// CHECK-NEXT: [[CALL:%.*]] = call i8* @alloc(i32 7)
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 6
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
// CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[CALL]], i64 7) ]
// CHECK-NEXT: ret void
//
void t1(int align) {
Expand Down
16 changes: 0 additions & 16 deletions clang/test/OpenMP/simd_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,25 +817,9 @@ void parallel_simd(float *a) {
// TERM_DEBUG: !{{[0-9]+}} = !DILocation(line: [[@LINE-11]],

// CHECK-LABEL: S8
// CHECK-DAG: ptrtoint [[SS_TY]]* %{{.+}} to i64
// CHECK-DAG: ptrtoint [[SS_TY]]* %{{.+}} to i64
// CHECK-DAG: ptrtoint [[SS_TY]]* %{{.+}} to i64
// CHECK-DAG: ptrtoint [[SS_TY]]* %{{.+}} to i64

// CHECK-DAG: and i64 %{{.+}}, 15
// CHECK-DAG: icmp eq i64 %{{.+}}, 0
// CHECK-DAG: call void @llvm.assume(i1

// CHECK-DAG: and i64 %{{.+}}, 7
// CHECK-DAG: icmp eq i64 %{{.+}}, 0
// CHECK-DAG: call void @llvm.assume(i1

// CHECK-DAG: and i64 %{{.+}}, 15
// CHECK-DAG: icmp eq i64 %{{.+}}, 0
// CHECK-DAG: call void @llvm.assume(i1

// CHECK-DAG: and i64 %{{.+}}, 3
// CHECK-DAG: icmp eq i64 %{{.+}}, 0
// CHECK-DAG: call void @llvm.assume(i1
struct SS {
SS(): a(0) {}
Expand Down
117 changes: 45 additions & 72 deletions clang/test/OpenMP/simd_metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,92 +21,65 @@ void h1(float *c, float *a, double b[], int size)
// CHECK-LABEL: define void @h1
int t = 0;
#pragma omp simd safelen(16) linear(t) aligned(c:32) aligned(a,b)
// CHECK: [[C_PTRINT:%.+]] = ptrtoint
// CHECK-NEXT: [[C_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[C_PTRINT]], 31
// CHECK-NEXT: [[C_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[C_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[C_MASKCOND]])
// CHECK: [[A_PTRINT:%.+]] = ptrtoint

// X86-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
// X86-AVX-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 31
// X86-AVX512-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 63
// PPC-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
// PPC-QPX-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15

// CHECK-NEXT: [[A_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[A_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[A_MASKCOND]])
// CHECK: [[B_PTRINT:%.+]] = ptrtoint

// X86-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
// X86-AVX-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 31
// X86-AVX512-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 63
// PPC-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
// PPC-QPX-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 31

// CHECK-NEXT: [[B_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[B_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[B_MASKCOND]])
// CHECK: call void @llvm.assume(i1 true) [ "align"(float* [[PTR4:%.*]], {{i64|i32}} 32) ]
// CHECK-NEXT: load

// X86-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// X86-AVX-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 32) ]
// X86-AVX512-NEXT:call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 64) ]
// PPC-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// PPC-QPX-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// CHECK-NEXT: load

// X86-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 16) ]
// X86-AVX-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 32) ]
// X86-AVX512-NEXT:call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 64) ]
// PPC-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 16) ]
// PPC-QPX-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 32) ]
for (int i = 0; i < size; ++i) {
c[i] = a[i] * a[i] + b[i] * b[t];
++t;
}
// do not emit llvm.access.group metadata due to usage of safelen clause.
// CHECK-NOT: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.access.group {{![0-9]+}}
#pragma omp simd safelen(16) linear(t) aligned(c:32) aligned(a,b) simdlen(8)
// CHECK: [[C_PTRINT:%.+]] = ptrtoint
// CHECK-NEXT: [[C_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[C_PTRINT]], 31
// CHECK-NEXT: [[C_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[C_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[C_MASKCOND]])
// CHECK: [[A_PTRINT:%.+]] = ptrtoint

// X86-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
// X86-AVX-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 31
// X86-AVX512-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 63
// PPC-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
// PPC-QPX-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15

// CHECK-NEXT: [[A_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[A_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[A_MASKCOND]])
// CHECK: [[B_PTRINT:%.+]] = ptrtoint

// X86-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
// X86-AVX-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 31
// X86-AVX512-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 63
// PPC-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
// PPC-QPX-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 31

// CHECK-NEXT: [[B_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[B_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[B_MASKCOND]])
// CHECK: call void @llvm.assume(i1 true) [ "align"(float* [[PTR4:%.*]], {{i64|i32}} 32) ]
// CHECK-NEXT: load

// X86-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// X86-AVX-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 32) ]
// X86-AVX512-NEXT:call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 64) ]
// PPC-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// PPC-QPX-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// CHECK-NEXT: load

// X86-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 16) ]
// X86-AVX-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 32) ]
// X86-AVX512-NEXT:call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 64) ]
// PPC-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 16) ]
// PPC-QPX-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 32) ]
for (int i = 0; i < size; ++i) {
c[i] = a[i] * a[i] + b[i] * b[t];
++t;
}
// do not emit llvm.access.group metadata due to usage of safelen clause.
// CHECK-NOT: store float {{.+}}, float* {{.+}}, align {{.+}}, !llvm.access.group {{![0-9]+}}
#pragma omp simd linear(t) aligned(c:32) aligned(a,b) simdlen(8)
// CHECK: [[C_PTRINT:%.+]] = ptrtoint
// CHECK-NEXT: [[C_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[C_PTRINT]], 31
// CHECK-NEXT: [[C_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[C_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[C_MASKCOND]])
// CHECK: [[A_PTRINT:%.+]] = ptrtoint

// X86-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
// X86-AVX-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 31
// X86-AVX512-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 63
// PPC-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15
// PPC-QPX-NEXT: [[A_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[A_PTRINT]], 15

// CHECK-NEXT: [[A_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[A_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[A_MASKCOND]])
// CHECK: [[B_PTRINT:%.+]] = ptrtoint

// X86-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
// X86-AVX-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 31
// X86-AVX512-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 63
// PPC-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 15
// PPC-QPX-NEXT: [[B_MASKEDPTR:%.+]] = and i{{[0-9]+}} [[B_PTRINT]], 31

// CHECK-NEXT: [[B_MASKCOND:%.+]] = icmp eq i{{[0-9]+}} [[B_MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[B_MASKCOND]])
// CHECK: call void @llvm.assume(i1 true) [ "align"(float* [[PTR4:%.*]], {{i64|i32}} 32) ]
// CHECK-NEXT: load

// X86-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// X86-AVX-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 32) ]
// X86-AVX512-NEXT:call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 64) ]
// PPC-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// PPC-QPX-NEXT: call void @llvm.assume(i1 true) [ "align"(float* [[PTR5:%.*]], {{i64|i32}} 16) ]
// CHECK-NEXT: load

// X86-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 16) ]
// X86-AVX-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 32) ]
// X86-AVX512-NEXT:call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 64) ]
// PPC-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 16) ]
// PPC-QPX-NEXT: call void @llvm.assume(i1 true) [ "align"(double* [[PTR6:%.*]], {{i64|i32}} 32) ]
for (int i = 0; i < size; ++i) {
c[i] = a[i] * a[i] + b[i] * b[t];
++t;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,7 @@ int target_teams_fun(int *g){

// CK1: define internal void @[[OUTL1]]({{.+}})
// CK1: [[ARRDECAY:%.+]] = getelementptr inbounds [1000 x i32], [1000 x i32]* %{{.+}}, i{{32|64}} 0, i{{32|64}} 0
// CK1: [[ARR_CAST:%.+]] = ptrtoint i32* [[ARRDECAY]] to i{{32|64}}
// CK1: [[MASKED_PTR:%.+]] = and i{{32|64}} [[ARR_CAST]], 7
// CK1: [[COND:%.+]] = icmp eq i{{32|64}} [[MASKED_PTR]], 0
// CK1: call void @llvm.assume(i1 [[COND]])
// CK1: call void @llvm.assume(i1 true) [ "align"(i32* [[ARRDECAY]], {{i64|i32}} 8) ]
// CK1: call void @__kmpc_for_static_init_4(
// CK1: call void {{.+}} @__kmpc_fork_call(
// CK1: call void @__kmpc_for_static_fini(
Expand Down
28 changes: 11 additions & 17 deletions llvm/include/llvm/IR/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,11 @@ class IRBuilderBase {

/// Create an assume intrinsic call that allows the optimizer to
/// assume that the provided condition will be true.
CallInst *CreateAssumption(Value *Cond);
///
/// The optional argument \p OpBundles specifies operand bundles that are
/// added to the call instruction.
CallInst *CreateAssumption(Value *Cond,
ArrayRef<OperandBundleDef> OpBundles = llvm::None);

/// Create a call to the experimental.gc.statepoint intrinsic to
/// start a new statepoint sequence.
Expand Down Expand Up @@ -2500,13 +2504,11 @@ class IRBuilderBase {

private:
/// Helper function that creates an assume intrinsic call that
/// represents an alignment assumption on the provided Ptr, Mask, Type
/// and Offset. It may be sometimes useful to do some other logic
/// based on this alignment check, thus it can be stored into 'TheCheck'.
/// represents an alignment assumption on the provided pointer \p PtrValue
/// with offset \p OffsetValue and alignment value \p AlignValue.
CallInst *CreateAlignmentAssumptionHelper(const DataLayout &DL,
Value *PtrValue, Value *Mask,
Type *IntPtrTy, Value *OffsetValue,
Value **TheCheck);
Value *PtrValue, Value *AlignValue,
Value *OffsetValue);

public:
/// Create an assume intrinsic call that represents an alignment
Expand All @@ -2515,13 +2517,9 @@ class IRBuilderBase {
/// An optional offset can be provided, and if it is provided, the offset
/// must be subtracted from the provided pointer to get the pointer with the
/// specified alignment.
///
/// It may be sometimes useful to do some other logic
/// based on this alignment check, thus it can be stored into 'TheCheck'.
CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue,
unsigned Alignment,
Value *OffsetValue = nullptr,
Value **TheCheck = nullptr);
Value *OffsetValue = nullptr);

/// Create an assume intrinsic call that represents an alignment
/// assumption on the provided pointer.
Expand All @@ -2530,15 +2528,11 @@ class IRBuilderBase {
/// must be subtracted from the provided pointer to get the pointer with the
/// specified alignment.
///
/// It may be sometimes useful to do some other logic
/// based on this alignment check, thus it can be stored into 'TheCheck'.
///
/// This overload handles the condition where the Alignment is dependent
/// on an existing value rather than a static value.
CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue,
Value *Alignment,
Value *OffsetValue = nullptr,
Value **TheCheck = nullptr);
Value *OffsetValue = nullptr);
};

/// This provides a uniform API for creating instructions and inserting
Expand Down
13 changes: 10 additions & 3 deletions llvm/lib/Analysis/AssumeBundleQueries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,17 @@ llvm::getKnowledgeFromBundle(CallInst &Assume,
Result.AttrKind = Attribute::getAttrKindFromName(BOI.Tag->getKey());
if (bundleHasArgument(BOI, ABA_WasOn))
Result.WasOn = getValueFromBundleOpInfo(Assume, BOI, ABA_WasOn);
auto GetArgOr1 = [&](unsigned Idx) -> unsigned {
if (auto *ConstInt = dyn_cast<ConstantInt>(
getValueFromBundleOpInfo(Assume, BOI, ABA_Argument + Idx)))
return ConstInt->getZExtValue();
return 1;
};
if (BOI.End - BOI.Begin > ABA_Argument)
Result.ArgValue =
cast<ConstantInt>(getValueFromBundleOpInfo(Assume, BOI, ABA_Argument))
->getZExtValue();
Result.ArgValue = GetArgOr1(0);
if (Result.AttrKind == Attribute::Alignment)
if (BOI.End - BOI.Begin > ABA_Argument + 1)
Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));
return Result;
}

Expand Down
77 changes: 27 additions & 50 deletions llvm/lib/IR/IRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ Value *IRBuilderBase::getCastedInt8PtrValue(Value *Ptr) {
static CallInst *createCallHelper(Function *Callee, ArrayRef<Value *> Ops,
IRBuilderBase *Builder,
const Twine &Name = "",
Instruction *FMFSource = nullptr) {
CallInst *CI = Builder->CreateCall(Callee, Ops, Name);
Instruction *FMFSource = nullptr,
ArrayRef<OperandBundleDef> OpBundles = {}) {
CallInst *CI = Builder->CreateCall(Callee, Ops, OpBundles, Name);
if (FMFSource)
CI->copyFastMathFlags(FMFSource);
return CI;
Expand Down Expand Up @@ -449,14 +450,16 @@ CallInst *IRBuilderBase::CreateInvariantStart(Value *Ptr, ConstantInt *Size) {
return createCallHelper(TheFn, Ops, this);
}

CallInst *IRBuilderBase::CreateAssumption(Value *Cond) {
CallInst *
IRBuilderBase::CreateAssumption(Value *Cond,
ArrayRef<OperandBundleDef> OpBundles) {
assert(Cond->getType() == getInt1Ty() &&
"an assumption condition must be of type i1");

Value *Ops[] = { Cond };
Module *M = BB->getParent()->getParent();
Function *FnAssume = Intrinsic::getDeclaration(M, Intrinsic::assume);
return createCallHelper(FnAssume, Ops, this);
return createCallHelper(FnAssume, Ops, this, "", nullptr, OpBundles);
}

/// Create a call to a Masked Load intrinsic.
Expand Down Expand Up @@ -1107,63 +1110,37 @@ Value *IRBuilderBase::CreatePreserveStructAccessIndex(
return Fn;
}

CallInst *IRBuilderBase::CreateAlignmentAssumptionHelper(
const DataLayout &DL, Value *PtrValue, Value *Mask, Type *IntPtrTy,
Value *OffsetValue, Value **TheCheck) {
Value *PtrIntValue = CreatePtrToInt(PtrValue, IntPtrTy, "ptrint");

if (OffsetValue) {
bool IsOffsetZero = false;
if (const auto *CI = dyn_cast<ConstantInt>(OffsetValue))
IsOffsetZero = CI->isZero();

if (!IsOffsetZero) {
if (OffsetValue->getType() != IntPtrTy)
OffsetValue = CreateIntCast(OffsetValue, IntPtrTy, /*isSigned*/ true,
"offsetcast");
PtrIntValue = CreateSub(PtrIntValue, OffsetValue, "offsetptr");
}
}

Value *Zero = ConstantInt::get(IntPtrTy, 0);
Value *MaskedPtr = CreateAnd(PtrIntValue, Mask, "maskedptr");
Value *InvCond = CreateICmpEQ(MaskedPtr, Zero, "maskcond");
if (TheCheck)
*TheCheck = InvCond;

return CreateAssumption(InvCond);
CallInst *IRBuilderBase::CreateAlignmentAssumptionHelper(const DataLayout &DL,
Value *PtrValue,
Value *AlignValue,
Value *OffsetValue) {
SmallVector<Value *, 4> Vals({PtrValue, AlignValue});
if (OffsetValue)
Vals.push_back(OffsetValue);
OperandBundleDefT<Value *> AlignOpB("align", Vals);
return CreateAssumption(ConstantInt::getTrue(getContext()), {AlignOpB});
}

CallInst *IRBuilderBase::CreateAlignmentAssumption(
const DataLayout &DL, Value *PtrValue, unsigned Alignment,
Value *OffsetValue, Value **TheCheck) {
CallInst *IRBuilderBase::CreateAlignmentAssumption(const DataLayout &DL,
Value *PtrValue,
unsigned Alignment,
Value *OffsetValue) {
assert(isa<PointerType>(PtrValue->getType()) &&
"trying to create an alignment assumption on a non-pointer?");
assert(Alignment != 0 && "Invalid Alignment");
auto *PtrTy = cast<PointerType>(PtrValue->getType());
Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace());

Value *Mask = ConstantInt::get(IntPtrTy, Alignment - 1);
return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy,
OffsetValue, TheCheck);
Value *AlignValue = ConstantInt::get(IntPtrTy, Alignment);
return CreateAlignmentAssumptionHelper(DL, PtrValue, AlignValue, OffsetValue);
}

CallInst *IRBuilderBase::CreateAlignmentAssumption(
const DataLayout &DL, Value *PtrValue, Value *Alignment,
Value *OffsetValue, Value **TheCheck) {
CallInst *IRBuilderBase::CreateAlignmentAssumption(const DataLayout &DL,
Value *PtrValue,
Value *Alignment,
Value *OffsetValue) {
assert(isa<PointerType>(PtrValue->getType()) &&
"trying to create an alignment assumption on a non-pointer?");
auto *PtrTy = cast<PointerType>(PtrValue->getType());
Type *IntPtrTy = getIntPtrTy(DL, PtrTy->getAddressSpace());

if (Alignment->getType() != IntPtrTy)
Alignment = CreateIntCast(Alignment, IntPtrTy, /*isSigned*/ false,
"alignmentcast");

Value *Mask = CreateSub(Alignment, ConstantInt::get(IntPtrTy, 1), "mask");

return CreateAlignmentAssumptionHelper(DL, PtrValue, Mask, IntPtrTy,
OffsetValue, TheCheck);
return CreateAlignmentAssumptionHelper(DL, PtrValue, Alignment, OffsetValue);
}

IRBuilderDefaultInserter::~IRBuilderDefaultInserter() {}
Expand Down
23 changes: 17 additions & 6 deletions llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4449,21 +4449,32 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Assert(Elem.Tag->getKey() == "ignore" ||
Attribute::isExistingAttribute(Elem.Tag->getKey()),
"tags must be valid attribute names");
Assert(Elem.End - Elem.Begin <= 2, "to many arguments");
Attribute::AttrKind Kind =
Attribute::getAttrKindFromName(Elem.Tag->getKey());
unsigned ArgCount = Elem.End - Elem.Begin;
if (Kind == Attribute::Alignment) {
Assert(ArgCount <= 3 && ArgCount >= 2,
"alignment assumptions should have 2 or 3 arguments");
Assert(Call.getOperand(Elem.Begin)->getType()->isPointerTy(),
"first argument should be a pointer");
Assert(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(),
"second argument should be an integer");
if (ArgCount == 3)
Assert(Call.getOperand(Elem.Begin + 2)->getType()->isIntegerTy(),
"third argument should be an integer if present");
return;
}
Assert(ArgCount <= 2, "to many arguments");
if (Kind == Attribute::None)
break;
if (Attribute::doesAttrKindHaveArgument(Kind)) {
Assert(Elem.End - Elem.Begin == 2,
"this attribute should have 2 arguments");
Assert(ArgCount == 2, "this attribute should have 2 arguments");
Assert(isa<ConstantInt>(Call.getOperand(Elem.Begin + 1)),
"the second argument should be a constant integral value");
} else if (isFuncOnlyAttr(Kind)) {
Assert((Elem.End - Elem.Begin) == 0, "this attribute has no argument");
Assert((ArgCount) == 0, "this attribute has no argument");
} else if (!isFuncOrArgAttr(Kind)) {
Assert((Elem.End - Elem.Begin) == 1,
"this attribute should have one argument");
Assert((ArgCount) == 1, "this attribute should have one argument");
}
}
break;
Expand Down
15 changes: 11 additions & 4 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4210,11 +4210,16 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
break;
case Intrinsic::assume: {
Value *IIOperand = II->getArgOperand(0);
SmallVector<OperandBundleDef, 4> OpBundles;
II->getOperandBundlesAsDefs(OpBundles);
bool HasOpBundles = !OpBundles.empty();
// Remove an assume if it is followed by an identical assume.
// TODO: Do we need this? Unless there are conflicting assumptions, the
// computeKnownBits(IIOperand) below here eliminates redundant assumes.
Instruction *Next = II->getNextNonDebugInstruction();
if (match(Next, m_Intrinsic<Intrinsic::assume>(m_Specific(IIOperand))))
if (HasOpBundles &&
match(Next, m_Intrinsic<Intrinsic::assume>(m_Specific(IIOperand))) &&
!cast<IntrinsicInst>(Next)->hasOperandBundles())
return eraseInstFromFunction(CI);

// Canonicalize assume(a && b) -> assume(a); assume(b);
Expand All @@ -4224,14 +4229,15 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
Value *AssumeIntrinsic = II->getCalledOperand();
Value *A, *B;
if (match(IIOperand, m_And(m_Value(A), m_Value(B)))) {
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, A, II->getName());
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, A, OpBundles,
II->getName());
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, B, II->getName());
return eraseInstFromFunction(*II);
}
// assume(!(a || b)) -> assume(!a); assume(!b);
if (match(IIOperand, m_Not(m_Or(m_Value(A), m_Value(B))))) {
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic,
Builder.CreateNot(A), II->getName());
Builder.CreateNot(A), OpBundles, II->getName());
Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic,
Builder.CreateNot(B), II->getName());
return eraseInstFromFunction(*II);
Expand All @@ -4247,7 +4253,8 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
isValidAssumeForContext(II, LHS, &DT)) {
MDNode *MD = MDNode::get(II->getContext(), None);
LHS->setMetadata(LLVMContext::MD_nonnull, MD);
return eraseInstFromFunction(*II);
if (!HasOpBundles)
return eraseInstFromFunction(*II);

// TODO: apply nonnull return attributes to calls and invokes
// TODO: apply range metadata for range check patterns?
Expand Down
112 changes: 23 additions & 89 deletions llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,94 +206,23 @@ bool AlignmentFromAssumptionsPass::extractAlignmentInfo(CallInst *I,
Value *&AAPtr,
const SCEV *&AlignSCEV,
const SCEV *&OffSCEV) {
// An alignment assume must be a statement about the least-significant
// bits of the pointer being zero, possibly with some offset.
ICmpInst *ICI = dyn_cast<ICmpInst>(I->getArgOperand(0));
if (!ICI)
return false;

// This must be an expression of the form: x & m == 0.
if (ICI->getPredicate() != ICmpInst::ICMP_EQ)
return false;

// Swap things around so that the RHS is 0.
Value *CmpLHS = ICI->getOperand(0);
Value *CmpRHS = ICI->getOperand(1);
const SCEV *CmpLHSSCEV = SE->getSCEV(CmpLHS);
const SCEV *CmpRHSSCEV = SE->getSCEV(CmpRHS);
if (CmpLHSSCEV->isZero())
std::swap(CmpLHS, CmpRHS);
else if (!CmpRHSSCEV->isZero())
return false;

BinaryOperator *CmpBO = dyn_cast<BinaryOperator>(CmpLHS);
if (!CmpBO || CmpBO->getOpcode() != Instruction::And)
return false;

// Swap things around so that the right operand of the and is a constant
// (the mask); we cannot deal with variable masks.
Value *AndLHS = CmpBO->getOperand(0);
Value *AndRHS = CmpBO->getOperand(1);
const SCEV *AndLHSSCEV = SE->getSCEV(AndLHS);
const SCEV *AndRHSSCEV = SE->getSCEV(AndRHS);
if (isa<SCEVConstant>(AndLHSSCEV)) {
std::swap(AndLHS, AndRHS);
std::swap(AndLHSSCEV, AndRHSSCEV);
Type *Int64Ty = Type::getInt64Ty(I->getContext());
Optional<OperandBundleUse> AlignOB = I->getOperandBundle("align");
if (AlignOB.hasValue()) {
assert(AlignOB.getValue().Inputs.size() >= 2);
AAPtr = AlignOB.getValue().Inputs[0].get();
// TODO: Consider accumulating the offset to the base.
AAPtr = AAPtr->stripPointerCastsSameRepresentation();
AlignSCEV = SE->getSCEV(AlignOB.getValue().Inputs[1].get());
AlignSCEV = SE->getTruncateOrZeroExtend(AlignSCEV, Int64Ty);
if (AlignOB.getValue().Inputs.size() == 3)
OffSCEV = SE->getSCEV(AlignOB.getValue().Inputs[2].get());
else
OffSCEV = SE->getZero(Int64Ty);
OffSCEV = SE->getTruncateOrZeroExtend(OffSCEV, Int64Ty);
return true;
}

const SCEVConstant *MaskSCEV = dyn_cast<SCEVConstant>(AndRHSSCEV);
if (!MaskSCEV)
return false;

// The mask must have some trailing ones (otherwise the condition is
// trivial and tells us nothing about the alignment of the left operand).
unsigned TrailingOnes = MaskSCEV->getAPInt().countTrailingOnes();
if (!TrailingOnes)
return false;

// Cap the alignment at the maximum with which LLVM can deal (and make sure
// we don't overflow the shift).
uint64_t Alignment;
TrailingOnes = std::min(TrailingOnes,
unsigned(sizeof(unsigned) * CHAR_BIT - 1));
Alignment = std::min(1u << TrailingOnes, +Value::MaximumAlignment);

Type *Int64Ty = Type::getInt64Ty(I->getParent()->getParent()->getContext());
AlignSCEV = SE->getConstant(Int64Ty, Alignment);

// The LHS might be a ptrtoint instruction, or it might be the pointer
// with an offset.
AAPtr = nullptr;
OffSCEV = nullptr;
if (PtrToIntInst *PToI = dyn_cast<PtrToIntInst>(AndLHS)) {
AAPtr = PToI->getPointerOperand();
OffSCEV = SE->getZero(Int64Ty);
} else if (const SCEVAddExpr* AndLHSAddSCEV =
dyn_cast<SCEVAddExpr>(AndLHSSCEV)) {
// Try to find the ptrtoint; subtract it and the rest is the offset.
for (SCEVAddExpr::op_iterator J = AndLHSAddSCEV->op_begin(),
JE = AndLHSAddSCEV->op_end(); J != JE; ++J)
if (const SCEVUnknown *OpUnk = dyn_cast<SCEVUnknown>(*J))
if (PtrToIntInst *PToI = dyn_cast<PtrToIntInst>(OpUnk->getValue())) {
AAPtr = PToI->getPointerOperand();
OffSCEV = SE->getMinusSCEV(AndLHSAddSCEV, *J);
break;
}
}

if (!AAPtr)
return false;

// Sign extend the offset to 64 bits (so that it is like all of the other
// expressions).
unsigned OffSCEVBits = OffSCEV->getType()->getPrimitiveSizeInBits();
if (OffSCEVBits < 64)
OffSCEV = SE->getSignExtendExpr(OffSCEV, Int64Ty);
else if (OffSCEVBits > 64)
return false;

AAPtr = AAPtr->stripPointerCasts();
return true;
return false;
}

bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall) {
Expand All @@ -317,27 +246,32 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall) {
continue;

if (Instruction *K = dyn_cast<Instruction>(J))
if (isValidAssumeForContext(ACall, K, DT))
WorkList.push_back(K);
}

while (!WorkList.empty()) {
Instruction *J = WorkList.pop_back_val();
if (LoadInst *LI = dyn_cast<LoadInst>(J)) {
if (!isValidAssumeForContext(ACall, J, DT))
continue;
Align NewAlignment = getNewAlignment(AASCEV, AlignSCEV, OffSCEV,
LI->getPointerOperand(), SE);
if (NewAlignment > LI->getAlign()) {
LI->setAlignment(NewAlignment);
++NumLoadAlignChanged;
}
} else if (StoreInst *SI = dyn_cast<StoreInst>(J)) {
if (!isValidAssumeForContext(ACall, J, DT))
continue;
Align NewAlignment = getNewAlignment(AASCEV, AlignSCEV, OffSCEV,
SI->getPointerOperand(), SE);
if (NewAlignment > SI->getAlign()) {
SI->setAlignment(NewAlignment);
++NumStoreAlignChanged;
}
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(J)) {
if (!isValidAssumeForContext(ACall, J, DT))
continue;
Align NewDestAlignment =
getNewAlignment(AASCEV, AlignSCEV, OffSCEV, MI->getDest(), SE);

Expand Down Expand Up @@ -369,7 +303,7 @@ bool AlignmentFromAssumptionsPass::processAssumption(CallInst *ACall) {
Visited.insert(J);
for (User *UJ : J->users()) {
Instruction *K = cast<Instruction>(UJ);
if (!Visited.count(K) && isValidAssumeForContext(ACall, K, DT))
if (!Visited.count(K))
WorkList.push_back(K);
}
}
Expand Down
62 changes: 12 additions & 50 deletions llvm/test/Transforms/AlignmentFromAssumptions/simple.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"

define i32 @foo(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i32 32)]
%0 = load i32, i32* %a, align 4
ret i32 %0

Expand All @@ -18,11 +15,7 @@ entry:

define i32 @foo2(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%offsetptr = add i64 %ptrint, 24
%maskedptr = and i64 %offsetptr, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i32 32, i32 24)]
%arrayidx = getelementptr inbounds i32, i32* %a, i64 2
%0 = load i32, i32* %arrayidx, align 4
ret i32 %0
Expand All @@ -34,11 +27,7 @@ entry:

define i32 @foo2a(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%offsetptr = add i64 %ptrint, 28
%maskedptr = and i64 %offsetptr, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i32 32, i32 28)]
%arrayidx = getelementptr inbounds i32, i32* %a, i64 -1
%0 = load i32, i32* %arrayidx, align 4
ret i32 %0
Expand All @@ -50,10 +39,7 @@ entry:

define i32 @goo(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i32 32, i32 0)]
%0 = load i32, i32* %a, align 4
ret i32 %0

Expand All @@ -64,10 +50,7 @@ entry:

define i32 @hoo(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i64 32, i32 0)]
br label %for.body

for.body: ; preds = %entry, %for.body
Expand Down Expand Up @@ -98,10 +81,7 @@ for.end: ; preds = %for.body
; load(a, i0+i1+i2+32)
define void @hoo2(i32* nocapture %a, i64 %id, i64 %num) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i8 32, i64 0)]
%id.mul = shl nsw i64 %id, 6
%num.mul = shl nsw i64 %num, 6
br label %for0.body
Expand Down Expand Up @@ -147,10 +127,7 @@ return:

define i32 @joo(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i8 32, i8 0)]
br label %for.body

for.body: ; preds = %entry, %for.body
Expand All @@ -175,16 +152,13 @@ for.end: ; preds = %for.body

define i32 @koo(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
br label %for.body

for.body: ; preds = %entry, %for.body
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
%r.06 = phi i32 [ 0, %entry ], [ %add, %for.body ]
%arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i8 32, i8 0)]
%0 = load i32, i32* %arrayidx, align 4
%add = add nsw i32 %0, %r.06
%indvars.iv.next = add i64 %indvars.iv, 4
Expand All @@ -203,10 +177,7 @@ for.end: ; preds = %for.body

define i32 @koo2(i32* nocapture %a) nounwind uwtable readonly {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i128 32, i128 0)]
br label %for.body

for.body: ; preds = %entry, %for.body
Expand All @@ -231,10 +202,7 @@ for.end: ; preds = %for.body

define i32 @moo(i32* nocapture %a) nounwind uwtable {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
tail call void @llvm.assume(i1 true) ["align"(i32* %a, i16 32)]
%0 = bitcast i32* %a to i8*
tail call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 64, i1 false)
ret i32 undef
Expand All @@ -246,15 +214,9 @@ entry:

define i32 @moo2(i32* nocapture %a, i32* nocapture %b) nounwind uwtable {
entry:
%ptrint = ptrtoint i32* %a to i64
%maskedptr = and i64 %ptrint, 31
%maskcond = icmp eq i64 %maskedptr, 0
tail call void @llvm.assume(i1 %maskcond)
%ptrint1 = ptrtoint i32* %b to i64
%maskedptr3 = and i64 %ptrint1, 127
%maskcond4 = icmp eq i64 %maskedptr3, 0
tail call void @llvm.assume(i1 %maskcond4)
tail call void @llvm.assume(i1 true) ["align"(i32* %b, i32 128)]
%0 = bitcast i32* %a to i8*
tail call void @llvm.assume(i1 true) ["align"(i8* %0, i16 32)]
%1 = bitcast i32* %b to i8*
tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 %1, i64 64, i1 false)
ret i32 undef
Expand Down
Loading