1+ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -std=c++2a -o %t.ll
2+ // RUN: FileCheck -check-prefix=CHECK-FN-CG -input-file=%t.ll %s
3+ // RUN: FileCheck -check-prefix=CHECK-STATIC -input-file=%t.ll %s
4+ // RUN: FileCheck -check-prefix=CHECK-DYN -input-file=%t.ll %s
5+ // RUN: FileCheck -check-prefix=CHECK-ARR -input-file=%t.ll %s
6+ // RUN: FileCheck -check-prefix=CHECK-FOLD -input-file=%t.ll %s
7+
8+ using size_t = decltype (sizeof (int ));
9+
10+ #define CONSTINIT __attribute__ ((require_constant_initialization))
11+
12+ extern "C" [[noreturn]] void BOOM();
13+ extern " C" void OK ();
14+ extern " C" size_t RANDU ();
15+
16+ namespace std {
17+ inline constexpr bool is_constant_evaluated () noexcept {
18+ return __builtin_is_constant_evaluated ();
19+ }
20+ } // namespace std
21+
22+ // CHECK-FN-CG-LABEL: define zeroext i1 @_Z3foov()
23+ // CHECK-FN-CG: ret i1 false
24+ bool foo () {
25+ return __builtin_is_constant_evaluated ();
26+ }
27+
28+ // CHECK-FN-CG-LABEL: define linkonce_odr i32 @_Z1fv()
29+ constexpr int f () {
30+ // CHECK-FN-CG: store i32 13, i32* %n, align 4
31+ // CHECK-FN-CG: store i32 17, i32* %m, align 4
32+ // CHECK-FN-CG: %1 = load i32, i32* %m, align 4
33+ // CHECK-FN-CG: %add = add nsw i32 %1, 13
34+ // CHECK-FN-CG: ret i32 %add
35+ const int n = __builtin_is_constant_evaluated () && std::is_constant_evaluated () ? 13 : 17 ; // n == 13
36+ int m = __builtin_is_constant_evaluated () ? 13 : 17 ; // m might be 13 or 17 (see below)
37+ char arr[n] = {}; // char[13]
38+ return m + int (sizeof (arr));
39+ }
40+
41+ // CHECK-STATIC-DAG: @p = global i32 26,
42+ CONSTINIT int p = f(); // f().m == 13; initialized to 26
43+ // CHECK-STATIC-DAG: @p2 = global i32 26,
44+ int p2 = f(); // same result without CONSTINIT
45+
46+ // CHECK-DYN-LABEL: define internal void @__cxx_global_var_init()
47+ // CHECK-DYN: %0 = load i32, i32* @p, align 4
48+ // CHECK-DYN-NEXT: %call = call i32 @_Z1fv()
49+ // CHECK-DYN-NEXT: %add = add nsw i32 %0, %call
50+ // CHECK-DYN-NEXT: store i32 %add, i32* @q, align 4
51+ // CHECK-DYN-NEXT: ret void
52+ int q = p + f(); // m == 17 for this call; initialized to 56
53+
54+ int y;
55+
56+ // CHECK-STATIC-DAG: @b = global i32 2,
57+ CONSTINIT int b = __builtin_is_constant_evaluated() ? 2 : y; // static initialization to 2
58+
59+ // CHECK-DYN-LABEL: define internal void @__cxx_global_var_init.1()
60+ // CHECK-DYN: %0 = load i32, i32* @y, align 4
61+ // CHECK-DYN: %1 = load i32, i32* @y, align 4
62+ // CHECK-DYN-NEXT: %add = add
63+ // CHECK-DYN-NEXT: store i32 %add, i32* @c,
64+ int c = y + (__builtin_is_constant_evaluated() ? 2 : y); // dynamic initialization to y+y
65+
66+ // CHECK-DYN-LABEL: define internal void @__cxx_global_var_init.2()
67+ // CHECK-DYN: store i32 1, i32* @_ZL1a, align 4
68+ // CHECK-DYN-NEXT: ret void
69+ const int a = __builtin_is_constant_evaluated() ? y : 1 ; // dynamic initialization to 1
70+ const int *a_sink = &a;
71+
72+ // CHECK-ARR-LABEL: define void @_Z13test_arr_exprv
73+ void test_arr_expr () {
74+ // CHECK-ARR: %x1 = alloca [101 x i8],
75+ char x1[std::is_constant_evaluated () && __builtin_is_constant_evaluated () ? 101 : 1 ];
76+
77+ // CHECK-ARR: %x2 = alloca [42 x i8],
78+ char x2[std::is_constant_evaluated () && __builtin_is_constant_evaluated () ? 42 : RANDU ()];
79+
80+ // CHECK-ARR: call i8* @llvm.stacksave()
81+ // CHECK-ARR: %vla = alloca i8, i64 13,
82+ char x3[std::is_constant_evaluated () || __builtin_is_constant_evaluated () ? RANDU () : 13 ];
83+ }
84+
85+ // CHECK-ARR-LABEL: define void @_Z17test_new_arr_exprv
86+ void test_new_arr_expr () {
87+ // CHECK-ARR: call i8* @_Znam(i64 17)
88+ new char [std::is_constant_evaluated () || __builtin_is_constant_evaluated () ? 1 : 17 ];
89+ }
90+
91+ // CHECK-FOLD-LABEL: @_Z31test_constant_initialized_locali(
92+ bool test_constant_initialized_local (int k) {
93+ // CHECK-FOLD: store i8 1, i8* %n,
94+ // CHECK-FOLD: store volatile i8* %n, i8** %p,
95+ const bool n = __builtin_is_constant_evaluated () && std::is_constant_evaluated ();
96+ const bool *volatile p = &n;
97+ return *p;
98+ }
99+
100+ // CHECK-FOLD-LABEL: define void @_Z21test_ir_constant_foldv()
101+ void test_ir_constant_fold () {
102+ // CHECK-FOLD-NEXT: entry:
103+ // CHECK-FOLD-NEXT: call void @OK()
104+ // CHECK-FOLD-NEXT: call void @OK()
105+ // CHECK-FOLD-NEXT: ret void
106+ if (std::is_constant_evaluated ()) {
107+ BOOM ();
108+ } else {
109+ OK ();
110+ }
111+ std::is_constant_evaluated () ? BOOM () : OK ();
112+ }
113+
114+ // CHECK-STATIC-DAG: @ir = constant i32* @i_constant,
115+ int i_constant;
116+ int i_not_constant;
117+ int &ir = __builtin_is_constant_evaluated() ? i_constant : i_not_constant;
118+
119+ // CHECK-FOLD-LABEL: @_Z35test_ref_initialization_local_scopev()
120+ void test_ref_initialization_local_scope () {
121+ const int i_constant = 42 ;
122+ const int i_non_constant = 101 ;
123+ // CHECK-FOLD: store i32* %i_non_constant, i32** %r,
124+ const int &r = __builtin_is_constant_evaluated () ? i_constant : i_non_constant;
125+ }
126+
127+ // CHECK-FOLD-LABEL: @_Z22test_ref_to_static_varv()
128+ void test_ref_to_static_var () {
129+ static int i_constant = 42 ;
130+ static int i_non_constant = 101 ;
131+ // CHECK-FOLD: store i32* @_ZZ22test_ref_to_static_varvE10i_constant, i32** %r,
132+ int &r = __builtin_is_constant_evaluated () ? i_constant : i_non_constant;
133+ }
0 commit comments