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 }