clang 22.0.0git
CIRGenCXX.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code dealing with C++ code generation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenCXXABI.h"
14#include "CIRGenFunction.h"
15#include "CIRGenModule.h"
16
19#include "llvm/Support/SaveAndRestore.h"
20
21using namespace clang;
22using namespace clang::CIRGen;
23
24static void emitDeclInit(CIRGenFunction &cgf, const VarDecl *varDecl,
25 cir::GlobalOp globalOp) {
26 assert((varDecl->hasGlobalStorage() ||
27 (varDecl->hasLocalStorage() &&
28 cgf.getContext().getLangOpts().OpenCLCPlusPlus)) &&
29 "VarDecl must have global or local (in the case of OpenCL) storage!");
30 assert(!varDecl->getType()->isReferenceType() &&
31 "Should not call emitDeclInit on a reference!");
32
33 CIRGenBuilderTy &builder = cgf.getBuilder();
34
35 // Set up the ctor region.
36 mlir::OpBuilder::InsertionGuard guard(builder);
37 mlir::Block *block = builder.createBlock(&globalOp.getCtorRegion());
38 CIRGenFunction::LexicalScope lexScope{cgf, globalOp.getLoc(),
39 builder.getInsertionBlock()};
40 lexScope.setAsGlobalInit();
41 builder.setInsertionPointToStart(block);
42
45
46 QualType type = varDecl->getType();
47 LValue lv = cgf.makeAddrLValue(declAddr, type);
48
49 const Expr *init = varDecl->getInit();
51 case cir::TEK_Scalar:
53 cgf.emitScalarInit(init, cgf.getLoc(varDecl->getLocation()), lv, false);
54 break;
56 cgf.cgm.errorNYI(varDecl->getSourceRange(), "complex global initializer");
57 break;
60 cgf.emitAggExpr(init,
64 break;
65 }
66
67 // Finish the ctor region.
68 builder.setInsertionPointToEnd(block);
69 cir::YieldOp::create(builder, globalOp.getLoc());
70}
71
72static void emitDeclDestroy(CIRGenFunction &cgf, const VarDecl *vd,
73 cir::GlobalOp addr) {
74 // Honor __attribute__((no_destroy)) and bail instead of attempting
75 // to emit a reference to a possibly nonexistent destructor, which
76 // in turn can cause a crash. This will result in a global constructor
77 // that isn't balanced out by a destructor call as intended by the
78 // attribute. This also checks for -fno-c++-static-destructors and
79 // bails even if the attribute is not present.
81
82 // FIXME: __attribute__((cleanup)) ?
83
84 switch (dtorKind) {
86 return;
87
89 break;
90
94 // We don't care about releasing objects during process teardown.
95 assert(!vd->getTLSKind() && "should have rejected this");
96 return;
97 }
98
99 // If not constant storage we'll emit this regardless of NeedsDtor value.
100 CIRGenBuilderTy &builder = cgf.getBuilder();
101
102 // Prepare the dtor region.
103 mlir::OpBuilder::InsertionGuard guard(builder);
104 mlir::Block *block = builder.createBlock(&addr.getDtorRegion());
105 CIRGenFunction::LexicalScope lexScope{cgf, addr.getLoc(),
106 builder.getInsertionBlock()};
107 lexScope.setAsGlobalInit();
108 builder.setInsertionPointToStart(block);
109
110 CIRGenModule &cgm = cgf.cgm;
111 QualType type = vd->getType();
112
113 // Special-case non-array C++ destructors, if they have the right signature.
114 // Under some ABIs, destructors return this instead of void, and cannot be
115 // passed directly to __cxa_atexit if the target does not allow this
116 // mismatch.
117 const CXXRecordDecl *record = type->getAsCXXRecordDecl();
118 bool canRegisterDestructor =
119 record && (!cgm.getCXXABI().hasThisReturn(
122
123 // If __cxa_atexit is disabled via a flag, a different helper function is
124 // generated elsewhere which uses atexit instead, and it takes the destructor
125 // directly.
126 cir::FuncOp fnOp;
127 if (record && (canRegisterDestructor || cgm.getCodeGenOpts().CXAAtExit)) {
128 if (vd->getTLSKind())
129 cgm.errorNYI(vd->getSourceRange(), "TLS destructor");
130 assert(!record->hasTrivialDestructor());
132 CXXDestructorDecl *dtor = record->getDestructor();
133 // In LLVM OG codegen this is done in registerGlobalDtor, but CIRGen
134 // relies on LoweringPrepare for further decoupling, so build the
135 // call right here.
136 auto gd = GlobalDecl(dtor, Dtor_Complete);
137 fnOp = cgm.getAddrAndTypeOfCXXStructor(gd).second;
139 cgf.getLoc(vd->getSourceRange()),
140 mlir::FlatSymbolRefAttr::get(fnOp.getSymNameAttr()),
141 mlir::ValueRange{cgm.getAddrOfGlobalVar(vd)});
142 } else {
143 cgm.errorNYI(vd->getSourceRange(), "array destructor");
144 }
145 assert(fnOp && "expected cir.func");
146 cgm.getCXXABI().registerGlobalDtor(vd, fnOp, nullptr);
147
148 builder.setInsertionPointToEnd(block);
149 if (block->empty()) {
150 block->erase();
151 // Don't confuse lexical cleanup.
152 builder.clearInsertionPoint();
153 } else {
154 builder.create<cir::YieldOp>(addr.getLoc());
155 }
156}
157
159 const CIRGenFunctionInfo &fnInfo =
161 cir::FuncType funcType = getTypes().getFunctionType(fnInfo);
162 cir::FuncOp fn = getAddrOfCXXStructor(gd, &fnInfo, /*FnType=*/nullptr,
163 /*DontDefer=*/true, ForDefinition);
164 setFunctionLinkage(gd, fn);
165 CIRGenFunction cgf{*this, builder};
166 curCGF = &cgf;
167 {
168 mlir::OpBuilder::InsertionGuard guard(builder);
169 cgf.generateCode(gd, fn, funcType);
170 }
171 curCGF = nullptr;
172
173 setNonAliasAttributes(gd, fn);
175 return fn;
176}
177
178// Global variables requiring non-trivial initialization are handled
179// differently in CIR than in classic codegen. Classic codegen emits
180// a global init function (__cxx_global_var_init) and inserts
181// initialization for each global there. In CIR, we attach a ctor
182// region to the global variable and insert the initialization code
183// into the ctor region. This will be moved into the
184// __cxx_global_var_init function during the LoweringPrepare pass.
186 cir::GlobalOp addr,
187 bool performInit) {
188 QualType ty = varDecl->getType();
189
190 // TODO: handle address space
191 // The address space of a static local variable (addr) may be different
192 // from the address space of the "this" argument of the constructor. In that
193 // case, we need an addrspacecast before calling the constructor.
194 //
195 // struct StructWithCtor {
196 // __device__ StructWithCtor() {...}
197 // };
198 // __device__ void foo() {
199 // __shared__ StructWithCtor s;
200 // ...
201 // }
202 //
203 // For example, in the above CUDA code, the static local variable s has a
204 // "shared" address space qualifier, but the constructor of StructWithCtor
205 // expects "this" in the "generic" address space.
207
208 // Create a CIRGenFunction to emit the initializer. While this isn't a true
209 // function, the handling works the same way.
210 CIRGenFunction cgf{*this, builder, true};
211 llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf);
212 curCGF->curFn = addr;
213
215 getLoc(varDecl->getLocation())};
216
218
219 if (!ty->isReferenceType()) {
221
222 bool needsDtor = varDecl->needsDestruction(getASTContext()) ==
224 // PerformInit, constant store invariant / destroy handled below.
225 if (performInit)
226 emitDeclInit(cgf, varDecl, addr);
227
228 if (varDecl->getType().isConstantStorage(getASTContext(), true, !needsDtor))
229 errorNYI(varDecl->getSourceRange(), "global with constant storage");
230 else
231 emitDeclDestroy(cgf, varDecl, addr);
232 return;
233 }
234
235 errorNYI(varDecl->getSourceRange(), "global with reference type");
236}
static void emitDeclDestroy(CIRGenFunction &cgf, const VarDecl *vd, cir::GlobalOp addr)
Definition CIRGenCXX.cpp:72
static void emitDeclInit(CIRGenFunction &cgf, const VarDecl *varDecl, cir::GlobalOp globalOp)
Definition CIRGenCXX.cpp:24
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee, mlir::Type returnType, mlir::ValueRange operands, llvm::ArrayRef< mlir::NamedAttribute > attrs={})
const LangOptions & getLangOpts() const
Definition ASTContext.h:926
CharUnits getDeclAlign(const Decl *D, bool ForAlignof=false) const
Return a conservative estimate of the alignment of the specified decl D.
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
virtual void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor, mlir::Value addr)=0
Emit code to force the execution of a destructor during global teardown.
virtual bool canCallMismatchedFunctionType() const
Returns true if the target allows calling a function through a pointer with a different signature tha...
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn, cir::FuncType funcType)
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit=false)
CIRGenBuilderTy & getBuilder()
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
clang::ASTContext & getContext() const
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
This class organizes the cross-function state that is used while generating CIR code.
void emitCXXGlobalVarDeclInit(const VarDecl *varDecl, cir::GlobalOp addr, bool performInit)
Emit the function that initializes the specified global.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
cir::FuncOp getAddrOfCXXStructor(clang::GlobalDecl gd, const CIRGenFunctionInfo *fnInfo=nullptr, cir::FuncType fnType=nullptr, bool dontDefer=false, ForDefinition_t isForDefinition=NotForDefinition)
std::pair< cir::FuncType, cir::FuncOp > getAddrAndTypeOfCXXStructor(clang::GlobalDecl gd, const CIRGenFunctionInfo *fnInfo=nullptr, cir::FuncType fnType=nullptr, bool dontDefer=false, ForDefinition_t isForDefinition=NotForDefinition)
mlir::Value getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty={}, ForDefinition_t isForDefinition=NotForDefinition)
Return the mlir::Value for the address of the given global variable.
const clang::CodeGenOptions & getCodeGenOpts() const
cir::FuncOp codegenCXXStructor(clang::GlobalDecl gd)
mlir::Location getLoc(clang::SourceLocation cLoc)
Helpers to convert the presumed location of Clang's SourceLocation to an MLIR Location.
CIRGenCXXABI & getCXXABI() const
void setFunctionLinkage(GlobalDecl gd, cir::FuncOp f)
const CIRGenFunctionInfo & arrangeCXXStructorDeclaration(clang::GlobalDecl gd)
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
Represents a C++ destructor within a class.
Definition DeclCXX.h:2869
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
Definition DeclCXX.h:1366
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
Definition DeclCXX.cpp:2121
This represents one expression.
Definition Expr.h:112
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isReferenceType() const
Definition TypeBase.h:8539
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
TLSKind getTLSKind() const
Definition Decl.cpp:2168
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2190
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2851
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
The JSON file list parser is used to communicate input to InstallAPI.
@ Dtor_Complete
Complete object dtor.
Definition ABI.h:36
static bool addressSpace()
static bool aggValueSlotGC()
static bool opFuncAttributesForDefinition()
static bool astVarDeclInterface()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...