8
8
9
9
#include " PassDetail.h"
10
10
#include " clang/AST/ASTContext.h"
11
+ #include " clang/Basic/Module.h"
11
12
#include " clang/Basic/TargetInfo.h"
12
13
#include " clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
13
14
#include " clang/CIR/Dialect/IR/CIRDialect.h"
14
15
#include " clang/CIR/Dialect/IR/CIROpsEnums.h"
15
16
#include " clang/CIR/Dialect/Passes.h"
16
17
#include " clang/CIR/MissingFeatures.h"
18
+ #include " llvm/Support/Path.h"
17
19
18
20
#include < memory>
19
21
20
22
using namespace mlir ;
21
23
using namespace cir ;
22
24
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
+
23
44
namespace {
24
45
struct LoweringPreparePass : public LoweringPrepareBase <LoweringPreparePass> {
25
46
LoweringPreparePass () = default ;
@@ -30,9 +51,16 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
30
51
void lowerComplexDivOp (cir::ComplexDivOp op);
31
52
void lowerComplexMulOp (cir::ComplexMulOp op);
32
53
void lowerUnaryOp (cir::UnaryOp op);
54
+ void lowerGlobalOp (cir::GlobalOp op);
33
55
void lowerArrayDtor (cir::ArrayDtor op);
34
56
void lowerArrayCtor (cir::ArrayCtor op);
35
57
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
+
36
64
cir::FuncOp buildRuntimeFunction (
37
65
mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
38
66
cir::FuncType type,
@@ -47,6 +75,10 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
47
75
// / Tracks current module.
48
76
mlir::ModuleOp mlirModule;
49
77
78
+ // / Tracks existing dynamic initializers.
79
+ llvm::StringMap<uint32_t > dynamicInitializerNames;
80
+ llvm::SmallVector<cir::FuncOp> dynamicInitializers;
81
+
50
82
void setASTContext (clang::ASTContext *c) { astCtx = c; }
51
83
};
52
84
@@ -589,6 +621,111 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
589
621
op.erase ();
590
622
}
591
623
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
+
592
729
static void lowerArrayDtorCtorIntoLoop (cir::CIRBaseBuilderTy &builder,
593
730
clang::ASTContext *astCtx,
594
731
mlir::Operation *op, mlir::Type eltTy,
@@ -691,6 +828,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
691
828
lowerComplexDivOp (complexDiv);
692
829
else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op))
693
830
lowerComplexMulOp (complexMul);
831
+ else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op))
832
+ lowerGlobalOp (glob);
694
833
else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op))
695
834
lowerUnaryOp (unary);
696
835
}
@@ -704,12 +843,15 @@ void LoweringPreparePass::runOnOperation() {
704
843
705
844
op->walk ([&](mlir::Operation *op) {
706
845
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))
708
848
opsToTransform.push_back (op);
709
849
});
710
850
711
851
for (mlir::Operation *o : opsToTransform)
712
852
runOnOp (o);
853
+
854
+ buildCXXGlobalInitFunc ();
713
855
}
714
856
715
857
std::unique_ptr<Pass> mlir::createLoweringPreparePass () {
0 commit comments