77// ===----------------------------------------------------------------------===//
88
99#include " PassDetail.h"
10+ #include " mlir/Dialect/Func/IR/FuncOps.h"
11+ #include " mlir/IR/Region.h"
1012#include " clang/AST/ASTContext.h"
13+ #include " clang/AST/Mangle.h"
14+ #include " clang/Basic/Module.h"
1115#include " clang/CIR/Dialect/IR/CIRDialect.h"
1216#include " clang/CIR/Dialect/Passes.h"
17+ #include " llvm/ADT/SmallVector.h"
18+ #include " llvm/ADT/StringMap.h"
19+ #include " llvm/ADT/Twine.h"
20+ #include " llvm/Support/Path.h"
1321
1422using namespace mlir ;
1523using namespace cir ;
1624
25+ static SmallString<128 > getTransformedFileName (ModuleOp theModule) {
26+ SmallString<128 > FileName;
27+
28+ if (theModule.getSymName ()) {
29+ FileName = llvm::sys::path::filename (theModule.getSymName ()->str ());
30+ }
31+
32+ if (FileName.empty ())
33+ FileName = " <null>" ;
34+
35+ for (size_t i = 0 ; i < FileName.size (); ++i) {
36+ // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
37+ // to be the set of C preprocessing numbers.
38+ if (!clang::isPreprocessingNumberBody (FileName[i]))
39+ FileName[i] = ' _' ;
40+ }
41+
42+ return FileName;
43+ }
44+
1745namespace {
1846struct LoweringPreparePass : public LoweringPrepareBase <LoweringPreparePass> {
1947 LoweringPreparePass () = default ;
2048 void runOnOperation () override ;
2149
50+ void runOnOp (Operation *op);
51+ void lowerGlobalOp (GlobalOp op);
52+
53+ // / Build the function that initializes the specified global
54+ cir::FuncOp buildCXXGlobalVarDeclInitFunc (GlobalOp op);
55+
56+ // / Build a module init function that calls all the dynamic initializers.
57+ void buildCXXGlobalInitFunc ();
58+
2259 // /
2360 // / AST related
2461 // / -----------
@@ -28,16 +65,139 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
2865
2966 // / Tracks current module.
3067 ModuleOp theModule;
68+
69+ // / Tracks existing dynamic initializers.
70+ llvm::StringMap<uint32_t > dynamicInitializerNames;
71+ llvm::SmallVector<FuncOp, 4 > dynamicInitializers;
3172};
3273} // namespace
3374
75+ cir::FuncOp LoweringPreparePass::buildCXXGlobalVarDeclInitFunc (GlobalOp op) {
76+ SmallString<256 > fnName;
77+ {
78+ std::unique_ptr<clang::MangleContext> MangleCtx (
79+ astCtx->createMangleContext ());
80+ llvm::raw_svector_ostream Out (fnName);
81+ auto varDecl = op.getAst ()->getAstDecl ();
82+ MangleCtx->mangleDynamicInitializer (varDecl, Out);
83+ // Name numbering
84+ uint32_t cnt = dynamicInitializerNames[fnName]++;
85+ if (cnt)
86+ fnName += " ." + llvm::Twine (cnt).str ();
87+ }
88+
89+ // Create a variable initialization function.
90+ mlir::OpBuilder builder (&getContext ());
91+ builder.setInsertionPointAfter (op);
92+ auto fnType = mlir::cir::FuncType::get (
93+ {}, mlir::cir::VoidType::get (builder.getContext ()));
94+ FuncOp f = builder.create <mlir::cir::FuncOp>(op.getLoc (), fnName, fnType);
95+ f.setLinkageAttr (mlir::cir::GlobalLinkageKindAttr::get (
96+ builder.getContext (), mlir::cir::GlobalLinkageKind::InternalLinkage));
97+ mlir::SymbolTable::setSymbolVisibility (
98+ f, mlir::SymbolTable::Visibility::Private);
99+ mlir::NamedAttrList attrs;
100+ f.setExtraAttrsAttr (mlir::cir::ExtraFuncAttributesAttr::get (
101+ builder.getContext (), attrs.getDictionary (builder.getContext ())));
102+
103+ // move over the initialzation code of the ctor region.
104+ auto &block = op.getCtorRegion ().front ();
105+ mlir::Block *EntryBB = f.addEntryBlock ();
106+ EntryBB->getOperations ().splice (EntryBB->begin (), block.getOperations (),
107+ block.begin (), std::prev (block.end ()));
108+
109+ // Replace cir.yield with cir.return
110+ builder.setInsertionPointToEnd (EntryBB);
111+ auto &yieldOp = block.getOperations ().back ();
112+ assert (isa<YieldOp>(yieldOp));
113+ builder.create <ReturnOp>(yieldOp.getLoc ());
114+ return f;
115+ }
116+
117+ void LoweringPreparePass::lowerGlobalOp (GlobalOp op) {
118+ auto &ctorRegion = op.getCtorRegion ();
119+ if (!ctorRegion.empty ()) {
120+ // Build a variable initialization function and move the initialzation code
121+ // in the ctor region over.
122+ auto f = buildCXXGlobalVarDeclInitFunc (op);
123+
124+ // Clear the ctor region
125+ ctorRegion.getBlocks ().clear ();
126+
127+ // Add a function call to the variable initialization function.
128+ dynamicInitializers.push_back (f);
129+ }
130+ }
131+
132+ void LoweringPreparePass::buildCXXGlobalInitFunc () {
133+ if (dynamicInitializers.empty ())
134+ return ;
135+
136+ SmallString<256 > fnName;
137+ // Include the filename in the symbol name. Including "sub_" matches gcc
138+ // and makes sure these symbols appear lexicographically behind the symbols
139+ // with priority emitted above. Module implementation units behave the same
140+ // way as a non-modular TU with imports.
141+ // TODO: check CXX20ModuleInits
142+ if (astCtx->getCurrentNamedModule () &&
143+ !astCtx->getCurrentNamedModule ()->isModuleImplementation ()) {
144+ llvm::raw_svector_ostream Out (fnName);
145+ std::unique_ptr<clang::MangleContext> MangleCtx (
146+ astCtx->createMangleContext ());
147+ cast<clang::ItaniumMangleContext>(*MangleCtx)
148+ .mangleModuleInitializer (astCtx->getCurrentNamedModule (), Out);
149+ } else {
150+ fnName += " _GLOBAL__sub_I_" ;
151+ fnName += getTransformedFileName (theModule);
152+ }
153+
154+ mlir::OpBuilder builder (&getContext ());
155+ builder.setInsertionPointToEnd (&theModule.getBodyRegion ().back ());
156+ auto fnType = mlir::cir::FuncType::get (
157+ {}, mlir::cir::VoidType::get (builder.getContext ()));
158+ FuncOp f =
159+ builder.create <mlir::cir::FuncOp>(theModule.getLoc (), fnName, fnType);
160+ f.setLinkageAttr (mlir::cir::GlobalLinkageKindAttr::get (
161+ builder.getContext (), mlir::cir::GlobalLinkageKind::ExternalLinkage));
162+ mlir::SymbolTable::setSymbolVisibility (
163+ f, mlir::SymbolTable::Visibility::Private);
164+ mlir::NamedAttrList attrs;
165+ f.setExtraAttrsAttr (mlir::cir::ExtraFuncAttributesAttr::get (
166+ builder.getContext (), attrs.getDictionary (builder.getContext ())));
167+
168+ builder.setInsertionPointToStart (f.addEntryBlock ());
169+ for (auto &f : dynamicInitializers) {
170+ builder.create <mlir::cir::CallOp>(f.getLoc (), f);
171+ }
172+
173+ builder.create <ReturnOp>(f.getLoc ());
174+ }
175+
176+ void LoweringPreparePass::runOnOp (Operation *op) {
177+ if (GlobalOp globalOp = cast<GlobalOp>(op)) {
178+ lowerGlobalOp (globalOp);
179+ return ;
180+ }
181+ }
34182
35183void LoweringPreparePass::runOnOperation () {
36184 assert (astCtx && " Missing ASTContext, please construct with the right ctor" );
37185 auto * op = getOperation ();
38186 if (isa<::mlir::ModuleOp>(op)) {
39187 theModule = cast<::mlir::ModuleOp>(op);
40188 }
189+
190+ SmallVector<Operation *> opsToTransform;
191+ op->walk ([&](Operation *op) {
192+ if (isa<GlobalOp>(op))
193+ opsToTransform.push_back (op);
194+ });
195+
196+ for (auto *o : opsToTransform) {
197+ runOnOp (o);
198+ }
199+
200+ buildCXXGlobalInitFunc ();
41201}
42202
43203std::unique_ptr<Pass> mlir::createLoweringPreparePass () {
0 commit comments