Skip to content

Commit 5b6e25b

Browse files
committed
[CIR][CodeGen] Support static references to temporaries
Pull Request: #872
1 parent b2795dc commit 5b6e25b

File tree

8 files changed

+176
-99
lines changed

8 files changed

+176
-99
lines changed

clang/lib/CIR/CodeGen/CIRGenCXX.cpp

+106-37
Original file line numberDiff line numberDiff line change
@@ -306,51 +306,120 @@ void CIRGenFunction::buildInvariantStart([[maybe_unused]] CharUnits Size) {
306306
assert(!MissingFeatures::createInvariantIntrinsic());
307307
}
308308

309-
void CIRGenModule::codegenGlobalInitCxxStructor(const VarDecl *D,
310-
mlir::cir::GlobalOp Addr,
311-
bool NeedsCtor, bool NeedsDtor,
312-
bool isCstStorage) {
313-
assert(D && " Expected a global declaration!");
314-
CIRGenFunction CGF{*this, builder, true};
315-
CurCGF = &CGF;
316-
CurCGF->CurFn = Addr;
317-
Addr.setAstAttr(mlir::cir::ASTVarDeclAttr::get(builder.getContext(), D));
309+
void CIRGenModule::buildCXXGlobalVarDeclInit(const VarDecl *varDecl,
310+
mlir::cir::GlobalOp addr,
311+
bool performInit) {
312+
const Expr *init = varDecl->getInit();
313+
QualType ty = varDecl->getType();
314+
315+
// TODO: handle address space
316+
// The address space of a static local variable (DeclPtr) may be different
317+
// from the address space of the "this" argument of the constructor. In that
318+
// case, we need an addrspacecast before calling the constructor.
319+
//
320+
// struct StructWithCtor {
321+
// __device__ StructWithCtor() {...}
322+
// };
323+
// __device__ void foo() {
324+
// __shared__ StructWithCtor s;
325+
// ...
326+
// }
327+
//
328+
// For example, in the above CUDA code, the static local variable s has a
329+
// "shared" address space qualifier, but the constructor of StructWithCtor
330+
// expects "this" in the "generic" address space.
331+
assert(!MissingFeatures::addressSpace());
332+
333+
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
334+
varDecl->hasAttr<OMPThreadPrivateDeclAttr>()) {
335+
llvm_unreachable("NYI");
336+
}
318337

319-
if (NeedsCtor) {
320-
mlir::OpBuilder::InsertionGuard guard(builder);
321-
auto block = builder.createBlock(&Addr.getCtorRegion());
322-
CIRGenFunction::LexicalScope lexScope{*CurCGF, Addr.getLoc(),
323-
builder.getInsertionBlock()};
324-
lexScope.setAsGlobalInit();
338+
assert(varDecl && " Expected a global declaration!");
339+
CIRGenFunction cgf{*this, builder, true};
340+
CurCGF = &cgf;
341+
CurCGF->CurFn = addr;
325342

326-
builder.setInsertionPointToStart(block);
327-
Address DeclAddr(getAddrOfGlobalVar(D), getASTContext().getDeclAlign(D));
328-
buildDeclInit(CGF, D, DeclAddr);
329-
builder.setInsertionPointToEnd(block);
330-
builder.create<mlir::cir::YieldOp>(Addr->getLoc());
331-
}
343+
CIRGenFunction::SourceLocRAIIObject fnLoc{cgf,
344+
getLoc(varDecl->getLocation())};
332345

333-
if (isCstStorage) {
334-
// TODO: this leads to a missing feature in the moment, probably also need a
335-
// LexicalScope to be inserted here.
336-
buildDeclInvariant(CGF, D);
337-
} else {
338-
// If not constant storage we'll emit this regardless of NeedsDtor value.
346+
addr.setAstAttr(
347+
mlir::cir::ASTVarDeclAttr::get(builder.getContext(), varDecl));
348+
349+
if (ty->isReferenceType()) {
339350
mlir::OpBuilder::InsertionGuard guard(builder);
340-
auto block = builder.createBlock(&Addr.getDtorRegion());
341-
CIRGenFunction::LexicalScope lexScope{*CurCGF, Addr.getLoc(),
351+
auto *block = builder.createBlock(&addr.getCtorRegion());
352+
CIRGenFunction::LexicalScope lexScope{*CurCGF, addr.getLoc(),
342353
builder.getInsertionBlock()};
343354
lexScope.setAsGlobalInit();
344-
345355
builder.setInsertionPointToStart(block);
346-
buildDeclDestroy(CGF, D);
356+
auto getGlobal = builder.createGetGlobal(addr);
357+
358+
Address declAddr(getGlobal, getGlobal.getType(),
359+
getASTContext().getDeclAlign(varDecl));
360+
assert(performInit && "cannot have constant initializer which needs "
361+
"destruction for reference");
362+
RValue rv = cgf.buildReferenceBindingToExpr(init);
363+
{
364+
mlir::OpBuilder::InsertionGuard guard(builder);
365+
mlir::Operation *rvalueDefOp = rv.getScalarVal().getDefiningOp();
366+
if (rvalueDefOp && rvalueDefOp->getBlock()) {
367+
mlir::Block *rvalSrcBlock = rvalueDefOp->getBlock();
368+
if (!rvalSrcBlock->empty() &&
369+
isa<mlir::cir::YieldOp>(rvalSrcBlock->back())) {
370+
auto &front = rvalSrcBlock->front();
371+
getGlobal.getDefiningOp()->moveBefore(&front);
372+
auto yield = cast<mlir::cir::YieldOp>(rvalSrcBlock->back());
373+
builder.setInsertionPoint(yield);
374+
}
375+
}
376+
cgf.buildStoreOfScalar(rv.getScalarVal(), declAddr, false, ty);
377+
}
347378
builder.setInsertionPointToEnd(block);
348-
if (block->empty()) {
349-
block->erase();
350-
// Don't confuse lexical cleanup.
351-
builder.clearInsertionPoint();
352-
} else
353-
builder.create<mlir::cir::YieldOp>(Addr->getLoc());
379+
builder.create<mlir::cir::YieldOp>(addr->getLoc());
380+
} else {
381+
bool needsDtor = varDecl->needsDestruction(getASTContext()) ==
382+
QualType::DK_cxx_destructor;
383+
// PerformInit, constant store invariant / destroy handled below.
384+
bool isConstantStorage =
385+
varDecl->getType().isConstantStorage(getASTContext(), true, !needsDtor);
386+
if (performInit) {
387+
mlir::OpBuilder::InsertionGuard guard(builder);
388+
auto *block = builder.createBlock(&addr.getCtorRegion());
389+
CIRGenFunction::LexicalScope lexScope{*CurCGF, addr.getLoc(),
390+
builder.getInsertionBlock()};
391+
lexScope.setAsGlobalInit();
392+
393+
builder.setInsertionPointToStart(block);
394+
Address declAddr(getAddrOfGlobalVar(varDecl),
395+
getASTContext().getDeclAlign(varDecl));
396+
buildDeclInit(cgf, varDecl, declAddr);
397+
builder.setInsertionPointToEnd(block);
398+
builder.create<mlir::cir::YieldOp>(addr->getLoc());
399+
}
400+
401+
if (isConstantStorage) {
402+
// TODO: this leads to a missing feature in the moment, probably also need
403+
// a LexicalScope to be inserted here.
404+
buildDeclInvariant(cgf, varDecl);
405+
} else {
406+
// If not constant storage we'll emit this regardless of NeedsDtor value.
407+
mlir::OpBuilder::InsertionGuard guard(builder);
408+
auto *block = builder.createBlock(&addr.getDtorRegion());
409+
CIRGenFunction::LexicalScope lexScope{*CurCGF, addr.getLoc(),
410+
builder.getInsertionBlock()};
411+
lexScope.setAsGlobalInit();
412+
413+
builder.setInsertionPointToStart(block);
414+
buildDeclDestroy(cgf, varDecl);
415+
builder.setInsertionPointToEnd(block);
416+
if (block->empty()) {
417+
block->erase();
418+
// Don't confuse lexical cleanup.
419+
builder.clearInsertionPoint();
420+
} else
421+
builder.create<mlir::cir::YieldOp>(addr->getLoc());
422+
}
354423
}
355424

356425
CurCGF = nullptr;

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ class CIRGenCXXABI {
170170
/// \param Dtor - a function taking a single pointer argument
171171
/// \param Addr - a pointer to pass to the destructor function.
172172
virtual void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D,
173-
mlir::cir::FuncOp dtor,
174-
mlir::Attribute Addr) = 0;
173+
mlir::cir::FuncOp dtor, mlir::Value Addr) = 0;
175174

176175
virtual size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
177176
FunctionArgList &Args) const = 0;

clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp

-45
Original file line numberDiff line numberDiff line change
@@ -44,55 +44,10 @@ void CIRGenModule::buildCXXGlobalVarDeclInitFunc(const VarDecl *D,
4444
D->hasAttr<CUDASharedAttr>()))
4545
return;
4646

47-
assert(!getLangOpts().OpenMP && "OpenMP global var init not implemented");
48-
4947
// Check if we've already initialized this decl.
5048
auto I = DelayedCXXInitPosition.find(D);
5149
if (I != DelayedCXXInitPosition.end() && I->second == ~0U)
5250
return;
5351

5452
buildCXXGlobalVarDeclInit(D, Addr, PerformInit);
5553
}
56-
57-
void CIRGenModule::buildCXXGlobalVarDeclInit(const VarDecl *D,
58-
mlir::cir::GlobalOp Addr,
59-
bool PerformInit) {
60-
QualType T = D->getType();
61-
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());
79-
80-
if (!T->isReferenceType()) {
81-
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
82-
D->hasAttr<OMPThreadPrivateDeclAttr>()) {
83-
llvm_unreachable("NYI");
84-
}
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;
92-
}
93-
94-
assert(PerformInit && "cannot have constant initializer which needs "
95-
"destruction for reference");
96-
// TODO(cir): buildReferenceBindingToExpr
97-
llvm_unreachable("NYI");
98-
}

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "EHScopeStack.h"
2121
#include "TargetInfo.h"
2222

23+
#include "clang/AST/Decl.h"
2324
#include "clang/AST/ExprCXX.h"
2425
#include "clang/AST/GlobalDecl.h"
2526
#include "clang/Basic/Builtins.h"
@@ -1949,6 +1950,9 @@ LValue CIRGenFunction::buildCastLValue(const CastExpr *E) {
19491950
// CK_NoOp can model a qualification conversion, which can remove an array
19501951
// bound and change the IR type.
19511952
LValue LV = buildLValue(E->getSubExpr());
1953+
// Propagate the volatile qualifier to LValue, if exists in E.
1954+
if (E->changesVolatileQualification())
1955+
llvm_unreachable("NYI");
19521956
if (LV.isSimple()) {
19531957
Address V = LV.getAddress();
19541958
if (V.isValid()) {
@@ -2192,8 +2196,14 @@ static Address createReferenceTemporary(CIRGenFunction &CGF,
21922196
CGF.getCounterRefTmpAsString(), Alloca, ip);
21932197
}
21942198
case SD_Thread:
2195-
case SD_Static:
2196-
assert(0 && "NYI");
2199+
case SD_Static: {
2200+
auto a = mlir::cast<mlir::cir::GlobalOp>(
2201+
CGF.CGM.getAddrOfGlobalTemporary(M, Inner));
2202+
auto f = CGF.CGM.getBuilder().createGetGlobal(a);
2203+
assert(a.getAlignment().has_value() &&
2204+
"This should always have an alignment");
2205+
return Address(f, clang::CharUnits::fromQuantity(a.getAlignment().value()));
2206+
}
21972207

21982208
case SD_Dynamic:
21992209
llvm_unreachable("temporary can't have dynamic storage duration");
@@ -2229,12 +2239,20 @@ static void pushTemporaryCleanup(CIRGenFunction &CGF,
22292239
switch (M->getStorageDuration()) {
22302240
case SD_Static:
22312241
case SD_Thread: {
2242+
mlir::cir::FuncOp cleanupFn;
2243+
mlir::Value cleanupArg;
22322244
if (E->getType()->isArrayType()) {
22332245
llvm_unreachable("SD_Static|SD_Thread + array types not implemented");
22342246
} else {
2235-
llvm_unreachable("SD_Static|SD_Thread for general types not implemented");
2247+
cleanupFn = CGF.CGM
2248+
.getAddrAndTypeOfCXXStructor(
2249+
GlobalDecl(ReferenceTemporaryDtor, Dtor_Complete))
2250+
.second;
2251+
cleanupArg = ReferenceTemporary.emitRawPointer();
22362252
}
2237-
llvm_unreachable("SD_Static|SD_Thread not implemented");
2253+
CGF.CGM.getCXXABI().registerGlobalDtor(
2254+
CGF, cast<VarDecl>(M->getExtendingDecl()), cleanupFn, cleanupArg);
2255+
break;
22382256
}
22392257

22402258
case SD_FullExpression:

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,7 @@ class CIRGenItaniumCXXABI : public cir::CIRGenCXXABI {
173173
bool Delegating, Address This,
174174
QualType ThisTy) override;
175175
void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D,
176-
mlir::cir::FuncOp dtor,
177-
mlir::Attribute Addr) override;
176+
mlir::cir::FuncOp dtor, mlir::Value Addr) override;
178177
virtual void buildRethrow(CIRGenFunction &CGF, bool isNoReturn) override;
179178
virtual void buildThrow(CIRGenFunction &CGF, const CXXThrowExpr *E) override;
180179
CatchTypeInfo
@@ -2144,7 +2143,7 @@ void CIRGenItaniumCXXABI::buildDestructorCall(
21442143
void CIRGenItaniumCXXABI::registerGlobalDtor(CIRGenFunction &CGF,
21452144
const VarDecl *D,
21462145
mlir::cir::FuncOp dtor,
2147-
mlir::Attribute Addr) {
2146+
mlir::Value Addr) {
21482147
if (D->isNoDestroy(CGM.getASTContext()))
21492148
return;
21502149

clang/lib/CIR/CodeGen/CIRGenModule.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1662,7 +1662,7 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *expr,
16621662
} else {
16631663
// No initializer, the initialization will be provided when we initialize
16641664
// the declaration which performed lifetime extension.
1665-
llvm_unreachable("else value");
1665+
type = getTypes().convertTypeForMem(materializedType);
16661666
}
16671667

16681668
// Create a global variable for this lifetime-extended temporary.

clang/lib/CIR/CodeGen/CIRGenModule.h

+2-7
Original file line numberDiff line numberDiff line change
@@ -630,8 +630,8 @@ class CIRGenModule : public CIRGenTypeCache {
630630
bool IsTentative = false);
631631

632632
/// Emit the function that initializes the specified global
633-
void buildCXXGlobalVarDeclInit(const VarDecl *D, mlir::cir::GlobalOp Addr,
634-
bool PerformInit);
633+
void buildCXXGlobalVarDeclInit(const VarDecl *varDecl,
634+
mlir::cir::GlobalOp addr, bool performInit);
635635

636636
void buildCXXGlobalVarDeclInitFunc(const VarDecl *D, mlir::cir::GlobalOp Addr,
637637
bool PerformInit);
@@ -673,11 +673,6 @@ class CIRGenModule : public CIRGenTypeCache {
673673
// or if they are alias to each other.
674674
mlir::cir::FuncOp codegenCXXStructor(clang::GlobalDecl GD);
675675

676-
// Produce code for this constructor/destructor for global initialzation.
677-
void codegenGlobalInitCxxStructor(const clang::VarDecl *D,
678-
mlir::cir::GlobalOp Addr, bool NeedsCtor,
679-
bool NeedsDtor, bool isCstStorage);
680-
681676
bool lookupRepresentativeDecl(llvm::StringRef MangledName,
682677
clang::GlobalDecl &Result) const;
683678

clang/test/CIR/CodeGen/tempref.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
// RUN: cir-translate %t.cir -cir-to-llvmir -o %t.ll
4+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
5+
6+
struct A { ~A(); };
7+
A &&a = dynamic_cast<A&&>(A{});
8+
9+
// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr<!ty_A>) extra(#fn_attr)
10+
// CHECK-NEXT: cir.global external @a = #cir.ptr<null> : !cir.ptr<!ty_A> {alignment = 8 : i64, ast = #cir.var.decl.ast}
11+
// CHECK-NEXT: cir.func internal private @__cxx_global_var_init() {
12+
// CHECK-NEXT: cir.scope {
13+
// CHECK-NEXT: %[[SEVEN:[0-9]+]] = cir.get_global @a : !cir.ptr<!cir.ptr<!ty_A>>
14+
// CHECK-NEXT: %[[EIGHT:[0-9]+]] = cir.get_global @_ZGR1a_ : !cir.ptr<!ty_A>
15+
// CHECK-NEXT: cir.store %[[EIGHT]], %[[SEVEN]] : !cir.ptr<!ty_A>, !cir.ptr<!cir.ptr<!ty_A>>
16+
// CHECK-NEXT: }
17+
// CHECK-NEXT: cir.return
18+
// CHECK-NEXT: }
19+
// CHECK-NEXT: cir.func private @_GLOBAL__sub_I_tempref.cpp() {
20+
// CHECK-NEXT: cir.call @__cxx_global_var_init() : () -> ()
21+
// CHECK-NEXT: cir.return
22+
// CHECK-NEXT: }
23+
24+
// LLVM: @_ZGR1a_ = internal global %struct.A undef
25+
// LLVM-DAG: @a = global ptr null, align 8
26+
// LLVM-DAG: @llvm.global_ctors = appending constant [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65536, ptr @__cxx_global_var_init, ptr null }]
27+
28+
// LLVM-DAG: declare {{.*}} void @_ZN1AD1Ev(ptr)
29+
30+
// LLVM-DAG: define internal void @__cxx_global_var_init()
31+
// LLVM-DAG: br label %[[L1:[0-9]+]]
32+
// LLVM-DAG: [[L1]]:
33+
// LLVM-DAG: store ptr @_ZGR1a_, ptr @a, align 8
34+
// LLVM-DAG: br label %[[L2:[0-9]+]]
35+
// LLVM-DAG: [[L2]]:
36+
// LLVM-DAG: ret void
37+
// LLVM-DAG: }
38+
39+
// LLVM-DAG: define void @_GLOBAL__sub_I_tempref.cpp()
40+
// LLVM-DAG: call void @__cxx_global_var_init()
41+
// LLVM-DAG: ret void
42+
// LLVM-DAG: }

0 commit comments

Comments
 (0)