blob: 62388a3fb0ea93af0876fec236fbc1f4840ba966 [file] [edit]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
int a = 42;
/* --- Compound literals */
struct foo { int x, y; };
int y;
struct foo f = (struct foo){ __builtin_constant_p(y), 42 };
// CIR: cir.global external @f = #cir.const_record<{#cir.int<0> : !s32i, #cir.int<42> : !s32i}> : !rec_foo
// LLVM: @f = global %struct.foo { i32 0, i32 42 }
// OGCG: @f = global %struct.foo { i32 0, i32 42 }
struct foo test0(int expr) {
struct foo f = (struct foo){ __builtin_constant_p(expr), 42 };
return f;
}
// CIR: cir.func {{.*}} @test0(%[[ARG0:.*]]: !s32i {{.*}}) -> !rec_foo
// CIR: %[[EXPR_ADDR:.*]] = cir.alloca "expr" {{.*}} init : !cir.ptr<!s32i>
// CIR: cir.store %[[ARG0]], %[[EXPR_ADDR]]
// CIR: %[[EXPR:.*]] = cir.load{{.*}} %[[EXPR_ADDR]]
// CIR: %[[IS_CONSTANT:.*]] = cir.is_constant %[[EXPR]] : !s32i -> !cir.bool
// LLVM: define{{.*}} %struct.foo @test0(i32 {{.*}} %[[ARG0:.*]])
// LLVM: %[[EXPR_ADDR:.*]] = alloca i32
// LLVM: store i32 %[[ARG0]], ptr %[[EXPR_ADDR]]
// LLVM: %[[EXPR:.*]] = load i32, ptr %[[EXPR_ADDR]]
// LLVM: %[[IS_CONSTANT:.*]] = call i1 @llvm.is.constant.i32(i32 %[[EXPR]])
// OGCG: define{{.*}} i64 @test0(i32 {{.*}} %[[ARG0:.*]])
// OGCG: %[[EXPR_ADDR:.*]] = alloca i32
// OGCG: store i32 %[[ARG0]], ptr %[[EXPR_ADDR]]
// OGCG: %[[EXPR:.*]] = load i32, ptr %[[EXPR_ADDR]]
// OGCG: %[[IS_CONSTANT:.*]] = call i1 @llvm.is.constant.i32(i32 %[[EXPR]])
/* --- Pointer types */
int test1(void) {
return __builtin_constant_p(&a - 13);
}
// CIR: cir.func {{.*}} @test1() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store %[[ZERO]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test1()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 0, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test1()
// OGCG: ret i32 0
/* --- Aggregate types */
int b[] = {1, 2, 3};
int test2(void) {
return __builtin_constant_p(b);
}
// CIR: cir.func {{.*}} @test2() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store %[[ZERO]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test2()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 0, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test2()
// OGCG: ret i32 0
const char test3_c[] = {1, 2, 3, 0};
int test3(void) {
return __builtin_constant_p(test3_c);
}
// CIR: cir.func {{.*}} @test3() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store %[[ZERO]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test3()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 0, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test3()
// OGCG: ret i32 0
inline char test4_i(const char *x) {
return x[1];
}
int test4(void) {
return __builtin_constant_p(test4_i(test3_c));
}
// CIR: cir.func {{.*}} @test4() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store %[[ZERO]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test4()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 0, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test4()
// OGCG: ret i32 0
/* --- Constant global variables */
const int c = 42;
int test5(void) {
return __builtin_constant_p(c);
}
// CIR: cir.func {{.*}} @test5() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store %[[ONE]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test5()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 1, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test5()
// OGCG: ret i32 1
/* --- Array types */
int arr[] = { 1, 2, 3 };
int test6(void) {
return __builtin_constant_p(arr[2]);
}
// CIR: cir.func {{.*}} @test6() -> !s32i
// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s64i
// CIR: %[[ARR:.*]] = cir.get_global @arr : !cir.ptr<!cir.array<!s32i x 3>>
// CIR: %[[ELE_PTR:.*]] = cir.get_element %[[ARR]][%[[TWO]] : !s64i] : !cir.ptr<!cir.array<!s32i x 3>> -> !cir.ptr<!s32i>
// CIR: %[[ELE:.*]] = cir.load{{.*}} %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[IS_CONSTANT:.*]] = cir.is_constant %[[ELE]] : !s32i -> !cir.bool
// LLVM: define {{.*}} i32 @test6()
// LLVM: %[[TMP1:.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @arr, i64 8)
// LLVM: %[[TMP2:.*]] = call i1 @llvm.is.constant.i32(i32 %[[TMP1]])
// OGCG: define {{.*}} i32 @test6()
// OGCG: %[[TMP1:.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @arr, i64 8)
// OGCG: %[[TMP2:.*]] = call i1 @llvm.is.constant.i32(i32 %[[TMP1]])
const int c_arr[] = { 1, 2, 3 };
int test7(void) {
return __builtin_constant_p(c_arr[2]);
}
// CIR: cir.func {{.*}} @test7() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store %[[ONE]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test7()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 1, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test7()
// OGCG: ret i32 1
int test8(void) {
return __builtin_constant_p(c_arr);
}
// CIR: cir.func {{.*}} @test8() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store %[[ZERO]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test8()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 0, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test8()
// OGCG: ret i32 0
/* --- Function pointers */
int test9(void) {
return __builtin_constant_p(&test9);
}
// CIR: cir.func {{.*}} @test9() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store %[[ZERO]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test9()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 0, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test9()
// OGCG: ret i32 0
int test10(void) {
return __builtin_constant_p(&test10 != 0);
}
// CIR: cir.func {{.*}} @test10() -> !s32i
// CIR: %[[TMP1:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store %[[ONE]], %[[TMP1]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[TMP2]] : !s32i
// LLVM: define{{.*}} i32 @test10()
// LLVM: %[[TMP1:.*]] = alloca i32
// LLVM: store i32 1, ptr %[[TMP1]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[TMP1]]
// LLVM: ret i32 %[[TMP2]]
// OGCG: define{{.*}} i32 @test10()
// OGCG: ret i32 1
int test11_f(void);
void test11(void) {
int a, b;
(void)__builtin_constant_p((a = b, test11_f()));
}
// CIR: cir.func {{.*}} @test11()
// CIR-NOT: call {{.*}}test11_f
// LLVM: define{{.*}} void @test11()
// LLVM-NOT: call {{.*}}test11_f
// OGCG: define{{.*}} void @test11()
// OGCG-NOT: call {{.*}}test11_f