clang 22.0.0git
CIRGenDecl.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 to emit Decl nodes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
14#include "CIRGenFunction.h"
15#include "mlir/IR/Location.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/Decl.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/ExprCXX.h"
22
23using namespace clang;
24using namespace clang::CIRGen;
25
28 mlir::OpBuilder::InsertPoint ip) {
29 QualType ty = d.getType();
31 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space");
32
33 mlir::Location loc = getLoc(d.getSourceRange());
34 bool nrvo =
35 getContext().getLangOpts().ElideConstructors && d.isNRVOVariable();
36
38 emission.IsEscapingByRef = d.isEscapingByref();
39 if (emission.IsEscapingByRef)
40 cgm.errorNYI(d.getSourceRange(),
41 "emitAutoVarDecl: decl escaping by reference");
42
43 CharUnits alignment = getContext().getDeclAlign(&d);
44
45 // If the type is variably-modified, emit all the VLA sizes for it.
46 if (ty->isVariablyModifiedType())
47 cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type");
48
50
51 Address address = Address::invalid();
52 if (!ty->isConstantSizeType())
53 cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type");
54
55 // A normal fixed sized variable becomes an alloca in the entry block,
56 // unless:
57 // - it's an NRVO variable.
58 // - we are compiling OpenMP and it's an OpenMP local variable.
59 if (nrvo) {
60 // The named return value optimization: allocate this variable in the
61 // return slot, so that we can elide the copy when returning this
62 // variable (C++0x [class.copy]p34).
63 address = returnValue;
64
65 if (const RecordDecl *rd = ty->getAsRecordDecl()) {
66 if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
67 (cxxrd && !cxxrd->hasTrivialDestructor()) ||
68 rd->isNonTrivialToPrimitiveDestroy())
69 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag");
70 }
71 } else {
72 // A normal fixed sized variable becomes an alloca in the entry block,
73 mlir::Type allocaTy = convertTypeForMem(ty);
74 // Create the temp alloca and declare variable using it.
75 address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
76 /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
77 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
78 alignment);
79 }
80
81 emission.Addr = address;
82 setAddrOfLocalVar(&d, address);
83
84 return emission;
85}
86
87/// Determine whether the given initializer is trivial in the sense
88/// that it requires no code to be generated.
90 if (!init)
91 return true;
92
93 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
94 if (CXXConstructorDecl *constructor = construct->getConstructor())
95 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
96 !construct->requiresZeroInitialization())
97 return true;
98
99 return false;
100}
101
103 const CIRGenFunction::AutoVarEmission &emission) {
104 assert(emission.Variable && "emission was not valid!");
105
106 // If this was emitted as a global constant, we're done.
107 if (emission.wasEmittedAsGlobal())
108 return;
109
110 const VarDecl &d = *emission.Variable;
111
112 QualType type = d.getType();
113
114 // If this local has an initializer, emit it now.
115 const Expr *init = d.getInit();
116
117 // Initialize the variable here if it doesn't have a initializer and it is a
118 // C struct that is non-trivial to initialize or an array containing such a
119 // struct.
120 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
122 cgm.errorNYI(d.getSourceRange(),
123 "emitAutoVarInit: non-trivial to default initialize");
124 return;
125 }
126
127 const Address addr = emission.Addr;
128
129 // Check whether this is a byref variable that's potentially
130 // captured and moved by its own initializer. If so, we'll need to
131 // emit the initializer first, then copy into the variable.
133
134 // Note: constexpr already initializes everything correctly.
135 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
136 (d.isConstexpr()
138 : (d.getAttr<UninitializedAttr>()
140 : getContext().getLangOpts().getTrivialAutoVarInit()));
141
142 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
143 if (trivialAutoVarInit ==
145 return;
146
147 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
148 };
149
150 if (isTrivialInitializer(init)) {
151 initializeWhatIsTechnicallyUninitialized(addr);
152 return;
153 }
154
155 mlir::Attribute constant;
156 if (emission.IsConstantAggregate ||
158 // FIXME: Differently from LLVM we try not to emit / lower too much
159 // here for CIR since we are interested in seeing the ctor in some
160 // analysis later on. So CIR's implementation of ConstantEmitter will
161 // frequently return an empty Attribute, to signal we want to codegen
162 // some trivial ctor calls and whatnots.
164 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
165 (trivialAutoVarInit !=
167 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
168 return;
169 }
170 }
171
172 // NOTE(cir): In case we have a constant initializer, we can just emit a
173 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
174 // CXX temporary object creation, we ensure the ctor call is used deferring
175 // its removal/optimization to the CIR lowering.
176 if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
177 initializeWhatIsTechnicallyUninitialized(addr);
179 emitExprAsInit(init, &d, lv);
180
181 if (!emission.wasEmittedAsOffloadClause()) {
182 // In case lv has uses it means we indeed initialized something
183 // out of it while trying to build the expression, mark it as such.
184 mlir::Value val = lv.getAddress().getPointer();
185 assert(val && "Should have an address");
186 auto allocaOp = val.getDefiningOp<cir::AllocaOp>();
187 assert(allocaOp && "Address should come straight out of the alloca");
188
189 if (!allocaOp.use_empty())
190 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
191 }
192
193 return;
194 }
195
196 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
197 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
198 assert(typedConstant && "expected typed attribute");
199 if (!emission.IsConstantAggregate) {
200 // For simple scalar/complex initialization, store the value directly.
201 LValue lv = makeAddrLValue(addr, type);
202 assert(init && "expected initializer");
203 mlir::Location initLoc = getLoc(init->getSourceRange());
204 // lv.setNonGC(true);
206 RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
207 }
208}
209
211 const CIRGenFunction::AutoVarEmission &emission) {
212 const VarDecl &d = *emission.Variable;
213
214 // Check the type for a cleanup.
216 emitAutoVarTypeCleanup(emission, dtorKind);
217
219
220 // Handle the cleanup attribute.
221 if (d.hasAttr<CleanupAttr>())
222 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
223}
224
225/// Emit code and set up symbol table for a variable declaration with auto,
226/// register, or no storage class specifier. These turn into simple stack
227/// objects, globals depending on target.
233
235 // If the declaration has external storage, don't emit it now, allow it to be
236 // emitted lazily on its first use.
237 if (d.hasExternalStorage())
238 return;
239
240 if (d.getStorageDuration() != SD_Automatic) {
241 // Static sampler variables translated to function calls.
242 if (d.getType()->isSamplerT()) {
243 // Nothing needs to be done here, but let's flag it as an error until we
244 // have a test. It requires OpenCL support.
245 cgm.errorNYI(d.getSourceRange(), "emitVarDecl static sampler type");
246 return;
247 }
248
249 cir::GlobalLinkageKind linkage =
250 cgm.getCIRLinkageVarDefinition(&d, /*IsConstant=*/false);
251
252 // FIXME: We need to force the emission/use of a guard variable for
253 // some variables even if we can constant-evaluate them because
254 // we can't guarantee every translation unit will constant-evaluate them.
255
256 return emitStaticVarDecl(d, linkage);
257 }
258
260 cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space");
261
262 assert(d.hasLocalStorage());
263
264 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
265 return emitAutoVarDecl(d);
266}
267
268static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
269 if (cgm.getLangOpts().CPlusPlus)
270 return cgm.getMangledName(&d).str();
271
272 // If this isn't C++, we don't need a mangled name, just a pretty one.
273 assert(!d.isExternallyVisible() && "name shouldn't matter");
274 std::string contextName;
275 const DeclContext *dc = d.getDeclContext();
276 if (auto *cd = dyn_cast<CapturedDecl>(dc))
277 dc = cast<DeclContext>(cd->getNonClosureContext());
278 if (const auto *fd = dyn_cast<FunctionDecl>(dc))
279 contextName = std::string(cgm.getMangledName(fd));
280 else if (isa<BlockDecl>(dc))
281 cgm.errorNYI(d.getSourceRange(), "block decl context for static var");
282 else if (isa<ObjCMethodDecl>(dc))
283 cgm.errorNYI(d.getSourceRange(), "ObjC decl context for static var");
284 else
285 cgm.errorNYI(d.getSourceRange(), "Unknown context for static var decl");
286
287 contextName += "." + d.getNameAsString();
288 return contextName;
289}
290
291// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
292// interface for all constants?
293cir::GlobalOp
295 cir::GlobalLinkageKind linkage) {
296 // In general, we don't always emit static var decls once before we reference
297 // them. It is possible to reference them before emitting the function that
298 // contains them, and it is possible to emit the containing function multiple
299 // times.
300 if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
301 return existingGV;
302
303 QualType ty = d.getType();
304 assert(ty->isConstantSizeType() && "VLAs can't be static");
305
306 // Use the label if the variable is renamed with the asm-label extension.
307 if (d.hasAttr<AsmLabelAttr>())
308 errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label");
309
310 std::string name = getStaticDeclName(*this, d);
311
312 mlir::Type lty = getTypes().convertTypeForMem(ty);
314
315 if (d.hasAttr<LoaderUninitializedAttr>() || d.hasAttr<CUDASharedAttr>())
317 "getOrCreateStaticVarDecl: LoaderUninitializedAttr");
319
320 mlir::Attribute init = builder.getZeroInitAttr(convertType(ty));
321
322 cir::GlobalOp gv = builder.createVersionedGlobal(
323 getModule(), getLoc(d.getLocation()), name, lty, false, linkage);
324 // TODO(cir): infer visibility from linkage in global op builder.
325 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
326 gv.setInitialValueAttr(init);
327 gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
328
329 if (supportsCOMDAT() && gv.isWeakForLinker())
330 gv.setComdat(true);
331
333
334 setGVProperties(gv, &d);
335
336 // OG checks if the expected address space, denoted by the type, is the
337 // same as the actual address space indicated by attributes. If they aren't
338 // the same, an addrspacecast is emitted when this variable is accessed.
339 // In CIR however, cir.get_global already carries that information in
340 // !cir.ptr type - if this global is in OpenCL local address space, then its
341 // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't
342 // need an explicit address space cast in CIR: they will get emitted when
343 // lowering to LLVM IR.
344
345 // Ensure that the static local gets initialized by making sure the parent
346 // function gets emitted eventually.
347 const Decl *dc = cast<Decl>(d.getDeclContext());
348
349 // We can't name blocks or captured statements directly, so try to emit their
350 // parents.
351 if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
352 dc = dc->getNonClosureContext();
353 // FIXME: Ensure that global blocks get emitted.
354 if (!dc)
355 errorNYI(d.getSourceRange(), "non-closure context");
356 }
357
358 GlobalDecl gd;
360 errorNYI(d.getSourceRange(), "C++ constructors static var context");
361 else if (isa<CXXDestructorDecl>(dc))
362 errorNYI(d.getSourceRange(), "C++ destructors static var context");
363 else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
364 gd = GlobalDecl(fd);
365 else {
366 // Don't do anything for Obj-C method decls or global closures. We should
367 // never defer them.
368 assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
369 }
371 // Disable emission of the parent function for the OpenMP device codegen.
372 errorNYI(d.getSourceRange(), "OpenMP");
373 }
374
375 return gv;
376}
377
378/// Add the initializer for 'd' to the global variable that has already been
379/// created for it. If the initializer has a different type than gv does, this
380/// may free gv and return a different one. Otherwise it just returns gv.
382 const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
383 ConstantEmitter emitter(*this);
384 mlir::TypedAttr init =
385 mlir::cast<mlir::TypedAttr>(emitter.tryEmitForInitializer(d));
386
387 // If constant emission failed, then this should be a C++ static
388 // initializer.
389 if (!init) {
390 cgm.errorNYI(d.getSourceRange(), "static var without initializer");
391 return gv;
392 }
393
394 // TODO(cir): There should be debug code here to assert that the decl size
395 // matches the CIR data layout type alloc size, but the code for calculating
396 // the type alloc size is not implemented yet.
398
399 // The initializer may differ in type from the global. Rewrite
400 // the global to match the initializer. (We have to do this
401 // because some types, like unions, can't be completely represented
402 // in the LLVM type system.)
403 if (gv.getSymType() != init.getType()) {
404 gv.setSymType(init.getType());
405
406 // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
407 // but since at this point the current block hasn't been really attached,
408 // there's no visibility into the GetGlobalOp corresponding to this Global.
409 // Given those constraints, thread in the GetGlobalOp and update it
410 // directly.
412 gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
413 }
414
415 bool needsDtor =
417
419 gv.setInitialValueAttr(init);
420
421 emitter.finalize(gv);
422
423 if (needsDtor) {
424 // We have a constant initializer, but a nontrivial destructor. We still
425 // need to perform a guarded "initialization" in order to register the
426 // destructor.
427 cgm.errorNYI(d.getSourceRange(), "C++ guarded init");
428 }
429
430 return gv;
431}
432
434 cir::GlobalLinkageKind linkage) {
435 // Check to see if we already have a global variable for this
436 // declaration. This can happen when double-emitting function
437 // bodies, e.g. with complete and base constructors.
438 cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
439 // TODO(cir): we should have a way to represent global ops as values without
440 // having to emit a get global op. Sometimes these emissions are not used.
441 mlir::Value addr = builder.createGetGlobal(globalOp);
442 auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>();
443 assert(getAddrOp && "expected cir::GetGlobalOp");
444
445 CharUnits alignment = getContext().getDeclAlign(&d);
446
447 // Store into LocalDeclMap before generating initializer to handle
448 // circular references.
449 mlir::Type elemTy = convertTypeForMem(d.getType());
450 setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
451
452 // We can't have a VLA here, but we can have a pointer to a VLA,
453 // even though that doesn't really make any sense.
454 // Make sure to evaluate VLA bounds now so that we have them for later.
455 if (d.getType()->isVariablyModifiedType()) {
456 cgm.errorNYI(d.getSourceRange(),
457 "emitStaticVarDecl: variably modified type");
458 }
459
460 // Save the type in case adding the initializer forces a type change.
461 mlir::Type expectedType = addr.getType();
462
463 cir::GlobalOp var = globalOp;
464
466
467 // If this value has an initializer, emit it.
468 if (d.getInit())
469 var = addInitializerToStaticVarDecl(d, var, getAddrOp);
470
471 var.setAlignment(alignment.getAsAlign().value());
472
473 // There are a lot of attributes that need to be handled here. Until
474 // we start to support them, we just report an error if there are any.
475 if (d.hasAttrs())
476 cgm.errorNYI(d.getSourceRange(), "static var with attrs");
477
478 if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
479 cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
480
481 // From traditional codegen:
482 // We may have to cast the constant because of the initializer
483 // mismatch above.
484 //
485 // FIXME: It is really dangerous to store this in the map; if anyone
486 // RAUW's the GV uses of this constant will be invalid.
487 mlir::Value castedAddr =
488 builder.createBitcast(getAddrOp.getAddr(), expectedType);
489 localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
490 cgm.setStaticLocalDeclAddress(&d, var);
491
494}
495
496void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
497 LValue lvalue, bool capturedByInit) {
499
500 SourceLocRAIIObject locRAII{*this, loc};
501 mlir::Value value = emitScalarExpr(init);
502 if (capturedByInit) {
503 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
504 return;
505 }
507 emitStoreThroughLValue(RValue::get(value), lvalue, true);
508}
509
511 LValue lvalue, bool capturedByInit) {
512 SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
513 if (capturedByInit) {
514 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
515 return;
516 }
517
518 QualType type = d->getType();
519
520 if (type->isReferenceType()) {
521 RValue rvalue = emitReferenceBindingToExpr(init);
522 if (capturedByInit)
523 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
524 emitStoreThroughLValue(rvalue, lvalue);
525 return;
526 }
528 case cir::TEK_Scalar:
529 emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
530 return;
531 case cir::TEK_Complex: {
532 mlir::Value complex = emitComplexExpr(init);
533 if (capturedByInit)
534 cgm.errorNYI(init->getSourceRange(),
535 "emitExprAsInit: complex type captured by init");
536 mlir::Location loc = getLoc(init->getExprLoc());
537 emitStoreOfComplex(loc, complex, lvalue,
538 /*isInit*/ true);
539 return;
540 }
542 // The overlap flag here should be calculated.
544 emitAggExpr(init,
548 return;
549 }
550 llvm_unreachable("bad evaluation kind");
551}
552
553void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
554 switch (d.getKind()) {
555 case Decl::BuiltinTemplate:
556 case Decl::TranslationUnit:
557 case Decl::ExternCContext:
558 case Decl::Namespace:
559 case Decl::UnresolvedUsingTypename:
560 case Decl::ClassTemplateSpecialization:
561 case Decl::ClassTemplatePartialSpecialization:
562 case Decl::VarTemplateSpecialization:
563 case Decl::VarTemplatePartialSpecialization:
564 case Decl::TemplateTypeParm:
565 case Decl::UnresolvedUsingValue:
566 case Decl::NonTypeTemplateParm:
567 case Decl::CXXDeductionGuide:
568 case Decl::CXXMethod:
569 case Decl::CXXConstructor:
570 case Decl::CXXDestructor:
571 case Decl::CXXConversion:
572 case Decl::Field:
573 case Decl::MSProperty:
574 case Decl::IndirectField:
575 case Decl::ObjCIvar:
576 case Decl::ObjCAtDefsField:
577 case Decl::ParmVar:
578 case Decl::ImplicitParam:
579 case Decl::ClassTemplate:
580 case Decl::VarTemplate:
581 case Decl::FunctionTemplate:
582 case Decl::TypeAliasTemplate:
583 case Decl::TemplateTemplateParm:
584 case Decl::ObjCMethod:
585 case Decl::ObjCCategory:
586 case Decl::ObjCProtocol:
587 case Decl::ObjCInterface:
588 case Decl::ObjCCategoryImpl:
589 case Decl::ObjCImplementation:
590 case Decl::ObjCProperty:
591 case Decl::ObjCCompatibleAlias:
592 case Decl::PragmaComment:
593 case Decl::PragmaDetectMismatch:
594 case Decl::AccessSpec:
595 case Decl::LinkageSpec:
596 case Decl::Export:
597 case Decl::ObjCPropertyImpl:
598 case Decl::FileScopeAsm:
599 case Decl::Friend:
600 case Decl::FriendTemplate:
601 case Decl::Block:
602 case Decl::OutlinedFunction:
603 case Decl::Captured:
604 case Decl::UsingShadow:
605 case Decl::ConstructorUsingShadow:
606 case Decl::ObjCTypeParam:
607 case Decl::Binding:
608 case Decl::UnresolvedUsingIfExists:
609 case Decl::HLSLBuffer:
610 case Decl::HLSLRootSignature:
611 llvm_unreachable("Declaration should not be in declstmts!");
612
613 case Decl::Function: // void X();
614 case Decl::EnumConstant: // enum ? { X = ? }
615 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
616 case Decl::Label: // __label__ x;
617 case Decl::Import:
618 case Decl::MSGuid: // __declspec(uuid("..."))
619 case Decl::TemplateParamObject:
620 case Decl::OMPThreadPrivate:
621 case Decl::OMPAllocate:
622 case Decl::OMPCapturedExpr:
623 case Decl::OMPRequires:
624 case Decl::Empty:
625 case Decl::Concept:
626 case Decl::LifetimeExtendedTemporary:
627 case Decl::RequiresExprBody:
628 case Decl::UnnamedGlobalConstant:
629 // None of these decls require codegen support.
630 return;
631
632 case Decl::Enum: // enum X;
633 case Decl::Record: // struct/union/class X;
634 case Decl::CXXRecord: // struct/union/class X; [C++]
635 case Decl::NamespaceAlias:
636 case Decl::Using: // using X; [C++]
637 case Decl::UsingEnum: // using enum X; [C++]
638 case Decl::UsingDirective: // using namespace X; [C++]
640 return;
641 case Decl::Var:
642 case Decl::Decomposition: {
643 const VarDecl &vd = cast<VarDecl>(d);
644 assert(vd.isLocalVarDecl() &&
645 "Should not see file-scope variables inside a function!");
646 emitVarDecl(vd);
647 if (evaluateConditionDecl)
649 return;
650 }
651 case Decl::OpenACCDeclare:
653 return;
654 case Decl::OpenACCRoutine:
656 return;
657 case Decl::Typedef: // typedef int X;
658 case Decl::TypeAlias: { // using X = int; [C++0x]
659 QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
661 if (ty->isVariablyModifiedType())
662 cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type");
663 return;
664 }
665 case Decl::ImplicitConceptSpecialization:
666 case Decl::TopLevelStmt:
667 case Decl::UsingPack:
668 case Decl::OMPDeclareReduction:
669 case Decl::OMPDeclareMapper:
670 cgm.errorNYI(d.getSourceRange(),
671 std::string("emitDecl: unhandled decl type: ") +
672 d.getDeclKindName());
673 }
674}
675
677 SourceLocation loc) {
678 if (!sanOpts.has(SanitizerKind::NullabilityAssign))
679 return;
680
682}
683
684namespace {
685struct DestroyObject final : EHScopeStack::Cleanup {
686 DestroyObject(Address addr, QualType type,
687 CIRGenFunction::Destroyer *destroyer)
688 : addr(addr), type(type), destroyer(destroyer) {}
689
690 Address addr;
692 CIRGenFunction::Destroyer *destroyer;
693
694 void emit(CIRGenFunction &cgf) override {
695 cgf.emitDestroy(addr, type, destroyer);
696 }
697
698 // This is a placeholder until EHCleanupScope is implemented.
699 size_t getSize() const override {
701 return sizeof(DestroyObject);
702 }
703};
704} // namespace
705
707 QualType type, Destroyer *destroyer) {
708 pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
709}
710
711/// Destroys all the elements of the given array, beginning from last to first.
712/// The array cannot be zero-length.
713///
714/// \param begin - a type* denoting the first element of the array
715/// \param end - a type* denoting one past the end of the array
716/// \param elementType - the element type of the array
717/// \param destroyer - the function to call to destroy elements
718void CIRGenFunction::emitArrayDestroy(mlir::Value begin, mlir::Value end,
719 QualType elementType,
720 CharUnits elementAlign,
721 Destroyer *destroyer) {
722 assert(!elementType->isArrayType());
723
724 // Differently from LLVM traditional codegen, use a higher level
725 // representation instead of lowering directly to a loop.
726 mlir::Type cirElementType = convertTypeForMem(elementType);
727 cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
728
729 // Emit the dtor call that will execute for every array element.
730 cir::ArrayDtor::create(
731 builder, *currSrcLoc, begin, [&](mlir::OpBuilder &b, mlir::Location loc) {
732 auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
733 Address curAddr = Address(arg, cirElementType, elementAlign);
735
736 // Perform the actual destruction there.
737 destroyer(*this, curAddr, elementType);
738
739 cir::YieldOp::create(builder, loc);
740 });
741}
742
743/// Immediately perform the destruction of the given object.
744///
745/// \param addr - the address of the object; a type*
746/// \param type - the type of the object; if an array type, all
747/// objects are destroyed in reverse order
748/// \param destroyer - the function to call to destroy individual
749/// elements
751 Destroyer *destroyer) {
753 if (!arrayType)
754 return destroyer(*this, addr, type);
755
756 mlir::Value length = emitArrayLength(arrayType, type, addr);
757
758 CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
759 getContext().getTypeSizeInChars(type));
760
761 auto constantCount = length.getDefiningOp<cir::ConstantOp>();
762 if (!constantCount) {
764 cgm.errorNYI("emitDestroy: variable length array");
765 return;
766 }
767
768 auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue());
769 // If it's constant zero, we can just skip the entire thing.
770 if (constIntAttr && constIntAttr.getUInt() == 0)
771 return;
772
773 mlir::Value begin = addr.getPointer();
774 mlir::Value end; // This will be used for future non-constant counts.
775 emitArrayDestroy(begin, end, type, elementAlign, destroyer);
776
777 // If the array destroy didn't use the length op, we can erase it.
778 if (constantCount.use_empty())
779 constantCount.erase();
780}
781
784 switch (kind) {
786 llvm_unreachable("no destroyer for trivial dtor");
788 return destroyCXXObject;
792 cgm.errorNYI("getDestroyer: other destruction kind");
793 return nullptr;
794 }
795 llvm_unreachable("Unknown DestructionKind");
796}
797
798/// Enter a destroy cleanup for the given local variable.
800 const CIRGenFunction::AutoVarEmission &emission,
801 QualType::DestructionKind dtorKind) {
802 assert(dtorKind != QualType::DK_none);
803
804 // Note that for __block variables, we want to destroy the
805 // original stack object, not the possibly forwarded object.
806 Address addr = emission.getObjectAddress(*this);
807
808 const VarDecl *var = emission.Variable;
809 QualType type = var->getType();
810
811 CleanupKind cleanupKind = NormalAndEHCleanup;
812 CIRGenFunction::Destroyer *destroyer = nullptr;
813
814 switch (dtorKind) {
816 llvm_unreachable("no cleanup for trivially-destructible variable");
817
819 // If there's an NRVO flag on the emission, we need a different
820 // cleanup.
821 if (emission.NRVOFlag) {
822 cgm.errorNYI(var->getSourceRange(), "emitAutoVarTypeCleanup: NRVO");
823 return;
824 }
825 // Otherwise, this is handled below.
826 break;
827
831 cgm.errorNYI(var->getSourceRange(),
832 "emitAutoVarTypeCleanup: other dtor kind");
833 return;
834 }
835
836 // If we haven't chosen a more specific destroyer, use the default.
837 if (!destroyer)
838 destroyer = getDestroyer(dtorKind);
839
841 ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
842}
843
845 if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
846 for (auto *b : dd->flat_bindings())
847 if (auto *hd = b->getHoldingVar())
848 emitVarDecl(*hd);
849 }
850}
static void emit(Program &P, llvm::SmallVectorImpl< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d)
This file defines OpenACC nodes for declarative directives.
Defines the clang::Expr interface and subclasses for C++ expressions.
__device__ __2f16 b
const LangOptions & getLangOpts() const
Definition ASTContext.h:891
CharUnits getDeclAlign(const Decl *D, bool ForAlignof=false) const
Return a conservative estimate of the alignment of the specified decl D.
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3720
mlir::Value getPointer() const
Definition Address.h:81
static Address invalid()
Definition Address.h:66
clang::CharUnits getAlignment() const
Definition Address.h:109
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
void emitOpenACCRoutine(const OpenACCRoutineDecl &d)
cir::GlobalOp addInitializerToStaticVarDecl(const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr)
Add the initializer for 'd' to the global variable that has already been created for it.
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, mlir::OpBuilder::InsertPoint ip={})
void emitAutoVarTypeCleanup(const AutoVarEmission &emission, clang::QualType::DestructionKind dtorKind)
Enter a destroy cleanup for the given local variable.
const clang::LangOptions & getLangOpts() const
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage)
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
bool isTrivialInitializer(const Expr *init)
Determine whether the given initializer is trivial in the sense that it requires no code to be genera...
void emitOpenACCDeclare(const OpenACCDeclareDecl &d)
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitArrayDestroy(mlir::Value begin, mlir::Value end, QualType elementType, CharUnits elementAlign, Destroyer *destroyer)
Destroys all the elements of the given array, beginning from last to first.
void emitExprAsInit(const clang::Expr *init, const clang::ValueDecl *d, LValue lvalue, bool capturedByInit=false)
Emit an expression as an initializer for an object (variable, field, etc.) at the given location.
mlir::Value emitArrayLength(const clang::ArrayType *arrayType, QualType &baseType, Address &addr)
Computes the length of an array in elements, as well as the base element type and a properly-typed fi...
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
mlir::Type convertTypeForMem(QualType t)
void emitVarDecl(const clang::VarDecl &d)
This method handles emission of any variable declaration inside a function, including static vars etc...
Address returnValue
The temporary alloca to hold the return value.
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit=false)
mlir::Value emitScalarExpr(const clang::Expr *e)
Emit the computation of the specified expression of scalar type.
void emitAutoVarInit(const AutoVarEmission &emission)
Emit the initializer for an allocated variable.
void maybeEmitDeferredVarDeclInit(const VarDecl *vd)
void emitAutoVarDecl(const clang::VarDecl &d)
Emit code and set up symbol table for a variable declaration with auto, register, or no storage class...
void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer)
void emitDecl(const clang::Decl &d, bool evaluateConditionDecl=false)
void emitDestroy(Address addr, QualType type, Destroyer *destroyer)
Immediately perform the destruction of the given object.
mlir::MLIRContext & getMLIRContext()
Destroyer * getDestroyer(clang::QualType::DestructionKind kind)
void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty)
DeclMapTy localDeclMap
This keeps track of the CIR allocas or globals for local C declarations.
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
void pushFullExprCleanup(CleanupKind kind, As... a)
Push a cleanup to be run at the end of the current full-expression.
std::optional< mlir::Location > currSrcLoc
Use to track source locations across nested visitor traversals.
clang::ASTContext & getContext() const
void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr)
Set the address of a local variable.
void emitNullabilityCheck(LValue lhs, mlir::Value rhs, clang::SourceLocation loc)
Given an assignment *lhs = rhs, emit a test that checks if rhs is nonnull, if 1LHS is marked _Nonnull...
void emitStoreThroughLValue(RValue src, LValue dst, bool isInit=false)
Store the specified rvalue into the specified lvalue, where both are guaranteed to the have the same ...
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
void emitAutoVarCleanups(const AutoVarEmission &emission)
This class organizes the cross-function state that is used while generating CIR code.
llvm::StringRef getMangledName(clang::GlobalDecl gd)
cir::GlobalOp getOrCreateStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
mlir::Type convertType(clang::QualType type)
void setGVProperties(mlir::Operation *op, const NamedDecl *d) const
Set visibility, dllimport/dllexport and dso_local.
static mlir::SymbolTable::Visibility getMLIRVisibilityFromCIRLinkage(cir::GlobalLinkageKind GLK)
const clang::LangOptions & getLangOpts() const
mlir::Location getLoc(clang::SourceLocation cLoc)
Helpers to convert the presumed location of Clang's SourceLocation to an MLIR Location.
mlir::ModuleOp getModule() const
cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d)
mlir::Type convertTypeForMem(clang::QualType, bool forBitField=false)
Convert type T into an mlir::Type.
mlir::Attribute tryEmitForInitializer(const VarDecl &d)
Try to emit the initializer of the given declaration as an abstract constant.
mlir::Attribute tryEmitAbstractForInitializer(const VarDecl &d)
Try to emit the initializer of the given declaration as an abstract constant.
Information for lazily generating a cleanup.
Address getAddress() const
This trivial value class is used to represent the result of an expression that is evaluated.
Definition CIRGenValue.h:33
static RValue get(mlir::Value v)
Definition CIRGenValue.h:82
Represents a call to a C++ constructor.
Definition ExprCXX.h:1549
Represents a C++ constructor within a class.
Definition DeclCXX.h:2604
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
CharUnits alignmentOfArrayElement(CharUnits elementSize) const
Given that this is the alignment of the first element of an array, return the minimum alignment of an...
Definition CharUnits.h:214
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1449
T * getAttr() const
Definition DeclBase.h:573
bool hasAttrs() const
Definition DeclBase.h:518
Decl * getNonClosureContext()
Find the innermost non-closure ancestor of this declaration, walking up through blocks,...
SourceLocation getLocation() const
Definition DeclBase.h:439
const char * getDeclKindName() const
Definition DeclBase.cpp:147
DeclContext * getDeclContext()
Definition DeclBase.h:448
bool hasAttr() const
Definition DeclBase.h:577
Kind getKind() const
Definition DeclBase.h:442
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:427
This represents one expression.
Definition Expr.h:112
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:273
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
const Decl * getDecl() const
Definition GlobalDecl.h:106
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:300
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:316
bool isExternallyVisible() const
Definition Decl.h:432
A (possibly-)qualified type.
Definition TypeBase.h:937
@ PDIK_Struct
The type is a struct containing a field whose type is not PCK_Trivial.
Definition TypeBase.h:1478
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8411
Represents a struct/union/class.
Definition Decl.h:4309
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:334
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
Definition Type.cpp:2426
bool isArrayType() const
Definition TypeBase.h:8621
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2800
bool isSamplerT() const
Definition TypeBase.h:8756
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:711
QualType getType() const
Definition Decl.h:722
Represents a variable declaration or definition.
Definition Decl.h:925
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1568
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2190
bool mightBeUsableInConstantExpressions(const ASTContext &C) const
Determine whether this variable's value might be usable in a constant expression, according to the re...
Definition Decl.cpp:2486
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1511
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 Expr * getInit() const
Definition Decl.h:1367
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
Definition Decl.h:1216
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1183
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition Decl.h:1252
StorageDuration getStorageDuration() const
Get the storage duration of this variable, per C++ [basic.stc].
Definition Decl.h:1228
bool isEscapingByref() const
Indicates the capture is a __block variable that is captured by a block that can potentially escape (...
Definition Decl.cpp:2698
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const AstTypeMatcher< ArrayType > arrayType
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ SD_Automatic
Automatic storage duration (most local variables).
Definition Specifiers.h:341
U cast(CodeGen::Address addr)
Definition Address.h:327
float __ovld __cnfn length(float)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
static bool opGlobalConstant()
static bool objCLifetime()
static bool addressSpace()
static bool emitNullabilityCheck()
static bool ehCleanupFlags()
static bool ehCleanupScope()
static bool opGlobalThreadLocal()
static bool aggValueSlotMayOverlap()
static bool dtorCleanups()
static bool dataLayoutTypeAllocSize()
static bool opAllocaCaptureByInit()
static bool opAllocaPreciseLifetime()
static bool cudaSupport()
static bool generateDebugInfo()
bool IsEscapingByRef
True if the variable is a __block variable that is captured by an escaping block.
Address getObjectAddress(CIRGenFunction &cgf) const
Returns the address of the object within this declaration.
Address Addr
The address of the alloca for languages with explicit address space (e.g.
bool IsConstantAggregate
True if the variable is of aggregate type and has a constant initializer.