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