Skip to content

Commit 9417d43

Browse files
committed
[CIR][CIRGen] Support global initialization with new
1 parent 2360bc9 commit 9417d43

File tree

7 files changed

+151
-62
lines changed

7 files changed

+151
-62
lines changed

clang/lib/CIR/CodeGen/CIRGenCXX.cpp

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -206,37 +206,70 @@ static void buildDeclInit(CIRGenFunction &CGF, const VarDecl *D,
206206
}
207207
}
208208

209-
static void buildDeclDestory(CIRGenFunction &CGF, const VarDecl *D,
210-
Address DeclPtr) {
209+
static void buildDeclDestroy(CIRGenFunction &CGF, const VarDecl *D) {
211210
// Honor __attribute__((no_destroy)) and bail instead of attempting
212211
// to emit a reference to a possibly nonexistent destructor, which
213212
// in turn can cause a crash. This will result in a global constructor
214213
// that isn't balanced out by a destructor call as intended by the
215214
// attribute. This also checks for -fno-c++-static-destructors and
216215
// bails even if the attribute is not present.
217-
assert(D->needsDestruction(CGF.getContext()) == QualType::DK_cxx_destructor);
216+
QualType::DestructionKind DtorKind = D->needsDestruction(CGF.getContext());
218217

219-
auto &CGM = CGF.CGM;
218+
// FIXME: __attribute__((cleanup)) ?
220219

221-
// If __cxa_atexit is disabled via a flag, a different helper function is
222-
// generated elsewhere which uses atexit instead, and it takes the destructor
223-
// directly.
224-
auto UsingExternalHelper = CGM.getCodeGenOpts().CXAAtExit;
220+
switch (DtorKind) {
221+
case QualType::DK_none:
222+
return;
223+
224+
case QualType::DK_cxx_destructor:
225+
break;
226+
227+
case QualType::DK_objc_strong_lifetime:
228+
case QualType::DK_objc_weak_lifetime:
229+
case QualType::DK_nontrivial_c_struct:
230+
// We don't care about releasing objects during process teardown.
231+
assert(!D->getTLSKind() && "should have rejected this");
232+
return;
233+
}
234+
235+
auto &CGM = CGF.CGM;
225236
QualType type = D->getType();
237+
238+
// Special-case non-array C++ destructors, if they have the right signature.
239+
// Under some ABIs, destructors return this instead of void, and cannot be
240+
// passed directly to __cxa_atexit if the target does not allow this
241+
// mismatch.
226242
const CXXRecordDecl *Record = type->getAsCXXRecordDecl();
227243
bool CanRegisterDestructor =
228244
Record && (!CGM.getCXXABI().HasThisReturn(
229245
GlobalDecl(Record->getDestructor(), Dtor_Complete)) ||
230246
CGM.getCXXABI().canCallMismatchedFunctionType());
247+
248+
// If __cxa_atexit is disabled via a flag, a different helper function is
249+
// generated elsewhere which uses atexit instead, and it takes the destructor
250+
// directly.
251+
auto UsingExternalHelper = CGM.getCodeGenOpts().CXAAtExit;
252+
mlir::cir::FuncOp fnOp;
231253
if (Record && (CanRegisterDestructor || UsingExternalHelper)) {
232254
assert(!D->getTLSKind() && "TLS NYI");
255+
assert(!Record->hasTrivialDestructor());
256+
assert(!MissingFeatures::openCL());
233257
CXXDestructorDecl *Dtor = Record->getDestructor();
234-
CGM.getCXXABI().buildDestructorCall(CGF, Dtor, Dtor_Complete,
235-
/*ForVirtualBase=*/false,
236-
/*Delegating=*/false, DeclPtr, type);
258+
// In LLVM OG codegen this is done in registerGlobalDtor, but CIRGen
259+
// relies on LoweringPrepare for further decoupling, so build the
260+
// call right here.
261+
auto GD = GlobalDecl(Dtor, Dtor_Complete);
262+
auto structorInfo = CGM.getAddrAndTypeOfCXXStructor(GD);
263+
fnOp = structorInfo.second;
264+
CGF.getBuilder().createCallOp(
265+
CGF.getLoc(D->getSourceRange()),
266+
mlir::FlatSymbolRefAttr::get(fnOp.getSymNameAttr()),
267+
mlir::ValueRange{CGF.CGM.getAddrOfGlobalVar(D)});
237268
} else {
238269
llvm_unreachable("array destructors not yet supported!");
239270
}
271+
assert(fnOp && "expected cir.func");
272+
CGM.getCXXABI().registerGlobalDtor(CGF, D, fnOp, nullptr);
240273
}
241274

242275
mlir::cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl GD) {
@@ -260,8 +293,8 @@ mlir::cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl GD) {
260293

261294
void CIRGenModule::codegenGlobalInitCxxStructor(const VarDecl *D,
262295
mlir::cir::GlobalOp Addr,
263-
bool NeedsCtor,
264-
bool NeedsDtor) {
296+
bool NeedsCtor, bool NeedsDtor,
297+
bool isCstStorage) {
265298
assert(D && " Expected a global declaration!");
266299
CIRGenFunction CGF{*this, builder, true};
267300
CurCGF = &CGF;
@@ -278,14 +311,20 @@ void CIRGenModule::codegenGlobalInitCxxStructor(const VarDecl *D,
278311
builder.create<mlir::cir::YieldOp>(Addr->getLoc());
279312
}
280313

281-
if (NeedsDtor) {
314+
if (isCstStorage) {
315+
// buildDeclInvariant(CGF, D, DeclPtr);
316+
llvm_unreachable("NYI");
317+
} else {
318+
// If not constant storage we'll emit this regardless of NeedsDtor value.
282319
mlir::OpBuilder::InsertionGuard guard(builder);
283320
auto block = builder.createBlock(&Addr.getDtorRegion());
284321
builder.setInsertionPointToStart(block);
285-
Address DeclAddr(getAddrOfGlobalVar(D), getASTContext().getDeclAlign(D));
286-
buildDeclDestory(CGF, D, DeclAddr);
322+
buildDeclDestroy(CGF, D);
287323
builder.setInsertionPointToEnd(block);
288-
builder.create<mlir::cir::YieldOp>(Addr->getLoc());
324+
if (block->empty())
325+
block->erase();
326+
else
327+
builder.create<mlir::cir::YieldOp>(Addr->getLoc());
289328
}
290329

291330
CurCGF = nullptr;

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ class CIRGenCXXABI {
164164
bool Delegating, Address This,
165165
QualType ThisTy) = 0;
166166

167+
/// Emit code to force the execution of a destructor during global
168+
/// teardown. The default implementation of this uses atexit.
169+
///
170+
/// \param Dtor - a function taking a single pointer argument
171+
/// \param Addr - a pointer to pass to the destructor function.
172+
virtual void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D,
173+
mlir::cir::FuncOp dtor,
174+
mlir::Attribute Addr) = 0;
175+
167176
virtual size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
168177
FunctionArgList &Args) const = 0;
169178

clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ void CIRGenModule::buildCXXGlobalInitFunc() {
3131
assert(0 && "NYE");
3232
}
3333

34-
void CIRGenModule::buildGlobalVarDeclInit(const VarDecl *D,
35-
mlir::cir::GlobalOp Addr,
36-
bool PerformInit) {
34+
void CIRGenModule::buildCXXGlobalVarDeclInitFunc(const VarDecl *D,
35+
mlir::cir::GlobalOp Addr,
36+
bool PerformInit) {
3737
// According to E.2.3.1 in CUDA-7.5 Programming guide: __device__,
3838
// __constant__ and __shared__ variables defined in namespace scope,
3939
// that are of class type, cannot have a non-empty constructor. All
@@ -51,36 +51,48 @@ void CIRGenModule::buildGlobalVarDeclInit(const VarDecl *D,
5151
if (I != DelayedCXXInitPosition.end() && I->second == ~0U)
5252
return;
5353

54-
if (PerformInit) {
55-
QualType T = D->getType();
54+
buildCXXGlobalVarDeclInit(D, Addr, PerformInit);
55+
}
5656

57-
// TODO: handle address space
58-
// The address space of a static local variable (DeclPtr) may be different
59-
// from the address space of the "this" argument of the constructor. In that
60-
// case, we need an addrspacecast before calling the constructor.
61-
//
62-
// struct StructWithCtor {
63-
// __device__ StructWithCtor() {...}
64-
// };
65-
// __device__ void foo() {
66-
// __shared__ StructWithCtor s;
67-
// ...
68-
// }
69-
//
70-
// For example, in the above CUDA code, the static local variable s has a
71-
// "shared" address space qualifier, but the constructor of StructWithCtor
72-
// expects "this" in the "generic" address space.
73-
assert(!MissingFeatures::addressSpace());
57+
void CIRGenModule::buildCXXGlobalVarDeclInit(const VarDecl *D,
58+
mlir::cir::GlobalOp Addr,
59+
bool PerformInit) {
60+
QualType T = D->getType();
7461

75-
if (!T->isReferenceType()) {
76-
bool NeedsDtor =
77-
D->needsDestruction(getASTContext()) == QualType::DK_cxx_destructor;
78-
assert(!isTypeConstant(D->getType(), true, !NeedsDtor) &&
79-
"invaraint-typed initialization NYI");
62+
// TODO: handle address space
63+
// The address space of a static local variable (DeclPtr) may be different
64+
// from the address space of the "this" argument of the constructor. In that
65+
// case, we need an addrspacecast before calling the constructor.
66+
//
67+
// struct StructWithCtor {
68+
// __device__ StructWithCtor() {...}
69+
// };
70+
// __device__ void foo() {
71+
// __shared__ StructWithCtor s;
72+
// ...
73+
// }
74+
//
75+
// For example, in the above CUDA code, the static local variable s has a
76+
// "shared" address space qualifier, but the constructor of StructWithCtor
77+
// expects "this" in the "generic" address space.
78+
assert(!MissingFeatures::addressSpace());
8079

81-
if (PerformInit || NeedsDtor)
82-
codegenGlobalInitCxxStructor(D, Addr, PerformInit, NeedsDtor);
83-
return;
80+
if (!T->isReferenceType()) {
81+
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
82+
D->hasAttr<OMPThreadPrivateDeclAttr>()) {
83+
llvm_unreachable("NYI");
8484
}
85+
bool NeedsDtor =
86+
D->needsDestruction(getASTContext()) == QualType::DK_cxx_destructor;
87+
// PerformInit, constant store invariant / destroy handled below.
88+
bool isCstStorage =
89+
D->getType().isConstantStorage(getASTContext(), true, !NeedsDtor);
90+
codegenGlobalInitCxxStructor(D, Addr, PerformInit, NeedsDtor, isCstStorage);
91+
return;
8592
}
93+
94+
assert(PerformInit && "cannot have constant initializer which needs "
95+
"destruction for reference");
96+
// TODO(cir): buildReferenceBindingToExpr
97+
llvm_unreachable("NYI");
8698
}

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ class CIRGenItaniumCXXABI : public cir::CIRGenCXXABI {
172172
CXXDtorType Type, bool ForVirtualBase,
173173
bool Delegating, Address This,
174174
QualType ThisTy) override;
175+
void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D,
176+
mlir::cir::FuncOp dtor,
177+
mlir::Attribute Addr) override;
175178
virtual void buildRethrow(CIRGenFunction &CGF, bool isNoReturn) override;
176179
virtual void buildThrow(CIRGenFunction &CGF, const CXXThrowExpr *E) override;
177180
CatchTypeInfo
@@ -2136,6 +2139,25 @@ void CIRGenItaniumCXXABI::buildDestructorCall(
21362139
nullptr);
21372140
}
21382141

2142+
void CIRGenItaniumCXXABI::registerGlobalDtor(CIRGenFunction &CGF,
2143+
const VarDecl *D,
2144+
mlir::cir::FuncOp dtor,
2145+
mlir::Attribute Addr) {
2146+
if (D->isNoDestroy(CGM.getASTContext()))
2147+
return;
2148+
2149+
if (D->getTLSKind())
2150+
llvm_unreachable("NYI");
2151+
2152+
// HLSL doesn't support atexit.
2153+
if (CGM.getLangOpts().HLSL)
2154+
llvm_unreachable("NYI");
2155+
2156+
// The default behavior is to use atexit. This is handled in lowering
2157+
// prepare. For now just emit the body for the dtor.
2158+
// ....
2159+
}
2160+
21392161
mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam(
21402162
CIRGenFunction &CGF, const CXXDestructorDecl *DD, CXXDtorType Type,
21412163
bool ForVirtualBase, bool Delegating) {

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,18 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D,
11061106
!IsDefinitionAvailableExternally &&
11071107
D->needsDestruction(astCtx) == QualType::DK_cxx_destructor;
11081108

1109+
// It is helpless to emit the definition for an available_externally variable
1110+
// which can't be marked as const.
1111+
// We don't need to check if it needs global ctor or dtor. See the above
1112+
// comment for ideas.
1113+
if (IsDefinitionAvailableExternally &&
1114+
(!D->hasConstantInitialization() ||
1115+
// TODO: Update this when we have interface to check constexpr
1116+
// destructor.
1117+
D->needsDestruction(getASTContext()) ||
1118+
!D->getType().isConstantStorage(getASTContext(), true, true)))
1119+
return;
1120+
11091121
const VarDecl *InitDecl;
11101122
const Expr *InitExpr = D->getAnyInitializer(InitDecl);
11111123

@@ -1199,9 +1211,7 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D,
11991211
auto Entry = buildGlobal(D, InitType, ForDefinition_t(!IsTentative));
12001212
// TODO(cir): Strip off pointer casts from Entry if we get them?
12011213

1202-
// TODO(cir): LLVM codegen used GlobalValue to handle both Function or
1203-
// GlobalVariable here. We currently only support GlobalOp, should this be
1204-
// used for FuncOp?
1214+
// TODO(cir): use GlobalValue interface
12051215
assert(dyn_cast<GlobalOp>(&Entry) && "FuncOp not supported here");
12061216
auto GV = Entry;
12071217

@@ -1314,10 +1324,12 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D,
13141324
// TODO(cir):
13151325
// Emit the initializer function if necessary.
13161326
if (NeedsGlobalCtor || NeedsGlobalDtor)
1317-
buildGlobalVarDeclInit(D, GV, NeedsGlobalCtor);
1327+
buildCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
13181328

13191329
// TODO(cir): sanitizers (reportGlobalToASan) and global variable debug
13201330
// information.
1331+
assert(!MissingFeatures::sanitizeOther());
1332+
assert(!MissingFeatures::generateDebugInfo());
13211333
}
13221334

13231335
void CIRGenModule::buildGlobalDefinition(GlobalDecl GD, mlir::Operation *Op) {

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,11 @@ class CIRGenModule : public CIRGenTypeCache {
577577
bool IsTentative = false);
578578

579579
/// Emit the function that initializes the specified global
580-
void buildGlobalVarDeclInit(const VarDecl *D, mlir::cir::GlobalOp Addr,
581-
bool PerformInit);
580+
void buildCXXGlobalVarDeclInit(const VarDecl *D, mlir::cir::GlobalOp Addr,
581+
bool PerformInit);
582+
583+
void buildCXXGlobalVarDeclInitFunc(const VarDecl *D, mlir::cir::GlobalOp Addr,
584+
bool PerformInit);
582585

583586
void addDeferredVTable(const CXXRecordDecl *RD) {
584587
DeferredVTables.push_back(RD);
@@ -614,7 +617,7 @@ class CIRGenModule : public CIRGenTypeCache {
614617
// Produce code for this constructor/destructor for global initialzation.
615618
void codegenGlobalInitCxxStructor(const clang::VarDecl *D,
616619
mlir::cir::GlobalOp Addr, bool NeedsCtor,
617-
bool NeedsDtor);
620+
bool NeedsDtor, bool isCstStorage);
618621

619622
bool lookupRepresentativeDecl(llvm::StringRef MangledName,
620623
clang::GlobalDecl &Result) const;

clang/test/CIR/CodeGen/ctor-srcloc-fix.cpp

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)