250 lines · cpp
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=unused2// 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=unused3// 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=unused4// 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=unused5// 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=unused6// 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=unused7 8// Check that we behave sensibly when importing a header containing strong and9// weak, ordered and unordered global initializers.10//11// Our behavior is as follows:12//13// -- for variables with one or more specific points of initialization14// (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 initialization16// is transitively #included / imported.17//18// -- for variables with unordered initialization (any kind of templated19// variable -- excluding explicit specializations), emit them if any part20// of any module that triggers an instantiation is imported.21//22// The intent is to:23//24// 1) preserve order of initialization guarantees25// 2) preserve the behavior of globals with ctors in headers, and specifically26// of std::ios_base::Init (do not run the iostreams initializer nor force27// linking in the iostreams portion of the static library unless <iostream>28// is included)29// 3) behave conservatively-correctly with regard to unordered initializers: we30// might run them in cases where a traditional compilation would not, but31// will never fail to run them in cases where a traditional compilation32// would do so33//34// Perfect handling of unordered initializers would require tracking all35// submodules containing points of instantiation, which is very hard when those36// points of instantiation are within definitions that we skip because we37// already have a (non-visible) definition for the entity:38//39// // a.h40// template<typename> int v = f();41// inline int get() { return v<int>; }42//43// // b.h44// 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 of48// instantiation for v<int> in one of the two headers, because we will only49// parse one of the two get() functions.50 51#pragma clang module build m52module m {53 module a {54 header "foo.h" { size 123 mtime 456789 }55 }56 module b {}57}58 59#pragma clang module contents60#pragma clang module begin m.a61inline int non_trivial() { return 3; }62 63#ifdef NS64namespace ns {65#endif66 67int a = non_trivial();68inline int b = non_trivial();69thread_local int c = non_trivial();70inline thread_local int d = non_trivial();71 72template<typename U> int e = non_trivial();73template<typename U> inline int f = non_trivial();74template<typename U> thread_local int g = non_trivial();75template<typename U> inline thread_local int h = non_trivial();76 77inline int unused = 123; // should not be emitted78 79template<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 emitted91};92 93template<typename T> int X<T>::a = non_trivial();94template<typename T> thread_local int X<T>::c = non_trivial();95template<typename T> template<typename U> int X<T>::e = non_trivial();96template<typename T> template<typename U> thread_local int X<T>::g = non_trivial();97 98inline 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 NS106}107#endif108 109#pragma clang module end110#pragma clang module endbuild111 112#if IMPORT == 1113// Import the module and the m.a submodule; runs the ordered initializers and114// the unordered initializers.115#pragma clang module import m.a116#elif IMPORT == 2117// Import the module but not the m.a submodule; runs only the unordered118// initializers.119#pragma clang module import m.b120#else121// Load the module but do not import any submodules; runs only the unordered122// initializers. FIXME: Should this skip all of them?123#pragma clang module load m124#endif125 126// CHECK-IMPORT-NO-NS-DAG: @[[A:a]] ={{.*}} global i32 0, align 4127// CHECK-IMPORT-NO-NS-DAG: @[[B:b]] = linkonce_odr global i32 0, comdat, align 4128// CHECK-IMPORT-NO-NS-DAG: @[[C:c]] ={{.*}} thread_local global i32 0, align 4129// CHECK-IMPORT-NO-NS-DAG: @[[D:d]] = linkonce_odr thread_local global i32 0, comdat, align 4130// CHECK-NO-NS-DAG: @[[E:_Z1eIiE]] = linkonce_odr global i32 0, comdat, align 4131// CHECK-NO-NS-DAG: @[[F:_Z1fIiE]] = linkonce_odr global i32 0, comdat, align 4132// CHECK-NO-NS-DAG: @[[G:_Z1gIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4133// CHECK-NO-NS-DAG: @[[H:_Z1hIiE]] = linkonce_odr thread_local global i32 0, comdat, align 4134 135// CHECK-IMPORT-NS-DAG: @[[A:_ZN2ns1aE]] ={{.*}} global i32 0, align 4136// CHECK-IMPORT-NS-DAG: @[[B:_ZN2ns1bE]] = linkonce_odr global i32 0, comdat, align 4137// CHECK-IMPORT-NS-DAG: @[[BG:_ZGVN2ns1bE]] = linkonce_odr global i64 0, comdat($[[B]]), align 8138// CHECK-IMPORT-NS-DAG: @[[C:_ZN2ns1cE]] ={{.*}} thread_local global i32 0, align 4139// CHECK-IMPORT-NS-DAG: @[[D:_ZN2ns1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4140// CHECK-IMPORT-NS-DAG: @[[DG:_ZGVN2ns1dE]] = linkonce_odr thread_local global i64 0, comdat($[[D]]), align 8141// CHECK-NS-DAG: @[[E:_ZN2ns1eIiEE]] = linkonce_odr global i32 0, comdat, align 4142// CHECK-NS-DAG: @[[F:_ZN2ns1fIiEE]] = linkonce_odr global i32 0, comdat, align 4143// CHECK-NS-DAG: @[[G:_ZN2ns1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4144// CHECK-NS-DAG: @[[H:_ZN2ns1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4145 146// CHECK-DAG: @[[XA:_ZN(2ns)?1XIiE1aE]] = linkonce_odr global i32 0, comdat, align 4147// CHECK-DAG: @[[XB:_ZN(2ns)?1XIiE1bE]] = linkonce_odr global i32 0, comdat, align 4148// CHECK-DAG: @[[XC:_ZN(2ns)?1XIiE1cE]] = linkonce_odr thread_local global i32 0, comdat, align 4149// CHECK-DAG: @[[XD:_ZN(2ns)?1XIiE1dE]] = linkonce_odr thread_local global i32 0, comdat, align 4150// CHECK-DAG: @[[XE:_ZN(2ns)?1XIiE1eIiEE]] = linkonce_odr global i32 0, comdat, align 4151// CHECK-DAG: @[[XF:_ZN(2ns)?1XIiE1fIiEE]] = linkonce_odr global i32 0, comdat, align 4152// CHECK-DAG: @[[XG:_ZN(2ns)?1XIiE1gIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4153// CHECK-DAG: @[[XH:_ZN(2ns)?1XIiE1hIiEE]] = linkonce_odr thread_local global i32 0, comdat, align 4154 155// It's OK if the order of the first 6 of these changes.156// CHECK: @llvm.global_ctors = appending global157// 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:[^,]*]], ptr null }]164 165// FIXME: Should this use __cxa_guard_acquire?166// CHECK: define {{.*}} @[[E_INIT]]()167// CHECK: load {{.*}} ptr @_ZGV168// CHECK: store {{.*}}, ptr @[[E]],169 170// FIXME: Should this use __cxa_guard_acquire?171// CHECK: define {{.*}} @[[F_INIT]]()172// CHECK: load {{.*}} ptr @_ZGV173// CHECK: store {{.*}}, ptr @[[F]],174 175// CHECK: define {{.*}} @[[G_INIT:__cxx_global.*]]()176// CHECK: load {{.*}} ptr @_ZGV177// CHECK: [[G_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[G]])178// CHECK: store {{.*}}, ptr [[G_ADDR]]179 180// CHECK: define {{.*}} @[[H_INIT:__cxx_global.*]]()181// CHECK: load {{.*}} ptr @_ZGV182// CHECK: [[H_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[H]])183// CHECK: store {{.*}}, ptr [[H_ADDR]],184 185// FIXME: Should this use __cxa_guard_acquire?186// CHECK: define {{.*}} @[[XA_INIT]]()187// CHECK: load {{.*}} ptr @_ZGV188// CHECK: store {{.*}}, ptr @[[XA]],189 190// CHECK: define {{.*}} @[[XC_INIT:__cxx_global.*]]()191// CHECK: load {{.*}} ptr @_ZGV192// CHECK: [[XC_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[XC]])193// CHECK: store {{.*}}, ptr [[XC_ADDR]],194 195// FIXME: Should this use __cxa_guard_acquire?196// CHECK: define {{.*}} @[[XE_INIT]]()197// CHECK: load {{.*}} ptr @_ZGV198// CHECK: store {{.*}}, ptr @[[XE]],199 200// CHECK: define {{.*}} @[[XG_INIT:__cxx_global.*]]()201// CHECK: load {{.*}} ptr @_ZGV202// CHECK: [[XG_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[XG]])203// CHECK: store {{.*}}, ptr [[XG_ADDR]],204 205// CHECK: define {{.*}} @[[XH_INIT:__cxx_global.*]]()206// CHECK: load {{.*}} ptr @_ZGV207// CHECK: [[XH_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[XH]])208// CHECK: store {{.*}}, ptr [[XH_ADDR]],209 210// FIXME: Should this use __cxa_guard_acquire?211// CHECK: define {{.*}} @[[XF_INIT]]()212// CHECK: load {{.*}} ptr @_ZGV213// CHECK: store {{.*}}, ptr @[[XF]],214 215// CHECK: define {{.*}} @[[XD_INIT:__cxx_global.*]]()216// CHECK: load {{.*}} ptr @_ZGV217// CHECK: [[XD_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[XD]])218// CHECK: store {{.*}}, ptr [[XD_ADDR]],219 220// FIXME: Should this use __cxa_guard_acquire?221// CHECK: define {{.*}} @[[XB_INIT]]()222// CHECK: load {{.*}} ptr @_ZGV223// CHECK: store {{.*}}, ptr @[[XB]],224 225// CHECK-IMPORT: define {{.*}} @[[A_INIT:__cxx_global.*]]()226// CHECK-IMPORT: call noundef i32 @_Z11non_trivialv(227// CHECK-IMPORT: store {{.*}}, ptr @[[A]],228 229// CHECK-IMPORT: define {{.*}} @[[B_INIT:__cxx_global.*]]()230// CHECK-IMPORT: call i32 @__cxa_guard_acquire(ptr @_ZGV231// CHECK-IMPORT: store {{.*}}, ptr @[[B]],232 233// CHECK-IMPORT: define {{.*}} @[[C_INIT:__cxx_global.*]]()234// CHECK-IMPORT: call noundef i32 @_Z11non_trivialv(235// CHECK-IMPORT: [[C_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[C]])236// CHECK-IMPORT: store {{.*}}, ptr [[C_ADDR]],237 238// CHECK-IMPORT: define {{.*}} @[[D_INIT:__cxx_global.*]]()239// CHECK-IMPORT: load {{.*}} ptr @_ZGV240// CHECK-IMPORT: [[D_ADDR:%.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @[[D]])241// CHECK-IMPORT: store {{.*}}, ptr [[D_ADDR]],242 243 244// CHECK-IMPORT: define {{.*}} @[[TU_INIT]]()245// CHECK-IMPORT: call void @[[A_INIT]]()246 247// CHECK-IMPORT: define {{.*}} @__tls_init()248// CHECK-IMPORT: call void @[[C_INIT]]()249// CHECK-IMPORT: call void @[[D_INIT]]()250