clang 23.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
13#include "CIRGenCleanup.h"
15#include "CIRGenFunction.h"
16#include "mlir/IR/Location.h"
17#include "clang/AST/Attr.h"
18#include "clang/AST/Attrs.inc"
19#include "clang/AST/Decl.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/ExprCXX.h"
23#include "clang/Basic/Cuda.h"
27
28using namespace clang;
29using namespace clang::CIRGen;
30
33 mlir::OpBuilder::InsertPoint ip) {
34 QualType ty = d.getType();
36 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space");
37
38 mlir::Location loc = getLoc(d.getSourceRange());
39 bool nrvo =
40 getContext().getLangOpts().ElideConstructors && d.isNRVOVariable();
41
43 emission.isEscapingByRef = d.isEscapingByref();
44 if (emission.isEscapingByRef)
45 cgm.errorNYI(d.getSourceRange(),
46 "emitAutoVarAlloca: decl escaping by reference");
47
48 CharUnits alignment = getContext().getDeclAlign(&d);
49
50 // If the type is variably-modified, emit all the VLA sizes for it.
51 if (ty->isVariablyModifiedType())
53
55
56 Address address = Address::invalid();
57 if (ty->isConstantSizeType()) {
58 // If this value is an array, struct, or vector with a statically
59 // determinable constant initializer, there are optimizations we can do.
60 //
61 // TODO: We should constant-evaluate the initializer of any variable,
62 // as long as it is initialized by a constant expression. Currently,
63 // isConstantInitializer produces wrong answers for structs with
64 // reference or bitfield members, and a few other cases, and checking
65 // for POD-ness protects us from some of these.
66 if (d.getInit() &&
67 (ty->isArrayType() || ty->isRecordType() || ty->isVectorType()) &&
68 (d.isConstexpr() ||
69 ((ty.isPODType(getContext()) ||
70 getContext().getBaseElementType(ty)->isObjCObjectPointerType()) &&
72
73 // If the variable's a const type, and it's neither an NRVO
74 // candidate nor a __block variable and has no mutable members,
75 // emit it as a global instead.
76 // Exception is if a variable is located in non-constant address space
77 // in OpenCL.
78 // TODO(cir): perhaps we don't need this at all at CIR since this can
79 // be done as part of lowering down to LLVM.
80 bool needsDtor =
82 if ((!getContext().getLangOpts().OpenCL ||
84 (cgm.getCodeGenOpts().MergeAllConstants && !nrvo &&
85 !d.isEscapingByref() &&
86 ty.isConstantStorage(getContext(), true, !needsDtor))) {
87 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: type constant");
88 }
89 // Otherwise, tell the initialization code that we're in this case.
90 emission.isConstantAggregate = true;
91 }
92
93 // A normal fixed sized variable becomes an alloca in the entry block,
94 // unless:
95 // - it's an NRVO variable.
96 // - we are compiling OpenMP and it's an OpenMP local variable.
97 if (nrvo) {
98 // The named return value optimization: allocate this variable in the
99 // return slot, so that we can elide the copy when returning this
100 // variable (C++0x [class.copy]p34).
101 address = returnValue;
102
103 if (const RecordDecl *rd = ty->getAsRecordDecl()) {
104 if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
105 (cxxrd && !cxxrd->hasTrivialDestructor()) ||
106 rd->isNonTrivialToPrimitiveDestroy()) {
107 // In LLVM: Create a flag that is used to indicate when the NRVO was
108 // applied to this variable. Set it to zero to indicate that NRVO was
109 // not applied. For now, use the same approach for CIRGen until we can
110 // be sure it's worth doing something more aggressive.
111 cir::ConstantOp falseNVRO = builder.getFalse(loc);
112 Address nrvoFlag = createTempAlloca(falseNVRO.getType(),
113 CharUnits::One(), loc, "nrvo",
114 /*arraySize=*/nullptr);
115 assert(builder.getInsertionBlock());
116 builder.createStore(loc, falseNVRO, nrvoFlag);
117
118 // Record the NRVO flag for this variable.
119 nrvoFlags[&d] = nrvoFlag.getPointer();
120 emission.nrvoFlag = nrvoFlag.getPointer();
121 }
122 }
123 } else {
124 // A normal fixed sized variable becomes an alloca in the entry block,
125 mlir::Type allocaTy = convertTypeForMem(ty);
126 // Create the temp alloca and declare variable using it.
127 address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
128 /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
129 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
130 alignment);
131 }
132 } else {
133 // Non-constant size type
135 if (!didCallStackSave) {
136 // Save the stack.
137 cir::PointerType defaultTy = allocaInt8PtrTy;
139 cgm.getDataLayout().getAlignment(defaultTy, false));
140 Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack");
141
142 mlir::Value v = builder.createStackSave(loc, defaultTy);
143 assert(v.getType() == allocaInt8PtrTy);
144 builder.createStore(loc, v, stack);
145
146 didCallStackSave = true;
147
148 // Push a cleanup block and restore the stack there.
149 // FIXME: in general circumstances, this should be an EH cleanup.
151 }
152
153 VlaSizePair vlaSize = getVLASize(ty);
154 mlir::Type memTy = convertTypeForMem(vlaSize.type);
155
156 // Allocate memory for the array.
157 address =
158 createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts,
159 /*alloca=*/nullptr, builder.saveInsertionPoint());
160
161 // If we have debug info enabled, properly describe the VLA dimensions for
162 // this type by registering the vla size expression for each of the
163 // dimensions.
165 }
166
167 emission.addr = address;
168 setAddrOfLocalVar(&d, address);
169
170 return emission;
171}
172
173/// Determine whether the given initializer is trivial in the sense
174/// that it requires no code to be generated.
176 if (!init)
177 return true;
178
179 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
180 if (CXXConstructorDecl *constructor = construct->getConstructor())
181 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
182 !construct->requiresZeroInitialization())
183 return true;
184
185 return false;
186}
187
188static void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d,
189 Address addr, bool isVolatile,
190 CIRGenBuilderTy &builder,
191 mlir::TypedAttr constant) {
192 mlir::Type ty = constant.getType();
193 cir::CIRDataLayout layout{cgm.getModule()};
194 uint64_t constantSize = layout.getTypeAllocSize(ty);
195 if (!constantSize)
196 return;
199
200 if (addr.getElementType() != ty)
201 addr = addr.withElementType(builder, ty);
202
203 // If the address is an alloca, set the init attribute.
204 // The address is usually and alloca, but there is at least one case where
205 // emitAutoVarInit is called from the OpenACC codegen with an address that
206 // is not an alloca.
207 cir::AllocaOp allocaOp = addr.getUnderlyingAllocaOp();
208 if (allocaOp)
209 allocaOp.setInitAttr(mlir::UnitAttr::get(&cgm.getMLIRContext()));
210
211 // There are cases where OpenACC codegen calls emitAutoVarInit with a
212 // temporary decl that doesn't have a source range set.
213 mlir::Location loc = builder.getUnknownLoc();
214 if (d.getSourceRange().isValid())
215 loc = cgm.getLoc(d.getSourceRange());
216
217 // Emit cir.const + cir.store, preserving source-level semantics. For
218 // aggregate types (arrays, records), LoweringPrepare implements the OG
219 // optimization tiers (shouldCreateMemCpyFromGlobal, shouldUseBZeroPlusStores,
220 // shouldUseMemSetToInitialize, shouldSplitConstantStore) by transforming
221 // into cir.global + cir.get_global + cir.copy when appropriate.
222 builder.createStore(loc, builder.getConstant(loc, constant), addr);
223}
224
226 const CIRGenFunction::AutoVarEmission &emission) {
227 assert(emission.variable && "emission was not valid!");
228
229 // If this was emitted as a global constant, we're done.
230 if (emission.wasEmittedAsGlobal())
231 return;
232
233 const VarDecl &d = *emission.variable;
234
235 QualType type = d.getType();
236
237 // If this local has an initializer, emit it now.
238 const Expr *init = d.getInit();
239
240 // Initialize the variable here if it doesn't have a initializer and it is a
241 // C struct that is non-trivial to initialize or an array containing such a
242 // struct.
243 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
245 cgm.errorNYI(d.getSourceRange(),
246 "emitAutoVarInit: non-trivial to default initialize");
247 return;
248 }
249
250 const Address addr = emission.addr;
251
252 // Check whether this is a byref variable that's potentially
253 // captured and moved by its own initializer. If so, we'll need to
254 // emit the initializer first, then copy into the variable.
256
257 // Note: constexpr already initializes everything correctly.
258 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
259 (d.isConstexpr()
261 : (d.getAttr<UninitializedAttr>()
263 : getContext().getLangOpts().getTrivialAutoVarInit()));
264
265 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
266 if (trivialAutoVarInit ==
268 return;
269
270 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
271 };
272
273 if (isTrivialInitializer(init)) {
274 initializeWhatIsTechnicallyUninitialized(addr);
275 return;
276 }
277
278 mlir::Attribute constant;
279 if (emission.isConstantAggregate ||
281 // FIXME: Differently from LLVM we try not to emit / lower too much
282 // here for CIR since we are interested in seeing the ctor in some
283 // analysis later on. So CIR's implementation of ConstantEmitter will
284 // frequently return an empty Attribute, to signal we want to codegen
285 // some trivial ctor calls and whatnots.
287 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
288 (trivialAutoVarInit !=
290 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
291 return;
292 }
293 }
294
295 // NOTE(cir): In case we have a constant initializer, we can just emit a
296 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
297 // CXX temporary object creation, we ensure the ctor call is used deferring
298 // its removal/optimization to the CIR lowering.
299 if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
300 initializeWhatIsTechnicallyUninitialized(addr);
302 emitExprAsInit(init, &d, lv);
303
304 if (!emission.wasEmittedAsOffloadClause()) {
305 // In case lv has uses it means we indeed initialized something
306 // out of it while trying to build the expression, mark it as such.
307 Address addr = lv.getAddress();
308 assert(addr.isValid() && "Should have an address");
309 cir::AllocaOp allocaOp = addr.getUnderlyingAllocaOp();
310 assert(allocaOp && "Address should come straight out of the alloca");
311
312 if (!allocaOp.use_empty())
313 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
314 }
315
316 return;
317 }
318
319 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
320 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
321 assert(typedConstant && "expected typed attribute");
322 if (!emission.isConstantAggregate) {
323 // For simple scalar/complex initialization, store the value directly.
324 LValue lv = makeAddrLValue(addr, type);
325 assert(init && "expected initializer");
326 mlir::Location initLoc = getLoc(init->getSourceRange());
327 // lv.setNonGC(true);
329 RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
330 }
331
332 emitStoresForConstant(cgm, d, addr, type.isVolatileQualified(), builder,
333 typedConstant);
334}
335
337 const CIRGenFunction::AutoVarEmission &emission) {
338 const VarDecl &d = *emission.variable;
339
340 // Check the type for a cleanup.
342 emitAutoVarTypeCleanup(emission, dtorKind);
343
345
346 // Handle the cleanup attribute.
347 if (d.hasAttr<CleanupAttr>())
348 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
349}
350
351/// Emit code and set up symbol table for a variable declaration with auto,
352/// register, or no storage class specifier. These turn into simple stack
353/// objects, globals depending on target.
359
361 // If the declaration has external storage, don't emit it now, allow it to be
362 // emitted lazily on its first use.
363 if (d.hasExternalStorage())
364 return;
365
366 if (d.getStorageDuration() != SD_Automatic) {
367 // Static sampler variables translated to function calls.
368 if (d.getType()->isSamplerT()) {
369 // Nothing needs to be done here, but let's flag it as an error until we
370 // have a test. It requires OpenCL support.
371 cgm.errorNYI(d.getSourceRange(), "emitVarDecl: static sampler type");
372 return;
373 }
374
375 cir::GlobalLinkageKind linkage = cgm.getCIRLinkageVarDefinition(&d);
376
377 // FIXME: We need to force the emission/use of a guard variable for
378 // some variables even if we can constant-evaluate them because
379 // we can't guarantee every translation unit will constant-evaluate them.
380
381 return emitStaticVarDecl(d, linkage);
382 }
383
385 cgm.errorNYI(d.getSourceRange(), "emitVarDecl: openCL address space");
386
387 assert(d.hasLocalStorage());
388
389 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
390 return emitAutoVarDecl(d);
391}
392
393static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
394 if (cgm.getLangOpts().CPlusPlus)
395 return cgm.getMangledName(&d).str();
396
397 // If this isn't C++, we don't need a mangled name, just a pretty one.
398 assert(!d.isExternallyVisible() && "name shouldn't matter");
399 std::string contextName;
400 const DeclContext *dc = d.getDeclContext();
401 if (auto *cd = dyn_cast<CapturedDecl>(dc))
402 dc = cast<DeclContext>(cd->getNonClosureContext());
403 if (const auto *fd = dyn_cast<FunctionDecl>(dc))
404 contextName = std::string(cgm.getMangledName(fd));
405 else if (isa<BlockDecl>(dc))
406 cgm.errorNYI(d.getSourceRange(),
407 "getStaticDeclName: block decl context for static var");
408 else if (isa<ObjCMethodDecl>(dc))
409 cgm.errorNYI(d.getSourceRange(),
410 "getStaticDeclName: ObjC decl context for static var");
411 else
412 cgm.errorNYI(d.getSourceRange(),
413 "getStaticDeclName: Unknown context for static var decl");
414
415 contextName += "." + d.getNameAsString();
416 return contextName;
417}
418
419// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
420// interface for all constants?
421cir::GlobalOp
423 cir::GlobalLinkageKind linkage) {
424 // In general, we don't always emit static var decls once before we reference
425 // them. It is possible to reference them before emitting the function that
426 // contains them, and it is possible to emit the containing function multiple
427 // times.
428 if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
429 return existingGV;
430
431 QualType ty = d.getType();
432 assert(ty->isConstantSizeType() && "VLAs can't be static");
433
434 // Use the label if the variable is renamed with the asm-label extension.
435 if (d.hasAttr<AsmLabelAttr>())
436 errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label");
437
438 std::string name = getStaticDeclName(*this, d);
439
440 mlir::Type lty = getTypes().convertTypeForMem(ty);
442
443 // OpenCL variables in local address space and CUDA shared
444 // variables cannot have an initializer.
445 mlir::Attribute init = nullptr;
447 d.hasAttr<CUDASharedAttr>() || d.hasAttr<LoaderUninitializedAttr>())
448 init = cir::UndefAttr::get(lty);
449 else
450 init = builder.getZeroInitAttr(convertType(ty));
451
452 cir::GlobalOp gv = builder.createVersionedGlobal(
453 getModule(), getLoc(d.getLocation()), name, lty, false, linkage);
455 // TODO(cir): infer visibility from linkage in global op builder.
456 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
457 gv.setInitialValueAttr(init);
458 gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
459
460 if (supportsCOMDAT() && gv.isWeakForLinker())
461 gv.setComdat(true);
462
463 if (d.getTLSKind())
464 setTLSMode(gv, d);
465
466 setGVProperties(gv, &d);
467
468 // OG checks if the expected address space, denoted by the type, is the
469 // same as the actual address space indicated by attributes. If they aren't
470 // the same, an addrspacecast is emitted when this variable is accessed.
471 // In CIR however, cir.get_global already carries that information in
472 // !cir.ptr type - if this global is in OpenCL local address space, then its
473 // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't
474 // need an explicit address space cast in CIR: they will get emitted when
475 // lowering to LLVM IR.
476
477 // Ensure that the static local gets initialized by making sure the parent
478 // function gets emitted eventually.
479 const Decl *dc = cast<Decl>(d.getDeclContext());
480
481 // We can't name blocks or captured statements directly, so try to emit their
482 // parents.
483 if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
484 dc = dc->getNonClosureContext();
485 // FIXME: Ensure that global blocks get emitted.
486 if (!dc)
487 errorNYI(d.getSourceRange(), "non-closure context");
488 }
489
490 GlobalDecl gd;
491 if (const auto *cd = dyn_cast<CXXConstructorDecl>(dc))
492 gd = GlobalDecl(cd, Ctor_Base);
493 else if (const auto *dd = dyn_cast<CXXDestructorDecl>(dc))
494 gd = GlobalDecl(dd, Dtor_Base);
495 else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
496 gd = GlobalDecl(fd);
497 else {
498 // Don't do anything for Obj-C method decls or global closures. We should
499 // never defer them.
500 assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
501 }
503 // Disable emission of the parent function for the OpenMP device codegen.
504 errorNYI(d.getSourceRange(), "OpenMP");
505 }
506
507 return gv;
508}
509
511 mlir::Attribute constAttr,
512 CharUnits align) {
513 auto functionName = [&](const DeclContext *dc) -> std::string {
514 if (const auto *fd = dyn_cast<FunctionDecl>(dc)) {
515 if (const auto *cc = dyn_cast<CXXConstructorDecl>(fd))
516 return cc->getNameAsString();
517 if (const auto *cd = dyn_cast<CXXDestructorDecl>(fd))
518 return cd->getNameAsString();
519 return std::string(getMangledName(fd));
520 } else if (const auto *om = dyn_cast<ObjCMethodDecl>(dc)) {
521 return om->getNameAsString();
522 } else if (isa<BlockDecl>(dc)) {
523 return "<block>";
524 } else if (isa<CapturedDecl>(dc)) {
525 return "<captured>";
526 } else {
527 llvm_unreachable("expected a function or method");
528 }
529 };
530
531 // Form a simple per-variable cache of these values in case we find we
532 // want to reuse them.
533 cir::GlobalOp &cacheEntry = initializerConstants[&d];
534 if (!cacheEntry || cacheEntry.getInitialValue() != constAttr) {
535 auto ty = mlir::cast<mlir::TypedAttr>(constAttr).getType();
536 bool isConstant = true;
537
538 std::string name;
539 if (d.hasGlobalStorage())
540 name = getMangledName(&d).str() + ".const";
541 else if (const DeclContext *dc = d.getParentFunctionOrMethod())
542 name = ("__const." + functionName(dc) + "." + d.getName()).str();
543 else
544 llvm_unreachable("local variable has no parent function or method");
545
547 cir::GlobalOp gv = builder.createVersionedGlobal(
548 getModule(), getLoc(d.getLocation()), name, ty, isConstant,
549 cir::GlobalLinkageKind::PrivateLinkage);
551 // TODO(cir): infer visibility from linkage in global op builder.
552 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(
553 cir::GlobalLinkageKind::PrivateLinkage));
554 gv.setInitialValueAttr(constAttr);
555 gv.setAlignment(align.getAsAlign().value());
556 // TODO(cir): Set unnamed address attribute when available in CIR
557
558 cacheEntry = gv;
559 } else if (cacheEntry.getAlignment() < align.getQuantity()) {
560 cacheEntry.setAlignment(align.getAsAlign().value());
561 }
562
563 // Create a GetGlobalOp to get a pointer to the global
565 mlir::Type eltTy = mlir::cast<mlir::TypedAttr>(constAttr).getType();
566 auto ptrTy = builder.getPointerTo(cacheEntry.getSymType());
567 mlir::Value globalPtr = cir::GetGlobalOp::create(
568 builder, getLoc(d.getLocation()), ptrTy, cacheEntry.getSymName());
569 return Address(globalPtr, eltTy, align);
570}
571
572/// Add the initializer for 'd' to the global variable that has already been
573/// created for it. If the initializer has a different type than gv does, this
574/// may free gv and return a different one. Otherwise it just returns gv.
576 const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
577 ConstantEmitter emitter(*this);
578 mlir::TypedAttr init = mlir::dyn_cast_if_present<mlir::TypedAttr>(
579 emitter.tryEmitForInitializer(d));
580
581 // If constant emission failed, then this should be a C++ static
582 // initializer.
583 if (!init) {
584 if (!getLangOpts().CPlusPlus) {
585 cgm.errorNYI(d.getInit()->getSourceRange(),
586 "constant l-value expression");
587 } else if (d.hasFlexibleArrayInit(getContext())) {
588 cgm.errorNYI(d.getInit()->getSourceRange(), "flexible array initializer");
589 } else {
590 // Since we have a static initializer, this global variable can't
591 // be constant.
592 gv.setConstant(false);
593 emitCXXGuardedInit(d, gv, /*performInit*/ true);
594 gvAddr.setStaticLocal(true);
595 }
596 return gv;
597 }
598
599 // TODO(cir): There should be debug code here to assert that the decl size
600 // matches the CIR data layout type alloc size, but the code for calculating
601 // the type alloc size is not implemented yet.
603
604 // The initializer may differ in type from the global. Rewrite
605 // the global to match the initializer. (We have to do this
606 // because some types, like unions, can't be completely represented
607 // in the LLVM type system.)
608 if (gv.getSymType() != init.getType()) {
609 gv.setSymType(init.getType());
610
611 // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
612 // but since at this point the current block hasn't been really attached,
613 // there's no visibility into the GetGlobalOp corresponding to this Global.
614 // Given those constraints, thread in the GetGlobalOp and update it
615 // directly.
617 gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
618 }
619
620 bool needsDtor =
622
623 gv.setConstant(d.getType().isConstantStorage(
624 getContext(), /*ExcludeCtor=*/true, !needsDtor));
625 gv.setInitialValueAttr(init);
626
627 emitter.finalize(gv);
628
629 if (needsDtor) {
630 // We have a constant initializer, but a nontrivial destructor. We still
631 // need to perform a guarded "initialization" in order to register the
632 // destructor.
633 emitCXXGuardedInit(d, gv, /*performInit=*/false);
634 gvAddr.setStaticLocal(true);
635 }
636
637 return gv;
638}
639
641 cir::GlobalLinkageKind linkage) {
642 // Check to see if we already have a global variable for this
643 // declaration. This can happen when double-emitting function
644 // bodies, e.g. with complete and base constructors.
645 cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
646 // TODO(cir): we should have a way to represent global ops as values without
647 // having to emit a get global op. Sometimes these emissions are not used.
648 mlir::Value addr =
649 builder.createGetGlobal(globalOp, d.getTLSKind() != VarDecl::TLS_None);
650 auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>();
651 assert(getAddrOp && "expected cir::GetGlobalOp");
652
653 CharUnits alignment = getContext().getDeclAlign(&d);
654
655 // Store into LocalDeclMap before generating initializer to handle
656 // circular references.
657 mlir::Type elemTy = convertTypeForMem(d.getType());
658 setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
659
660 // We can't have a VLA here, but we can have a pointer to a VLA,
661 // even though that doesn't really make any sense.
662 // Make sure to evaluate VLA bounds now so that we have them for later.
663 if (d.getType()->isVariablyModifiedType()) {
664 cgm.errorNYI(d.getSourceRange(),
665 "emitStaticVarDecl: variably modified type");
666 }
667
668 // Save the type in case adding the initializer forces a type change.
669 mlir::Type expectedType = addr.getType();
670
671 cir::GlobalOp var = globalOp;
672
674
675 // If this value has an initializer, emit it.
676 if (d.getInit())
677 var = addInitializerToStaticVarDecl(d, var, getAddrOp);
678
679 var.setAlignment(alignment.getAsAlign().value());
680
681 // There are a lot of attributes that need to be handled here. Until
682 // we start to support them, we just report an error if there are any.
683 if (d.hasAttr<AnnotateAttr>())
684 cgm.addGlobalAnnotations(&d, var);
685 if (d.getAttr<PragmaClangBSSSectionAttr>())
686 cgm.errorNYI(d.getSourceRange(),
687 "emitStaticVarDecl: CIR global BSS section attribute");
688 if (d.getAttr<PragmaClangDataSectionAttr>())
689 cgm.errorNYI(d.getSourceRange(),
690 "emitStaticVarDecl: CIR global Data section attribute");
691 if (d.getAttr<PragmaClangRodataSectionAttr>())
692 cgm.errorNYI(d.getSourceRange(),
693 "emitStaticVarDecl: CIR global Rodata section attribute");
694 if (d.getAttr<PragmaClangRelroSectionAttr>())
695 cgm.errorNYI(d.getSourceRange(),
696 "emitStaticVarDecl: CIR global Relro section attribute");
697
698 if (d.getAttr<SectionAttr>())
699 cgm.errorNYI(d.getSourceRange(),
700 "emitStaticVarDecl: CIR global object file section attribute");
701
702 if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
703 cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
704
705 // From traditional codegen:
706 // We may have to cast the constant because of the initializer
707 // mismatch above.
708 //
709 // FIXME: It is really dangerous to store this in the map; if anyone
710 // RAUW's the GV uses of this constant will be invalid.
711 mlir::Value castedAddr =
712 builder.createBitcast(getAddrOp.getAddr(), expectedType);
713 localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
714 cgm.setStaticLocalDeclAddress(&d, var);
715
718}
719
720void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
721 LValue lvalue, bool capturedByInit) {
723
724 SourceLocRAIIObject locRAII{*this, loc};
725 mlir::Value value = emitScalarExpr(init);
726 if (capturedByInit) {
727 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
728 return;
729 }
731 emitStoreThroughLValue(RValue::get(value), lvalue, true);
732}
733
735 LValue lvalue, bool capturedByInit) {
736 SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
737 if (capturedByInit) {
738 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
739 return;
740 }
741
742 QualType type = d->getType();
743
744 if (type->isReferenceType()) {
745 RValue rvalue = emitReferenceBindingToExpr(init);
746 if (capturedByInit)
747 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
748 emitStoreThroughLValue(rvalue, lvalue);
749 return;
750 }
752 case cir::TEK_Scalar:
753 emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
754 return;
755 case cir::TEK_Complex: {
756 mlir::Value complex = emitComplexExpr(init);
757 if (capturedByInit)
758 cgm.errorNYI(init->getSourceRange(),
759 "emitExprAsInit: complex type captured by init");
760 mlir::Location loc = getLoc(init->getExprLoc());
761 emitStoreOfComplex(loc, complex, lvalue,
762 /*isInit*/ true);
763 return;
764 }
766 // The overlap flag here should be calculated.
768 emitAggExpr(init,
772 return;
773 }
774 llvm_unreachable("bad evaluation kind");
775}
776
777void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
778 switch (d.getKind()) {
779 case Decl::BuiltinTemplate:
780 case Decl::TranslationUnit:
781 case Decl::ExternCContext:
782 case Decl::Namespace:
783 case Decl::UnresolvedUsingTypename:
784 case Decl::ClassTemplateSpecialization:
785 case Decl::ClassTemplatePartialSpecialization:
786 case Decl::VarTemplateSpecialization:
787 case Decl::VarTemplatePartialSpecialization:
788 case Decl::TemplateTypeParm:
789 case Decl::UnresolvedUsingValue:
790 case Decl::NonTypeTemplateParm:
791 case Decl::CXXDeductionGuide:
792 case Decl::CXXMethod:
793 case Decl::CXXConstructor:
794 case Decl::CXXDestructor:
795 case Decl::CXXConversion:
796 case Decl::Field:
797 case Decl::MSProperty:
798 case Decl::IndirectField:
799 case Decl::ObjCIvar:
800 case Decl::ObjCAtDefsField:
801 case Decl::ParmVar:
802 case Decl::ImplicitParam:
803 case Decl::ClassTemplate:
804 case Decl::VarTemplate:
805 case Decl::FunctionTemplate:
806 case Decl::TypeAliasTemplate:
807 case Decl::TemplateTemplateParm:
808 case Decl::ObjCMethod:
809 case Decl::ObjCCategory:
810 case Decl::ObjCProtocol:
811 case Decl::ObjCInterface:
812 case Decl::ObjCCategoryImpl:
813 case Decl::ObjCImplementation:
814 case Decl::ObjCProperty:
815 case Decl::ObjCCompatibleAlias:
816 case Decl::PragmaComment:
817 case Decl::PragmaDetectMismatch:
818 case Decl::AccessSpec:
819 case Decl::LinkageSpec:
820 case Decl::Export:
821 case Decl::ObjCPropertyImpl:
822 case Decl::FileScopeAsm:
823 case Decl::Friend:
824 case Decl::FriendTemplate:
825 case Decl::Block:
826 case Decl::OutlinedFunction:
827 case Decl::Captured:
828 case Decl::UsingShadow:
829 case Decl::ConstructorUsingShadow:
830 case Decl::ObjCTypeParam:
831 case Decl::Binding:
832 case Decl::UnresolvedUsingIfExists:
833 case Decl::HLSLBuffer:
834 case Decl::HLSLRootSignature:
835 llvm_unreachable("Declaration should not be in declstmts!");
836
837 case Decl::Function: // void X();
838 case Decl::EnumConstant: // enum ? { X = ? }
839 case Decl::ExplicitInstantiation:
840 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
841 case Decl::Label: // __label__ x;
842 case Decl::Import:
843 case Decl::MSGuid: // __declspec(uuid("..."))
844 case Decl::TemplateParamObject:
845 case Decl::Empty:
846 case Decl::Concept:
847 case Decl::LifetimeExtendedTemporary:
848 case Decl::RequiresExprBody:
849 case Decl::UnnamedGlobalConstant:
850 // None of these decls require codegen support.
851 return;
852
853 case Decl::Enum: // enum X;
854 case Decl::Record: // struct/union/class X;
855 case Decl::CXXRecord: // struct/union/class X; [C++]
856 case Decl::NamespaceAlias:
857 case Decl::Using: // using X; [C++]
858 case Decl::UsingEnum: // using enum X; [C++]
859 case Decl::UsingDirective: // using namespace X; [C++]
861 return;
862 case Decl::Var:
863 case Decl::Decomposition: {
864 const VarDecl &vd = cast<VarDecl>(d);
865 assert(vd.isLocalVarDecl() &&
866 "Should not see file-scope variables inside a function!");
867 emitVarDecl(vd);
868 if (evaluateConditionDecl)
870 return;
871 }
872 case Decl::OpenACCDeclare:
874 return;
875 case Decl::OpenACCRoutine:
877 return;
878 case Decl::OMPThreadPrivate:
880 return;
881 case Decl::OMPGroupPrivate:
883 return;
884 case Decl::OMPAllocate:
886 return;
887 case Decl::OMPCapturedExpr:
889 return;
890 case Decl::OMPRequires:
892 return;
893 case Decl::OMPDeclareMapper:
895 return;
896 case Decl::OMPDeclareReduction:
898 return;
899 case Decl::Typedef: // typedef int X;
900 case Decl::TypeAlias: { // using X = int; [C++0x]
901 QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
903 if (ty->isVariablyModifiedType())
905 return;
906 }
907 case Decl::ImplicitConceptSpecialization:
908 case Decl::TopLevelStmt:
909 case Decl::UsingPack:
910 cgm.errorNYI(d.getSourceRange(),
911 std::string("emitDecl: unhandled decl type: ") +
912 d.getDeclKindName());
913 }
914}
915
917 SourceLocation loc) {
918 if (!sanOpts.has(SanitizerKind::NullabilityAssign))
919 return;
920
922}
923
924namespace {
925struct DestroyObject final : EHScopeStack::Cleanup {
926 DestroyObject(Address addr, QualType type,
927 CIRGenFunction::Destroyer *destroyer)
928 : addr(addr), type(type), destroyer(destroyer) {
930 }
931
932 Address addr;
934 CIRGenFunction::Destroyer *destroyer;
935
936 void emit(CIRGenFunction &cgf, Flags flags) override {
938 cgf.emitDestroy(addr, type, destroyer);
939 }
940};
941
942template <class Derived> struct DestroyNRVOVariable : EHScopeStack::Cleanup {
943 DestroyNRVOVariable(Address addr, QualType type, mlir::Value nrvoFlag)
944 : nrvoFlag(nrvoFlag), addr(addr), ty(type) {}
945
946 mlir::Value nrvoFlag;
947 Address addr;
948 QualType ty;
949
950 void emit(CIRGenFunction &cgf, Flags flags) override {
951 // Along the exceptions path we always execute the dtor.
952 bool nrvo = flags.isForNormalCleanup() && nrvoFlag;
953
954 CIRGenBuilderTy &builder = cgf.getBuilder();
955 mlir::OpBuilder::InsertionGuard guard(builder);
956 if (nrvo) {
957 // If we exited via NRVO, we skip the destructor call.
958 mlir::Location loc = addr.getPointer().getLoc();
959 mlir::Value didNRVO = builder.createFlagLoad(loc, nrvoFlag);
960 mlir::Value notNRVO = builder.createNot(didNRVO);
961 cir::IfOp::create(builder, loc, notNRVO, /*withElseRegion=*/false,
962 [&](mlir::OpBuilder &b, mlir::Location) {
963 static_cast<Derived *>(this)->emitDestructorCall(cgf);
964 builder.createYield(loc);
965 });
966 } else {
967 static_cast<Derived *>(this)->emitDestructorCall(cgf);
968 }
969 }
970
971 virtual ~DestroyNRVOVariable() = default;
972};
973
974struct DestroyNRVOVariableCXX final
975 : DestroyNRVOVariable<DestroyNRVOVariableCXX> {
976 DestroyNRVOVariableCXX(Address addr, QualType type,
977 const CXXDestructorDecl *dtor, mlir::Value nrvoFlag)
978 : DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, type, nrvoFlag),
979 dtor(dtor) {}
980
981 const CXXDestructorDecl *dtor;
982
983 void emitDestructorCall(CIRGenFunction &cgf) {
985 /*forVirtualBase=*/false,
986 /*delegating=*/false, addr, ty);
987 }
988};
989
990struct CallStackRestore final : EHScopeStack::Cleanup {
991 Address stack;
992 CallStackRestore(Address stack) : stack(stack) {}
993 void emit(CIRGenFunction &cgf, Flags flags) override {
994 mlir::Location loc = stack.getPointer().getLoc();
995 mlir::Value v = cgf.getBuilder().createLoad(loc, stack);
996 cgf.getBuilder().createStackRestore(loc, v);
997 }
998};
999
1000/// A cleanup which performs a partial array destroy where the end pointer is
1001/// irregularly determined and must be loaded from a local.
1002struct IrregularPartialArrayDestroy final : EHScopeStack::Cleanup {
1003 mlir::Value arrayBegin;
1004 Address arrayEndPointer;
1005 QualType elementType;
1006 CharUnits elementAlign;
1007 CIRGenFunction::Destroyer *destroyer;
1008
1009 IrregularPartialArrayDestroy(mlir::Value arrayBegin, Address arrayEndPointer,
1010 QualType elementType, CharUnits elementAlign,
1011 CIRGenFunction::Destroyer *destroyer)
1012 : arrayBegin(arrayBegin), arrayEndPointer(arrayEndPointer),
1013 elementType(elementType), elementAlign(elementAlign),
1014 destroyer(destroyer) {}
1015
1016 void emit(CIRGenFunction &cgf, Flags flags) override {
1017 CIRGenBuilderTy &builder = cgf.getBuilder();
1018 mlir::Location loc = arrayBegin.getLoc();
1019
1020 mlir::Value arrayEnd = builder.createLoad(loc, arrayEndPointer);
1021
1022 // The cleanup is destroying elements in reverse from arrayEnd back to
1023 // arrayBegin, but only if arrayEnd != arrayBegin (i.e. something was
1024 // constructed).
1025 mlir::Type cirElementType = cgf.convertTypeForMem(elementType);
1026 cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
1027
1028 mlir::Value ne = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
1029 arrayEnd, arrayBegin);
1030 cir::IfOp::create(
1031 builder, loc, ne, /*withElseRegion=*/false,
1032 [&](mlir::OpBuilder &b, mlir::Location loc) {
1033 Address iterAddr = cgf.createTempAlloca(
1034 ptrToElmType, cgf.getPointerAlign(), loc, "__array_idx");
1035 builder.createStore(loc, arrayEnd, iterAddr);
1036 builder.createDoWhile(
1037 loc,
1038 /*condBuilder=*/
1039 [&](mlir::OpBuilder &b, mlir::Location loc) {
1040 mlir::Value cur = builder.createLoad(loc, iterAddr);
1041 mlir::Value cmp = cir::CmpOp::create(
1042 builder, loc, cir::CmpOpKind::ne, cur, arrayBegin);
1043 builder.createCondition(cmp);
1044 },
1045 /*bodyBuilder=*/
1046 [&](mlir::OpBuilder &b, mlir::Location loc) {
1047 mlir::Value cur = builder.createLoad(loc, iterAddr);
1048 cir::ConstantOp negOne = builder.getConstInt(
1049 loc, mlir::cast<cir::IntType>(cgf.ptrDiffTy), -1);
1050 mlir::Value prev = cir::PtrStrideOp::create(
1051 builder, loc, ptrToElmType, cur, negOne);
1052 builder.createStore(loc, prev, iterAddr);
1053 Address elemAddr = Address(prev, cirElementType, elementAlign);
1054 destroyer(cgf, elemAddr, elementType);
1055 builder.createYield(loc);
1056 });
1057 builder.createYield(loc);
1058 });
1059 }
1060};
1061} // namespace
1062
1063/// Push an EH cleanup to destroy already-constructed elements of the given
1064/// array. The cleanup may be popped with deactivateCleanupBlock or
1065/// popCleanupBlock.
1066///
1067/// \param elementType - the immediate element type of the array;
1068/// possibly still an array type
1070 Address arrayEndPointer,
1071 QualType elementType,
1072 CharUnits elementAlign,
1073 Destroyer *destroyer) {
1074 ehStack.pushCleanup<IrregularPartialArrayDestroy>(
1075 EHCleanup, arrayBegin, arrayEndPointer, elementType, elementAlign,
1076 destroyer);
1077}
1078
1079/// pushEHDestroyIfNeeded - Push the standard destructor for the given type as
1080/// an EH-only cleanup. If EH cleanup is not needed, just return.
1082 Address addr, QualType type) {
1083 if (!needsEHCleanup(dtorKind))
1084 return;
1085
1087 pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind));
1088}
1089
1090/// Push the standard destructor for the given type as
1091/// at least a normal cleanup.
1093 Address addr, QualType type) {
1094 assert(dtorKind && "cannot push destructor for trivial type");
1095
1096 CleanupKind cleanupKind = getCleanupKind(dtorKind);
1097 pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind));
1098}
1099
1101 QualType type, Destroyer *destroyer) {
1102 pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
1103}
1104
1107 assert(dtorKind && "cannot push destructor for trivial type");
1108
1109 CleanupKind cleanupKind = getCleanupKind(dtorKind);
1111 cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup);
1112}
1113
1115 CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
1116 bool useEHCleanupForArray) {
1119 destroyer);
1120}
1121
1123 Address addr, QualType type,
1124 Destroyer *destroyer,
1125 bool useEHCleanupForArray) {
1126 if (isInConditionalBranch()) {
1127 cgm.errorNYI("conditional lifetime-extended destroy");
1128 return;
1129 }
1130
1131 // Add the cleanup to the EHStack. After the full-expr, this would be
1132 // deactivated before being popped from the stack.
1133 pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer,
1134 useEHCleanupForArray);
1135
1137
1138 pushCleanupAfterFullExpr(cleanupKind, addr, type, destroyer);
1139}
1140
1142 const PendingCleanupEntry &entry) {
1143 ehStack.pushCleanup<DestroyObject>(entry.kind, entry.addr, entry.type,
1144 entry.destroyer);
1145
1146 if (entry.activeFlag.isValid()) {
1147 EHCleanupScope &scope = cast<EHCleanupScope>(*ehStack.begin());
1148 scope.setActiveFlag(entry.activeFlag);
1150 scope.setTestFlagInEHCleanup(scope.isEHCleanup());
1151 }
1152}
1153
1154/// Destroys all the elements of the given array, beginning from last to first.
1155///
1156/// \param begin - a type* denoting the first element of the array
1157/// \param numElements - the number of elements in the array
1158/// \param elementType - the element type of the array
1159/// \param destroyer - the function to call to destroy elements
1161 mlir::Value numElements,
1162 QualType elementType,
1163 CharUnits elementAlign,
1164 Destroyer *destroyer) {
1165 assert(!elementType->isArrayType());
1166
1167 // Differently from LLVM traditional codegen, use a higher level
1168 // representation instead of lowering directly to a loop.
1169 mlir::Type cirElementType = convertTypeForMem(elementType);
1170 cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
1171
1172 auto regionBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1173 mlir::BlockArgument arg =
1174 b.getInsertionBlock()->addArgument(ptrToElmType, loc);
1175 Address curAddr = Address(arg, cirElementType, elementAlign);
1177
1178 // Perform the actual destruction there.
1179 destroyer(*this, curAddr, elementType);
1180
1181 cir::YieldOp::create(b, loc);
1182 };
1183
1184 // For a constant array size, use the static form of ArrayDtor.
1185 if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
1186 uint64_t size = 0;
1187 if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>())
1188 size = constIntAttr.getUInt();
1189 auto arrayTy = cir::ArrayType::get(cirElementType, size);
1190 mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
1191 cir::ArrayDtor::create(builder, *currSrcLoc, arrayOp, regionBuilder);
1192 return;
1193 }
1194
1195 // For a dynamic array size (VLA), use the dynamic form of ArrayDtor.
1196 mlir::Value elemBegin = builder.createPtrBitcast(begin, cirElementType);
1197 cir::ArrayDtor::create(builder, *currSrcLoc, elemBegin, numElements,
1198 regionBuilder);
1199}
1200
1201/// Immediately perform the destruction of the given object.
1202///
1203/// \param addr - the address of the object; a type*
1204/// \param type - the type of the object; if an array type, all
1205/// objects are destroyed in reverse order
1206/// \param destroyer - the function to call to destroy individual
1207/// elements
1209 Destroyer *destroyer) {
1211 if (!arrayType)
1212 return destroyer(*this, addr, type);
1213
1214 mlir::Value length = emitArrayLength(arrayType, type, addr);
1215
1216 CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
1217 getContext().getTypeSizeInChars(type));
1218
1219 // If the array length is constant, we can check for zero at compile time.
1220 auto constantCount = length.getDefiningOp<cir::ConstantOp>();
1221 if (constantCount) {
1222 auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue());
1223 if (constIntAttr && constIntAttr.getUInt() == 0)
1224 return;
1225 }
1226
1227 mlir::Value begin = addr.getPointer();
1229 emitArrayDestroy(begin, length, type, elementAlign, destroyer);
1230
1231 // If the array destroy didn't use the length op, we can erase it.
1232 if (constantCount && constantCount.use_empty())
1233 constantCount.erase();
1234}
1235
1238 switch (kind) {
1239 case QualType::DK_none:
1240 llvm_unreachable("no destroyer for trivial dtor");
1242 return destroyCXXObject;
1246 cgm.errorNYI("getDestroyer: other destruction kind");
1247 return nullptr;
1248 }
1249 llvm_unreachable("Unknown DestructionKind");
1250}
1251
1253 ehStack.pushCleanup<CallStackRestore>(kind, spMem);
1254}
1255
1256/// Enter a destroy cleanup for the given local variable.
1258 const CIRGenFunction::AutoVarEmission &emission,
1259 QualType::DestructionKind dtorKind) {
1260 assert(dtorKind != QualType::DK_none);
1261
1262 // Note that for __block variables, we want to destroy the
1263 // original stack object, not the possibly forwarded object.
1264 Address addr = emission.getObjectAddress(*this);
1265
1266 const VarDecl *var = emission.variable;
1267 QualType type = var->getType();
1268
1269 CleanupKind cleanupKind = NormalAndEHCleanup;
1270 CIRGenFunction::Destroyer *destroyer = nullptr;
1271
1272 switch (dtorKind) {
1273 case QualType::DK_none:
1274 llvm_unreachable("no cleanup for trivially-destructible variable");
1275
1277 // If there's an NRVO flag on the emission, we need a different
1278 // cleanup.
1279 if (emission.nrvoFlag) {
1280 assert(!type->isArrayType());
1281 CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
1282 ehStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, type, dtor,
1283 emission.nrvoFlag);
1284 return;
1285 }
1286 // Otherwise, this is handled below.
1287 break;
1288
1292 cgm.errorNYI(var->getSourceRange(),
1293 "emitAutoVarTypeCleanup: other dtor kind");
1294 return;
1295 }
1296
1297 // If we haven't chosen a more specific destroyer, use the default.
1298 if (!destroyer)
1299 destroyer = getDestroyer(dtorKind);
1300
1302 ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
1303}
1304
1306 if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
1307 for (auto *b : dd->flat_bindings())
1308 if (auto *hd = b->getHoldingVar())
1309 emitVarDecl(*hd);
1310 }
1311}
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 void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d, Address addr, bool isVolatile, CIRGenBuilderTy &builder, mlir::TypedAttr constant)
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.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
__device__ __2f16 b
cir::ConditionOp createCondition(mlir::Value condition)
Create a loop condition.
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
cir::PointerType getPointerTo(mlir::Type ty)
cir::DoWhileOp createDoWhile(mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> condBuilder, llvm::function_ref< void(mlir::OpBuilder &, mlir::Location)> bodyBuilder)
Create a do-while operation.
mlir::Value createNot(mlir::Location loc, mlir::Value value)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr)
Emit a load from an boolean flag variable.
llvm::TypeSize getTypeAllocSize(mlir::Type ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
const LangOptions & getLangOpts() const
Definition ASTContext.h:961
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:3784
mlir::Value getPointer() const
Definition Address.h:98
mlir::Type getElementType() const
Definition Address.h:125
static Address invalid()
Definition Address.h:76
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
clang::CharUnits getAlignment() const
Definition Address.h:138
bool isValid() const
Definition Address.h:77
cir::AllocaOp getUnderlyingAllocaOp() const
Return the underlying alloca for this address, if any.
Definition Address.h:157
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
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.
void emitVariablyModifiedType(QualType ty)
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 emitOMPRequiresDecl(const OMPRequiresDecl &d)
VlaSizePair getVLASize(const VariableArrayType *type)
Returns an MLIR::Value+QualType pair that corresponds to the size, in non-variably-sized elements,...
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)
void pushIrregularPartialArrayCleanup(mlir::Value arrayBegin, Address arrayEndPointer, QualType elementType, CharUnits elementAlign, Destroyer *destroyer)
Push an EH cleanup to destroy already-constructed elements of the given array.
void pushCleanupAndDeferDeactivation(CleanupKind kind, As... a)
Push a cleanup and record it for deferred deactivation.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitOMPDeclareReduction(const OMPDeclareReductionDecl &d)
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.
void emitCXXGuardedInit(const VarDecl &varDecl, cir::GlobalOp globalOp, bool performInit)
Emit a guarded initializer for a static local variable.
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.
void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind, Address addr, QualType type)
CleanupKind getCleanupKind(QualType::DestructionKind kind)
void emitOMPAllocateDecl(const OMPAllocateDecl &d)
void emitOMPDeclareMapper(const OMPDeclareMapperDecl &d)
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
mlir::Type convertTypeForMem(QualType t)
void pushDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type)
Push the standard destructor for the given type as at least a normal cleanup.
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 emitArrayDestroy(mlir::Value begin, mlir::Value numElements, QualType elementType, CharUnits elementAlign, Destroyer *destroyer)
Destroys all the elements of the given array, beginning from last to first.
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)
void emitAutoVarInit(const AutoVarEmission &emission)
Emit the initializer for an allocated variable.
void maybeEmitDeferredVarDeclInit(const VarDecl *vd)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
void pushStackRestore(CleanupKind kind, Address spMem)
void emitAutoVarDecl(const clang::VarDecl &d)
Emit code and set up symbol table for a variable declaration with auto, register, or no storage class...
bool needsEHCleanup(QualType::DestructionKind kind)
Determines whether an EH cleanup is required to destroy a type with the given destruction kind.
CIRGenBuilderTy & getBuilder()
bool didCallStackSave
Whether a cir.stacksave operation has been added.
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.
void pushPendingCleanupToEHStack(const PendingCleanupEntry &entry)
Promote a single pending cleanup entry onto the EH scope stack.
llvm::DenseMap< const VarDecl *, mlir::Value > nrvoFlags
A mapping from NRVO variables to the flags used to indicate when the NRVO has been applied to this va...
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.
void pushEHDestroyIfNeeded(QualType::DestructionKind dtorKind, Address addr, QualType type)
pushEHDestroyIfNeeded - Push the standard destructor for the given type as an EH-only cleanup.
void emitOMPThreadPrivateDecl(const OMPThreadPrivateDecl &d)
void emitOMPGroupPrivateDecl(const OMPGroupPrivateDecl &d)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
void emitCXXDestructorCall(const CXXDestructorDecl *dd, CXXDtorType type, bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy)
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 pushCleanupAfterFullExpr(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer)
Queue a cleanup to be pushed after finishing the current full-expression.
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 emitOMPCapturedExpr(const OMPCapturedExprDecl &d)
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 pushLifetimeExtendedDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray)
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
void insertGlobalSymbol(mlir::Operation *op)
mlir::Type convertType(clang::QualType type)
llvm::DenseMap< const VarDecl *, cir::GlobalOp > initializerConstants
void setGVProperties(mlir::Operation *op, const NamedDecl *d) const
Set visibility, dllimport/dllexport and dso_local.
static mlir::SymbolTable::Visibility getMLIRVisibilityFromCIRLinkage(cir::GlobalLinkageKind GLK)
void setTLSMode(mlir::Operation *op, const VarDecl &d)
Set TLS mode for the given operation based on the given variable declaration.
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
mlir::MLIRContext & getMLIRContext()
cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d)
Address createUnnamedGlobalFrom(const VarDecl &d, mlir::Attribute constAttr, CharUnits align)
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.
A cleanup scope which generates the cleanup blocks lazily.
void setTestFlagInEHCleanup(bool value)
void setTestFlagInNormalCleanup(bool value)
void setActiveFlag(Address var)
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:83
Represents a call to a C++ constructor.
Definition ExprCXX.h:1552
Represents a C++ constructor within a class.
Definition DeclCXX.h:2620
Represents a C++ destructor within a class.
Definition DeclCXX.h:2882
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
static CharUnits One()
One - Construct a CharUnits quantity of one.
Definition CharUnits.h:58
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
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1462
const DeclContext * getParentFunctionOrMethod(bool LexicalParent=false) const
If this decl is defined inside a function/method/block it returns the corresponding DeclContext,...
Definition DeclBase.cpp:341
T * getAttr() const
Definition DeclBase.h:581
Decl * getNonClosureContext()
Find the innermost non-closure ancestor of this declaration, walking up through blocks,...
SourceLocation getLocation() const
Definition DeclBase.h:447
const char * getDeclKindName() const
Definition DeclBase.cpp:169
DeclContext * getDeclContext()
Definition DeclBase.h:456
bool hasAttr() const
Definition DeclBase.h:585
Kind getKind() const
Definition DeclBase.h:450
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:435
This represents one expression.
Definition Expr.h:112
bool isConstantInitializer(ASTContext &Ctx, bool ForRef=false, const Expr **Culprit=nullptr) const
Returns true if this expression can be emitted to IR as a constant, and thus can be used as a constan...
Definition Expr.cpp:3354
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:282
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:301
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:317
bool isExternallyVisible() const
Definition Decl.h:433
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:1493
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8571
bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, bool ExcludeDtor)
Definition TypeBase.h:1036
bool isPODType(const ASTContext &Context) const
Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
Definition Type.cpp:2788
Represents a struct/union/class.
Definition Decl.h:4347
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:343
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:2517
bool isArrayType() const
Definition TypeBase.h:8781
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2862
bool isVectorType() const
Definition TypeBase.h:8821
bool isSamplerT() const
Definition TypeBase.h:8926
bool isRecordType() const
Definition TypeBase.h:8809
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:924
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1582
TLSKind getTLSKind() const
Definition Decl.cpp:2147
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2169
bool hasFlexibleArrayInit(const ASTContext &Ctx) const
Whether this variable has a flexible array member initialized with one or more elements.
Definition Decl.cpp:2820
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1239
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:2465
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1525
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2809
const Expr * getInit() const
Definition Decl.h:1381
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
Definition Decl.h:1230
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1182
@ TLS_None
Not a TLS variable.
Definition Decl.h:944
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition Decl.h:1266
StorageDuration getStorageDuration() const
Get the storage duration of this variable, per C++ [basic.stc].
Definition Decl.h:1242
bool isEscapingByref() const
Indicates the capture is a __block variable that is captured by a block that can potentially escape (...
Definition Decl.cpp:2669
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
@ EHCleanup
Denotes a cleanup that should run when a scope is exited using exceptional control flow (a throw stat...
@ NormalCleanup
Denotes a cleanup that should run when a scope is exited using normal control flow (falling off the e...
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const AstTypeMatcher< ArrayType > arrayType
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
The JSON file list parser is used to communicate input to InstallAPI.
@ Ctor_Base
Base object ctor.
Definition ABI.h:26
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ CPlusPlus
@ SD_Automatic
Automatic storage duration (most local variables).
Definition Specifiers.h:342
@ Dtor_Base
Base object dtor.
Definition ABI.h:37
@ Dtor_Complete
Complete object dtor.
Definition ABI.h:36
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 objCLifetime()
static bool addAutoInitAnnotation()
static bool addressSpace()
static bool emitNullabilityCheck()
static bool useEHCleanupForArray()
static bool vectorConstants()
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 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.
Address getObjectAddress(CIRGenFunction &cgf) const
Returns the address of the object within this declaration.
A cleanup entry that will be promoted onto the EH scope stack at a later point.
clang::CharUnits getPointerAlign() const
cir::PointerType allocaInt8PtrTy
void* in alloca address space