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 to emit Decl nodes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenConstantEmitter.h"
14#include "CIRGenFunction.h"
15#include "mlir/IR/Location.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclOpenACC.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/ExprCXX.h"
21#include "clang/CIR/MissingFeatures.h"
22
23using namespace clang;
24using namespace clang::CIRGen;
25
26CIRGenFunction::AutoVarEmission
27CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) {
28 QualType ty = d.getType();
29 if (ty.getAddressSpace() != LangAS::Default)
30 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space");
31
32 mlir::Location loc = getLoc(d.getSourceRange());
33
34 CIRGenFunction::AutoVarEmission emission(d);
35 emission.IsEscapingByRef = d.isEscapingByref();
36 if (emission.IsEscapingByRef)
37 cgm.errorNYI(d.getSourceRange(),
38 "emitAutoVarDecl: decl escaping by reference");
39
40 CharUnits alignment = getContext().getDeclAlign(&d);
41
42 // If the type is variably-modified, emit all the VLA sizes for it.
43 if (ty->isVariablyModifiedType())
44 cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type");
45
46 Address address = Address::invalid();
47 if (!ty->isConstantSizeType())
48 cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type");
49
50 // A normal fixed sized variable becomes an alloca in the entry block,
51 mlir::Type allocaTy = convertTypeForMem(ty);
52 // Create the temp alloca and declare variable using it.
53 address = createTempAlloca(allocaTy, alignment, loc, d.getName());
54 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
55
56 emission.Addr = address;
57 setAddrOfLocalVar(vd: &d, addr: address);
58
59 return emission;
60}
61
62/// Determine whether the given initializer is trivial in the sense
63/// that it requires no code to be generated.
64bool CIRGenFunction::isTrivialInitializer(const Expr *init) {
65 if (!init)
66 return true;
67
68 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(Val: init))
69 if (CXXConstructorDecl *constructor = construct->getConstructor())
70 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
71 !construct->requiresZeroInitialization())
72 return true;
73
74 return false;
75}
76
77void CIRGenFunction::emitAutoVarInit(
78 const CIRGenFunction::AutoVarEmission &emission) {
79 assert(emission.Variable && "emission was not valid!");
80
81 // If this was emitted as a global constant, we're done.
82 if (emission.wasEmittedAsGlobal())
83 return;
84
85 const VarDecl &d = *emission.Variable;
86
87 QualType type = d.getType();
88
89 // If this local has an initializer, emit it now.
90 const Expr *init = d.getInit();
91
92 // Initialize the variable here if it doesn't have a initializer and it is a
93 // C struct that is non-trivial to initialize or an array containing such a
94 // struct.
95 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
96 QualType::PDIK_Struct) {
97 cgm.errorNYI(d.getSourceRange(),
98 "emitAutoVarInit: non-trivial to default initialize");
99 return;
100 }
101
102 const Address addr = emission.Addr;
103
104 // Check whether this is a byref variable that's potentially
105 // captured and moved by its own initializer. If so, we'll need to
106 // emit the initializer first, then copy into the variable.
107 assert(!cir::MissingFeatures::opAllocaCaptureByInit());
108
109 // Note: constexpr already initializes everything correctly.
110 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
111 (d.isConstexpr()
112 ? LangOptions::TrivialAutoVarInitKind::Uninitialized
113 : (d.getAttr<UninitializedAttr>()
114 ? LangOptions::TrivialAutoVarInitKind::Uninitialized
115 : getContext().getLangOpts().getTrivialAutoVarInit()));
116
117 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
118 if (trivialAutoVarInit ==
119 LangOptions::TrivialAutoVarInitKind::Uninitialized)
120 return;
121
122 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
123 };
124
125 if (isTrivialInitializer(init)) {
126 initializeWhatIsTechnicallyUninitialized(addr);
127 return;
128 }
129
130 mlir::Attribute constant;
131 if (emission.IsConstantAggregate ||
132 d.mightBeUsableInConstantExpressions(C: getContext())) {
133 // FIXME: Differently from LLVM we try not to emit / lower too much
134 // here for CIR since we are interested in seeing the ctor in some
135 // analysis later on. So CIR's implementation of ConstantEmitter will
136 // frequently return an empty Attribute, to signal we want to codegen
137 // some trivial ctor calls and whatnots.
138 constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(d);
139 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
140 (trivialAutoVarInit !=
141 LangOptions::TrivialAutoVarInitKind::Uninitialized)) {
142 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
143 return;
144 }
145 }
146
147 // NOTE(cir): In case we have a constant initializer, we can just emit a
148 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
149 // CXX temporary object creation, we ensure the ctor call is used deferring
150 // its removal/optimization to the CIR lowering.
151 if (!constant || isa<CXXTemporaryObjectExpr>(Val: init)) {
152 initializeWhatIsTechnicallyUninitialized(addr);
153 LValue lv = makeAddrLValue(addr, ty: type, source: AlignmentSource::Decl);
154 emitExprAsInit(init, &d, lv);
155 // In case lv has uses it means we indeed initialized something
156 // out of it while trying to build the expression, mark it as such.
157 mlir::Value val = lv.getAddress().getPointer();
158 assert(val && "Should have an address");
159 auto allocaOp = dyn_cast_or_null<cir::AllocaOp>(val.getDefiningOp());
160 assert(allocaOp && "Address should come straight out of the alloca");
161
162 if (!allocaOp.use_empty())
163 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
164 return;
165 }
166
167 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
168 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
169 assert(typedConstant && "expected typed attribute");
170 if (!emission.IsConstantAggregate) {
171 // For simple scalar/complex initialization, store the value directly.
172 LValue lv = makeAddrLValue(addr, ty: type);
173 assert(init && "expected initializer");
174 mlir::Location initLoc = getLoc(init->getSourceRange());
175 // lv.setNonGC(true);
176 return emitStoreThroughLValue(
177 RValue::src: get(builder.getConstant(initLoc, typedConstant)), dst: lv);
178 }
179}
180
181void CIRGenFunction::emitAutoVarCleanups(
182 const CIRGenFunction::AutoVarEmission &emission) {
183 const VarDecl &d = *emission.Variable;
184
185 // Check the type for a cleanup.
186 if (d.needsDestruction(Ctx: getContext()))
187 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: type cleanup");
188
189 assert(!cir::MissingFeatures::opAllocaPreciseLifetime());
190
191 // Handle the cleanup attribute.
192 if (d.hasAttr<CleanupAttr>())
193 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
194}
195
196/// Emit code and set up symbol table for a variable declaration with auto,
197/// register, or no storage class specifier. These turn into simple stack
198/// objects, globals depending on target.
199void CIRGenFunction::emitAutoVarDecl(const VarDecl &d) {
200 CIRGenFunction::AutoVarEmission emission = emitAutoVarAlloca(d);
201 emitAutoVarInit(emission);
202 emitAutoVarCleanups(emission);
203}
204
205void CIRGenFunction::emitVarDecl(const VarDecl &d) {
206 // If the declaration has external storage, don't emit it now, allow it to be
207 // emitted lazily on its first use.
208 if (d.hasExternalStorage())
209 return;
210
211 if (d.getStorageDuration() != SD_Automatic)
212 cgm.errorNYI(d.getSourceRange(), "emitVarDecl automatic storage duration");
213 if (d.getType().getAddressSpace() == LangAS::opencl_local)
214 cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space");
215
216 assert(d.hasLocalStorage());
217
218 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
219 return emitAutoVarDecl(d);
220}
221
222void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
223 LValue lvalue, bool capturedByInit) {
224 assert(!cir::MissingFeatures::objCLifetime());
225
226 SourceLocRAIIObject locRAII{*this, loc};
227 mlir::Value value = emitScalarExpr(init);
228 if (capturedByInit) {
229 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
230 return;
231 }
232 assert(!cir::MissingFeatures::emitNullabilityCheck());
233 emitStoreThroughLValue(RValue::src: get(value), dst: lvalue, isInit: true);
234}
235
236void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,
237 LValue lvalue, bool capturedByInit) {
238 SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
239 if (capturedByInit) {
240 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
241 return;
242 }
243
244 QualType type = d->getType();
245
246 if (type->isReferenceType()) {
247 RValue rvalue = emitReferenceBindingToExpr(e: init);
248 if (capturedByInit)
249 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
250 emitStoreThroughLValue(src: rvalue, dst: lvalue);
251 return;
252 }
253 switch (CIRGenFunction::getEvaluationKind(type)) {
254 case cir::TEK_Scalar:
255 emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
256 return;
257 case cir::TEK_Complex: {
258 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: complex type");
259 return;
260 }
261 case cir::TEK_Aggregate:
262 emitAggExpr(e: init, slot: AggValueSlot::forLValue(lv: lvalue));
263 return;
264 }
265 llvm_unreachable("bad evaluation kind");
266}
267
268void CIRGenFunction::emitDecl(const Decl &d) {
269 switch (d.getKind()) {
270 case Decl::BuiltinTemplate:
271 case Decl::TranslationUnit:
272 case Decl::ExternCContext:
273 case Decl::Namespace:
274 case Decl::UnresolvedUsingTypename:
275 case Decl::ClassTemplateSpecialization:
276 case Decl::ClassTemplatePartialSpecialization:
277 case Decl::VarTemplateSpecialization:
278 case Decl::VarTemplatePartialSpecialization:
279 case Decl::TemplateTypeParm:
280 case Decl::UnresolvedUsingValue:
281 case Decl::NonTypeTemplateParm:
282 case Decl::CXXDeductionGuide:
283 case Decl::CXXMethod:
284 case Decl::CXXConstructor:
285 case Decl::CXXDestructor:
286 case Decl::CXXConversion:
287 case Decl::Field:
288 case Decl::MSProperty:
289 case Decl::IndirectField:
290 case Decl::ObjCIvar:
291 case Decl::ObjCAtDefsField:
292 case Decl::ParmVar:
293 case Decl::ImplicitParam:
294 case Decl::ClassTemplate:
295 case Decl::VarTemplate:
296 case Decl::FunctionTemplate:
297 case Decl::TypeAliasTemplate:
298 case Decl::TemplateTemplateParm:
299 case Decl::ObjCMethod:
300 case Decl::ObjCCategory:
301 case Decl::ObjCProtocol:
302 case Decl::ObjCInterface:
303 case Decl::ObjCCategoryImpl:
304 case Decl::ObjCImplementation:
305 case Decl::ObjCProperty:
306 case Decl::ObjCCompatibleAlias:
307 case Decl::PragmaComment:
308 case Decl::PragmaDetectMismatch:
309 case Decl::AccessSpec:
310 case Decl::LinkageSpec:
311 case Decl::Export:
312 case Decl::ObjCPropertyImpl:
313 case Decl::FileScopeAsm:
314 case Decl::Friend:
315 case Decl::FriendTemplate:
316 case Decl::Block:
317 case Decl::OutlinedFunction:
318 case Decl::Captured:
319 case Decl::UsingShadow:
320 case Decl::ConstructorUsingShadow:
321 case Decl::ObjCTypeParam:
322 case Decl::Binding:
323 case Decl::UnresolvedUsingIfExists:
324 case Decl::HLSLBuffer:
325 case Decl::HLSLRootSignature:
326 llvm_unreachable("Declaration should not be in declstmts!");
327
328 case Decl::Function: // void X();
329 case Decl::EnumConstant: // enum ? { X = ? }
330 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
331 case Decl::Label: // __label__ x;
332 case Decl::Import:
333 case Decl::MSGuid: // __declspec(uuid("..."))
334 case Decl::TemplateParamObject:
335 case Decl::OMPThreadPrivate:
336 case Decl::OMPAllocate:
337 case Decl::OMPCapturedExpr:
338 case Decl::OMPRequires:
339 case Decl::Empty:
340 case Decl::Concept:
341 case Decl::LifetimeExtendedTemporary:
342 case Decl::RequiresExprBody:
343 case Decl::UnnamedGlobalConstant:
344 // None of these decls require codegen support.
345 return;
346
347 case Decl::Enum: // enum X;
348 case Decl::Record: // struct/union/class X;
349 case Decl::CXXRecord: // struct/union/class X; [C++]
350 case Decl::NamespaceAlias:
351 case Decl::Using: // using X; [C++]
352 case Decl::UsingEnum: // using enum X; [C++]
353 case Decl::UsingDirective: // using namespace X; [C++]
354 assert(!cir::MissingFeatures::generateDebugInfo());
355 return;
356 case Decl::Var: {
357 const VarDecl &vd = cast<VarDecl>(Val: d);
358 assert(vd.isLocalVarDecl() &&
359 "Should not see file-scope variables inside a function!");
360 emitVarDecl(d: vd);
361 return;
362 }
363 case Decl::OpenACCDeclare:
364 emitOpenACCDeclare(d: cast<OpenACCDeclareDecl>(Val: d));
365 return;
366 case Decl::OpenACCRoutine:
367 emitOpenACCRoutine(d: cast<OpenACCRoutineDecl>(Val: d));
368 return;
369 case Decl::Typedef: // typedef int X;
370 case Decl::TypeAlias: { // using X = int; [C++0x]
371 QualType ty = cast<TypedefNameDecl>(Val: d).getUnderlyingType();
372 assert(!cir::MissingFeatures::generateDebugInfo());
373 if (ty->isVariablyModifiedType())
374 cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type");
375 return;
376 }
377 case Decl::ImplicitConceptSpecialization:
378 case Decl::TopLevelStmt:
379 case Decl::UsingPack:
380 case Decl::Decomposition: // This could be moved to join Decl::Var
381 case Decl::OMPDeclareReduction:
382 case Decl::OMPDeclareMapper:
383 cgm.errorNYI(d.getSourceRange(),
384 std::string("emitDecl: unhandled decl type: ") +
385 d.getDeclKindName());
386 }
387}
388
389void CIRGenFunction::emitNullabilityCheck(LValue lhs, mlir::Value rhs,
390 SourceLocation loc) {
391 if (!sanOpts.has(K: SanitizerKind::NullabilityAssign))
392 return;
393
394 assert(!cir::MissingFeatures::sanitizers());
395}
396

source code of clang/lib/CIR/CodeGen/CIRGenDecl.cpp