88
99#include " PassDetail.h"
1010#include " clang/AST/ASTContext.h"
11+ #include " clang/Basic/Module.h"
1112#include " clang/Basic/TargetInfo.h"
1213#include " clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
1314#include " clang/CIR/Dialect/IR/CIRDialect.h"
1415#include " clang/CIR/Dialect/IR/CIROpsEnums.h"
1516#include " clang/CIR/Dialect/Passes.h"
1617#include " clang/CIR/MissingFeatures.h"
18+ #include " llvm/Support/Path.h"
1719
1820#include < memory>
1921
2022using namespace mlir ;
2123using namespace cir ;
2224
25+ static SmallString<128 > getTransformedFileName (mlir::ModuleOp mlirModule) {
26+ SmallString<128 > fileName;
27+
28+ if (mlirModule.getSymName ())
29+ fileName = llvm::sys::path::filename (mlirModule.getSymName ()->str ());
30+
31+ if (fileName.empty ())
32+ fileName = " <null>" ;
33+
34+ for (size_t i = 0 ; i < fileName.size (); ++i) {
35+ // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
36+ // to be the set of C preprocessing numbers.
37+ if (!clang::isPreprocessingNumberBody (fileName[i]))
38+ fileName[i] = ' _' ;
39+ }
40+
41+ return fileName;
42+ }
43+
2344namespace {
2445struct LoweringPreparePass : public LoweringPrepareBase <LoweringPreparePass> {
2546 LoweringPreparePass () = default ;
@@ -30,9 +51,16 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
3051 void lowerComplexDivOp (cir::ComplexDivOp op);
3152 void lowerComplexMulOp (cir::ComplexMulOp op);
3253 void lowerUnaryOp (cir::UnaryOp op);
54+ void lowerGlobalOp (cir::GlobalOp op);
3355 void lowerArrayDtor (cir::ArrayDtor op);
3456 void lowerArrayCtor (cir::ArrayCtor op);
3557
58+ // / Build the function that initializes the specified global
59+ cir::FuncOp buildCXXGlobalVarDeclInitFunc (cir::GlobalOp op);
60+
61+ // / Build a module init function that calls all the dynamic initializers.
62+ void buildCXXGlobalInitFunc ();
63+
3664 cir::FuncOp buildRuntimeFunction (
3765 mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
3866 cir::FuncType type,
@@ -47,6 +75,10 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
4775 // / Tracks current module.
4876 mlir::ModuleOp mlirModule;
4977
78+ // / Tracks existing dynamic initializers.
79+ llvm::StringMap<uint32_t > dynamicInitializerNames;
80+ llvm::SmallVector<cir::FuncOp> dynamicInitializers;
81+
5082 void setASTContext (clang::ASTContext *c) { astCtx = c; }
5183};
5284
@@ -589,6 +621,111 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
589621 op.erase ();
590622}
591623
624+ cir::FuncOp
625+ LoweringPreparePass::buildCXXGlobalVarDeclInitFunc (cir::GlobalOp op) {
626+ // TODO(cir): Store this in the GlobalOp.
627+ // This should come from the MangleContext, but for now I'm hardcoding it.
628+ SmallString<256 > fnName (" __cxx_global_var_init" );
629+ // Get a unique name
630+ uint32_t cnt = dynamicInitializerNames[fnName]++;
631+ if (cnt)
632+ fnName += " ." + llvm::Twine (cnt).str ();
633+
634+ // Create a variable initialization function.
635+ CIRBaseBuilderTy builder (getContext ());
636+ builder.setInsertionPointAfter (op);
637+ auto fnType = cir::FuncType::get ({}, builder.getVoidTy ());
638+ FuncOp f = buildRuntimeFunction (builder, fnName, op.getLoc (), fnType,
639+ cir::GlobalLinkageKind::InternalLinkage);
640+
641+ // Move over the initialzation code of the ctor region.
642+ mlir::Block *entryBB = f.addEntryBlock ();
643+ if (!op.getCtorRegion ().empty ()) {
644+ mlir::Block &block = op.getCtorRegion ().front ();
645+ entryBB->getOperations ().splice (entryBB->begin (), block.getOperations (),
646+ block.begin (), std::prev (block.end ()));
647+ }
648+
649+ // Register the destructor call with __cxa_atexit
650+ mlir::Region &dtorRegion = op.getDtorRegion ();
651+ if (!dtorRegion.empty ()) {
652+ assert (!cir::MissingFeatures::opGlobalDtorLowering ());
653+ llvm_unreachable (" dtor region lowering is NYI" );
654+ }
655+
656+ // Replace cir.yield with cir.return
657+ builder.setInsertionPointToEnd (entryBB);
658+ mlir::Operation *yieldOp = nullptr ;
659+ if (!op.getCtorRegion ().empty ()) {
660+ mlir::Block &block = op.getCtorRegion ().front ();
661+ yieldOp = &block.getOperations ().back ();
662+ } else {
663+ assert (!cir::MissingFeatures::opGlobalDtorLowering ());
664+ llvm_unreachable (" dtor region lowering is NYI" );
665+ }
666+
667+ assert (isa<YieldOp>(*yieldOp));
668+ cir::ReturnOp::create (builder, yieldOp->getLoc ());
669+ return f;
670+ }
671+
672+ void LoweringPreparePass::lowerGlobalOp (GlobalOp op) {
673+ mlir::Region &ctorRegion = op.getCtorRegion ();
674+ mlir::Region &dtorRegion = op.getDtorRegion ();
675+
676+ if (!ctorRegion.empty () || !dtorRegion.empty ()) {
677+ // Build a variable initialization function and move the initialzation code
678+ // in the ctor region over.
679+ cir::FuncOp f = buildCXXGlobalVarDeclInitFunc (op);
680+
681+ // Clear the ctor and dtor region
682+ ctorRegion.getBlocks ().clear ();
683+ dtorRegion.getBlocks ().clear ();
684+
685+ assert (!cir::MissingFeatures::astVarDeclInterface ());
686+ dynamicInitializers.push_back (f);
687+ }
688+
689+ assert (!cir::MissingFeatures::opGlobalAnnotations ());
690+ }
691+
692+ void LoweringPreparePass::buildCXXGlobalInitFunc () {
693+ if (dynamicInitializers.empty ())
694+ return ;
695+
696+ assert (!cir::MissingFeatures::opGlobalCtorList ());
697+
698+ SmallString<256 > fnName;
699+ // Include the filename in the symbol name. Including "sub_" matches gcc
700+ // and makes sure these symbols appear lexicographically behind the symbols
701+ // with priority (TBD). Module implementation units behave the same
702+ // way as a non-modular TU with imports.
703+ // TODO: check CXX20ModuleInits
704+ if (astCtx->getCurrentNamedModule () &&
705+ !astCtx->getCurrentNamedModule ()->isModuleImplementation ()) {
706+ llvm::raw_svector_ostream out (fnName);
707+ std::unique_ptr<clang::MangleContext> mangleCtx (
708+ astCtx->createMangleContext ());
709+ cast<clang::ItaniumMangleContext>(*mangleCtx)
710+ .mangleModuleInitializer (astCtx->getCurrentNamedModule (), out);
711+ } else {
712+ fnName += " _GLOBAL__sub_I_" ;
713+ fnName += getTransformedFileName (mlirModule);
714+ }
715+
716+ CIRBaseBuilderTy builder (getContext ());
717+ builder.setInsertionPointToEnd (&mlirModule.getBodyRegion ().back ());
718+ auto fnType = cir::FuncType::get ({}, builder.getVoidTy ());
719+ cir::FuncOp f =
720+ buildRuntimeFunction (builder, fnName, mlirModule.getLoc (), fnType,
721+ cir::GlobalLinkageKind::ExternalLinkage);
722+ builder.setInsertionPointToStart (f.addEntryBlock ());
723+ for (cir::FuncOp &f : dynamicInitializers)
724+ builder.createCallOp (f.getLoc (), f, {});
725+
726+ cir::ReturnOp::create (builder, f.getLoc ());
727+ }
728+
592729static void lowerArrayDtorCtorIntoLoop (cir::CIRBaseBuilderTy &builder,
593730 clang::ASTContext *astCtx,
594731 mlir::Operation *op, mlir::Type eltTy,
@@ -691,6 +828,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
691828 lowerComplexDivOp (complexDiv);
692829 else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op))
693830 lowerComplexMulOp (complexMul);
831+ else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op))
832+ lowerGlobalOp (glob);
694833 else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
695834 lowerUnaryOp (unary);
696835}
@@ -704,12 +843,15 @@ void LoweringPreparePass::runOnOperation() {
704843
705844 op->walk ([&](mlir::Operation *op) {
706845 if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
707- cir::ComplexMulOp, cir::ComplexDivOp, cir::UnaryOp>(op))
846+ cir::ComplexMulOp, cir::ComplexDivOp, cir::GlobalOp,
847+ cir::UnaryOp>(op))
708848 opsToTransform.push_back (op);
709849 });
710850
711851 for (mlir::Operation *o : opsToTransform)
712852 runOnOp (o);
853+
854+ buildCXXGlobalInitFunc ();
713855}
714856
715857std::unique_ptr<Pass> mlir::createLoweringPreparePass () {
0 commit comments