clang 23.0.0git
CIRGenDecl.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code to emit Decl nodes as CIR code.
10//
11//===----------------------------------------------------------------------===//
12
14#include "CIRGenFunction.h"
15#include "mlir/IR/Location.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/Attrs.inc"
18#include "clang/AST/Decl.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/ExprCXX.h"
22#include "clang/Basic/Cuda.h"
25
26using namespace clang;
27using namespace clang::CIRGen;
28
31 mlir::OpBuilder::InsertPoint ip) {
32 QualType ty = d.getType();
34 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space");
35
36 mlir::Location loc = getLoc(d.getSourceRange());
37 bool nrvo =
38 getContext().getLangOpts().ElideConstructors && d.isNRVOVariable();
39
41 emission.isEscapingByRef = d.isEscapingByref();
42 if (emission.isEscapingByRef)
43 cgm.errorNYI(d.getSourceRange(),
44 "emitAutoVarAlloca: decl escaping by reference");
45
46 CharUnits alignment = getContext().getDeclAlign(&d);
47
48 // If the type is variably-modified, emit all the VLA sizes for it.
49 if (ty->isVariablyModifiedType())
51
53
54 Address address = Address::invalid();
55 if (ty->isConstantSizeType()) {
56 // If this value is an array, struct, or vector with a statically
57 // determinable constant initializer, there are optimizations we can do.
58 //
59 // TODO: We should constant-evaluate the initializer of any variable,
60 // as long as it is initialized by a constant expression. Currently,
61 // isConstantInitializer produces wrong answers for structs with
62 // reference or bitfield members, and a few other cases, and checking
63 // for POD-ness protects us from some of these.
64 if (d.getInit() &&
65 (ty->isArrayType() || ty->isRecordType() || ty->isVectorType()) &&
66 (d.isConstexpr() ||
67 ((ty.isPODType(getContext()) ||
68 getContext().getBaseElementType(ty)->isObjCObjectPointerType()) &&
69 d.getInit()->isConstantInitializer(getContext(), false)))) {
70
71 // If the variable's a const type, and it's neither an NRVO
72 // candidate nor a __block variable and has no mutable members,
73 // emit it as a global instead.
74 // Exception is if a variable is located in non-constant address space
75 // in OpenCL.
76 // TODO(cir): perhaps we don't need this at all at CIR since this can
77 // be done as part of lowering down to LLVM.
78 bool needsDtor =
80 if ((!getContext().getLangOpts().OpenCL ||
82 (cgm.getCodeGenOpts().MergeAllConstants && !nrvo &&
83 !d.isEscapingByref() &&
84 ty.isConstantStorage(getContext(), true, !needsDtor))) {
85 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: type constant");
86 }
87 // Otherwise, tell the initialization code that we're in this case.
88 emission.isConstantAggregate = true;
89 }
90
91 // A normal fixed sized variable becomes an alloca in the entry block,
92 // unless:
93 // - it's an NRVO variable.
94 // - we are compiling OpenMP and it's an OpenMP local variable.
95 if (nrvo) {
96 // The named return value optimization: allocate this variable in the
97 // return slot, so that we can elide the copy when returning this
98 // variable (C++0x [class.copy]p34).
99 address = returnValue;
100
101 if (const RecordDecl *rd = ty->getAsRecordDecl()) {
102 if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
103 (cxxrd && !cxxrd->hasTrivialDestructor()) ||
104 rd->isNonTrivialToPrimitiveDestroy()) {
105 // In LLVM: Create a flag that is used to indicate when the NRVO was
106 // applied to this variable. Set it to zero to indicate that NRVO was
107 // not applied. For now, use the same approach for CIRGen until we can
108 // be sure it's worth doing something more aggressive.
109 cir::ConstantOp falseNVRO = builder.getFalse(loc);
110 Address nrvoFlag = createTempAlloca(falseNVRO.getType(),
111 CharUnits::One(), loc, "nrvo",
112 /*arraySize=*/nullptr);
113 assert(builder.getInsertionBlock());
114 builder.createStore(loc, falseNVRO, nrvoFlag);
115
116 // Record the NRVO flag for this variable.
117 nrvoFlags[&d] = nrvoFlag.getPointer();
118 emission.nrvoFlag = nrvoFlag.getPointer();
119 }
120 }
121 } else {
122 // A normal fixed sized variable becomes an alloca in the entry block,
123 mlir::Type allocaTy = convertTypeForMem(ty);
124 // Create the temp alloca and declare variable using it.
125 address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
126 /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
127 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
128 alignment);
129 }
130 } else {
131 // Non-constant size type
133 if (!didCallStackSave) {
134 // Save the stack.
135 cir::PointerType defaultTy = allocaInt8PtrTy;
137 cgm.getDataLayout().getAlignment(defaultTy, false));
138 Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack");
139
140 mlir::Value v = builder.createStackSave(loc, defaultTy);
141 assert(v.getType() == allocaInt8PtrTy);
142 builder.createStore(loc, v, stack);
143
144 didCallStackSave = true;
145
146 // Push a cleanup block and restore the stack there.
147 // FIXME: in general circumstances, this should be an EH cleanup.
149 }
150
151 VlaSizePair vlaSize = getVLASize(ty);
152 mlir::Type memTy = convertTypeForMem(vlaSize.type);
153
154 // Allocate memory for the array.
155 address =
156 createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts,
157 /*alloca=*/nullptr, builder.saveInsertionPoint());
158
159 // If we have debug info enabled, properly describe the VLA dimensions for
160 // this type by registering the vla size expression for each of the
161 // dimensions.
163 }
164
165 emission.addr = address;
166 setAddrOfLocalVar(&d, address);
167
168 return emission;
169}
170
171/// Determine whether the given initializer is trivial in the sense
172/// that it requires no code to be generated.
174 if (!init)
175 return true;
176
177 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
178 if (CXXConstructorDecl *constructor = construct->getConstructor())
179 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
180 !construct->requiresZeroInitialization())
181 return true;
182
183 return false;
184}
185
186static void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d,
187 Address addr, bool isVolatile,
188 CIRGenBuilderTy &builder,
189 mlir::TypedAttr constant) {
190 mlir::Type ty = constant.getType();
191 cir::CIRDataLayout layout{cgm.getModule()};
192 uint64_t constantSize = layout.getTypeAllocSize(ty);
193 if (!constantSize)
194 return;
197
198 if (addr.getElementType() != ty)
199 addr = addr.withElementType(builder, ty);
200
201 // If the address is an alloca, set the init attribute.
202 // The address is usually and alloca, but there is at least one case where
203 // emitAutoVarInit is called from the OpenACC codegen with an address that
204 // is not an alloca.
205 auto allocaOp = addr.getDefiningOp<cir::AllocaOp>();
206 if (allocaOp)
207 allocaOp.setInitAttr(mlir::UnitAttr::get(&cgm.getMLIRContext()));
208
209 // There are cases where OpenACC codegen calls emitAutoVarInit with a
210 // temporary decl that doesn't have a source range set.
211 mlir::Location loc = builder.getUnknownLoc();
212 if (d.getSourceRange().isValid())
213 loc = cgm.getLoc(d.getSourceRange());
214
215 // Emit cir.const + cir.store, preserving source-level semantics. For
216 // aggregate types (arrays, records), LoweringPrepare implements the OG
217 // optimization tiers (shouldCreateMemCpyFromGlobal, shouldUseBZeroPlusStores,
218 // shouldUseMemSetToInitialize, shouldSplitConstantStore) by transforming
219 // into cir.global + cir.get_global + cir.copy when appropriate.
220 builder.createStore(loc, builder.getConstant(loc, constant), addr);
221}
222
224 const CIRGenFunction::AutoVarEmission &emission) {
225 assert(emission.variable && "emission was not valid!");
226
227 // If this was emitted as a global constant, we're done.
228 if (emission.wasEmittedAsGlobal())
229 return;
230
231 const VarDecl &d = *emission.variable;
232
233 QualType type = d.getType();
234
235 // If this local has an initializer, emit it now.
236 const Expr *init = d.getInit();
237
238 // Initialize the variable here if it doesn't have a initializer and it is a
239 // C struct that is non-trivial to initialize or an array containing such a
240 // struct.
241 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
243 cgm.errorNYI(d.getSourceRange(),
244 "emitAutoVarInit: non-trivial to default initialize");
245 return;
246 }
247
248 const Address addr = emission.addr;
249
250 // Check whether this is a byref variable that's potentially
251 // captured and moved by its own initializer. If so, we'll need to
252 // emit the initializer first, then copy into the variable.
254
255 // Note: constexpr already initializes everything correctly.
256 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
257 (d.isConstexpr()
259 : (d.getAttr<UninitializedAttr>()
261 : getContext().getLangOpts().getTrivialAutoVarInit()));
262
263 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
264 if (trivialAutoVarInit ==
266 return;
267
268 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
269 };
270
271 if (isTrivialInitializer(init)) {
272 initializeWhatIsTechnicallyUninitialized(addr);
273 return;
274 }
275
276 mlir::Attribute constant;
277 if (emission.isConstantAggregate ||
279 // FIXME: Differently from LLVM we try not to emit / lower too much
280 // here for CIR since we are interested in seeing the ctor in some
281 // analysis later on. So CIR's implementation of ConstantEmitter will
282 // frequently return an empty Attribute, to signal we want to codegen
283 // some trivial ctor calls and whatnots.
285 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
286 (trivialAutoVarInit !=
288 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
289 return;
290 }
291 }
292
293 // NOTE(cir): In case we have a constant initializer, we can just emit a
294 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
295 // CXX temporary object creation, we ensure the ctor call is used deferring
296 // its removal/optimization to the CIR lowering.
297 if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
298 initializeWhatIsTechnicallyUninitialized(addr);
300 emitExprAsInit(init, &d, lv);
301
302 if (!emission.wasEmittedAsOffloadClause()) {
303 // In case lv has uses it means we indeed initialized something
304 // out of it while trying to build the expression, mark it as such.
305 mlir::Value val = lv.getAddress().getPointer();
306 assert(val && "Should have an address");
307 auto allocaOp = val.getDefiningOp<cir::AllocaOp>();
308 assert(allocaOp && "Address should come straight out of the alloca");
309
310 if (!allocaOp.use_empty())
311 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
312 }
313
314 return;
315 }
316
317 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
318 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
319 assert(typedConstant && "expected typed attribute");
320 if (!emission.isConstantAggregate) {
321 // For simple scalar/complex initialization, store the value directly.
322 LValue lv = makeAddrLValue(addr, type);
323 assert(init && "expected initializer");
324 mlir::Location initLoc = getLoc(init->getSourceRange());
325 // lv.setNonGC(true);
327 RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
328 }
329
330 emitStoresForConstant(cgm, d, addr, type.isVolatileQualified(), builder,
331 typedConstant);
332}
333
335 const CIRGenFunction::AutoVarEmission &emission) {
336 const VarDecl &d = *emission.variable;
337
338 // Check the type for a cleanup.
340 emitAutoVarTypeCleanup(emission, dtorKind);
341
343
344 // Handle the cleanup attribute.
345 if (d.hasAttr<CleanupAttr>())
346 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
347}
348
349/// Emit code and set up symbol table for a variable declaration with auto,
350/// register, or no storage class specifier. These turn into simple stack
351/// objects, globals depending on target.
357
359 // If the declaration has external storage, don't emit it now, allow it to be
360 // emitted lazily on its first use.
361 if (d.hasExternalStorage())
362 return;
363
364 if (d.getStorageDuration() != SD_Automatic) {
365 // Static sampler variables translated to function calls.
366 if (d.getType()->isSamplerT()) {
367 // Nothing needs to be done here, but let's flag it as an error until we
368 // have a test. It requires OpenCL support.
369 cgm.errorNYI(d.getSourceRange(), "emitVarDecl: static sampler type");
370 return;
371 }
372
373 cir::GlobalLinkageKind linkage =
374 cgm.getCIRLinkageVarDefinition(&d, /*IsConstant=*/false);
375
376 // FIXME: We need to force the emission/use of a guard variable for
377 // some variables even if we can constant-evaluate them because
378 // we can't guarantee every translation unit will constant-evaluate them.
379
380 return emitStaticVarDecl(d, linkage);
381 }
382
384 cgm.errorNYI(d.getSourceRange(), "emitVarDecl: openCL address space");
385
386 assert(d.hasLocalStorage());
387
388 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
389 return emitAutoVarDecl(d);
390}
391
392static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
393 if (cgm.getLangOpts().CPlusPlus)
394 return cgm.getMangledName(&d).str();
395
396 // If this isn't C++, we don't need a mangled name, just a pretty one.
397 assert(!d.isExternallyVisible() && "name shouldn't matter");
398 std::string contextName;
399 const DeclContext *dc = d.getDeclContext();
400 if (auto *cd = dyn_cast<CapturedDecl>(dc))
401 dc = cast<DeclContext>(cd->getNonClosureContext());
402 if (const auto *fd = dyn_cast<FunctionDecl>(dc))
403 contextName = std::string(cgm.getMangledName(fd));
404 else if (isa<BlockDecl>(dc))
405 cgm.errorNYI(d.getSourceRange(),
406 "getStaticDeclName: block decl context for static var");
407 else if (isa<ObjCMethodDecl>(dc))
408 cgm.errorNYI(d.getSourceRange(),
409 "getStaticDeclName: ObjC decl context for static var");
410 else
411 cgm.errorNYI(d.getSourceRange(),
412 "getStaticDeclName: Unknown context for static var decl");
413
414 contextName += "." + d.getNameAsString();
415 return contextName;
416}
417
418// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
419// interface for all constants?
420cir::GlobalOp
422 cir::GlobalLinkageKind linkage) {
423 // In general, we don't always emit static var decls once before we reference
424 // them. It is possible to reference them before emitting the function that
425 // contains them, and it is possible to emit the containing function multiple
426 // times.
427 if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
428 return existingGV;
429
430 QualType ty = d.getType();
431 assert(ty->isConstantSizeType() && "VLAs can't be static");
432
433 // Use the label if the variable is renamed with the asm-label extension.
434 if (d.hasAttr<AsmLabelAttr>())
435 errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label");
436
437 std::string name = getStaticDeclName(*this, d);
438
439 mlir::Type lty = getTypes().convertTypeForMem(ty);
441
442 // OpenCL variables in local address space and CUDA shared
443 // variables cannot have an initializer.
444 mlir::Attribute init = nullptr;
446 d.hasAttr<CUDASharedAttr>() || d.hasAttr<LoaderUninitializedAttr>())
447 init = cir::UndefAttr::get(lty);
448 else
449 init = builder.getZeroInitAttr(convertType(ty));
450
451 cir::GlobalOp gv = builder.createVersionedGlobal(
452 getModule(), getLoc(d.getLocation()), name, lty, false, linkage);
453 // TODO(cir): infer visibility from linkage in global op builder.
454 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
455 gv.setInitialValueAttr(init);
456 gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
457
458 if (supportsCOMDAT() && gv.isWeakForLinker())
459 gv.setComdat(true);
460
461 if (d.getTLSKind())
462 errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: TLS");
463
464 setGVProperties(gv, &d);
465
466 // OG checks if the expected address space, denoted by the type, is the
467 // same as the actual address space indicated by attributes. If they aren't
468 // the same, an addrspacecast is emitted when this variable is accessed.
469 // In CIR however, cir.get_global already carries that information in
470 // !cir.ptr type - if this global is in OpenCL local address space, then its
471 // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't
472 // need an explicit address space cast in CIR: they will get emitted when
473 // lowering to LLVM IR.
474
475 // Ensure that the static local gets initialized by making sure the parent
476 // function gets emitted eventually.
477 const Decl *dc = cast<Decl>(d.getDeclContext());
478
479 // We can't name blocks or captured statements directly, so try to emit their
480 // parents.
481 if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
482 dc = dc->getNonClosureContext();
483 // FIXME: Ensure that global blocks get emitted.
484 if (!dc)
485 errorNYI(d.getSourceRange(), "non-closure context");
486 }
487
488 GlobalDecl gd;
490 errorNYI(d.getSourceRange(), "C++ constructors static var context");
491 else if (isa<CXXDestructorDecl>(dc))
492 errorNYI(d.getSourceRange(), "C++ destructors static var context");
493 else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
494 gd = GlobalDecl(fd);
495 else {
496 // Don't do anything for Obj-C method decls or global closures. We should
497 // never defer them.
498 assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
499 }
501 // Disable emission of the parent function for the OpenMP device codegen.
502 errorNYI(d.getSourceRange(), "OpenMP");
503 }
504
505 return gv;
506}
507
509 mlir::Attribute constAttr,
510 CharUnits align) {
511 auto functionName = [&](const DeclContext *dc) -> std::string {
512 if (const auto *fd = dyn_cast<FunctionDecl>(dc)) {
513 if (const auto *cc = dyn_cast<CXXConstructorDecl>(fd))
514 return cc->getNameAsString();
515 if (const auto *cd = dyn_cast<CXXDestructorDecl>(fd))
516 return cd->getNameAsString();
517 return std::string(getMangledName(fd));
518 } else if (const auto *om = dyn_cast<ObjCMethodDecl>(dc)) {
519 return om->getNameAsString();
520 } else if (isa<BlockDecl>(dc)) {
521 return "<block>";
522 } else if (isa<CapturedDecl>(dc)) {
523 return "<captured>";
524 } else {
525 llvm_unreachable("expected a function or method");
526 }
527 };
528
529 // Form a simple per-variable cache of these values in case we find we
530 // want to reuse them.
531 cir::GlobalOp &cacheEntry = initializerConstants[&d];
532 if (!cacheEntry || cacheEntry.getInitialValue() != constAttr) {
533 auto ty = mlir::cast<mlir::TypedAttr>(constAttr).getType();
534 bool isConstant = true;
535
536 std::string name;
537 if (d.hasGlobalStorage())
538 name = getMangledName(&d).str() + ".const";
539 else if (const DeclContext *dc = d.getParentFunctionOrMethod())
540 name = ("__const." + functionName(dc) + "." + d.getName()).str();
541 else
542 llvm_unreachable("local variable has no parent function or method");
543
545 cir::GlobalOp gv = builder.createVersionedGlobal(
546 getModule(), getLoc(d.getLocation()), name, ty, isConstant,
547 cir::GlobalLinkageKind::PrivateLinkage);
548 // TODO(cir): infer visibility from linkage in global op builder.
549 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(
550 cir::GlobalLinkageKind::PrivateLinkage));
551 gv.setInitialValueAttr(constAttr);
552 gv.setAlignment(align.getAsAlign().value());
553 // TODO(cir): Set unnamed address attribute when available in CIR
554
555 cacheEntry = gv;
556 } else if (cacheEntry.getAlignment() < align.getQuantity()) {
557 cacheEntry.setAlignment(align.getAsAlign().value());
558 }
559
560 // Create a GetGlobalOp to get a pointer to the global
562 mlir::Type eltTy = mlir::cast<mlir::TypedAttr>(constAttr).getType();
563 auto ptrTy = builder.getPointerTo(cacheEntry.getSymType());
564 mlir::Value globalPtr = cir::GetGlobalOp::create(
565 builder, getLoc(d.getLocation()), ptrTy, cacheEntry.getSymName());
566 return Address(globalPtr, eltTy, align);
567}
568
569/// Add the initializer for 'd' to the global variable that has already been
570/// created for it. If the initializer has a different type than gv does, this
571/// may free gv and return a different one. Otherwise it just returns gv.
573 const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
574 ConstantEmitter emitter(*this);
575 mlir::TypedAttr init = mlir::dyn_cast_if_present<mlir::TypedAttr>(
576 emitter.tryEmitForInitializer(d));
577
578 // If constant emission failed, then this should be a C++ static
579 // initializer.
580 if (!init) {
581 if (!getLangOpts().CPlusPlus) {
582 cgm.errorNYI(d.getInit()->getSourceRange(),
583 "constant l-value expression");
584 } else if (d.hasFlexibleArrayInit(getContext())) {
585 cgm.errorNYI(d.getInit()->getSourceRange(), "flexible array initializer");
586 } else {
587 // Since we have a static initializer, this global variable can't
588 // be constant.
589 gv.setConstant(false);
590 emitCXXGuardedInit(d, gv, /*performInit*/ true);
591 gvAddr.setStaticLocal(true);
592 }
593 return gv;
594 }
595
596 // TODO(cir): There should be debug code here to assert that the decl size
597 // matches the CIR data layout type alloc size, but the code for calculating
598 // the type alloc size is not implemented yet.
600
601 // The initializer may differ in type from the global. Rewrite
602 // the global to match the initializer. (We have to do this
603 // because some types, like unions, can't be completely represented
604 // in the LLVM type system.)
605 if (gv.getSymType() != init.getType()) {
606 gv.setSymType(init.getType());
607
608 // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
609 // but since at this point the current block hasn't been really attached,
610 // there's no visibility into the GetGlobalOp corresponding to this Global.
611 // Given those constraints, thread in the GetGlobalOp and update it
612 // directly.
614 gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
615 }
616
617 bool needsDtor =
619
620 gv.setConstant(d.getType().isConstantStorage(
621 getContext(), /*ExcludeCtor=*/true, !needsDtor));
622 gv.setInitialValueAttr(init);
623
624 emitter.finalize(gv);
625
626 if (needsDtor) {
627 // We have a constant initializer, but a nontrivial destructor. We still
628 // need to perform a guarded "initialization" in order to register the
629 // destructor.
630 cgm.errorNYI(d.getSourceRange(), "C++ guarded init");
631 }
632
633 return gv;
634}
635
637 cir::GlobalLinkageKind linkage) {
638 // Check to see if we already have a global variable for this
639 // declaration. This can happen when double-emitting function
640 // bodies, e.g. with complete and base constructors.
641 cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
642 // TODO(cir): we should have a way to represent global ops as values without
643 // having to emit a get global op. Sometimes these emissions are not used.
644 mlir::Value addr = builder.createGetGlobal(globalOp);
645 auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>();
646 assert(getAddrOp && "expected cir::GetGlobalOp");
647
648 CharUnits alignment = getContext().getDeclAlign(&d);
649
650 // Store into LocalDeclMap before generating initializer to handle
651 // circular references.
652 mlir::Type elemTy = convertTypeForMem(d.getType());
653 setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
654
655 // We can't have a VLA here, but we can have a pointer to a VLA,
656 // even though that doesn't really make any sense.
657 // Make sure to evaluate VLA bounds now so that we have them for later.
658 if (d.getType()->isVariablyModifiedType()) {
659 cgm.errorNYI(d.getSourceRange(),
660 "emitStaticVarDecl: variably modified type");
661 }
662
663 // Save the type in case adding the initializer forces a type change.
664 mlir::Type expectedType = addr.getType();
665
666 cir::GlobalOp var = globalOp;
667
669
670 // If this value has an initializer, emit it.
671 if (d.getInit())
672 var = addInitializerToStaticVarDecl(d, var, getAddrOp);
673
674 var.setAlignment(alignment.getAsAlign().value());
675
676 // There are a lot of attributes that need to be handled here. Until
677 // we start to support them, we just report an error if there are any.
678 if (d.hasAttr<AnnotateAttr>())
679 cgm.errorNYI(d.getSourceRange(), "emitStaticVarDecl: Global annotations");
680 if (d.getAttr<PragmaClangBSSSectionAttr>())
681 cgm.errorNYI(d.getSourceRange(),
682 "emitStaticVarDecl: CIR global BSS section attribute");
683 if (d.getAttr<PragmaClangDataSectionAttr>())
684 cgm.errorNYI(d.getSourceRange(),
685 "emitStaticVarDecl: CIR global Data section attribute");
686 if (d.getAttr<PragmaClangRodataSectionAttr>())
687 cgm.errorNYI(d.getSourceRange(),
688 "emitStaticVarDecl: CIR global Rodata section attribute");
689 if (d.getAttr<PragmaClangRelroSectionAttr>())
690 cgm.errorNYI(d.getSourceRange(),
691 "emitStaticVarDecl: CIR global Relro section attribute");
692
693 if (d.getAttr<SectionAttr>())
694 cgm.errorNYI(d.getSourceRange(),
695 "emitStaticVarDecl: CIR global object file section attribute");
696
697 if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
698 cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
699
700 // From traditional codegen:
701 // We may have to cast the constant because of the initializer
702 // mismatch above.
703 //
704 // FIXME: It is really dangerous to store this in the map; if anyone
705 // RAUW's the GV uses of this constant will be invalid.
706 mlir::Value castedAddr =
707 builder.createBitcast(getAddrOp.getAddr(), expectedType);
708 localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
709 cgm.setStaticLocalDeclAddress(&d, var);
710
713}
714
715void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
716 LValue lvalue, bool capturedByInit) {
718
719 SourceLocRAIIObject locRAII{*this, loc};
720 mlir::Value value = emitScalarExpr(init);
721 if (capturedByInit) {
722 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
723 return;
724 }
726 emitStoreThroughLValue(RValue::get(value), lvalue, true);
727}
728
730 LValue lvalue, bool capturedByInit) {
731 SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
732 if (capturedByInit) {
733 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
734 return;
735 }
736
737 QualType type = d->getType();
738
739 if (type->isReferenceType()) {
740 RValue rvalue = emitReferenceBindingToExpr(init);
741 if (capturedByInit)
742 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
743 emitStoreThroughLValue(rvalue, lvalue);
744 return;
745 }
747 case cir::TEK_Scalar:
748 emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
749 return;
750 case cir::TEK_Complex: {
751 mlir::Value complex = emitComplexExpr(init);
752 if (capturedByInit)
753 cgm.errorNYI(init->getSourceRange(),
754 "emitExprAsInit: complex type captured by init");
755 mlir::Location loc = getLoc(init->getExprLoc());
756 emitStoreOfComplex(loc, complex, lvalue,
757 /*isInit*/ true);
758 return;
759 }
761 // The overlap flag here should be calculated.
763 emitAggExpr(init,
767 return;
768 }
769 llvm_unreachable("bad evaluation kind");
770}
771
772void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
773 switch (d.getKind()) {
774 case Decl::BuiltinTemplate:
775 case Decl::TranslationUnit:
776 case Decl::ExternCContext:
777 case Decl::Namespace:
778 case Decl::UnresolvedUsingTypename:
779 case Decl::ClassTemplateSpecialization:
780 case Decl::ClassTemplatePartialSpecialization:
781 case Decl::VarTemplateSpecialization:
782 case Decl::VarTemplatePartialSpecialization:
783 case Decl::TemplateTypeParm:
784 case Decl::UnresolvedUsingValue:
785 case Decl::NonTypeTemplateParm:
786 case Decl::CXXDeductionGuide:
787 case Decl::CXXMethod:
788 case Decl::CXXConstructor:
789 case Decl::CXXDestructor:
790 case Decl::CXXConversion:
791 case Decl::Field:
792 case Decl::MSProperty:
793 case Decl::IndirectField:
794 case Decl::ObjCIvar:
795 case Decl::ObjCAtDefsField:
796 case Decl::ParmVar:
797 case Decl::ImplicitParam:
798 case Decl::ClassTemplate:
799 case Decl::VarTemplate:
800 case Decl::FunctionTemplate:
801 case Decl::TypeAliasTemplate:
802 case Decl::TemplateTemplateParm:
803 case Decl::ObjCMethod:
804 case Decl::ObjCCategory:
805 case Decl::ObjCProtocol:
806 case Decl::ObjCInterface:
807 case Decl::ObjCCategoryImpl:
808 case Decl::ObjCImplementation:
809 case Decl::ObjCProperty:
810 case Decl::ObjCCompatibleAlias:
811 case Decl::PragmaComment:
812 case Decl::PragmaDetectMismatch:
813 case Decl::AccessSpec:
814 case Decl::LinkageSpec:
815 case Decl::Export:
816 case Decl::ObjCPropertyImpl:
817 case Decl::FileScopeAsm:
818 case Decl::Friend:
819 case Decl::FriendTemplate:
820 case Decl::Block:
821 case Decl::OutlinedFunction:
822 case Decl::Captured:
823 case Decl::UsingShadow:
824 case Decl::ConstructorUsingShadow:
825 case Decl::ObjCTypeParam:
826 case Decl::Binding:
827 case Decl::UnresolvedUsingIfExists:
828 case Decl::HLSLBuffer:
829 case Decl::HLSLRootSignature:
830 llvm_unreachable("Declaration should not be in declstmts!");
831
832 case Decl::Function: // void X();
833 case Decl::EnumConstant: // enum ? { X = ? }
834 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
835 case Decl::Label: // __label__ x;
836 case Decl::Import:
837 case Decl::MSGuid: // __declspec(uuid("..."))
838 case Decl::TemplateParamObject:
839 case Decl::Empty:
840 case Decl::Concept:
841 case Decl::LifetimeExtendedTemporary:
842 case Decl::RequiresExprBody:
843 case Decl::UnnamedGlobalConstant:
844 // None of these decls require codegen support.
845 return;
846
847 case Decl::Enum: // enum X;
848 case Decl::Record: // struct/union/class X;
849 case Decl::CXXRecord: // struct/union/class X; [C++]
850 case Decl::NamespaceAlias:
851 case Decl::Using: // using X; [C++]
852 case Decl::UsingEnum: // using enum X; [C++]
853 case Decl::UsingDirective: // using namespace X; [C++]
855 return;
856 case Decl::Var:
857 case Decl::Decomposition: {
858 const VarDecl &vd = cast<VarDecl>(d);
859 assert(vd.isLocalVarDecl() &&
860 "Should not see file-scope variables inside a function!");
861 emitVarDecl(vd);
862 if (evaluateConditionDecl)
864 return;
865 }
866 case Decl::OpenACCDeclare:
868 return;
869 case Decl::OpenACCRoutine:
871 return;
872 case Decl::OMPThreadPrivate:
874 return;
875 case Decl::OMPGroupPrivate:
877 return;
878 case Decl::OMPAllocate:
880 return;
881 case Decl::OMPCapturedExpr:
883 return;
884 case Decl::OMPRequires:
886 return;
887 case Decl::OMPDeclareMapper:
889 return;
890 case Decl::OMPDeclareReduction:
892 return;
893 case Decl::Typedef: // typedef int X;
894 case Decl::TypeAlias: { // using X = int; [C++0x]
895 QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
897 if (ty->isVariablyModifiedType())
898 cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type");
899 return;
900 }
901 case Decl::ImplicitConceptSpecialization:
902 case Decl::TopLevelStmt:
903 case Decl::UsingPack:
904 cgm.errorNYI(d.getSourceRange(),
905 std::string("emitDecl: unhandled decl type: ") +
906 d.getDeclKindName());
907 }
908}
909
911 SourceLocation loc) {
912 if (!sanOpts.has(SanitizerKind::NullabilityAssign))
913 return;
914
916}
917
918namespace {
919struct DestroyObject final : EHScopeStack::Cleanup {
920 DestroyObject(Address addr, QualType type,
921 CIRGenFunction::Destroyer *destroyer)
922 : addr(addr), type(type), destroyer(destroyer) {
924 }
925
926 Address addr;
928 CIRGenFunction::Destroyer *destroyer;
929
930 void emit(CIRGenFunction &cgf, Flags flags) override {
932 cgf.emitDestroy(addr, type, destroyer);
933 }
934};
935
936template <class Derived> struct DestroyNRVOVariable : EHScopeStack::Cleanup {
937 DestroyNRVOVariable(Address addr, QualType type, mlir::Value nrvoFlag)
938 : nrvoFlag(nrvoFlag), addr(addr), ty(type) {}
939
940 mlir::Value nrvoFlag;
941 Address addr;
942 QualType ty;
943
944 void emit(CIRGenFunction &cgf, Flags flags) override {
945 // Along the exceptions path we always execute the dtor.
946 bool nrvo = flags.isForNormalCleanup() && nrvoFlag;
947
948 CIRGenBuilderTy &builder = cgf.getBuilder();
949 mlir::OpBuilder::InsertionGuard guard(builder);
950 if (nrvo) {
951 // If we exited via NRVO, we skip the destructor call.
952 mlir::Location loc = addr.getPointer().getLoc();
953 mlir::Value didNRVO = builder.createFlagLoad(loc, nrvoFlag);
954 mlir::Value notNRVO = builder.createNot(didNRVO);
955 cir::IfOp::create(builder, loc, notNRVO, /*withElseRegion=*/false,
956 [&](mlir::OpBuilder &b, mlir::Location) {
957 static_cast<Derived *>(this)->emitDestructorCall(cgf);
958 builder.createYield(loc);
959 });
960 } else {
961 static_cast<Derived *>(this)->emitDestructorCall(cgf);
962 }
963 }
964
965 virtual ~DestroyNRVOVariable() = default;
966};
967
968struct DestroyNRVOVariableCXX final
969 : DestroyNRVOVariable<DestroyNRVOVariableCXX> {
970 DestroyNRVOVariableCXX(Address addr, QualType type,
971 const CXXDestructorDecl *dtor, mlir::Value nrvoFlag)
972 : DestroyNRVOVariable<DestroyNRVOVariableCXX>(addr, type, nrvoFlag),
973 dtor(dtor) {}
974
975 const CXXDestructorDecl *dtor;
976
977 void emitDestructorCall(CIRGenFunction &cgf) {
979 /*forVirtualBase=*/false,
980 /*delegating=*/false, addr, ty);
981 }
982};
983
984struct CallStackRestore final : EHScopeStack::Cleanup {
985 Address stack;
986 CallStackRestore(Address stack) : stack(stack) {}
987 void emit(CIRGenFunction &cgf, Flags flags) override {
988 mlir::Location loc = stack.getPointer().getLoc();
989 mlir::Value v = cgf.getBuilder().createLoad(loc, stack);
990 cgf.getBuilder().createStackRestore(loc, v);
991 }
992};
993} // namespace
994
995/// Push the standard destructor for the given type as
996/// at least a normal cleanup.
998 Address addr, QualType type) {
999 assert(dtorKind && "cannot push destructor for trivial type");
1000
1001 CleanupKind cleanupKind = getCleanupKind(dtorKind);
1002 pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind));
1003}
1004
1006 QualType type, Destroyer *destroyer) {
1007 pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
1008}
1009
1010/// Destroys all the elements of the given array, beginning from last to first.
1011/// The array cannot be zero-length.
1012///
1013/// \param begin - a type* denoting the first element of the array
1014/// \param numElements - the number of elements in the array
1015/// \param elementType - the element type of the array
1016/// \param destroyer - the function to call to destroy elements
1018 mlir::Value numElements,
1019 QualType elementType,
1020 CharUnits elementAlign,
1021 Destroyer *destroyer) {
1022 assert(!elementType->isArrayType());
1023
1024 // Differently from LLVM traditional codegen, use a higher level
1025 // representation instead of lowering directly to a loop.
1026 mlir::Type cirElementType = convertTypeForMem(elementType);
1027 cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
1028
1029 uint64_t size = 0;
1030
1031 // Optimize for a constant array size.
1032 if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
1033 if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>())
1034 size = constIntAttr.getUInt();
1035 } else {
1036 cgm.errorNYI(begin.getDefiningOp()->getLoc(),
1037 "emitArrayDestroy: dynamic-length array expression");
1038 }
1039
1040 auto arrayTy = cir::ArrayType::get(cirElementType, size);
1041 mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
1042
1043 // Emit the dtor call that will execute for every array element.
1044 cir::ArrayDtor::create(
1045 builder, *currSrcLoc, arrayOp,
1046 [&](mlir::OpBuilder &b, mlir::Location loc) {
1047 auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
1048 Address curAddr = Address(arg, cirElementType, elementAlign);
1050
1051 // Perform the actual destruction there.
1052 destroyer(*this, curAddr, elementType);
1053
1054 cir::YieldOp::create(builder, loc);
1055 });
1056}
1057
1058/// Immediately perform the destruction of the given object.
1059///
1060/// \param addr - the address of the object; a type*
1061/// \param type - the type of the object; if an array type, all
1062/// objects are destroyed in reverse order
1063/// \param destroyer - the function to call to destroy individual
1064/// elements
1066 Destroyer *destroyer) {
1068 if (!arrayType)
1069 return destroyer(*this, addr, type);
1070
1071 mlir::Value length = emitArrayLength(arrayType, type, addr);
1072
1073 CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
1074 getContext().getTypeSizeInChars(type));
1075
1076 auto constantCount = length.getDefiningOp<cir::ConstantOp>();
1077 if (!constantCount) {
1078 assert(!cir::MissingFeatures::vlas());
1079 cgm.errorNYI("emitDestroy: variable length array");
1080 return;
1081 }
1082
1083 auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue());
1084 // If it's constant zero, we can just skip the entire thing.
1085 if (constIntAttr && constIntAttr.getUInt() == 0)
1086 return;
1087
1088 mlir::Value begin = addr.getPointer();
1090 emitArrayDestroy(begin, length, type, elementAlign, destroyer);
1091
1092 // If the array destroy didn't use the length op, we can erase it.
1093 if (constantCount.use_empty())
1094 constantCount.erase();
1095}
1096
1099 switch (kind) {
1100 case QualType::DK_none:
1101 llvm_unreachable("no destroyer for trivial dtor");
1103 return destroyCXXObject;
1107 cgm.errorNYI("getDestroyer: other destruction kind");
1108 return nullptr;
1109 }
1110 llvm_unreachable("Unknown DestructionKind");
1111}
1112
1114 ehStack.pushCleanup<CallStackRestore>(kind, spMem);
1115}
1116
1117/// Enter a destroy cleanup for the given local variable.
1119 const CIRGenFunction::AutoVarEmission &emission,
1120 QualType::DestructionKind dtorKind) {
1121 assert(dtorKind != QualType::DK_none);
1122
1123 // Note that for __block variables, we want to destroy the
1124 // original stack object, not the possibly forwarded object.
1125 Address addr = emission.getObjectAddress(*this);
1126
1127 const VarDecl *var = emission.variable;
1128 QualType type = var->getType();
1129
1130 CleanupKind cleanupKind = NormalAndEHCleanup;
1131 CIRGenFunction::Destroyer *destroyer = nullptr;
1132
1133 switch (dtorKind) {
1134 case QualType::DK_none:
1135 llvm_unreachable("no cleanup for trivially-destructible variable");
1136
1138 // If there's an NRVO flag on the emission, we need a different
1139 // cleanup.
1140 if (emission.nrvoFlag) {
1141 assert(!type->isArrayType());
1142 CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
1143 ehStack.pushCleanup<DestroyNRVOVariableCXX>(cleanupKind, addr, type, dtor,
1144 emission.nrvoFlag);
1145 return;
1146 }
1147 // Otherwise, this is handled below.
1148 break;
1149
1153 cgm.errorNYI(var->getSourceRange(),
1154 "emitAutoVarTypeCleanup: other dtor kind");
1155 return;
1156 }
1157
1158 // If we haven't chosen a more specific destroyer, use the default.
1159 if (!destroyer)
1160 destroyer = getDestroyer(dtorKind);
1161
1163 ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
1164}
1165
1167 if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
1168 for (auto *b : dd->flat_bindings())
1169 if (auto *hd = b->getHoldingVar())
1170 emitVarDecl(*hd);
1171 }
1172}
static void emit(Program &P, llvm::SmallVectorImpl< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static void emitStoresForConstant(CIRGenModule &cgm, const VarDecl &d, Address addr, bool isVolatile, CIRGenBuilderTy &builder, mlir::TypedAttr constant)
static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d)
This file defines OpenACC nodes for declarative directives.
Defines the clang::Expr interface and subclasses for C++ expressions.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
__device__ __2f16 b
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::LoadOp createFlagLoad(mlir::Location loc, mlir::Value addr)
Emit a load from an boolean flag variable.
llvm::TypeSize getTypeAllocSize(mlir::Type ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
const LangOptions & getLangOpts() const
Definition ASTContext.h:952
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:3772
mlir::Value getPointer() const
Definition Address.h:96
mlir::Type getElementType() const
Definition Address.h:123
static Address invalid()
Definition Address.h:74
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
clang::CharUnits getAlignment() const
Definition Address.h:136
mlir::Operation * getDefiningOp() const
Get the operation which defines this address.
Definition Address.h:139
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::StackRestoreOp createStackRestore(mlir::Location loc, mlir::Value v)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
void emitOpenACCRoutine(const OpenACCRoutineDecl &d)
cir::GlobalOp addInitializerToStaticVarDecl(const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr)
Add the initializer for 'd' to the global variable that has already been created for it.
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, mlir::OpBuilder::InsertPoint ip={})
void emitAutoVarTypeCleanup(const AutoVarEmission &emission, clang::QualType::DestructionKind dtorKind)
Enter a destroy cleanup for the given local variable.
void emitVariablyModifiedType(QualType ty)
const clang::LangOptions & getLangOpts() const
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
void emitOMPRequiresDecl(const OMPRequiresDecl &d)
VlaSizePair getVLASize(const VariableArrayType *type)
Returns an MLIR::Value+QualType pair that corresponds to the size, in non-variably-sized elements,...
void emitStaticVarDecl(const VarDecl &d, cir::GlobalLinkageKind linkage)
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
bool isTrivialInitializer(const Expr *init)
Determine whether the given initializer is trivial in the sense that it requires no code to be genera...
void emitOpenACCDeclare(const OpenACCDeclareDecl &d)
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 or a static data member of a class template in...
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.
CleanupKind getCleanupKind(QualType::DestructionKind kind)
void emitOMPAllocateDecl(const OMPAllocateDecl &d)
void emitOMPDeclareMapper(const OMPDeclareMapperDecl &d)
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
clang::SanitizerSet sanOpts
Sanitizers enabled for this function.
mlir::Type convertTypeForMem(QualType t)
void pushDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type)
Push the standard destructor for the given type as at least a normal cleanup.
void emitVarDecl(const clang::VarDecl &d)
This method handles emission of any variable declaration inside a function, including static vars etc...
Address returnValue
The temporary alloca to hold the return value.
void emitArrayDestroy(mlir::Value begin, mlir::Value numElements, QualType elementType, CharUnits elementAlign, Destroyer *destroyer)
Destroys all the elements of the given array, beginning from last to first.
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
void emitScalarInit(const clang::Expr *init, mlir::Location loc, LValue lvalue, bool capturedByInit=false)
void emitAutoVarInit(const AutoVarEmission &emission)
Emit the initializer for an allocated variable.
void maybeEmitDeferredVarDeclInit(const VarDecl *vd)
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
void pushStackRestore(CleanupKind kind, Address spMem)
void emitAutoVarDecl(const clang::VarDecl &d)
Emit code and set up symbol table for a variable declaration with auto, register, or no storage class...
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.
llvm::DenseMap< const VarDecl *, mlir::Value > nrvoFlags
A mapping from NRVO variables to the flags used to indicate when the NRVO has been applied to this va...
mlir::MLIRContext & getMLIRContext()
Destroyer * getDestroyer(clang::QualType::DestructionKind kind)
void Destroyer(CIRGenFunction &cgf, Address addr, QualType ty)
DeclMapTy localDeclMap
This keeps track of the CIR allocas or globals for local C declarations.
void emitOMPThreadPrivateDecl(const OMPThreadPrivateDecl &d)
void emitOMPGroupPrivateDecl(const OMPGroupPrivateDecl &d)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
void emitCXXDestructorCall(const CXXDestructorDecl *dd, CXXDtorType type, bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy)
void pushFullExprCleanup(CleanupKind kind, As... a)
Push a cleanup to be run at the end of the current full-expression.
std::optional< mlir::Location > currSrcLoc
Use to track source locations across nested visitor traversals.
clang::ASTContext & getContext() const
void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr)
Set the address of a local variable.
void 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 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
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)
const clang::LangOptions & getLangOpts() const
mlir::Location getLoc(clang::SourceLocation cLoc)
Helpers to convert the presumed location of Clang's SourceLocation to an MLIR Location.
mlir::ModuleOp getModule() const
mlir::MLIRContext & getMLIRContext()
cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d)
Address createUnnamedGlobalFrom(const VarDecl &d, mlir::Attribute constAttr, CharUnits align)
mlir::Type convertTypeForMem(clang::QualType, bool forBitField=false)
Convert type T into an mlir::Type.
mlir::Attribute tryEmitForInitializer(const VarDecl &d)
Try to emit the initializer of the given declaration as an abstract constant.
mlir::Attribute tryEmitAbstractForInitializer(const VarDecl &d)
Try to emit the initializer of the given declaration as an abstract constant.
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:1549
Represents a C++ constructor within a class.
Definition DeclCXX.h:2611
Represents a C++ destructor within a class.
Definition DeclCXX.h:2876
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:1449
const DeclContext * getParentFunctionOrMethod(bool LexicalParent=false) const
If this decl is defined inside a function/method/block it returns the corresponding DeclContext,...
Definition DeclBase.cpp:341
T * getAttr() const
Definition DeclBase.h:573
Decl * getNonClosureContext()
Find the innermost non-closure ancestor of this declaration, walking up through blocks,...
SourceLocation getLocation() const
Definition DeclBase.h:439
const char * getDeclKindName() const
Definition DeclBase.cpp:169
DeclContext * getDeclContext()
Definition DeclBase.h:448
bool hasAttr() const
Definition DeclBase.h:577
Kind getKind() const
Definition DeclBase.h:442
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:427
This represents one expression.
Definition Expr.h:112
bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit=nullptr) const
isConstantInitializer - Returns true if this expression can be emitted to IR as a constant,...
Definition Expr.cpp:3347
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:277
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
const Decl * getDecl() const
Definition GlobalDecl.h:106
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:317
bool isExternallyVisible() const
Definition Decl.h:433
A (possibly-)qualified type.
Definition TypeBase.h:937
@ PDIK_Struct
The type is a struct containing a field whose type is not PCK_Trivial.
Definition TypeBase.h:1484
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8557
bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor, bool ExcludeDtor)
Definition TypeBase.h:1036
bool isPODType(const ASTContext &Context) const
Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
Definition Type.cpp:2739
Represents a struct/union/class.
Definition Decl.h:4342
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:2470
bool isArrayType() const
Definition TypeBase.h:8767
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2850
bool isVectorType() const
Definition TypeBase.h:8807
bool isSamplerT() const
Definition TypeBase.h:8912
bool isRecordType() const
Definition TypeBase.h:8795
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1584
TLSKind getTLSKind() const
Definition Decl.cpp:2180
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2202
bool hasFlexibleArrayInit(const ASTContext &Ctx) const
Whether this variable has a flexible array member initialized with one or more elements.
Definition Decl.cpp:2874
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1241
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:2498
bool isNRVOVariable() const
Determine whether this local variable can be used with the named return value optimization (NRVO).
Definition Decl.h:1527
QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const
Would the destruction of this variable have any effect, and if so, what kind?
Definition Decl.cpp:2863
const Expr * getInit() const
Definition Decl.h:1383
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
Definition Decl.h:1232
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1184
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
Definition Decl.h:1268
StorageDuration getStorageDuration() const
Get the storage duration of this variable, per C++ [basic.stc].
Definition Decl.h:1244
bool isEscapingByref() const
Indicates the capture is a __block variable that is captured by a block that can potentially escape (...
Definition Decl.cpp:2710
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
@ 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
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ CPlusPlus
@ SD_Automatic
Automatic storage duration (most local variables).
Definition Specifiers.h:341
@ Dtor_Complete
Complete object dtor.
Definition ABI.h:36
U cast(CodeGen::Address addr)
Definition Address.h:327
float __ovld __cnfn length(float)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
static bool objCLifetime()
static bool addAutoInitAnnotation()
static bool addressSpace()
static bool emitNullabilityCheck()
static bool useEHCleanupForArray()
static bool vectorConstants()
static bool aggValueSlotMayOverlap()
static bool dtorCleanups()
static bool dataLayoutTypeAllocSize()
static bool opAllocaCaptureByInit()
static bool opAllocaPreciseLifetime()
static bool cudaSupport()
static bool generateDebugInfo()
bool isEscapingByRef
True if the variable is a __block variable that is captured by an escaping block.
Address addr
The address of the alloca for languages with explicit address space (e.g.
bool isConstantAggregate
True if the variable is of aggregate type and has a constant initializer.
Address getObjectAddress(CIRGenFunction &cgf) const
Returns the address of the object within this declaration.
cir::PointerType allocaInt8PtrTy
void* in alloca address space