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,149 @@ 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+ if (!ctorRegion.hasOneBlock ()) {
121+ op.emitError () << " ctor region must have exactly one block." ;
122+ return ;
123+ }
124+ auto &block = ctorRegion.front ();
125+ if (block.empty ()) {
126+ op.emitError () << " ctor region shall not be empty." ;
127+ return ;
128+ }
129+
130+ // Build a variable initialization function and move the initialzation code
131+ // in the ctor region over.
132+ auto f = buildCXXGlobalVarDeclInitFunc (op);
133+
134+ // Clear the ctor region
135+ ctorRegion.getBlocks ().clear ();
136+
137+ // Add a function call to the variable initialization function.
138+ dynamicInitializers.push_back (f);
139+ }
140+ }
141+
142+ void LoweringPreparePass::buildCXXGlobalInitFunc () {
143+ if (dynamicInitializers.empty ())
144+ return ;
145+
146+ SmallString<256 > fnName;
147+ // Include the filename in the symbol name. Including "sub_" matches gcc
148+ // and makes sure these symbols appear lexicographically behind the symbols
149+ // with priority emitted above. Module implementation units behave the same
150+ // way as a non-modular TU with imports.
151+ // TODO: check CXX20ModuleInits
152+ if (astCtx->getCurrentNamedModule () &&
153+ !astCtx->getCurrentNamedModule ()->isModuleImplementation ()) {
154+ llvm::raw_svector_ostream Out (fnName);
155+ std::unique_ptr<clang::MangleContext> MangleCtx (
156+ astCtx->createMangleContext ());
157+ cast<clang::ItaniumMangleContext>(*MangleCtx)
158+ .mangleModuleInitializer (astCtx->getCurrentNamedModule (), Out);
159+ } else {
160+ fnName += " _GLOBAL__sub_I_" ;
161+ fnName += getTransformedFileName (theModule);
162+ }
163+
164+ mlir::OpBuilder builder (&getContext ());
165+ builder.setInsertionPointToEnd (&theModule.getBodyRegion ().back ());
166+ auto fnType = mlir::cir::FuncType::get (
167+ {}, mlir::cir::VoidType::get (builder.getContext ()));
168+ FuncOp f =
169+ builder.create <mlir::cir::FuncOp>(theModule.getLoc (), fnName, fnType);
170+ f.setLinkageAttr (mlir::cir::GlobalLinkageKindAttr::get (
171+ builder.getContext (), mlir::cir::GlobalLinkageKind::ExternalLinkage));
172+ mlir::SymbolTable::setSymbolVisibility (
173+ f, mlir::SymbolTable::Visibility::Private);
174+ mlir::NamedAttrList attrs;
175+ f.setExtraAttrsAttr (mlir::cir::ExtraFuncAttributesAttr::get (
176+ builder.getContext (), attrs.getDictionary (builder.getContext ())));
177+
178+ builder.setInsertionPointToStart (f.addEntryBlock ());
179+ for (auto &f : dynamicInitializers) {
180+ builder.create <mlir::cir::CallOp>(f.getLoc (), f);
181+ }
182+
183+ builder.create <ReturnOp>(f.getLoc ());
184+ }
185+
186+ void LoweringPreparePass::runOnOp (Operation *op) {
187+ if (GlobalOp globalOp = cast<GlobalOp>(op)) {
188+ lowerGlobalOp (globalOp);
189+ return ;
190+ }
191+ }
34192
35193void LoweringPreparePass::runOnOperation () {
36194 assert (astCtx && " Missing ASTContext, please construct with the right ctor" );
37195 auto * op = getOperation ();
38196 if (isa<::mlir::ModuleOp>(op)) {
39197 theModule = cast<::mlir::ModuleOp>(op);
40198 }
199+
200+ SmallVector<Operation *> opsToTransform;
201+ op->walk ([&](Operation *op) {
202+ if (isa<GlobalOp>(op))
203+ opsToTransform.push_back (op);
204+ });
205+
206+ for (auto *o : opsToTransform) {
207+ runOnOp (o);
208+ }
209+
210+ buildCXXGlobalInitFunc ();
41211}
42212
43213std::unique_ptr<Pass> mlir::createLoweringPreparePass () {
0 commit comments