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