The re-land fixes module map module dependencies seen on Greendragon, but not in the clang test suite. --- Currently we only implement this for the Itanium ABI since the correct mangling for the initializers in other ABIs is not yet known. Intended result: For a module interface [which includes partition interface and implementation units] (instead of the generic CXX initializer) we emit a module init that: - wraps the contained initializations in a control variable to ensure that the inits only happen once, even if a module is imported many times by imports of the main unit. - calls module initializers for imported modules first. Note that the order of module import is not significant, and therefore neither is the order of imported module initializers. - We then call initializers for the Global Module Fragment (if present) - We then call initializers for the current module. - We then call initializers for the Private Module Fragment (if present) For a module implementation unit, or a non-module TU that imports at least one module we emit a regular CXX init that: - Calls the initializers for any imported modules first. - Then proceeds as normal with remaining inits. For all module unit kinds we include a global constructor entry, this allows for the (in most cases unusual) possibility that a module object could be included in a final binary without a specific call to its initializer. Implementation: - We provide the module pointer in the AST Context so that CodeGen can act on it and its sub-modules. - We need to account for module build lines like this: ` clang -cc1 -std=c++20 Foo.pcm -emit-obj -o Foo.o` or ` clang -cc1 -std=c++20 -xc++-module Foo.cpp -emit-obj -o Foo.o` - in order to do this, we add to ParseAST to set the module pointer in the ASTContext, once we establish that this is a module build and we know the module pointer. To be able to do this, we make the query for current module public in Sema. - In CodeGen, we determine if the current build requires a CXX20-style module init and, if so, we defer any module initializers during the "Eagerly Emitted" phase. - We then walk the module initializers at the end of the TU but before emitting deferred inits (which adds any hidden and static ones, fixing https://github.com/llvm/llvm-project/issues/51873 ). - We then proceed to emit the deferred inits and continue to emit the CXX init function. Differential Revision: https://reviews.llvm.org/D126189
187 lines
4.2 KiB
C++
187 lines
4.2 KiB
C++
// RUN: rm -rf %t
|
|
// RUN: split-file %s %t
|
|
// RUN: cd %t
|
|
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 N.cpp \
|
|
// RUN: -emit-module-interface -o N.pcm
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 N.pcm -S -emit-llvm \
|
|
// RUN: -o - | FileCheck %s --check-prefix=CHECK-N
|
|
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 O.cpp \
|
|
// RUN: -emit-module-interface -o O.pcm
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 O.pcm -S -emit-llvm \
|
|
// RUN: -o - | FileCheck %s --check-prefix=CHECK-O
|
|
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 M-part.cpp \
|
|
// RUN: -emit-module-interface -o M-part.pcm
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 M-part.pcm -S \
|
|
// RUN: -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-P
|
|
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 M.cpp \
|
|
// RUN: -fmodule-file=N.pcm -fmodule-file=O.pcm -fmodule-file=M-part.pcm \
|
|
// RUN: -emit-module-interface -o M.pcm
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 M.pcm -S -emit-llvm \
|
|
// RUN: -o - | FileCheck %s --check-prefix=CHECK-M
|
|
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 useM.cpp \
|
|
// RUN: -fmodule-file=M.pcm -S -emit-llvm -o - \
|
|
// RUN: | FileCheck %s --check-prefix=CHECK-USE
|
|
|
|
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 M-impl.cpp \
|
|
// RUN: -fmodule-file=M.pcm -S -emit-llvm -o - \
|
|
// RUN: | FileCheck %s --check-prefix=CHECK-IMPL
|
|
|
|
//--- N-h.h
|
|
|
|
struct Oink {
|
|
Oink(){};
|
|
};
|
|
|
|
Oink Hog;
|
|
|
|
//--- N.cpp
|
|
|
|
module;
|
|
#include "N-h.h"
|
|
|
|
export module N;
|
|
|
|
export struct Quack {
|
|
Quack(){};
|
|
};
|
|
|
|
export Quack Duck;
|
|
|
|
// CHECK-N: define internal void @__cxx_global_var_init
|
|
// CHECK-N: call {{.*}} @_ZN4OinkC1Ev
|
|
// CHECK-N: define internal void @__cxx_global_var_init
|
|
// CHECK-N: call {{.*}} @_ZNW1N5QuackC1Ev
|
|
// CHECK-N: define void @_ZGIW1N
|
|
// CHECK-N: store i8 1, ptr @_ZGIW1N__in_chrg
|
|
// CHECK-N: call void @__cxx_global_var_init
|
|
// CHECK-N: call void @__cxx_global_var_init
|
|
|
|
//--- O-h.h
|
|
|
|
struct Meow {
|
|
Meow(){};
|
|
};
|
|
|
|
Meow Cat;
|
|
|
|
//--- O.cpp
|
|
|
|
module;
|
|
#include "O-h.h"
|
|
|
|
export module O;
|
|
|
|
export struct Bark {
|
|
Bark(){};
|
|
};
|
|
|
|
export Bark Dog;
|
|
|
|
// CHECK-O: define internal void @__cxx_global_var_init
|
|
// CHECK-O: call {{.*}} @_ZN4MeowC2Ev
|
|
// CHECK-O: define internal void @__cxx_global_var_init
|
|
// CHECK-O: call {{.*}} @_ZNW1O4BarkC1Ev
|
|
// CHECK-O: define void @_ZGIW1O
|
|
// CHECK-O: store i8 1, ptr @_ZGIW1O__in_chrg
|
|
// CHECK-O: call void @__cxx_global_var_init
|
|
// CHECK-O: call void @__cxx_global_var_init
|
|
|
|
//--- P-h.h
|
|
|
|
struct Croak {
|
|
Croak(){};
|
|
};
|
|
|
|
Croak Frog;
|
|
|
|
//--- M-part.cpp
|
|
|
|
module;
|
|
#include "P-h.h"
|
|
|
|
module M:Part;
|
|
|
|
struct Squawk {
|
|
Squawk(){};
|
|
};
|
|
|
|
Squawk parrot;
|
|
|
|
// CHECK-P: define internal void @__cxx_global_var_init
|
|
// CHECK-P: call {{.*}} @_ZN5CroakC1Ev
|
|
// CHECK-P: define internal void @__cxx_global_var_init
|
|
// CHECK-P: call {{.*}} @_ZNW1M6SquawkC1Ev
|
|
// CHECK-P: define void @_ZGIW1MWP4Part
|
|
// CHECK-P: store i8 1, ptr @_ZGIW1MWP4Part__in_chrg
|
|
// CHECK-P: call void @__cxx_global_var_init
|
|
// CHECK-P: call void @__cxx_global_var_init
|
|
|
|
//--- M-h.h
|
|
|
|
struct Moo {
|
|
Moo(){};
|
|
};
|
|
|
|
Moo Cow;
|
|
|
|
//--- M.cpp
|
|
|
|
module;
|
|
#include "M-h.h"
|
|
|
|
export module M;
|
|
import N;
|
|
export import O;
|
|
import :Part;
|
|
|
|
export struct Baa {
|
|
int x;
|
|
Baa(){};
|
|
Baa(int x) : x(x) {}
|
|
int getX() { return x; }
|
|
};
|
|
|
|
export Baa Sheep(10);
|
|
|
|
// CHECK-M: define internal void @__cxx_global_var_init
|
|
// CHECK-M: call {{.*}} @_ZN3MooC1Ev
|
|
// CHECK-M: define internal void @__cxx_global_var_init
|
|
// CHECK-M: call {{.*}} @_ZNW1M3BaaC1Ei
|
|
// CHECK-M: declare void @_ZGIW1O()
|
|
// CHECK-M: declare void @_ZGIW1N()
|
|
// CHECK-M: declare void @_ZGIW1MWP4Part()
|
|
// CHECK-M: define void @_ZGIW1M
|
|
// CHECK-M: store i8 1, ptr @_ZGIW1M__in_chrg
|
|
// CHECK-M: call void @_ZGIW1O()
|
|
// CHECK-M: call void @_ZGIW1N()
|
|
// CHECK-M: call void @_ZGIW1MWP4Part()
|
|
// CHECK-M: call void @__cxx_global_var_init
|
|
// CHECK-M: call void @__cxx_global_var_init
|
|
|
|
//--- useM.cpp
|
|
|
|
import M;
|
|
|
|
int main() {
|
|
return Sheep.getX();
|
|
}
|
|
|
|
// CHECK-USE: declare void @_ZGIW1M
|
|
// CHECK-USE: define internal void @_GLOBAL__sub_I_useM.cpp
|
|
// CHECK-USE: call void @_ZGIW1M()
|
|
|
|
//--- M-impl.cpp
|
|
|
|
module M;
|
|
|
|
int foo(int i) { return i + 1; }
|
|
|
|
// CHECK-IMPL: declare void @_ZGIW1M
|
|
// CHECK-IMPL: define internal void @_GLOBAL__sub_I_M_impl.cpp
|
|
// CHECK-IMPL: call void @_ZGIW1M()
|