Richard Smith | 520a37f | 2019-02-05 23:37:13 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=1 -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-IMPORT,CHECK-NO-NS,CHECK-IMPORT-NO-NS --implicit-check-not=unused |
| 2 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=1 -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-IMPORT,CHECK-NS,CHECK-IMPORT-NS --implicit-check-not=unused |
| 3 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=2 -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-NS --implicit-check-not=unused |
| 4 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DIMPORT=2 -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NS --implicit-check-not=unused |
| 5 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NO-NS --implicit-check-not=unused |
| 6 | // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -DNS -fmodules %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-NS --implicit-check-not=unused |
| 7 | |
| 8 | // Check that we behave sensibly when importing a header containing strong and |
| 9 | // weak, ordered and unordered global initializers. |
| 10 | // |
| 11 | // Our behavior is as follows: |
| 12 | // |
| 13 | // -- for variables with one or more specific points of initialization |
| 14 | // (non-template variables, whether or not they are inline or thread_local), |
| 15 | // emit them if (and only if) a header containing a point of initialization |
| 16 | // is transitively #included / imported. |
| 17 | // |
| 18 | // -- for variables with unordered initialization (any kind of templated |
| 19 | // variable -- excluding explicit specializations), emit them if any part |
| 20 | // of any module that triggers an instantiation is imported. |
| 21 | // |
| 22 | // The intent is to: |
| 23 | // |
| 24 | // 1) preserve order of initialization guarantees |
| 25 | // 2) preserve the behavior of globals with ctors in headers, and specifically |
| 26 | // of std::ios_base::Init (do not run the iostreams initializer nor force |
| 27 | // linking in the iostreams portion of the static library unless <iostream> |
| 28 | // is included) |
| 29 | // 3) behave conservatively-correctly with regard to unordered initializers: we |
| 30 | // might run them in cases where a traditional compilation would not, but |
| 31 | // will never fail to run them in cases where a traditional compilation |
| 32 | // would do so |
| 33 | // |
| 34 | // Perfect handling of unordered initializers would require tracking all |
| 35 | // submodules containing points of instantiation, which is very hard when those |
| 36 | // points of instantiation are within definitions that we skip because we |
| 37 | // already have a (non-visible) definition for the entity: |
| 38 | // |
| 39 | // // a.h |
| 40 | // template<typename> int v = f(); |
| 41 | // inline int get() { return v<int>; } |
| 42 | // |
| 43 | // // b.h |
| 44 | // template<typename> int v = f(); |
| 45 | // inline int get() { return v<int>; } |
| 46 | // |
| 47 | // If a.h and b.h are built as a module, we will only have a point of |
| 48 | // instantiation for v<int> in one of the two headers, because we will only |
| 49 | // parse one of the two get() functions. |
| 50 | |
| 51 | #pragma clang module build m |
| 52 | module m { |
| 53 | module a { |
| 54 | header "foo.h" { size 123 mtime 456789 } |
| 55 | } |
| 56 | module b {} |
| 57 | } |
| 58 | |
| 59 | #pragma clang module contents |
| 60 | #pragma clang module begin m.a |
| 61 | inline int non_trivial() { return 3; } |
| 62 | |
| 63 | #ifdef NS |
| 64 | namespace ns { |
| 65 | #endif |
| 66 | |
| 67 | int a = non_trivial(); |
| 68 | inline int b = non_trivial(); |
| 69 | thread_local int c = non_trivial(); |
| 70 | inline thread_local int d = non_trivial(); |
| 71 | |
| 72 | template<typename U> int e = non_trivial(); |
| 73 | template<typename U> inline int f = non_trivial(); |
| 74 | template<typename U> thread_local int g = non_trivial(); |
| 75 | template<typename U> inline thread_local int h = non_trivial(); |
| 76 | |
| 77 | inline int unused = 123; // should not be emitted |
| 78 | |
| 79 | template<typename T> struct X { |
| 80 | static int a; |
| 81 | static inline int b = non_trivial(); |
| 82 | static thread_local int c; |
| 83 | static inline thread_local int d = non_trivial(); |
| 84 | |
| 85 | template<typename U> static int e; |
| 86 | template<typename U> static inline int f = non_trivial(); |
| 87 | template<typename U> static thread_local int g; |
| 88 | template<typename U> static inline thread_local int h = non_trivial(); |
| 89 | |
| 90 | static inline int unused = 123; // should not be emitted |
| 91 | }; |
| 92 | |
| 93 | template<typename T> int X<T>::a = non_trivial(); |
| 94 | template<typename T> thread_local int X<T>::c = non_trivial(); |
| 95 | template<typename T> template<typename U> int X<T>::e = non_trivial(); |
| 96 | template<typename T> template<typename U> thread_local int X<T>::g = non_trivial(); |
| 97 | |
| 98 | inline void use(bool b, ...) { |
| 99 | if (b) return; |
| 100 | use(true, e<int>, f<int>, g<int>, h<int>, |
| 101 | X<int>::a, X<int>::b, X<int>::c, X<int>::d, |
| 102 | X<int>::e<int>, X<int>::f<int>, X<int>::g<int>, X<int>::h<int>); |
| 103 | } |
| 104 | |
| 105 | #ifdef NS |
| 106 | } |
| 107 | #endif |
| 108 | |
| 109 | #pragma clang module end |
| 110 | #pragma clang module endbuild |
| 111 | |
| 112 | #if IMPORT == 1 |
| 113 | // Import the module and the m.a submodule; runs the ordered initializers and |
| 114 | // the unordered initializers. |
| 115 | #pragma clang module import m.a |
| 116 | #elif IMPORT == 2 |
| 117 | // Import the module but not the m.a submodule; runs only the unordered |
| 118 | // initializers. |
| 119 | #pragma clang module import m.b |
| 120 | #else |
| 121 | // Load the module but do not import any submodules; runs only the unordered |
| 122 | // initializers. FIXME: Should this skip all of them? |
| 123 | #pragma clang module load m |
| 124 | #endif |
| 125 | |
| 126 | // CHECK-IMPORT-NO-NS-DAG: @[[A:a]] = global i32 0, align 4 |
| 127 | // CHECK-IMPORT-NO-NS-DAG: @[[B:b]] = linkonce_odr global i32 0, comdat, align 4 |
| 128 | // CHECK-IMPORT-NO-NS-DAG: @[[C:c]] = thread_local global i32 0, align 4 |
| 129 | // CHECK-IMPORT-NO-NS-DAG: @[[D:d]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 130 | // CHECK-NO-NS-DAG: @[[E:_Z1eIiE]] = linkonce_odr global i32 0, comdat, align 4 |
| 131 | // CHECK-NO-NS-DAG: @[[F:_Z1fIiE]] = linkonce_odr global i32 0, comdat, align 4 |
| 132 | // CHECK-NO-NS-DAG: @[[G:_Z1gIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 133 | // CHECK-NO-NS-DAG: @[[H:_Z1hIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 134 | |
| 135 | // CHECK-IMPORT-NS-DAG: @[[A:_ZN2ns1aE]] = global i32 0, align 4 |
| 136 | // CHECK-IMPORT-NS-DAG: @[[B:_ZN2ns1bE]] = linkonce_odr global i32 0, comdat, align 4 |
| 137 | // CHECK-IMPORT-NS-DAG: @[[BG:_ZGVN2ns1bE]] = linkonce_odr global i64 0, comdat($[[B]]), align 8 |
| 138 | // CHECK-IMPORT-NS-DAG: @[[C:_ZN2ns1cE]] = thread_local global i32 0, align 4 |
| 139 | // CHECK-IMPORT-NS-DAG: @[[D:_ZN2ns1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 140 | // CHECK-IMPORT-NS-DAG: @[[DG:_ZGVN2ns1dE]] = linkonce_odr thread_local global i64 0, comdat($[[D]]), align 8 |
| 141 | // CHECK-NS-DAG: @[[E:_ZN2ns1eIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
| 142 | // CHECK-NS-DAG: @[[F:_ZN2ns1fIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
| 143 | // CHECK-NS-DAG: @[[G:_ZN2ns1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 144 | // CHECK-NS-DAG: @[[H:_ZN2ns1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 145 | |
| 146 | // CHECK-DAG: @[[XA:_ZN(2ns)?1XIiE1aE]] = linkonce_odr global i32 0, comdat, align 4 |
| 147 | // CHECK-DAG: @[[XB:_ZN(2ns)?1XIiE1bE]] = linkonce_odr global i32 0, comdat, align 4 |
| 148 | // CHECK-DAG: @[[XC:_ZN(2ns)?1XIiE1cE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 149 | // CHECK-DAG: @[[XD:_ZN(2ns)?1XIiE1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 150 | // CHECK-DAG: @[[XE:_ZN(2ns)?1XIiE1eIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
| 151 | // CHECK-DAG: @[[XF:_ZN(2ns)?1XIiE1fIiEE]] = linkonce_odr global i32 0, comdat, align 4 |
| 152 | // CHECK-DAG: @[[XG:_ZN(2ns)?1XIiE1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 153 | // CHECK-DAG: @[[XH:_ZN(2ns)?1XIiE1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4 |
| 154 | |
| 155 | // It's OK if the order of the first 6 of these changes. |
| 156 | // CHECK: @llvm.global_ctors = appending global |
| 157 | // CHECK-SAME: @[[E_INIT:[^,]*]], {{[^@]*}} @[[E]] |
| 158 | // CHECK-SAME: @[[F_INIT:[^,]*]], {{[^@]*}} @[[F]] |
| 159 | // CHECK-SAME: @[[XA_INIT:[^,]*]], {{[^@]*}} @[[XA]] |
| 160 | // CHECK-SAME: @[[XE_INIT:[^,]*]], {{[^@]*}} @[[XE]] |
| 161 | // CHECK-SAME: @[[XF_INIT:[^,]*]], {{[^@]*}} @[[XF]] |
| 162 | // CHECK-SAME: @[[XB_INIT:[^,]*]], {{[^@]*}} @[[XB]] |
| 163 | // CHECK-IMPORT-SAME: @[[TU_INIT:[^,]*]], i8* null }] |
| 164 | |
| 165 | // FIXME: Should this use __cxa_guard_acquire? |
| 166 | // CHECK: define {{.*}} @[[E_INIT]]() |
| 167 | // CHECK: load {{.*}} (i64* @_ZGV |
| 168 | // CHECK: store {{.*}}, i32* @[[E]], |
| 169 | |
| 170 | // FIXME: Should this use __cxa_guard_acquire? |
| 171 | // CHECK: define {{.*}} @[[F_INIT]]() |
| 172 | // CHECK: load {{.*}} (i64* @_ZGV |
| 173 | // CHECK: store {{.*}}, i32* @[[F]], |
| 174 | |
| 175 | // CHECK: define {{.*}} @[[G_INIT:__cxx_global.*]]() |
| 176 | // CHECK: load {{.*}} (i64* @_ZGV |
| 177 | // CHECK: store {{.*}}, i32* @[[G]], |
| 178 | |
| 179 | // CHECK: define {{.*}} @[[H_INIT:__cxx_global.*]]() |
| 180 | // CHECK: load {{.*}} (i64* @_ZGV |
| 181 | // CHECK: store {{.*}}, i32* @[[H]], |
| 182 | |
| 183 | // FIXME: Should this use __cxa_guard_acquire? |
| 184 | // CHECK: define {{.*}} @[[XA_INIT]]() |
| 185 | // CHECK: load {{.*}} (i64* @_ZGV |
| 186 | // CHECK: store {{.*}}, i32* @[[XA]], |
| 187 | |
| 188 | // CHECK: define {{.*}} @[[XC_INIT:__cxx_global.*]]() |
| 189 | // CHECK: load {{.*}} (i64* @_ZGV |
| 190 | // CHECK: store {{.*}}, i32* @[[XC]], |
| 191 | |
| 192 | // FIXME: Should this use __cxa_guard_acquire? |
| 193 | // CHECK: define {{.*}} @[[XE_INIT]]() |
| 194 | // CHECK: load {{.*}} (i64* @_ZGV |
| 195 | // CHECK: store {{.*}}, i32* @[[XE]], |
| 196 | |
| 197 | // CHECK: define {{.*}} @[[XG_INIT:__cxx_global.*]]() |
| 198 | // CHECK: load {{.*}} (i64* @_ZGV |
| 199 | // CHECK: store {{.*}}, i32* @[[XG]], |
| 200 | |
| 201 | // CHECK: define {{.*}} @[[XH_INIT:__cxx_global.*]]() |
| 202 | // CHECK: load {{.*}} (i64* @_ZGV |
| 203 | // CHECK: store {{.*}}, i32* @[[XH]], |
| 204 | |
| 205 | // FIXME: Should this use __cxa_guard_acquire? |
| 206 | // CHECK: define {{.*}} @[[XF_INIT]]() |
| 207 | // CHECK: load {{.*}} (i64* @_ZGV |
| 208 | // CHECK: store {{.*}}, i32* @[[XF]], |
| 209 | |
| 210 | // CHECK: define {{.*}} @[[XD_INIT:__cxx_global.*]]() |
| 211 | // CHECK: load {{.*}} (i64* @_ZGV |
| 212 | // CHECK: store {{.*}}, i32* @[[XD]], |
| 213 | |
| 214 | // FIXME: Should this use __cxa_guard_acquire? |
| 215 | // CHECK: define {{.*}} @[[XB_INIT]]() |
| 216 | // CHECK: load {{.*}} (i64* @_ZGV |
| 217 | // CHECK: store {{.*}}, i32* @[[XB]], |
| 218 | |
| 219 | // CHECK-IMPORT: define {{.*}} @[[A_INIT:__cxx_global.*]]() |
| 220 | // CHECK-IMPORT: call i32 @_Z11non_trivialv( |
| 221 | // CHECK-IMPORT: store {{.*}}, i32* @[[A]], |
| 222 | |
| 223 | // CHECK-IMPORT: define {{.*}} @[[B_INIT:__cxx_global.*]]() |
| 224 | // CHECK-IMPORT: call i32 @__cxa_guard_acquire(i64* @_ZGV |
| 225 | // CHECK-IMPORT: store {{.*}}, i32* @[[B]], |
| 226 | |
| 227 | // CHECK-IMPORT: define {{.*}} @[[C_INIT:__cxx_global.*]]() |
| 228 | // CHECK-IMPORT: call i32 @_Z11non_trivialv( |
| 229 | // CHECK-IMPORT: store {{.*}}, i32* @[[C]], |
| 230 | |
| 231 | // CHECK-IMPORT: define {{.*}} @[[D_INIT:__cxx_global.*]]() |
| 232 | // CHECK-IMPORT: load {{.*}} (i64* @_ZGV |
| 233 | // CHECK-IMPORT: store {{.*}}, i32* @[[D]], |
| 234 | |
| 235 | |
| 236 | // CHECK-IMPORT: define {{.*}} @[[TU_INIT]]() |
| 237 | // CHECK-IMPORT: call void @[[A_INIT]]() |
Richard Smith | 520a37f | 2019-02-05 23:37:13 +0000 | [diff] [blame] | 238 | |
| 239 | // CHECK-IMPORT: define {{.*}} @__tls_init() |
| 240 | // CHECK-IMPORT: call void @[[C_INIT]]() |
| 241 | // CHECK-IMPORT: call void @[[D_INIT]]() |