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
36 emission.IsEscapingByRef = d.isEscapingByref();
37 if (emission.IsEscapingByRef)
39 "emitAutoVarDecl: decl escaping by reference");
40
41 CharUnits alignment = getContext().getDeclAlign(&d);
42
43 // If the type is variably-modified, emit all the VLA sizes for it.
44 if (ty->isVariablyModifiedType())
45 cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type");
46
47 Address address = Address::invalid();
48 if (!ty->isConstantSizeType())
49 cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type");
50
51 // A normal fixed sized variable becomes an alloca in the entry block,
52 mlir::Type allocaTy = convertTypeForMem(ty);
53 // Create the temp alloca and declare variable using it.
54 address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
55 /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
56 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment);
57
58 emission.Addr = address;
59 setAddrOfLocalVar(&d, address);
60
61 return emission;
62}
63
64/// Determine whether the given initializer is trivial in the sense
65/// that it requires no code to be generated.
67 if (!init)
68 return true;
69
70 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
71 if (CXXConstructorDecl *constructor = construct->getConstructor())
72 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
73 !construct->requiresZeroInitialization())
74 return true;
75
76 return false;
77}
78
80 const CIRGenFunction::AutoVarEmission &emission) {
81 assert(emission.Variable && "emission was not valid!");
82
83 // If this was emitted as a global constant, we're done.
84 if (emission.wasEmittedAsGlobal())
85 return;
86
87 const VarDecl &d = *emission.Variable;
88
89 QualType type = d.getType();
90
91 // If this local has an initializer, emit it now.
92 const Expr *init = d.getInit();
93
94 // Initialize the variable here if it doesn't have a initializer and it is a
95 // C struct that is non-trivial to initialize or an array containing such a
96 // struct.
97 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
100 "emitAutoVarInit: non-trivial to default initialize");
101 return;
102 }
103
104 const Address addr = emission.Addr;
105
106 // Check whether this is a byref variable that's potentially
107 // captured and moved by its own initializer. If so, we'll need to
108 // emit the initializer first, then copy into the variable.
110
111 // Note: constexpr already initializes everything correctly.
112 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
113 (d.isConstexpr()
115 : (d.getAttr<UninitializedAttr>()
117 : getContext().getLangOpts().getTrivialAutoVarInit()));
118
119 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
120 if (trivialAutoVarInit ==
122 return;
123
124 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
125 };
126
127 if (isTrivialInitializer(init)) {
128 initializeWhatIsTechnicallyUninitialized(addr);
129 return;
130 }
131
132 mlir::Attribute constant;
133 if (emission.IsConstantAggregate ||
135 // FIXME: Differently from LLVM we try not to emit / lower too much
136 // here for CIR since we are interested in seeing the ctor in some
137 // analysis later on. So CIR's implementation of ConstantEmitter will
138 // frequently return an empty Attribute, to signal we want to codegen
139 // some trivial ctor calls and whatnots.
141 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
142 (trivialAutoVarInit !=
144 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
145 return;
146 }
147 }
148
149 // NOTE(cir): In case we have a constant initializer, we can just emit a
150 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
151 // CXX temporary object creation, we ensure the ctor call is used deferring
152 // its removal/optimization to the CIR lowering.
153 if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
154 initializeWhatIsTechnicallyUninitialized(addr);
156 emitExprAsInit(init, &d, lv);
157
158 if (!emission.wasEmittedAsOffloadClause()) {
159 // In case lv has uses it means we indeed initialized something
160 // out of it while trying to build the expression, mark it as such.
161 mlir::Value val = lv.getAddress().getPointer();
162 assert(val && "Should have an address");
163 auto allocaOp = val.getDefiningOp<cir::AllocaOp>();
164 assert(allocaOp && "Address should come straight out of the alloca");
165
166 if (!allocaOp.use_empty())
167 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
168 }
169
170 return;
171 }
172
173 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
174 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
175 assert(typedConstant && "expected typed attribute");
176 if (!emission.IsConstantAggregate) {
177 // For simple scalar/complex initialization, store the value directly.
178 LValue lv = makeAddrLValue(addr, type);
179 assert(init && "expected initializer");
180 mlir::Location initLoc = getLoc(init->getSourceRange());
181 // lv.setNonGC(true);
183 RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
184 }
185}
186
188 const CIRGenFunction::AutoVarEmission &emission) {
189 const VarDecl &d = *emission.Variable;
190
191 // Check the type for a cleanup.
193 emitAutoVarTypeCleanup(emission, dtorKind);
194
196
197 // Handle the cleanup attribute.
198 if (d.hasAttr<CleanupAttr>())
199 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
200}
201
202/// Emit code and set up symbol table for a variable declaration with auto,
203/// register, or no storage class specifier. These turn into simple stack
204/// objects, globals depending on target.
207 emitAutoVarInit(emission);
208 emitAutoVarCleanups(emission);
209}
210
212 // If the declaration has external storage, don't emit it now, allow it to be
213 // emitted lazily on its first use.
214 if (d.hasExternalStorage())
215 return;
216
217 if (d.getStorageDuration() != SD_Automatic) {
218 // Static sampler variables translated to function calls.
219 if (d.getType()->isSamplerT()) {
220 // Nothing needs to be done here, but let's flag it as an error until we
221 // have a test. It requires OpenCL support.
222 cgm.errorNYI(d.getSourceRange(), "emitVarDecl static sampler type");
223 return;
224 }
225
226 cir::GlobalLinkageKind linkage =
227 cgm.getCIRLinkageVarDefinition(&d, /*IsConstant=*/false);
228
229 // FIXME: We need to force the emission/use of a guard variable for
230 // some variables even if we can constant-evaluate them because
231 // we can't guarantee every translation unit will constant-evaluate them.
232
233 return emitStaticVarDecl(d, linkage);
234 }
235
237 cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space");
238
239 assert(d.hasLocalStorage());
240
241 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
242 return emitAutoVarDecl(d);
243}
244
245static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
246 if (cgm.getLangOpts().CPlusPlus)
247 return cgm.getMangledName(&d).str();
248
249 // If this isn't C++, we don't need a mangled name, just a pretty one.
250 assert(!d.isExternallyVisible() && "name shouldn't matter");
251 std::string contextName;
252 const DeclContext *dc = d.getDeclContext();
253 if (auto *cd = dyn_cast<CapturedDecl>(dc))
254 dc = cast<DeclContext>(cd->getNonClosureContext());
255 if (const auto *fd = dyn_cast<FunctionDecl>(dc))
256 contextName = std::string(cgm.getMangledName(fd));
257 else if (isa<BlockDecl>(dc))
258 cgm.errorNYI(d.getSourceRange(), "block decl context for static var");
259 else if (isa<ObjCMethodDecl>(dc))
260 cgm.errorNYI(d.getSourceRange(), "ObjC decl context for static var");
261 else
262 cgm.errorNYI(d.getSourceRange(), "Unknown context for static var decl");
263
264 contextName += "." + d.getNameAsString();
265 return contextName;
266}
267
268// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
269// interface for all constants?
270cir::GlobalOp
272 cir::GlobalLinkageKind linkage) {
273 // In general, we don't always emit static var decls once before we reference
274 // them. It is possible to reference them before emitting the function that
275 // contains them, and it is possible to emit the containing function multiple
276 // times.
277 if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
278 return existingGV;
279
280 QualType ty = d.getType();
281 assert(ty->isConstantSizeType() && "VLAs can't be static");
282
283 // Use the label if the variable is renamed with the asm-label extension.
284 if (d.hasAttr<AsmLabelAttr>())
285 errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label");
286
287 std::string name = getStaticDeclName(*this, d);
288
289 mlir::Type lty = getTypes().convertTypeForMem(ty);
291
292 if (d.hasAttr<LoaderUninitializedAttr>() || d.hasAttr<CUDASharedAttr>())
294 "getOrCreateStaticVarDecl: LoaderUninitializedAttr");
296
297 mlir::Attribute init = builder.getZeroInitAttr(convertType(ty));
298
299 cir::GlobalOp gv = builder.createVersionedGlobal(
300 getModule(), getLoc(d.getLocation()), name, lty, false, linkage);
301 // TODO(cir): infer visibility from linkage in global op builder.
302 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
303 gv.setInitialValueAttr(init);
304 gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
305
306 if (supportsCOMDAT() && gv.isWeakForLinker())
307 gv.setComdat(true);
308
310
311 setGVProperties(gv, &d);
312
313 // OG checks if the expected address space, denoted by the type, is the
314 // same as the actual address space indicated by attributes. If they aren't
315 // the same, an addrspacecast is emitted when this variable is accessed.
316 // In CIR however, cir.get_global already carries that information in
317 // !cir.ptr type - if this global is in OpenCL local address space, then its
318 // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't
319 // need an explicit address space cast in CIR: they will get emitted when
320 // lowering to LLVM IR.
321
322 // Ensure that the static local gets initialized by making sure the parent
323 // function gets emitted eventually.
324 const Decl *dc = cast<Decl>(d.getDeclContext());
325
326 // We can't name blocks or captured statements directly, so try to emit their
327 // parents.
328 if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
329 dc = dc->getNonClosureContext();
330 // FIXME: Ensure that global blocks get emitted.
331 if (!dc)
332 errorNYI(d.getSourceRange(), "non-closure context");
333 }
334
335 GlobalDecl gd;
336 if (isa<CXXConstructorDecl>(dc))
337 errorNYI(d.getSourceRange(), "C++ constructors static var context");
338 else if (isa<CXXDestructorDecl>(dc))
339 errorNYI(d.getSourceRange(), "C++ destructors static var context");
340 else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
341 gd = GlobalDecl(fd);
342 else {
343 // Don't do anything for Obj-C method decls or global closures. We should
344 // never defer them.
345 assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
346 }
348 // Disable emission of the parent function for the OpenMP device codegen.
349 errorNYI(d.getSourceRange(), "OpenMP");
350 }
351
352 return gv;
353}
354
355/// Add the initializer for 'd' to the global variable that has already been
356/// created for it. If the initializer has a different type than gv does, this
357/// may free gv and return a different one. Otherwise it just returns gv.
359 const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
360 ConstantEmitter emitter(*this);
361 mlir::TypedAttr init =
362 mlir::cast<mlir::TypedAttr>(emitter.tryEmitForInitializer(d));
363
364 // If constant emission failed, then this should be a C++ static
365 // initializer.
366 if (!init) {
367 cgm.errorNYI(d.getSourceRange(), "static var without initializer");
368 return gv;
369 }
370
371 // TODO(cir): There should be debug code here to assert that the decl size
372 // matches the CIR data layout type alloc size, but the code for calculating
373 // the type alloc size is not implemented yet.
375
376 // The initializer may differ in type from the global. Rewrite
377 // the global to match the initializer. (We have to do this
378 // because some types, like unions, can't be completely represented
379 // in the LLVM type system.)
380 if (gv.getSymType() != init.getType()) {
381 gv.setSymType(init.getType());
382
383 // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
384 // but since at this point the current block hasn't been really attached,
385 // there's no visibility into the GetGlobalOp corresponding to this Global.
386 // Given those constraints, thread in the GetGlobalOp and update it
387 // directly.
389 gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
390 }
391
392 bool needsDtor =
394
396 gv.setInitialValueAttr(init);
397
398 emitter.finalize(gv);
399
400 if (needsDtor) {
401 // We have a constant initializer, but a nontrivial destructor. We still
402 // need to perform a guarded "initialization" in order to register the
403 // destructor.
404 cgm.errorNYI(d.getSourceRange(), "C++ guarded init");
405 }
406
407 return gv;
408}
409
411 cir::GlobalLinkageKind linkage) {
412 // Check to see if we already have a global variable for this
413 // declaration. This can happen when double-emitting function
414 // bodies, e.g. with complete and base constructors.
415 cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
416 // TODO(cir): we should have a way to represent global ops as values without
417 // having to emit a get global op. Sometimes these emissions are not used.
418 mlir::Value addr = builder.createGetGlobal(globalOp);
419 auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>();
420 assert(getAddrOp && "expected cir::GetGlobalOp");
421
422 CharUnits alignment = getContext().getDeclAlign(&d);
423
424 // Store into LocalDeclMap before generating initializer to handle
425 // circular references.
426 mlir::Type elemTy = convertTypeForMem(d.getType());
427 setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
428
429 // We can't have a VLA here, but we can have a pointer to a VLA,
430 // even though that doesn't really make any sense.
431 // Make sure to evaluate VLA bounds now so that we have them for later.
432 if (d.getType()->isVariablyModifiedType()) {
434 "emitStaticVarDecl: variably modified type");
435 }
436
437 // Save the type in case adding the initializer forces a type change.
438 mlir::Type expectedType = addr.getType();
439
440 cir::GlobalOp var = globalOp;
441
443
444 // If this value has an initializer, emit it.
445 if (d.getInit())
446 var = addInitializerToStaticVarDecl(d, var, getAddrOp);
447
448 var.setAlignment(alignment.getAsAlign().value());
449
450 // There are a lot of attributes that need to be handled here. Until
451 // we start to support them, we just report an error if there are any.
452 if (d.hasAttrs())
453 cgm.errorNYI(d.getSourceRange(), "static var with attrs");
454
455 if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
456 cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
457
458 // From traditional codegen:
459 // We may have to cast the constant because of the initializer
460 // mismatch above.
461 //
462 // FIXME: It is really dangerous to store this in the map; if anyone
463 // RAUW's the GV uses of this constant will be invalid.
464 mlir::Value castedAddr =
465 builder.createBitcast(getAddrOp.getAddr(), expectedType);
466 localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
468
471}
472
473void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
474 LValue lvalue, bool capturedByInit) {
476
477 SourceLocRAIIObject locRAII{*this, loc};
478 mlir::Value value = emitScalarExpr(init);
479 if (capturedByInit) {
480 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
481 return;
482 }
484 emitStoreThroughLValue(RValue::get(value), lvalue, true);
485}
486
488 LValue lvalue, bool capturedByInit) {
489 SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
490 if (capturedByInit) {
491 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
492 return;
493 }
494
495 QualType type = d->getType();
496
497 if (type->isReferenceType()) {
498 RValue rvalue = emitReferenceBindingToExpr(init);
499 if (capturedByInit)
500 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
501 emitStoreThroughLValue(rvalue, lvalue);
502 return;
503 }
505 case cir::TEK_Scalar:
506 emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
507 return;
508 case cir::TEK_Complex: {
509 mlir::Value complex = emitComplexExpr(init);
510 if (capturedByInit)
512 "emitExprAsInit: complex type captured by init");
513 mlir::Location loc = getLoc(init->getExprLoc());
514 emitStoreOfComplex(loc, complex, lvalue,
515 /*isInit*/ true);
516 return;
517 }
519 // The overlap flag here should be calculated.
521 emitAggExpr(init,
525 return;
526 }
527 llvm_unreachable("bad evaluation kind");
528}
529
530void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
531 switch (d.getKind()) {
532 case Decl::BuiltinTemplate:
533 case Decl::TranslationUnit:
534 case Decl::ExternCContext:
535 case Decl::Namespace:
536 case Decl::UnresolvedUsingTypename:
537 case Decl::ClassTemplateSpecialization:
538 case Decl::ClassTemplatePartialSpecialization:
539 case Decl::VarTemplateSpecialization:
540 case Decl::VarTemplatePartialSpecialization:
541 case Decl::TemplateTypeParm:
542 case Decl::UnresolvedUsingValue:
543 case Decl::NonTypeTemplateParm:
544 case Decl::CXXDeductionGuide:
545 case Decl::CXXMethod:
546 case Decl::CXXConstructor:
547 case Decl::CXXDestructor:
548 case Decl::CXXConversion:
549 case Decl::Field:
550 case Decl::MSProperty:
551 case Decl::IndirectField:
552 case Decl::ObjCIvar:
553 case Decl::ObjCAtDefsField:
554 case Decl::ParmVar:
555 case Decl::ImplicitParam:
556 case Decl::ClassTemplate:
557 case Decl::VarTemplate:
558 case Decl::FunctionTemplate:
559 case Decl::TypeAliasTemplate:
560 case Decl::TemplateTemplateParm:
561 case Decl::ObjCMethod:
562 case Decl::ObjCCategory:
563 case Decl::ObjCProtocol:
564 case Decl::ObjCInterface:
565 case Decl::ObjCCategoryImpl:
566 case Decl::ObjCImplementation:
567 case Decl::ObjCProperty:
568 case Decl::ObjCCompatibleAlias:
569 case Decl::PragmaComment:
570 case Decl::PragmaDetectMismatch:
571 case Decl::AccessSpec:
572 case Decl::LinkageSpec:
573 case Decl::Export:
574 case Decl::ObjCPropertyImpl:
575 case Decl::FileScopeAsm:
576 case Decl::Friend:
577 case Decl::FriendTemplate:
578 case Decl::Block:
579 case Decl::OutlinedFunction:
580 case Decl::Captured:
581 case Decl::UsingShadow:
582 case Decl::ConstructorUsingShadow:
583 case Decl::ObjCTypeParam:
584 case Decl::Binding:
585 case Decl::UnresolvedUsingIfExists:
586 case Decl::HLSLBuffer:
587 case Decl::HLSLRootSignature:
588 llvm_unreachable("Declaration should not be in declstmts!");
589
590 case Decl::Function: // void X();
591 case Decl::EnumConstant: // enum ? { X = ? }
592 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
593 case Decl::Label: // __label__ x;
594 case Decl::Import:
595 case Decl::MSGuid: // __declspec(uuid("..."))
596 case Decl::TemplateParamObject:
597 case Decl::OMPThreadPrivate:
598 case Decl::OMPAllocate:
599 case Decl::OMPCapturedExpr:
600 case Decl::OMPRequires:
601 case Decl::Empty:
602 case Decl::Concept:
603 case Decl::LifetimeExtendedTemporary:
604 case Decl::RequiresExprBody:
605 case Decl::UnnamedGlobalConstant:
606 // None of these decls require codegen support.
607 return;
608
609 case Decl::Enum: // enum X;
610 case Decl::Record: // struct/union/class X;
611 case Decl::CXXRecord: // struct/union/class X; [C++]
612 case Decl::NamespaceAlias:
613 case Decl::Using: // using X; [C++]
614 case Decl::UsingEnum: // using enum X; [C++]
615 case Decl::UsingDirective: // using namespace X; [C++]
617 return;
618 case Decl::Var:
619 case Decl::Decomposition: {
620 const VarDecl &vd = cast<VarDecl>(d);
621 assert(vd.isLocalVarDecl() &&
622 "Should not see file-scope variables inside a function!");
623 emitVarDecl(vd);
624 if (evaluateConditionDecl)
626 return;
627 }
628 case Decl::OpenACCDeclare:
629 emitOpenACCDeclare(cast<OpenACCDeclareDecl>(d));
630 return;
631 case Decl::OpenACCRoutine:
632 emitOpenACCRoutine(cast<OpenACCRoutineDecl>(d));
633 return;
634 case Decl::Typedef: // typedef int X;
635 case Decl::TypeAlias: { // using X = int; [C++0x]
636 QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
638 if (ty->isVariablyModifiedType())
639 cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type");
640 return;
641 }
642 case Decl::ImplicitConceptSpecialization:
643 case Decl::TopLevelStmt:
644 case Decl::UsingPack:
645 case Decl::OMPDeclareReduction:
646 case Decl::OMPDeclareMapper:
648 std::string("emitDecl: unhandled decl type: ") +
649 d.getDeclKindName());
650 }
651}
652
654 SourceLocation loc) {
655 if (!sanOpts.has(SanitizerKind::NullabilityAssign))
656 return;
657
659}
660
661namespace {
662struct DestroyObject final : EHScopeStack::Cleanup {
663 DestroyObject(Address addr, QualType type,
664 CIRGenFunction::Destroyer *destroyer)
665 : addr(addr), type(type), destroyer(destroyer) {}
666
667 Address addr;
669 CIRGenFunction::Destroyer *destroyer;
670
671 void emit(CIRGenFunction &cgf) override {
672 cgf.emitDestroy(addr, type, destroyer);
673 }
674
675 // This is a placeholder until EHCleanupScope is implemented.
676 size_t getSize() const override {
678 return sizeof(DestroyObject);
679 }
680};
681} // namespace
682
684 QualType type, Destroyer *destroyer) {
685 pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
686}
687
688/// Destroys all the elements of the given array, beginning from last to first.
689/// The array cannot be zero-length.
690///
691/// \param begin - a type* denoting the first element of the array
692/// \param end - a type* denoting one past the end of the array
693/// \param elementType - the element type of the array
694/// \param destroyer - the function to call to destroy elements
695void CIRGenFunction::emitArrayDestroy(mlir::Value begin, mlir::Value end,
696 QualType elementType,
697 CharUnits elementAlign,
698 Destroyer *destroyer) {
699 assert(!elementType->isArrayType());
700
701 // Differently from LLVM traditional codegen, use a higher level
702 // representation instead of lowering directly to a loop.
703 mlir::Type cirElementType = convertTypeForMem(elementType);
704 cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
705
706 // Emit the dtor call that will execute for every array element.
707 cir::ArrayDtor::create(
708 builder, *currSrcLoc, begin, [&](mlir::OpBuilder &b, mlir::Location loc) {
709 auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
710 Address curAddr = Address(arg, cirElementType, elementAlign);
712
713 // Perform the actual destruction there.
714 destroyer(*this, curAddr, elementType);
715
716 cir::YieldOp::create(builder, loc);
717 });
718}
719
720/// Immediately perform the destruction of the given object.
721///
722/// \param addr - the address of the object; a type*
723/// \param type - the type of the object; if an array type, all
724/// objects are destroyed in reverse order
725/// \param destroyer - the function to call to destroy individual
726/// elements
728 Destroyer *destroyer) {
730 if (!arrayType)
731 return destroyer(*this, addr, type);
732
733 mlir::Value length = emitArrayLength(arrayType, type, addr);
734
735 CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
736 getContext().getTypeSizeInChars(type));
737
738 auto constantCount = length.getDefiningOp<cir::ConstantOp>();
739 if (!constantCount) {
741 cgm.errorNYI("emitDestroy: variable length array");
742 return;
743 }
744
745 auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue());
746 // If it's constant zero, we can just skip the entire thing.
747 if (constIntAttr && constIntAttr.getUInt() == 0)
748 return;
749
750 mlir::Value begin = addr.getPointer();
751 mlir::Value end; // This will be used for future non-constant counts.
752 emitArrayDestroy(begin, end, type, elementAlign, destroyer);
753
754 // If the array destroy didn't use the length op, we can erase it.
755 if (constantCount.use_empty())
756 constantCount.erase();
757}
758
761 switch (kind) {
763 llvm_unreachable("no destroyer for trivial dtor");
765 return destroyCXXObject;
769 cgm.errorNYI("getDestroyer: other destruction kind");
770 return nullptr;
771 }
772 llvm_unreachable("Unknown DestructionKind");
773}
774
775/// Enter a destroy cleanup for the given local variable.
777 const CIRGenFunction::AutoVarEmission &emission,
778 QualType::DestructionKind dtorKind) {
779 assert(dtorKind != QualType::DK_none);
780
781 // Note that for __block variables, we want to destroy the
782 // original stack object, not the possibly forwarded object.
783 Address addr = emission.getObjectAddress(*this);
784
785 const VarDecl *var = emission.Variable;
786 QualType type = var->getType();
787
788 CleanupKind cleanupKind = NormalAndEHCleanup;
789 CIRGenFunction::Destroyer *destroyer = nullptr;
790
791 switch (dtorKind) {
793 llvm_unreachable("no cleanup for trivially-destructible variable");
794
796 // If there's an NRVO flag on the emission, we need a different
797 // cleanup.
798 if (emission.NRVOFlag) {
799 cgm.errorNYI(var->getSourceRange(), "emitAutoVarTypeCleanup: NRVO");
800 return;
801 }
802 // Otherwise, this is handled below.
803 break;
804
808 cgm.errorNYI(var->getSourceRange(),
809 "emitAutoVarTypeCleanup: other dtor kind");
810 return;
811 }
812
813 // If we haven't chosen a more specific destroyer, use the default.
814 if (!destroyer)
815 destroyer = getDestroyer(dtorKind);
816
818 ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
819}
820
822 if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
823 for (auto *b : dd->flat_bindings())
824 if (auto *hd = b->getHoldingVar())
825 emitVarDecl(*hd);
826 }
827}
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)
Definition: CIRGenDecl.cpp:245
This file defines OpenACC nodes for declarative directives.
Defines the clang::Expr interface and subclasses for C++ expressions.
__device__ __2f16 b
mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global)
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
mlir::TypedAttr getZeroInitAttr(mlir::Type ty)
const LangOptions & getLangOpts() const
Definition: ASTContext.h:894
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:3738
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)
Definition: CIRGenValue.h:367
cir::GlobalOp createVersionedGlobal(mlir::ModuleOp module, mlir::Location loc, mlir::StringRef name, mlir::Type type, bool isConstant, cir::GlobalLinkageKind linkage)
Creates a versioned global variable.
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.
Definition: CIRGenDecl.cpp:358
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, mlir::OpBuilder::InsertPoint ip={})
Definition: CIRGenDecl.cpp:27
void emitAutoVarTypeCleanup(const AutoVarEmission &emission, clang::QualType::DestructionKind dtorKind)
Enter a destroy cleanup for the given local variable.
Definition: CIRGenDecl.cpp:776
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)
Definition: CIRGenDecl.cpp:410
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...
Definition: CIRGenDecl.cpp:66
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.
Definition: CIRGenDecl.cpp:695
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.
Definition: CIRGenDecl.cpp:487
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...
Definition: CIRGenDecl.cpp:211
static Destroyer destroyCXXObject
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit=false)
Definition: CIRGenDecl.cpp:473
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.
Definition: CIRGenDecl.cpp:79
void maybeEmitDeferredVarDeclInit(const VarDecl *vd)
Definition: CIRGenDecl.cpp:821
void emitAutoVarDecl(const clang::VarDecl &d)
Emit code and set up symbol table for a variable declaration with auto, register, or no storage class...
Definition: CIRGenDecl.cpp:205
void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer)
Definition: CIRGenDecl.cpp:683
void emitDecl(const clang::Decl &d, bool evaluateConditionDecl=false)
Definition: CIRGenDecl.cpp:530
void emitDestroy(Address addr, QualType type, Destroyer *destroyer)
Immediately perform the destruction of the given object.
Definition: CIRGenDecl.cpp:727
mlir::MLIRContext & getMLIRContext()
Destroyer * getDestroyer(clang::QualType::DestructionKind kind)
Definition: CIRGenDecl.cpp:760
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)
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...
Definition: CIRGenDecl.cpp:653
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 ...
Definition: CIRGenExpr.cpp:246
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
void emitAutoVarCleanups(const AutoVarEmission &emission)
Definition: CIRGenDecl.cpp:187
This class organizes the cross-function state that is used while generating CIR code.
Definition: CIRGenModule.h:56
llvm::StringRef getMangledName(clang::GlobalDecl gd)
cir::GlobalOp getOrCreateStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage)
Definition: CIRGenDecl.cpp:271
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
Definition: CIRGenModule.h:102
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::CodeGenOptions & getCodeGenOpts() const
Definition: CIRGenModule.h:104
const clang::LangOptions & getLangOpts() const
Definition: CIRGenModule.h:107
void setStaticLocalDeclAddress(const VarDecl *d, cir::GlobalOp c)
Definition: CIRGenModule.h:135
mlir::Location getLoc(clang::SourceLocation cLoc)
Helpers to convert the presumed location of Clang's SourceLocation to an MLIR Location.
mlir::ModuleOp getModule() const
Definition: CIRGenModule.h:100
cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d)
Definition: CIRGenModule.h:131
cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *vd, bool isConstant)
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.
Definition: EHScopeStack.h:93
Address getAddress() const
Definition: CIRGenValue.h:211
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
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
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,...
Definition: DeclBase.cpp:1267
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
@ DK_nontrivial_c_struct
Definition: TypeBase.h:1538
@ DK_objc_strong_lifetime
Definition: TypeBase.h:1536
@ 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:8469
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
bool isConstantSizeType() const
Return true if this is not a variable sized type, according to the rules of C99 6....
Definition: Type.cpp:2430
bool isArrayType() const
Definition: TypeBase.h:8679
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition: TypeBase.h:2818
bool isSamplerT() const
Definition: TypeBase.h:8814
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
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
Matches all kinds of arrays.
The JSON file list parser is used to communicate input to InstallAPI.
@ SD_Automatic
Automatic storage duration (most local variables).
Definition: Specifiers.h:341
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 sanitizers()
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.
bool has(SanitizerMask K) const
Check if a certain (single) sanitizer is enabled.
Definition: Sanitizers.h:174