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