1515
1616#include " clang/AST/GlobalDecl.h"
1717#include " clang/CIR/MissingFeatures.h"
18+ #include " llvm/Support/SaveAndRestore.h"
1819
1920using namespace clang ;
2021using namespace clang ::CIRGen;
2122
23+ static void emitDeclInit (CIRGenFunction &cgf, const VarDecl *varDecl,
24+ cir::GlobalOp globalOp) {
25+ assert ((varDecl->hasGlobalStorage () ||
26+ (varDecl->hasLocalStorage () &&
27+ cgf.getContext ().getLangOpts ().OpenCLCPlusPlus )) &&
28+ " VarDecl must have global or local (in the case of OpenCL) storage!" );
29+ assert (!varDecl->getType ()->isReferenceType () &&
30+ " Should not call emitDeclInit on a reference!" );
31+
32+ CIRGenBuilderTy &builder = cgf.getBuilder ();
33+
34+ // Set up the ctor region.
35+ mlir::OpBuilder::InsertionGuard guard (builder);
36+ mlir::Block *block = builder.createBlock (&globalOp.getCtorRegion ());
37+ CIRGenFunction::LexicalScope lexScope{cgf, globalOp.getLoc (),
38+ builder.getInsertionBlock ()};
39+ lexScope.setAsGlobalInit ();
40+ builder.setInsertionPointToStart (block);
41+
42+ Address declAddr (cgf.cgm .getAddrOfGlobalVar (varDecl),
43+ cgf.cgm .getASTContext ().getDeclAlign (varDecl));
44+
45+ QualType type = varDecl->getType ();
46+ LValue lv = cgf.makeAddrLValue (declAddr, type);
47+
48+ const Expr *init = varDecl->getInit ();
49+ switch (CIRGenFunction::getEvaluationKind (type)) {
50+ case cir::TEK_Scalar:
51+ assert (!cir::MissingFeatures::objCGC ());
52+ cgf.emitScalarInit (init, cgf.getLoc (varDecl->getLocation ()), lv, false );
53+ break ;
54+ case cir::TEK_Complex:
55+ cgf.cgm .errorNYI (varDecl->getSourceRange (), " complex global initializer" );
56+ break ;
57+ case cir::TEK_Aggregate:
58+ assert (!cir::MissingFeatures::aggValueSlotGC ());
59+ cgf.emitAggExpr (init,
60+ AggValueSlot::forLValue (lv, AggValueSlot::IsDestructed,
61+ AggValueSlot::IsNotAliased,
62+ AggValueSlot::DoesNotOverlap));
63+ break ;
64+ }
65+
66+ // Finish the ctor region.
67+ builder.setInsertionPointToEnd (block);
68+ cir::YieldOp::create (builder, globalOp.getLoc ());
69+ }
70+
71+ static void emitDeclDestroy (CIRGenFunction &cgf, const VarDecl *vd,
72+ cir::GlobalOp addr) {
73+ // Honor __attribute__((no_destroy)) and bail instead of attempting
74+ // to emit a reference to a possibly nonexistent destructor, which
75+ // in turn can cause a crash. This will result in a global constructor
76+ // that isn't balanced out by a destructor call as intended by the
77+ // attribute. This also checks for -fno-c++-static-destructors and
78+ // bails even if the attribute is not present.
79+ QualType::DestructionKind dtorKind = vd->needsDestruction (cgf.getContext ());
80+
81+ // FIXME: __attribute__((cleanup)) ?
82+
83+ switch (dtorKind) {
84+ case QualType::DK_none:
85+ return ;
86+
87+ case QualType::DK_cxx_destructor:
88+ break ;
89+
90+ case QualType::DK_objc_strong_lifetime:
91+ case QualType::DK_objc_weak_lifetime:
92+ case QualType::DK_nontrivial_c_struct:
93+ // We don't care about releasing objects during process teardown.
94+ assert (!vd->getTLSKind () && " should have rejected this" );
95+ return ;
96+ }
97+
98+ cgf.cgm .errorNYI (vd->getSourceRange (), " global with destructor" );
99+ }
100+
22101cir::FuncOp CIRGenModule::codegenCXXStructor (GlobalDecl gd) {
23102 const CIRGenFunctionInfo &fnInfo =
24103 getTypes ().arrangeCXXStructorDeclaration (gd);
@@ -38,3 +117,63 @@ cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl gd) {
38117 assert (!cir::MissingFeatures::opFuncAttributesForDefinition ());
39118 return fn;
40119}
120+
121+ // Global variables requiring non-trivial initialization are handled
122+ // differently in CIR than in classic codegen. Classic codegen emits
123+ // a global init function (__cxx_global_var_init) and inserts
124+ // initialization for each global there. In CIR, we attach a ctor
125+ // region to the global variable and insert the initialization code
126+ // into the ctor region. This will be moved into the
127+ // __cxx_global_var_init function during the LoweringPrepare pass.
128+ void CIRGenModule::emitCXXGlobalVarDeclInit (const VarDecl *varDecl,
129+ cir::GlobalOp addr,
130+ bool performInit) {
131+ QualType ty = varDecl->getType ();
132+
133+ // TODO: handle address space
134+ // The address space of a static local variable (addr) may be different
135+ // from the address space of the "this" argument of the constructor. In that
136+ // case, we need an addrspacecast before calling the constructor.
137+ //
138+ // struct StructWithCtor {
139+ // __device__ StructWithCtor() {...}
140+ // };
141+ // __device__ void foo() {
142+ // __shared__ StructWithCtor s;
143+ // ...
144+ // }
145+ //
146+ // For example, in the above CUDA code, the static local variable s has a
147+ // "shared" address space qualifier, but the constructor of StructWithCtor
148+ // expects "this" in the "generic" address space.
149+ assert (!cir::MissingFeatures::addressSpace ());
150+
151+ // Create a CIRGenFunction to emit the initializer. While this isn't a true
152+ // function, the handling works the same way.
153+ CIRGenFunction cgf{*this , builder, true };
154+ llvm::SaveAndRestore<CIRGenFunction *> savedCGF (curCGF, &cgf);
155+ curCGF->curFn = addr;
156+
157+ CIRGenFunction::SourceLocRAIIObject fnLoc{cgf,
158+ getLoc (varDecl->getLocation ())};
159+
160+ assert (!cir::MissingFeatures::astVarDeclInterface ());
161+
162+ if (!ty->isReferenceType ()) {
163+ assert (!cir::MissingFeatures::openMP ());
164+
165+ bool needsDtor = varDecl->needsDestruction (getASTContext ()) ==
166+ QualType::DK_cxx_destructor;
167+ // PerformInit, constant store invariant / destroy handled below.
168+ if (performInit)
169+ emitDeclInit (cgf, varDecl, addr);
170+
171+ if (varDecl->getType ().isConstantStorage (getASTContext (), true , !needsDtor))
172+ errorNYI (varDecl->getSourceRange (), " global with constant storage" );
173+ else
174+ emitDeclDestroy (cgf, varDecl, addr);
175+ return ;
176+ }
177+
178+ errorNYI (varDecl->getSourceRange (), " global with reference type" );
179+ }
0 commit comments