clang 24.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 "Address.h"
14#include "CIRGenCleanup.h"
16#include "CIRGenFunction.h"
17#include "EHScopeStack.h"
18#include "mlir/IR/Location.h"
19#include "clang/AST/Attr.h"
20#include "clang/AST/Attrs.inc"
21#include "clang/AST/Decl.h"
23#include "clang/AST/Expr.h"
24#include "clang/AST/ExprCXX.h"
26#include "clang/Basic/Cuda.h"
30#include "llvm/Support/SaveAndRestore.h"
31
32using namespace clang;
33using namespace clang::CIRGen;
34
35namespace {
36/// Call the function named by a variable's `cleanup` attribute with the
37/// variable's address when it goes out of scope.
38struct CallCleanupFunction final : EHScopeStack::Cleanup {
39 const CIRGenFunctionInfo &fnInfo;
40 Address addr;
41 QualType varType;
42 CIRGenCallee callee;
43 SourceRange attrRange;
44
45 CallCleanupFunction(cir::FuncOp cleanupFn, const CIRGenFunctionInfo *info,
46 Address addr, QualType varType, const CleanupAttr *attr)
47 : fnInfo(*info), addr(addr), varType(varType),
48 callee(CIRGenCallee::forDirect(
49 cleanupFn, CIRGenCalleeInfo(attr->getFunctionDecl()))),
50 attrRange(attr->getRange()) {}
51
52 void emit(CIRGenFunction &cgf, Flags flags) override {
53 assert(!fnInfo.arguments().empty());
54 QualType argTy = fnInfo.arguments()[0];
55 // Sema only guarantees that these are assignable/convertible pointers (that
56 // is, the address-of the cleanup variable and the function parameter type),
57 // which don't necessarily match in either pointee type or address space.
58 // For example: address-of-g is void**, but the function takes void*.
59 // void f(void* arg);
60 // __attribute__((cleanup(f))) void *g;
61 // Likewise `int *__ptr32` parameters are accepted for an `int` variable.
62 // Classic codegen only emits a bitcast, which asserts for the latter.
63 // Both casts are no-ops when the types already match.
64 CIRGenBuilderTy &builder = cgf.getBuilder();
65 auto argPtrTy = mlir::cast<cir::PointerType>(cgf.convertType(argTy));
66 mlir::Value arg =
67 builder.createPtrBitcast(addr.getPointer(), argPtrTy.getPointee());
68 arg = cgf.performAddrSpaceCast(arg, argPtrTy);
69
70 CallArgList args;
71 args.add(RValue::get(arg), cgf.getContext().getPointerType(varType));
72 cgf.emitCall(fnInfo, callee, ReturnValueSlot(), args,
73 /*callOp=*/nullptr, /*isMustTail=*/false, attrRange);
74 }
75};
76} // namespace
77
78struct CallLifetimeEnd final : EHScopeStack::Cleanup {
79 // The raw alloca pointer (in the alloca address space). Mirrors classic
80 // CodeGen's CallLifetimeEnd, which stores the llvm::Value pointer rather
81 // than an Address.
82 mlir::Value addr;
83 CallLifetimeEnd(mlir::Value addr) : addr(addr) {}
84 bool isRedundantBeforeReturn() override { return true; }
85 void emit(CIRGenFunction &cgf, Flags flags) override {
86 cgf.emitLifetimeEndOp(addr.getLoc(), addr);
87 }
88};
89
92 mlir::OpBuilder::InsertPoint ip) {
93 QualType ty = d.getType();
94 assert(
97
98 mlir::Location loc = getLoc(d.getSourceRange());
99 bool nrvo =
100 getContext().getLangOpts().ElideConstructors && d.isNRVOVariable();
101
103 emission.isEscapingByRef = d.isEscapingByref();
104 if (emission.isEscapingByRef)
105 cgm.errorNYI(d.getSourceRange(),
106 "emitAutoVarAlloca: decl escaping by reference");
107
108 CharUnits alignment = getContext().getDeclAlign(&d);
109
110 // If the type is variably-modified, emit all the VLA sizes for it.
111 if (ty->isVariablyModifiedType())
113
115
116 Address address = Address::invalid();
117 if (ty->isConstantSizeType()) {
118 // If this value is an array, struct, or vector with a statically
119 // determinable constant initializer, there are optimizations we can do.
120 //
121 // TODO: We should constant-evaluate the initializer of any variable,
122 // as long as it is initialized by a constant expression. Currently,
123 // isConstantInitializer produces wrong answers for structs with
124 // reference or bitfield members, and a few other cases, and checking
125 // for POD-ness protects us from some of these.
126 if (d.getInit() &&
127 (ty->isArrayType() || ty->isRecordType() || ty->isVectorType()) &&
128 (d.isConstexpr() ||
129 ((ty.isPODType(getContext()) ||
130 getContext().getBaseElementType(ty)->isObjCObjectPointerType()) &&
132
133 // If the variable's a const type, and it's neither an NRVO
134 // candidate nor a __block variable and has no mutable members,
135 // emit it as a global instead.
136 // Exception is if a variable is located in non-constant address space
137 // in OpenCL.
138 // TODO(cir): perhaps we don't need this at all at CIR since this can
139 // be done as part of lowering down to LLVM.
140 bool needsDtor =
142 if ((!getContext().getLangOpts().OpenCL ||
144 (cgm.getCodeGenOpts().MergeAllConstants && !nrvo &&
145 !d.isEscapingByref() &&
146 ty.isConstantStorage(getContext(), true, !needsDtor))) {
147 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: type constant");
148 }
149 // Otherwise, tell the initialization code that we're in this case.
150 emission.isConstantAggregate = true;
151 }
152
153 // A normal fixed sized variable becomes an alloca in the entry block,
154 // unless:
155 // - it's an NRVO variable.
156 // - we are compiling OpenMP and it's an OpenMP local variable.
157 if (nrvo) {
158 // The named return value optimization: allocate this variable in the
159 // return slot, so that we can elide the copy when returning this
160 // variable (C++0x [class.copy]p34).
161 address = returnValue;
162
163 if (const RecordDecl *rd = ty->getAsRecordDecl()) {
164 if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
165 (cxxrd && !cxxrd->hasTrivialDestructor()) ||
166 rd->isNonTrivialToPrimitiveDestroy()) {
167 // In LLVM: Create a flag that is used to indicate when the NRVO was
168 // applied to this variable. Set it to zero to indicate that NRVO was
169 // not applied. For now, use the same approach for CIRGen until we can
170 // be sure it's worth doing something more aggressive.
171 cir::ConstantOp falseNVRO = builder.getFalse(loc);
172 Address nrvoFlag = createTempAlloca(falseNVRO.getType(),
173 CharUnits::One(), loc, "nrvo",
174 /*arraySize=*/nullptr);
175 assert(builder.getInsertionBlock());
176 builder.createStore(loc, falseNVRO, nrvoFlag);
177
178 // Record the NRVO flag for this variable.
179 nrvoFlags[&d] = nrvoFlag.getPointer();
180 emission.nrvoFlag = nrvoFlag.getPointer();
181 }
182 }
183 } else {
184 // A normal fixed sized variable becomes an alloca in the entry block,
185 mlir::Type allocaTy = convertTypeForMem(ty);
186 // Create the temp alloca and declare variable using it.
187 address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
188 /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
189 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
190 alignment);
191 // A goto/switch that bypasses the init splits the lifetime across IR
192 // regions and miscompiles under stack coloring (PR28267). Lacking
193 // classic's per-decl bypass analysis, drop markers for the whole
194 // function if any such statement is present.
196 if (shouldEmitLifetimeMarkersForAutoVar() && haveInsertPoint()) {
198 loc, address.getUnderlyingAllocaOp().getResult());
199 }
200 }
201 } else {
202 // Non-constant size type
204 if (!didCallStackSave) {
205 // Save the stack.
206 cir::PointerType defaultTy = allocaInt8PtrTy;
208 cgm.getDataLayout().getAlignment(defaultTy, false));
209 Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack");
210
211 mlir::Value v = builder.createStackSave(loc, defaultTy);
212 assert(v.getType() == allocaInt8PtrTy);
213 builder.createStore(loc, v, stack);
214
215 didCallStackSave = true;
216
217 // Push a cleanup block and restore the stack there.
218 // FIXME: in general circumstances, this should be an EH cleanup.
220 }
221
222 VlaSizePair vlaSize = getVLASize(ty);
223 mlir::Type memTy = convertTypeForMem(vlaSize.type);
224
225 // Allocate memory for the array.
226 address =
227 createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts,
228 /*alloca=*/nullptr, builder.saveInsertionPoint());
229
230 // If we have debug info enabled, properly describe the VLA dimensions for
231 // this type by registering the vla size expression for each of the
232 // dimensions.
234 }
235
236 emission.addr = address;
237 setAddrOfLocalVar(&d, address);
238
239 // The lifetime marker must reference the original alloca, so peel any
240 // address-space cast back to it.
241 if (emission.useLifetimeMarkers)
242 ehStack.pushCleanup<CallLifetimeEnd>(
243 NormalEHLifetimeMarker, address.getUnderlyingAllocaOp().getResult());
244
245 return emission;
246}
247
248/// Determine whether the given initializer is trivial in the sense
249/// that it requires no code to be generated.
251 if (!init)
252 return true;
253
254 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
255 if (CXXConstructorDecl *constructor = construct->getConstructor())
256 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
257 !construct->requiresZeroInitialization())
258 return true;
259
260 return false;
261}
262
263static void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d,
264 Address addr, bool isVolatile,
265 CIRGenBuilderTy &builder,
266 mlir::TypedAttr constant) {
267 mlir::Type ty = constant.getType();
268 cir::CIRDataLayout layout{cgm.getModule()};
269 uint64_t constantSize = layout.getTypeAllocSize(ty);
270 if (!constantSize)
271 return;
274
275 if (addr.getElementType() != ty)
276 addr = addr.withElementType(builder, ty);
277
278 // If the address is an alloca, set the init attribute.
279 // The address is usually and alloca, but there is at least one case where
280 // emitAutoVarInit is called from the OpenACC codegen with an address that
281 // is not an alloca.
282 cir::AllocaOp allocaOp = addr.getUnderlyingAllocaOp();
283 if (allocaOp)
284 allocaOp.setInitAttr(mlir::UnitAttr::get(&cgm.getMLIRContext()));
285
286 // There are cases where OpenACC codegen calls emitAutoVarInit with a
287 // temporary decl that doesn't have a source range set.
288 mlir::Location loc = builder.getUnknownLoc();
289 if (d.getSourceRange().isValid())
290 loc = cgm.getLoc(d.getSourceRange());
291
292 // Emit cir.const + cir.store, preserving source-level semantics. For
293 // aggregate types (arrays, records), LoweringPrepare implements the OG
294 // optimization tiers (shouldCreateMemCpyFromGlobal, shouldUseBZeroPlusStores,
295 // shouldUseMemSetToInitialize, shouldSplitConstantStore) by transforming
296 // into cir.global + cir.get_global + cir.copy when appropriate.
297 builder.createStore(loc, builder.getConstant(loc, constant), addr);
298}
299
301 const CIRGenFunction::AutoVarEmission &emission) {
302 assert(emission.variable && "emission was not valid!");
303
304 // If this was emitted as a global constant, we're done.
305 if (emission.wasEmittedAsGlobal())
306 return;
307
308 const VarDecl &d = *emission.variable;
309
310 QualType type = d.getType();
311
312 // If this local has an initializer, emit it now.
313 const Expr *init = d.getInit();
314
315 // Initialize the variable here if it doesn't have a initializer and it is a
316 // C struct that is non-trivial to initialize or an array containing such a
317 // struct.
318 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
320 cgm.errorNYI(d.getSourceRange(),
321 "emitAutoVarInit: non-trivial to default initialize");
322 return;
323 }
324
325 const Address addr = emission.addr;
326
327 // Check whether this is a byref variable that's potentially
328 // captured and moved by its own initializer. If so, we'll need to
329 // emit the initializer first, then copy into the variable.
331
332 // Note: constexpr already initializes everything correctly.
333 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
334 (d.isConstexpr()
336 : (d.getAttr<UninitializedAttr>()
338 : getContext().getLangOpts().getTrivialAutoVarInit()));
339
340 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
341 if (trivialAutoVarInit ==
343 return;
344
345 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
346 };
347
348 if (isTrivialInitializer(init)) {
349 initializeWhatIsTechnicallyUninitialized(addr);
350 return;
351 }
352
353 mlir::Attribute constant;
354 if (emission.isConstantAggregate ||
356 // FIXME: Differently from LLVM we try not to emit / lower too much
357 // here for CIR since we are interested in seeing the ctor in some
358 // analysis later on. So CIR's implementation of ConstantEmitter will
359 // frequently return an empty Attribute, to signal we want to codegen
360 // some trivial ctor calls and whatnots.
362 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
363 (trivialAutoVarInit !=
365 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
366 return;
367 }
368 }
369
370 // NOTE(cir): In case we have a constant initializer, we can just emit a
371 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
372 // CXX temporary object creation, we ensure the ctor call is used deferring
373 // its removal/optimization to the CIR lowering.
374 if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
375 initializeWhatIsTechnicallyUninitialized(addr);
377 emitExprAsInit(init, &d, lv);
378
379 if (!emission.wasEmittedAsOffloadClause()) {
380 // In case lv has uses it means we indeed initialized something
381 // out of it while trying to build the expression, mark it as such.
382 Address addr = lv.getAddress();
383 assert(addr.isValid() && "Should have an address");
384 cir::AllocaOp allocaOp = addr.getUnderlyingAllocaOp();
385 assert(allocaOp && "Address should come straight out of the alloca");
386
387 if (!allocaOp.use_empty())
388 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
389 }
390
391 return;
392 }
393
394 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
395 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
396 assert(typedConstant && "expected typed attribute");
397 if (!emission.isConstantAggregate) {
398 // For simple scalar/complex initialization, store the value directly.
399 LValue lv = makeAddrLValue(addr, type);
400 assert(init && "expected initializer");
401 mlir::Location initLoc = getLoc(init->getSourceRange());
402 // lv.setNonGC(true);
404 RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
405 }
406
407 emitStoresForConstant(cgm, d, addr, type.isVolatileQualified(), builder,
408 typedConstant);
409}
410
412 const CIRGenFunction::AutoVarEmission &emission) {
413 const VarDecl &d = *emission.variable;
414
415 // Check the type for a cleanup.
417 emitAutoVarTypeCleanup(emission, dtorKind);
418
420
421 // Handle the cleanup attribute.
422 if (const CleanupAttr *ca = d.getAttr<CleanupAttr>()) {
423 const FunctionDecl *fd = ca->getFunctionDecl();
424
425 cir::FuncOp f = cgm.getAddrOfFunction(fd);
426 assert(f && "Could not find function!");
427
428 const CIRGenFunctionInfo &info =
429 cgm.getTypes().arrangeFunctionDeclaration(fd);
430 ehStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup, f, &info,
431 emission.getObjectAddress(*this),
432 d.getType(), ca);
433 }
434}
435
436/// Emit code and set up symbol table for a variable declaration with auto,
437/// register, or no storage class specifier. These turn into simple stack
438/// objects, globals depending on target.
444
445namespace {
446/// Finds the temporaries with a destructor that the initializer of a variable
447/// with automatic storage duration lifetime-extends. Their cleanups are pushed
448/// onto the EH stack when the initializer's full-expression ends.
449class LifetimeExtendedTemporaryFinder
450 : public RecursiveASTVisitor<LifetimeExtendedTemporaryFinder> {
451 const VarDecl &var;
454
455public:
456 explicit LifetimeExtendedTemporaryFinder(const VarDecl &var) : var(var) {}
457
458 /// The types of the temporaries that were found.
459 ArrayRef<QualType> found() const { return types; }
460
461 // Look into the semantic form of initializer lists, which holds the backing
462 // array of a std::initializer_list, and into default member initializers.
463 // The array filler of an initializer list is not visited.
464 bool shouldVisitImplicitCode() const { return true; }
465
466 /// Records the type of each temporary requiring destruction whose lifetime
467 /// is extended by \c var.
468 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *m) {
469 if (m->getExtendingDecl() != &var ||
470 m->getStorageDuration() != SD_Automatic || !visited.insert(m).second)
471 return true;
472 // Like pushTemporaryCleanup, look at the type of the whole temporary, not
473 // at the subobject that the reference binds to.
474 SmallVector<const Expr *, 2> commaLHSs;
475 SmallVector<SubobjectAdjustment, 2> adjustments;
476 const Expr *e =
477 m->getSubExpr()->skipRValueSubobjectAdjustments(commaLHSs, adjustments);
479 types.push_back(e->getType());
480 return true;
481 }
482};
483} // namespace
484
486 const CXXRecordDecl *rd =
487 type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
488 if (!rd || rd->hasTrivialDestructor())
489 return false;
490 const auto *fpt = rd->getDestructor()->getType()->castAs<FunctionProtoType>();
491 return isUnresolvedExceptionSpec(fpt->getExceptionSpecType()) ||
492 !fpt->isNothrow();
493}
494
495SmallVector<QualType, 2>
497 const Expr *init = d.getInit();
498 if (!init)
499 return {};
500 LifetimeExtendedTemporaryFinder finder(d);
501 finder.TraverseStmt(const_cast<Expr *>(init));
502 return SmallVector<QualType, 2>(finder.found());
503}
504
506 const VarDecl &d, CapturedCleanups &condCleanup,
507 ArrayRef<QualType> extendedTemporaries) {
508 // A condition variable always has automatic storage duration, so this
509 // mirrors the auto-var path of emitVarDecl/emitAutoVarDecl. Capture the
510 // lifetime-end cleanup pushed while emitting the alloca, but emit the
511 // initializer with capturing disabled so the cleanups of its temporaries get
512 // their normal cir.cleanup.scope handling. Only the cleanups of the
513 // temporaries that it lifetime-extends are captured, when its
514 // full-expression ends. The variable's destructor cleanup is captured
515 // separately after initialization.
516 assert(d.hasLocalStorage() && "loop condition variable is not local");
517
518 // Mirror the diagnostic emitted by emitVarDecl on the automatic-storage path.
519 // A condition variable is implicitly in the private address space, so this is
520 // not expected to fire, but keep it to preserve emitVarDecl's behavior.
522 cgm.errorNYI(d.getSourceRange(),
523 "emitLoopConditionVariable: OpenCL local address space");
524
525 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
526 CIRGenFunction::AutoVarEmission emission = [&] {
527 CapturedCleanups::CaptureScope capture(condCleanup);
528 return emitAutoVarAlloca(d);
529 }();
530
531 // The condition variable's destructor is captured into the loop op's
532 // per-iteration cleanup region, which structurally spans the initializer.
533 // If the initializer throws, the variable was never constructed and its
534 // destructor must not run. Classic codegen avoids this by pushing the
535 // cleanup only after the initializer, but our deferred cleanup necessarily
536 // covers the whole condition region, so guard it with an active flag that is
537 // false while the initializer runs and set to true once construction
538 // completes. The flag is stored to on every iteration, so it also resets
539 // correctly across iterations.
540 //
541 // The temporaries that the initializer lifetime-extends are destroyed with
542 // the variable as well ([class.temporary]p6). Their cleanups are pushed when
543 // the initializer's full-expression ends, so capture them too and guard them
544 // with the same flag.
545 bool needsCleanup = d.needsDestruction(getContext()) != QualType::DK_none;
546 bool extendsTemporaries = !extendedTemporaries.empty();
547
548 // Destroy the variable first, then the temporaries in reverse order of
549 // construction. A throw would skip the remaining destructors because CFG
550 // flattening does not yet support EH paths in loop cleanup regions.
551 if (getLangOpts().Exceptions && extendsTemporaries &&
552 ((needsCleanup && destructorMayThrow(d.getType())) ||
553 (extendedTemporaries.size() > 1 &&
554 llvm::any_of(extendedTemporaries, destructorMayThrow))))
555 cgm.errorNYI(d.getSourceRange(),
556 "loop condition variable cleanup with a potentially-throwing "
557 "destructor before another destructor");
558
559 Address activeFlag = Address::invalid();
560 if (needsCleanup || extendsTemporaries) {
561 mlir::Location loc = getLoc(d.getSourceRange());
562 activeFlag = createTempAllocaWithoutCast(
563 builder.getBoolTy(), CharUnits::One(), loc, "cond.cleanup.isactive",
564 /*arraySize=*/nullptr,
565 builder.getBestAllocaInsertPoint(getCurFunctionEntryBlock()));
566 builder.createFlagStore(loc, false, activeFlag.getPointer());
567 }
568
569 EHScopeStack::stable_iterator initDepth = ehStack.stable_begin();
570 {
571 LifetimeExtensionCapture capture{&d, &condCleanup, activeFlag};
573 lifetimeExtensionCapture, extendsTemporaries ? &capture : nullptr);
574 emitAutoVarInit(emission);
575 }
576
577 // Only lifetime-extended cleanups remain after initialization. If the AST
578 // walk found no extended temporaries, these cleanups are uncaptured and wrap
579 // cir.condition in cir.cleanup.scope (e.g. for initializer-list array
580 // fillers).
581 if (!extendsTemporaries && ehStack.stable_begin() != initDepth) {
582 cgm.errorNYI(d.getSourceRange(),
583 "loop condition variable whose initializer leaves uncaptured "
584 "cleanups");
585 popCleanupBlocks(initDepth);
586 }
587#ifndef NDEBUG
588 for (auto it = ehStack.begin(), ie = ehStack.find(initDepth); it != ie; ++it)
589 assert(!cast<EHCleanupScope>(*it).getCleanupScopeOp() &&
590 "loop condition variable initializer left an uncaptured cleanup");
591#endif
592
593 if (activeFlag.isValid()) {
594 // Construction has completed, so activate the destructor cleanups.
595 mlir::Location loc = getLoc(d.getSourceRange());
596 builder.createFlagStore(loc, true, activeFlag.getPointer());
597 }
598
599 {
600 CapturedCleanups::CaptureScope capture(condCleanup);
601 emitAutoVarCleanups(emission);
602 }
603
604 if (needsCleanup)
605 initFullExprCleanupWithFlag(activeFlag);
606}
607
609 // If the declaration has external storage, don't emit it now, allow it to be
610 // emitted lazily on its first use.
611 if (d.hasExternalStorage())
612 return;
613
614 if (d.getStorageDuration() != SD_Automatic) {
615 // Static sampler variables translated to function calls.
616 if (d.getType()->isSamplerT()) {
617 // Nothing needs to be done here, but let's flag it as an error until we
618 // have a test. It requires OpenCL support.
619 cgm.errorNYI(d.getSourceRange(), "emitVarDecl: static sampler type");
620 return;
621 }
622
623 cir::GlobalLinkageKind linkage = cgm.getCIRLinkageVarDefinition(&d);
624
625 // FIXME: We need to force the emission/use of a guard variable for
626 // some variables even if we can constant-evaluate them because
627 // we can't guarantee every translation unit will constant-evaluate them.
628
629 return emitStaticVarDecl(d, linkage);
630 }
631
633 cgm.errorNYI(d.getSourceRange(), "emitVarDecl: openCL address space");
634
635 assert(d.hasLocalStorage());
636
637 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
638 return emitAutoVarDecl(d);
639}
640
641static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
642 if (cgm.getLangOpts().CPlusPlus)
643 return cgm.getMangledName(&d).str();
644
645 // If this isn't C++, we don't need a mangled name, just a pretty one.
646 assert(!d.isExternallyVisible() && "name shouldn't matter");
647 std::string contextName;
648 const DeclContext *dc = d.getDeclContext();
649 if (auto *cd = dyn_cast<CapturedDecl>(dc))
650 dc = cast<DeclContext>(cd->getNonClosureContext());
651 if (const auto *fd = dyn_cast<FunctionDecl>(dc))
652 contextName = std::string(cgm.getMangledName(fd));
653 else if (isa<BlockDecl>(dc))
654 cgm.errorNYI(d.getSourceRange(),
655 "getStaticDeclName: block decl context for static var");
656 else if (isa<ObjCMethodDecl>(dc))
657 cgm.errorNYI(d.getSourceRange(),
658 "getStaticDeclName: ObjC decl context for static var");
659 else
660 cgm.errorNYI(d.getSourceRange(),
661 "getStaticDeclName: Unknown context for static var decl");
662
663 contextName += "." + d.getNameAsString();
664 return contextName;
665}
666
667// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
668// interface for all constants?
669cir::GlobalOp
671 cir::GlobalLinkageKind linkage) {
672 // In general, we don't always emit static var decls once before we reference
673 // them. It is possible to reference them before emitting the function that
674 // contains them, and it is possible to emit the containing function multiple
675 // times.
676 if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
677 return existingGV;
678
679 QualType ty = d.getType();
680 assert(ty->isConstantSizeType() && "VLAs can't be static");
681
682 // Use the label if the variable is renamed with the asm-label extension.
683 std::string name;
684 if (d.hasAttr<AsmLabelAttr>())
685 name = std::string(getMangledName(&d));
686 else
687 name = getStaticDeclName(*this, d);
688
689 mlir::Type lty = getTypes().convertTypeForMem(ty);
690
691 // OpenCL variables in local address space and CUDA shared
692 // variables cannot have an initializer.
693 mlir::Attribute init = nullptr;
695 d.hasAttr<CUDASharedAttr>() || d.hasAttr<LoaderUninitializedAttr>())
696 init = cir::UndefAttr::get(lty);
697 else
698 init = emitNullConstantAttr(ty);
699
700 mlir::ptr::MemorySpaceAttrInterface addrSpace =
701 getGlobalCIRAddressSpace(getGlobalVarAddressSpace(&d));
702
703 cir::GlobalOp gv =
704 builder.createVersionedGlobal(getModule(), getLoc(d.getLocation()), name,
705 lty, false, linkage, addrSpace);
707 // TODO(cir): infer visibility from linkage in global op builder.
708 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
709 gv.setInitialValueAttr(init);
710 gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
711
712 if (supportsCOMDAT() && gv.isWeakForLinker())
713 gv.setSelfComdat();
714
715 if (d.getTLSKind())
716 setTLSMode(gv, d);
717
718 setGVProperties(gv, &d);
719
720 // The global may live in a different address space than the declared type.
721 // Users of the address cast it through castGlobalToDeclAddrSpace.
723
724 // Ensure that the static local gets initialized by making sure the parent
725 // function gets emitted eventually.
726 const Decl *dc = cast<Decl>(d.getDeclContext());
727
728 // We can't name blocks or captured statements directly, so try to emit their
729 // parents.
730 if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
731 dc = dc->getNonClosureContext();
732 // FIXME: Ensure that global blocks get emitted.
733 if (!dc)
734 errorNYI(d.getSourceRange(), "non-closure context");
735 }
736
737 GlobalDecl gd;
738 if (const auto *cd = dyn_cast<CXXConstructorDecl>(dc))
739 gd = GlobalDecl(cd, Ctor_Base);
740 else if (const auto *dd = dyn_cast<CXXDestructorDecl>(dc))
741 gd = GlobalDecl(dd, Dtor_Base);
742 else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
743 gd = GlobalDecl(fd);
744 else {
745 // Don't do anything for Obj-C method decls or global closures. We should
746 // never defer them.
747 assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
748 }
749 if (gd.getDecl()) {
750 if (getLangOpts().OpenMPIsTargetDevice) {
751 // Disable emission of the parent function for the OpenMP device codegen.
752 // TODO(cir): Use CGOpenMPRuntime::DisableAutoDeclareTargetRAII here.
754 "OpenMP: DisableAutoDeclareTargetRAII for static local");
755 }
756 (void)getAddrOfGlobal(gd);
757 }
758
759 return gv;
760}
761
763 mlir::Attribute constAttr,
764 CharUnits align) {
765 auto functionName = [&](const DeclContext *dc) -> std::string {
766 if (const auto *fd = dyn_cast<FunctionDecl>(dc)) {
767 if (const auto *cc = dyn_cast<CXXConstructorDecl>(fd))
768 return cc->getNameAsString();
769 if (const auto *cd = dyn_cast<CXXDestructorDecl>(fd))
770 return cd->getNameAsString();
771 return std::string(getMangledName(fd));
772 } else if (const auto *om = dyn_cast<ObjCMethodDecl>(dc)) {
773 return om->getNameAsString();
774 } else if (isa<BlockDecl>(dc)) {
775 return "<block>";
776 } else if (isa<CapturedDecl>(dc)) {
777 return "<captured>";
778 } else {
779 llvm_unreachable("expected a function or method");
780 }
781 };
782
783 // Form a simple per-variable cache of these values in case we find we
784 // want to reuse them.
785 cir::GlobalOp &cacheEntry = initializerConstants[&d];
786 if (!cacheEntry || cacheEntry.getInitialValue() != constAttr) {
787 auto ty = mlir::cast<mlir::TypedAttr>(constAttr).getType();
788 bool isConstant = true;
789
790 std::string name;
791 if (d.hasGlobalStorage())
792 name = getMangledName(&d).str() + ".const";
793 else if (const DeclContext *dc = d.getParentFunctionOrMethod())
794 name = ("__const." + functionName(dc) + "." + d.getName()).str();
795 else
796 llvm_unreachable("local variable has no parent function or method");
797
799 cir::GlobalOp gv = builder.createVersionedGlobal(
800 getModule(), getLoc(d.getLocation()), name, ty, isConstant,
801 cir::GlobalLinkageKind::PrivateLinkage);
803 // TODO(cir): infer visibility from linkage in global op builder.
804 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(
805 cir::GlobalLinkageKind::PrivateLinkage));
806 gv.setInitialValueAttr(constAttr);
807 gv.setAlignment(align.getAsAlign().value());
808 // TODO(cir): Set unnamed address attribute when available in CIR
809
810 cacheEntry = gv;
811 } else if (cacheEntry.getAlignment() <
812 static_cast<uint64_t>(align.getQuantity())) {
813 cacheEntry.setAlignment(align.getAsAlign().value());
814 }
815
816 // Create a GetGlobalOp to get a pointer to the global
818 mlir::Type eltTy = mlir::cast<mlir::TypedAttr>(constAttr).getType();
819 auto ptrTy = builder.getPointerTo(cacheEntry.getSymType());
820 mlir::Value globalPtr = cir::GetGlobalOp::create(
821 builder, getLoc(d.getLocation()), ptrTy, cacheEntry.getSymName());
822 return Address(globalPtr, eltTy, align);
823}
824
825/// Add the initializer for 'd' to the global variable that has already been
826/// created for it. If the initializer has a different type than gv does, this
827/// may free gv and return a different one. Otherwise it just returns gv.
829 const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
830 ConstantEmitter emitter(*this);
831 mlir::TypedAttr init = mlir::dyn_cast_if_present<mlir::TypedAttr>(
832 emitter.tryEmitForInitializer(d));
833
834 // If constant emission failed, then this should be a C++ static
835 // initializer.
836 if (!init) {
837 if (!getLangOpts().CPlusPlus) {
838 cgm.errorNYI(d.getInit()->getSourceRange(),
839 "constant l-value expression");
840 } else if (d.hasFlexibleArrayInit(getContext())) {
841 cgm.errorNYI(d.getInit()->getSourceRange(), "flexible array initializer");
842 } else {
843 // Since we have a static initializer, this global variable can't
844 // be constant.
845 gv.setConstant(false);
846 emitCXXGuardedInit(d, gv, /*performInit*/ true);
847 gvAddr.setStaticLocal(true);
848 }
849 return gv;
850 }
851
852 // TODO(cir): There should be debug code here to assert that the decl size
853 // matches the CIR data layout type alloc size, but the code for calculating
854 // the type alloc size is not implemented yet.
856
857 // The initializer may differ in type from the global. Rewrite
858 // the global to match the initializer. (We have to do this
859 // because some types, like unions, can't be completely represented
860 // in the LLVM type system.)
861 if (gv.getSymType() != init.getType()) {
862 gv.setSymType(init.getType());
863
864 // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
865 // but since at this point the current block hasn't been really attached,
866 // there's no visibility into the GetGlobalOp corresponding to this Global.
867 // Given those constraints, thread in the GetGlobalOp and update it
868 // directly.
870 gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
871 }
872
873 bool needsDtor =
875
876 gv.setConstant(d.getType().isConstantStorage(
877 getContext(), /*ExcludeCtor=*/true, !needsDtor));
878 gv.setInitialValueAttr(init);
879
880 emitter.finalize(gv);
881
882 if (needsDtor) {
883 // We have a constant initializer, but a nontrivial destructor. We still
884 // need to perform a guarded "initialization" in order to register the
885 // destructor.
886 emitCXXGuardedInit(d, gv, /*performInit=*/false);
887 gvAddr.setStaticLocal(true);
888 }
889
890 return gv;
891}
892
894 cir::GlobalLinkageKind linkage) {
895 // Check to see if we already have a global variable for this
896 // declaration. This can happen when double-emitting function
897 // bodies, e.g. with complete and base constructors.
898 cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
899 // TODO(cir): we should have a way to represent global ops as values without
900 // having to emit a get global op. Sometimes these emissions are not used.
901 mlir::Value addr =
902 builder.createGetGlobal(globalOp, d.getTLSKind() != VarDecl::TLS_None);
903 auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>();
904 assert(getAddrOp && "expected cir::GetGlobalOp");
905
906 CharUnits alignment = getContext().getDeclAlign(&d);
907
908 // Store into LocalDeclMap before generating initializer to handle
909 // circular references.
910 mlir::Type elemTy = convertTypeForMem(d.getType());
911 setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
912
913 // We can't have a VLA here, but we can have a pointer to a VLA,
914 // even though that doesn't really make any sense.
915 // Make sure to evaluate VLA bounds now so that we have them for later.
918
919 // Save the type in case adding the initializer forces a type change.
920 mlir::Type expectedType = addr.getType();
921
922 cir::GlobalOp var = globalOp;
923
924 // Sema ensures any initializer of a CUDA __shared__ variable is a no-op.
925 bool isCudaSharedVar = getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
926 d.hasAttr<CUDASharedAttr>();
927 // If this value has an initializer, emit it.
928 if (d.getInit() && !isCudaSharedVar)
929 var = addInitializerToStaticVarDecl(d, var, getAddrOp);
930
931 var.setAlignment(alignment.getAsAlign().value());
932
933 // There are a lot of attributes that need to be handled here. Until
934 // we start to support them, we just report an error if there are any.
935 if (d.hasAttr<AnnotateAttr>())
936 cgm.addGlobalAnnotations(&d, var);
937 if (d.getAttr<PragmaClangBSSSectionAttr>())
938 cgm.errorNYI(d.getSourceRange(),
939 "emitStaticVarDecl: CIR global BSS section attribute");
940 if (d.getAttr<PragmaClangDataSectionAttr>())
941 cgm.errorNYI(d.getSourceRange(),
942 "emitStaticVarDecl: CIR global Data section attribute");
943 if (d.getAttr<PragmaClangRodataSectionAttr>())
944 cgm.errorNYI(d.getSourceRange(),
945 "emitStaticVarDecl: CIR global Rodata section attribute");
946 if (d.getAttr<PragmaClangRelroSectionAttr>())
947 cgm.errorNYI(d.getSourceRange(),
948 "emitStaticVarDecl: CIR global Relro section attribute");
949
950 if (const SectionAttr *sa = d.getAttr<SectionAttr>())
951 var.setSectionAttr(builder.getStringAttr(sa->getName()));
952
953 if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
954 cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
955
956 // From traditional codegen:
957 // We may have to cast the constant because of the initializer
958 // mismatch above.
959 //
960 // FIXME: It is really dangerous to store this in the map; if anyone
961 // RAUW's the GV uses of this constant will be invalid.
962 mlir::Value castedAddr =
963 builder.createBitcast(getAddrOp.getAddr(), expectedType);
964 castedAddr = cgm.castGlobalToDeclAddrSpace(castedAddr, d);
965 localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
966 cgm.setStaticLocalDeclAddress(&d, var);
967
970}
971
973 bool capturedByInit) {
975
976 SourceLocRAIIObject locRAII{*this, init->getSourceRange()};
977 mlir::Value value = emitScalarExpr(init);
978 if (capturedByInit) {
979 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
980 return;
981 }
983 emitStoreThroughLValue(RValue::get(value), lvalue, true);
984}
985
987 LValue lvalue, bool capturedByInit) {
988 SourceLocRAIIObject loc{*this, init->getSourceRange()};
989 if (capturedByInit) {
990 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
991 return;
992 }
993
994 QualType type = d->getType();
995
996 if (type->isReferenceType()) {
997 RValue rvalue = emitReferenceBindingToExpr(init);
998 if (capturedByInit)
999 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
1000 emitStoreThroughLValue(rvalue, lvalue);
1001 return;
1002 }
1004 case cir::TEK_Scalar:
1005 emitScalarInit(init, lvalue);
1006 return;
1007 case cir::TEK_Complex: {
1008 mlir::Value complex = emitComplexExpr(init);
1009 if (capturedByInit)
1010 cgm.errorNYI(init->getSourceRange(),
1011 "emitExprAsInit: complex type captured by init");
1012 mlir::Location loc = getLoc(init->getExprLoc());
1013 emitStoreOfComplex(loc, complex, lvalue,
1014 /*isInit*/ true);
1015 return;
1016 }
1017 case cir::TEK_Aggregate:
1018 // The overlap flag here should be calculated.
1020 emitAggExpr(init,
1024 return;
1025 }
1026 llvm_unreachable("bad evaluation kind");
1027}
1028
1029void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
1030 switch (d.getKind()) {
1031 case Decl::BuiltinTemplate:
1032 case Decl::TranslationUnit:
1033 case Decl::ExternCContext:
1034 case Decl::Namespace:
1035 case Decl::UnresolvedUsingTypename:
1036 case Decl::ClassTemplateSpecialization:
1037 case Decl::ClassTemplatePartialSpecialization:
1038 case Decl::VarTemplateSpecialization:
1039 case Decl::VarTemplatePartialSpecialization:
1040 case Decl::TemplateTypeParm:
1041 case Decl::UnresolvedUsingValue:
1042 case Decl::NonTypeTemplateParm:
1043 case Decl::CXXDeductionGuide:
1044 case Decl::CXXMethod:
1045 case Decl::CXXConstructor:
1046 case Decl::CXXDestructor:
1047 case Decl::CXXConversion:
1048 case Decl::Field:
1049 case Decl::MSProperty:
1050 case Decl::IndirectField:
1051 case Decl::ObjCIvar:
1052 case Decl::ObjCAtDefsField:
1053 case Decl::ParmVar:
1054 case Decl::ImplicitParam:
1055 case Decl::ClassTemplate:
1056 case Decl::VarTemplate:
1057 case Decl::FunctionTemplate:
1058 case Decl::TypeAliasTemplate:
1059 case Decl::TemplateTemplateParm:
1060 case Decl::ObjCMethod:
1061 case Decl::ObjCCategory:
1062 case Decl::ObjCProtocol:
1063 case Decl::ObjCInterface:
1064 case Decl::ObjCCategoryImpl:
1065 case Decl::ObjCImplementation:
1066 case Decl::ObjCProperty:
1067 case Decl::ObjCCompatibleAlias:
1068 case Decl::PragmaComment:
1069 case Decl::PragmaDetectMismatch:
1070 case Decl::AccessSpec:
1071 case Decl::LinkageSpec:
1072 case Decl::Export:
1073 case Decl::ObjCPropertyImpl:
1074 case Decl::FileScopeAsm:
1075 case Decl::Friend:
1076 case Decl::FriendTemplate:
1077 case Decl::Block:
1078 case Decl::OutlinedFunction:
1079 case Decl::Captured:
1080 case Decl::UsingShadow:
1081 case Decl::ConstructorUsingShadow:
1082 case Decl::ObjCTypeParam:
1083 case Decl::Binding:
1084 case Decl::UnresolvedUsingIfExists:
1085 case Decl::HLSLBuffer:
1086 case Decl::HLSLRootSignature:
1087 llvm_unreachable("Declaration should not be in declstmts!");
1088
1089 case Decl::Function: // void X();
1090 case Decl::EnumConstant: // enum ? { X = ? }
1091 case Decl::ExplicitInstantiation:
1092 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
1093 case Decl::Label: // __label__ x;
1094 case Decl::Import:
1095 case Decl::MSGuid: // __declspec(uuid("..."))
1096 case Decl::TemplateParamObject:
1097 case Decl::Empty:
1098 case Decl::Concept:
1099 case Decl::LifetimeExtendedTemporary:
1100 case Decl::RequiresExprBody:
1101 case Decl::UnnamedGlobalConstant:
1102 // None of these decls require codegen support.
1103 return;
1104
1105 case Decl::Enum: // enum X;
1106 case Decl::Record: // struct/union/class X;
1107 case Decl::CXXRecord: // struct/union/class X; [C++]
1108 case Decl::NamespaceAlias:
1109 case Decl::Using: // using X; [C++]
1110 case Decl::UsingEnum: // using enum X; [C++]
1111 case Decl::UsingDirective: // using namespace X; [C++]
1113 return;
1114 case Decl::Var:
1115 case Decl::Decomposition: {
1116 const VarDecl &vd = cast<VarDecl>(d);
1117 assert(vd.isLocalVarDecl() &&
1118 "Should not see file-scope variables inside a function!");
1119 emitVarDecl(vd);
1120 if (evaluateConditionDecl)
1122 return;
1123 }
1124 case Decl::OpenACCDeclare:
1126 return;
1127 case Decl::OpenACCRoutine:
1129 return;
1130 case Decl::OMPThreadPrivate:
1132 return;
1133 case Decl::OMPGroupPrivate:
1135 return;
1136 case Decl::OMPAllocate:
1138 return;
1139 case Decl::OMPCapturedExpr:
1141 return;
1142 case Decl::OMPRequires:
1144 return;
1145 case Decl::OMPDeclareMapper:
1147 return;
1148 case Decl::OMPDeclareReduction:
1150 return;
1151 case Decl::Typedef: // typedef int X;
1152 case Decl::TypeAlias: { // using X = int; [C++0x]
1153 QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
1155 if (ty->isVariablyModifiedType())
1157 return;
1158 }
1159 case Decl::ImplicitConceptSpecialization:
1160 case Decl::TopLevelStmt:
1161 case Decl::UsingPack:
1162 case Decl::CXXExpansionStmt:
1163 cgm.errorNYI(d.getSourceRange(),
1164 std::string("emitDecl: unhandled decl type: ") +
1165 d.getDeclKindName());
1166 }
1167}
1168
1170 SourceLocation loc) {
1171 if (!sanOpts.has(SanitizerKind::NullabilityAssign))
1172 return;
1173
1175}
1176
1177namespace {
1178struct DestroyObject final : EHScopeStack::Cleanup {
1179 DestroyObject(Address addr, QualType type,
1180 CIRGenFunction::Destroyer *destroyer)
1181 : addr(addr), type(type), destroyer(destroyer) {
1183 }
1184
1185 Address addr;
1186 QualType type;
1187 CIRGenFunction::Destroyer *destroyer;
1188
1189 void emit(CIRGenFunction &cgf, Flags flags) override {
1191 cgf.emitDestroy(addr, type, destroyer);
1192 }
1193};
1194
1195template <class Derived> struct DestroyNRVOVariable : EHScopeStack::Cleanup {
1196 DestroyNRVOVariable(Address addr, QualType type, mlir::Value nrvoFlag)
1197 : nrvoFlag(nrvoFlag), addr(addr), ty(type) {}
1198
1199 mlir::Value nrvoFlag;
1200 Address addr;
1201 QualType ty;
1202
1203 void emit(CIRGenFunction &cgf, Flags flags) override {
1204 // Along the exceptions path we always execute the dtor.
1205 bool nrvo = flags.isForNormalCleanup() && nrvoFlag;
1206
1207 CIRGenBuilderTy &builder = cgf.getBuilder();
1208 mlir::OpBuilder::InsertionGuard guard(builder);
1209 if (nrvo) {
1210 // If we exited via NRVO, we skip the destructor call.
1211 mlir::Location loc = addr.getPointer().getLoc();
1212 mlir::Value didNRVO = builder.createFlagLoad(loc, nrvoFlag);
1213 mlir::Value notNRVO = builder.createNot(didNRVO);
1214 cir::IfOp::create(builder, loc, notNRVO, /*withElseRegion=*/false,
1215 [&](mlir::OpBuilder &b, mlir::Location) {
1216 static_cast<Derived *>(this)->emitDestructorCall(cgf);
1217 builder.createYield(loc);
1218 });
1219 } else {
1220 static_cast<Derived *>(this)->emitDestructorCall(cgf);
1221 }
1222 }
1223
1224 virtual ~DestroyNRVOVariable() = default;
1225};
1226
1227struct DestroyNRVOVariableCXX final
1228 : DestroyNRVOVariable<DestroyNRVOVariableCXX> {
1229 DestroyNRVOVariableCXX(Address addr, QualType type,
1230 const CXXDestructorDecl *dtor, mlir::Value nrvoFlag)
1231 : DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, type, nrvoFlag),
1232 dtor(dtor) {}
1233
1234 const CXXDestructorDecl *dtor;
1235
1236 void emitDestructorCall(CIRGenFunction &cgf) {
1238 /*forVirtualBase=*/false,
1239 /*delegating=*/false, addr, ty);
1240 }
1241};
1242
1243struct CallStackRestore final : EHScopeStack::Cleanup {
1244 Address stack;
1245 CallStackRestore(Address stack) : stack(stack) {}
1246 bool isRedundantBeforeReturn() override { return true; }
1247 void emit(CIRGenFunction &cgf, Flags flags) override {
1248 mlir::Location loc = stack.getPointer().getLoc();
1249 mlir::Value v = cgf.getBuilder().createLoad(loc, stack);
1250 cgf.getBuilder().createStackRestore(loc, v);
1251 }
1252};
1253
1254/// A cleanup which performs a partial array destroy where the end pointer is
1255/// irregularly determined and must be loaded from a local.
1256struct IrregularPartialArrayDestroy final : EHScopeStack::Cleanup {
1257 mlir::Value arrayBegin;
1258 Address arrayEndPointer;
1259 QualType elementType;
1260 CharUnits elementAlign;
1261 CIRGenFunction::Destroyer *destroyer;
1262
1263 IrregularPartialArrayDestroy(mlir::Value arrayBegin, Address arrayEndPointer,
1264 QualType elementType, CharUnits elementAlign,
1265 CIRGenFunction::Destroyer *destroyer)
1266 : arrayBegin(arrayBegin), arrayEndPointer(arrayEndPointer),
1267 elementType(elementType), elementAlign(elementAlign),
1268 destroyer(destroyer) {}
1269
1270 void emit(CIRGenFunction &cgf, Flags flags) override {
1271 CIRGenBuilderTy &builder = cgf.getBuilder();
1272 mlir::Location loc = arrayBegin.getLoc();
1273
1274 mlir::Value arrayEnd = builder.createLoad(loc, arrayEndPointer);
1275
1276 // baseElementType gets us the final 'element' type, which should be the
1277 // RecordType, looking through any multi-dimension arrays.
1278 QualType baseElementType = cgf.getContext().getBaseElementType(elementType);
1279
1280 mlir::Type cirElementType = cgf.convertTypeForMem(baseElementType);
1281 cir::PointerType ptrToElmType = builder.getPointerTo(
1282 cirElementType,
1283 mlir::cast<cir::PointerType>(arrayBegin.getType()).getAddrSpace());
1284
1285 mlir::Value begin = arrayBegin;
1286 if (baseElementType != elementType) {
1287 begin = builder.createPtrBitcast(begin, cirElementType);
1288 arrayEnd = builder.createPtrBitcast(arrayEnd, cirElementType);
1289 }
1290
1291 // The cleanup is destroying elements in reverse from arrayEnd back to
1292 // begin, but only if arrayEnd != begin (i.e. something was
1293 // constructed).
1294 mlir::Value ne =
1295 cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, arrayEnd, begin);
1296 cir::IfOp::create(
1297 builder, loc, ne, /*withElseRegion=*/false,
1298 [&](mlir::OpBuilder &b, mlir::Location loc) {
1299 Address iterAddr = cgf.createTempAlloca(
1300 ptrToElmType, cgf.getPointerAlign(), loc, "__array_idx");
1301 builder.createStore(loc, arrayEnd, iterAddr);
1302 builder.createDoWhile(
1303 loc,
1304 /*condBuilder=*/
1305 [&](mlir::OpBuilder &b, mlir::Location loc) {
1306 mlir::Value cur = builder.createLoad(loc, iterAddr);
1307 mlir::Value cmp = cir::CmpOp::create(
1308 builder, loc, cir::CmpOpKind::ne, cur, begin);
1309 builder.createCondition(cmp);
1310 },
1311 /*bodyBuilder=*/
1312 [&](mlir::OpBuilder &b, mlir::Location loc) {
1313 mlir::Value cur = builder.createLoad(loc, iterAddr);
1314 cir::ConstantOp negOne = builder.getConstInt(
1315 loc, mlir::cast<cir::IntType>(cgf.ptrDiffTy), -1);
1316 mlir::Value prev = cir::PtrStrideOp::create(
1317 builder, loc, ptrToElmType, cur, negOne);
1318 builder.createStore(loc, prev, iterAddr);
1319 Address elemAddr = Address(prev, cirElementType, elementAlign);
1320 destroyer(cgf, elemAddr, baseElementType);
1321 builder.createYield(loc);
1322 });
1323 builder.createYield(loc);
1324 });
1325 }
1326};
1327} // namespace
1328
1329/// Push an EH cleanup to destroy already-constructed elements of the given
1330/// array. The cleanup is deactivated when the enclosing
1331/// CleanupDeactivationScope exits.
1332///
1333/// \param elementType - the immediate element type of the array;
1334/// possibly still an array type
1336 Address arrayEndPointer,
1337 QualType elementType,
1338 CharUnits elementAlign,
1339 Destroyer *destroyer) {
1341 EHCleanup, arrayBegin, arrayEndPointer, elementType, elementAlign,
1342 destroyer);
1343}
1344
1345/// pushEHDestroyIfNeeded - Push the standard destructor for the given type as
1346/// an EH-only cleanup. If EH cleanup is not needed, just return.
1348 Address addr, QualType type) {
1349 if (!needsEHCleanup(dtorKind))
1350 return;
1351
1353 pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind));
1354}
1355
1356/// Push the standard destructor for the given type as
1357/// at least a normal cleanup.
1359 Address addr, QualType type) {
1360 assert(dtorKind && "cannot push destructor for trivial type");
1361
1362 CleanupKind cleanupKind = getCleanupKind(dtorKind);
1363 pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind));
1364}
1365
1367 QualType type, Destroyer *destroyer) {
1368 pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
1369}
1370
1373 assert(dtorKind && "cannot push destructor for trivial type");
1374
1375 CleanupKind cleanupKind = getCleanupKind(dtorKind);
1377 cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup);
1378}
1379
1381 CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
1382 bool useEHCleanupForArray) {
1385 destroyer);
1386}
1387
1389 CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
1390 bool useEHCleanupForArray, const ValueDecl *extendingDecl) {
1392 cgm.errorNYI("conditional lifetime-extended destroy");
1393 return;
1394 }
1395
1396 // Add the cleanup to the EHStack. After the full-expr, this would be
1397 // deactivated before being popped from the stack.
1398 pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer,
1399 useEHCleanupForArray);
1400
1402
1403 pushCleanupAfterFullExpr(cleanupKind, addr, type, destroyer);
1404
1405 // A temporary that a loop condition variable extends is destroyed with the
1406 // variable at the end of each iteration, in the loop's cleanup region.
1408 extendingDecl == lifetimeExtensionCapture->extendingDecl) {
1410 entry.activeFlag = lifetimeExtensionCapture->activeFlag;
1411 entry.capturedBy = lifetimeExtensionCapture->cleanups;
1412 }
1413}
1414
1416 const PendingCleanupEntry &entry) {
1417 std::optional<CapturedCleanups::CaptureScope> capture;
1418 if (entry.capturedBy)
1419 capture.emplace(*entry.capturedBy);
1420 ehStack.pushCleanup<DestroyObject>(entry.kind, entry.addr, entry.type,
1421 entry.destroyer);
1422
1423 if (entry.activeFlag.isValid()) {
1424 EHCleanupScope &scope = cast<EHCleanupScope>(*ehStack.begin());
1425 scope.setActiveFlag(entry.activeFlag);
1427 scope.setTestFlagInEHCleanup(scope.isEHCleanup());
1428 }
1429}
1430
1431/// Destroys all the elements of the given array, beginning from last to first.
1432///
1433/// \param begin - a type* denoting the first element of the array
1434/// \param numElements - the number of elements in the array
1435/// \param elementType - the element type of the array
1436/// \param destroyer - the function to call to destroy elements
1438 mlir::Value numElements,
1439 QualType elementType,
1440 CharUnits elementAlign,
1441 Destroyer *destroyer) {
1442 assert(!elementType->isArrayType());
1443
1444 // Differently from LLVM traditional codegen, use a higher level
1445 // representation instead of lowering directly to a loop.
1446 mlir::Type cirElementType = convertTypeForMem(elementType);
1447 cir::PointerType ptrToElmType = builder.getPointerTo(
1448 cirElementType,
1449 mlir::cast<cir::PointerType>(begin.getType()).getAddrSpace());
1450
1451 auto regionBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
1452 mlir::BlockArgument arg =
1453 b.getInsertionBlock()->addArgument(ptrToElmType, loc);
1454 Address curAddr = Address(arg, cirElementType, elementAlign);
1456
1457 // Perform the actual destruction there.
1458 destroyer(*this, curAddr, elementType);
1459
1460 cir::YieldOp::create(b, loc);
1461 };
1462
1463 // For a constant array size, use the static form of ArrayDtor.
1464 if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
1465 uint64_t size = 0;
1466 if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>())
1467 size = constIntAttr.getUInt();
1468 auto arrayTy = cir::ArrayType::get(cirElementType, size);
1469 mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
1470 cir::ArrayDtor::create(builder, getLoc(*currSrcLoc), arrayOp,
1471 regionBuilder);
1472 return;
1473 }
1474
1475 // For a dynamic array size (VLA), use the dynamic form of ArrayDtor.
1476 mlir::Value elemBegin = builder.createPtrBitcast(begin, cirElementType);
1477 cir::ArrayDtor::create(builder, getLoc(*currSrcLoc), elemBegin, numElements,
1478 regionBuilder);
1479}
1480
1481/// Immediately perform the destruction of the given object.
1482///
1483/// \param addr - the address of the object; a type*
1484/// \param type - the type of the object; if an array type, all
1485/// objects are destroyed in reverse order
1486/// \param destroyer - the function to call to destroy individual
1487/// elements
1489 Destroyer *destroyer) {
1491 if (!arrayType)
1492 return destroyer(*this, addr, type);
1493
1494 mlir::Value length = emitArrayLength(arrayType, type, addr);
1495
1496 CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
1497 getContext().getTypeSizeInChars(type));
1498
1499 // If the array length is constant, we can check for zero at compile time.
1500 auto constantCount = length.getDefiningOp<cir::ConstantOp>();
1501 if (constantCount) {
1502 auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue());
1503 if (constIntAttr && constIntAttr.getUInt() == 0)
1504 return;
1505 }
1506
1507 mlir::Value begin = addr.getPointer();
1509 emitArrayDestroy(begin, length, type, elementAlign, destroyer);
1510
1511 // If the array destroy didn't use the length op, we can erase it.
1512 if (constantCount && constantCount.use_empty())
1513 constantCount.erase();
1514}
1515
1518 switch (kind) {
1519 case QualType::DK_none:
1520 llvm_unreachable("no destroyer for trivial dtor");
1522 return destroyCXXObject;
1526 cgm.errorNYI("getDestroyer: other destruction kind");
1527 return nullptr;
1528 }
1529 llvm_unreachable("Unknown DestructionKind");
1530}
1531
1533 ehStack.pushCleanup<CallStackRestore>(kind, spMem);
1534}
1535
1536/// Enter a destroy cleanup for the given local variable.
1538 const CIRGenFunction::AutoVarEmission &emission,
1539 QualType::DestructionKind dtorKind) {
1540 assert(dtorKind != QualType::DK_none);
1541
1542 // Note that for __block variables, we want to destroy the
1543 // original stack object, not the possibly forwarded object.
1544 Address addr = emission.getObjectAddress(*this);
1545
1546 const VarDecl *var = emission.variable;
1547 QualType type = var->getType();
1548
1549 CleanupKind cleanupKind = NormalAndEHCleanup;
1550 CIRGenFunction::Destroyer *destroyer = nullptr;
1551
1552 switch (dtorKind) {
1553 case QualType::DK_none:
1554 llvm_unreachable("no cleanup for trivially-destructible variable");
1555
1557 // If there's an NRVO flag on the emission, we need a different
1558 // cleanup.
1559 if (emission.nrvoFlag) {
1560 assert(!type->isArrayType());
1561 CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
1562 ehStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, type, dtor,
1563 emission.nrvoFlag);
1564 return;
1565 }
1566 // Otherwise, this is handled below.
1567 break;
1568
1572 cgm.errorNYI(var->getSourceRange(),
1573 "emitAutoVarTypeCleanup: other dtor kind");
1574 return;
1575 }
1576
1577 // If we haven't chosen a more specific destroyer, use the default.
1578 if (!destroyer)
1579 destroyer = getDestroyer(dtorKind);
1580
1582 ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
1583}
1584
1586 if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
1587 for (auto *b : dd->flat_bindings())
1588 if (auto *hd = b->getHoldingVar())
1589 emitVarDecl(*hd);
1590 }
1591}
1592
1593bool CIRGenFunction::emitLifetimeStartOp(mlir::Location loc, mlir::Value addr) {
1594 if (!shouldEmitLifetimeMarkers)
1595 return false;
1596
1597 assert(mlir::cast<cir::PointerType>(addr.getType()).getAddrSpace() ==
1599 "Pointer should be in alloca address space");
1600
1601 cir::LifetimeStartOp::create(builder, loc, addr);
1602 return true;
1603}
1604
1605void CIRGenFunction::emitLifetimeEndOp(mlir::Location loc, mlir::Value addr) {
1606 if (!shouldEmitLifetimeMarkers)
1607 return;
1608
1609 assert(mlir::cast<cir::PointerType>(addr.getType()).getAddrSpace() ==
1611 "Pointer should be in alloca address space");
1612
1613 cir::LifetimeEndOp::create(builder, loc, addr);
1614}
static bool emit(llvm::SmallVectorImpl< std::byte > &Code, const T &Val)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static bool isRedundantBeforeReturn(mlir::Region &cleanupRegion)
static bool destructorMayThrow(QualType type)
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.
static constexpr bool needsDtor()
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
static CharSourceRange getRange(const CharSourceRange &EditRange, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeMacroExpansion)
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 createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
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...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
const LangOptions & getLangOpts() const
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
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:3820
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:152
mlir::Operation * getDefiningOp() const
Get the operation which defines this address.
Definition Address.h:141
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false, bool isNontemporal=false)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v)
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
An RAII class that suppresses cir.cleanup.scope creation for cleanups pushed onto the EH stack while ...
Captures cleanups for variables whose lifetime ends in a region owned by an enclosing op rather than ...
void emitOpenACCRoutine(const OpenACCRoutineDecl &d)
mlir::Type convertType(clang::QualType t)
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.
llvm::SmallVector< PendingCleanupEntry > lifetimeExtendedCleanupStack
ConditionalEvaluation * hiddenOutermostConditional
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,...
mlir::Block * getCurFunctionEntryBlock()
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 emitLifetimeEndOp(mlir::Location loc, mlir::Value addr)
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.
void emitLoopConditionVariable(const clang::VarDecl &d, CapturedCleanups &condCleanup, llvm::ArrayRef< QualType > extendedTemporaries)
Emit a loop's condition-variable declaration.
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...
mlir::Value performAddrSpaceCast(mlir::Value v, mlir::Type destTy) const
RValue emitReferenceBindingToExpr(const Expr *e)
Emits a reference binding to the passed in expression.
void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind, Address addr, QualType type)
void emitScalarInit(const clang::Expr *init, LValue lvalue, bool capturedByInit=false)
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 initFullExprCleanupWithFlag(Address activeFlag)
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
bool haveInsertPoint() const
True if an insertion point is defined.
void emitAutoVarInit(const AutoVarEmission &emission)
Emit the initializer for an allocated variable.
void maybeEmitDeferredVarDeclInit(const VarDecl *vd)
const LifetimeExtensionCapture * lifetimeExtensionCapture
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...
void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray, const clang::ValueDecl *extendingDecl)
void popCleanupBlocks(EHScopeStack::stable_iterator oldCleanupStackDepth, ArrayRef< mlir::Value * > valuesToReload={})
Takes the old cleanup stack size and emits the cleanup blocks that have been added.
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)
std::optional< SourceRange > currSrcLoc
Use to track source locations across nested visitor traversals.
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)
bool emitLifetimeStartOp(mlir::Location loc, mlir::Value addr)
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, bool isMustTail, SourceRange clangLoc)
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.
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 ...
static llvm::SmallVector< QualType, 2 > getLifetimeExtendedTemporariesWithDestructor(const clang::VarDecl &d)
The types of the temporaries with a destructor that the initializer of the variable d,...
Address createTempAllocaWithoutCast(mlir::Type ty, CharUnits align, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, mlir::OpBuilder::InsertPoint ip={})
This creates a alloca and inserts it into the entry block of the current region.
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)
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)
mlir::TypedAttr emitNullConstantAttr(QualType t)
void setTLSMode(mlir::Operation *op, const VarDecl &d, bool isExtendingDecl=false)
Set TLS mode for the given operation based on the given variable declaration.
const clang::LangOptions & getLangOpts() const
void setStaticLocalDeclAddress(const VarDecl *d, cir::GlobalOp c)
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()
mlir::Operation * getAddrOfGlobal(clang::GlobalDecl gd, ForDefinition_t isForDefinition=NotForDefinition)
cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d)
mlir::ptr::MemorySpaceAttrInterface getGlobalCIRAddressSpace(LangAS as)
Return the CIR address space attribute for a global in as, honoring the target address space map wher...
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.
void add(RValue rvalue, clang::QualType type)
Definition CIRGenCall.h:241
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.
A saved depth on the scope stack.
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:1553
Represents a C++ constructor within a class.
Definition DeclCXX.h:2642
Represents a C++ destructor within a class.
Definition DeclCXX.h:2907
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
Definition DeclCXX.h:1382
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
Definition DeclCXX.cpp:2129
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
llvm::Align getAsAlign() const
Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit bytes.
Definition CharUnits.h:159
static CharUnits One()
Construct a CharUnits quantity of one.
Definition CharUnits.h:55
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:184
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1467
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:344
T * getAttr() const
Definition DeclBase.h:582
Decl * getNonClosureContext()
Find the innermost non-closure ancestor of this declaration, walking up through blocks,...
SourceLocation getLocation() const
Definition DeclBase.h:448
const char * getDeclKindName() const
Definition DeclBase.cpp:169
DeclContext * getDeclContext()
Definition DeclBase.h:457
bool hasAttr() const
Definition DeclBase.h:586
Kind getKind() const
Definition DeclBase.h:451
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:436
This represents one expression.
Definition Expr.h:114
const Expr * skipRValueSubobjectAdjustments(SmallVectorImpl< const Expr * > &CommaLHS, SmallVectorImpl< SubobjectAdjustment > &Adjustments) const
Walk outwards from an expression we want to bind a reference to and find the expression whose lifetim...
Definition Expr.cpp:85
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:3386
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
QualType getType() const
Definition Expr.h:146
Represents a function declaration or definition.
Definition Decl.h:2071
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5548
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
const Decl * getDecl() const
Definition GlobalDecl.h:115
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Definition ExprCXX.h:4999
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition ExprCXX.h:4991
ValueDecl * getExtendingDecl()
Get the declaration which triggered the lifetime-extension of this temporary, if any.
Definition ExprCXX.h:5024
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:303
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:319
bool isExternallyVisible() const
Definition Decl.h:435
A (possibly-)qualified type.
Definition TypeBase.h:938
@ PDIK_Struct
The type is a struct containing a field whose type is not PCK_Trivial.
Definition TypeBase.h:1494
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8704
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Definition TypeBase.h:1561
bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, bool ExcludeDtor)
Definition TypeBase.h:1037
bool isPODType(const ASTContext &Context) const
Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
Definition Type.cpp:2914
Represents a struct/union/class.
Definition Decl.h:4476
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
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:2645
bool isArrayType() const
Definition TypeBase.h:8914
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9498
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2881
bool isVectorType() const
Definition TypeBase.h:8954
bool isSamplerT() const
Definition TypeBase.h:9059
bool isRecordType() const
Definition TypeBase.h:8942
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
QualType getType() const
Definition Decl.h:725
Represents a variable declaration or definition.
Definition Decl.h:934
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1606
TLSKind getTLSKind() const
Definition Decl.cpp:2149
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2171
bool hasFlexibleArrayInit(const ASTContext &Ctx) const
Whether this variable has a flexible array member initialized with one or more elements.
Definition Decl.cpp:2854
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1249
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:2479
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1549
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2843
const Expr * getInit() const
Definition Decl.h:1393
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
Definition Decl.h:1240
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1192
@ TLS_None
Not a TLS variable.
Definition Decl.h:954
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition Decl.h:1276
StorageDuration getStorageDuration() const
Get the storage duration of this variable, per C++ [basic.stc].
Definition Decl.h:1252
bool isEscapingByref() const
Indicates the capture is a __block variable that is captured by a block that can potentially escape (...
Definition Decl.cpp:2703
mlir::ptr::MemorySpaceAttrInterface normalizeDefaultAddressSpace(mlir::ptr::MemorySpaceAttrInterface addrSpace)
Normalize LangAddressSpace::Default to null (empty attribute).
@ 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< Attr > attr
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
void info(bool Verbose, unsigned Level, const char *Fmt, Ts &&...Args)
Prints an indented note to stderr when Verbose is set.
Definition Utils.h:57
Top level wrappers for InstallAPI frontend operations.
@ Ctor_Base
Base object ctor.
Definition ABI.h:26
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ CPlusPlus
bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType)
@ SD_Automatic
Automatic storage duration (most local variables).
Definition Specifiers.h:343
@ 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
__DEVICE__ _Tp arg(const std::complex< _Tp > &__c)
float __ovld __cnfn length(float)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
CallLifetimeEnd(mlir::Value addr)
bool isRedundantBeforeReturn() override
void emit(CIRGenFunction &cgf, Flags flags) override
Emit the cleanup.
mlir::Value addr
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 lifetimeMarkersBypass()
static bool opAllocaPreciseLifetime()
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 useLifetimeMarkers
True if lifetime op should be used.
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.
Set by emitLoopConditionVariable while it emits the initializer of a loop condition variable that lif...
A cleanup whose destructor call is not emitted where the cleanup is registered.
CapturedCleanups * capturedBy
If set, the cleanup is captured by this owner instead of opening a cir.cleanup.scope when it is pushe...
clang::CharUnits getPointerAlign() const
cir::PointerType allocaInt8PtrTy
void* in alloca address space
mlir::ptr::MemorySpaceAttrInterface getCIRAllocaAddressSpace() const