clang 22.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 // A normal fixed sized variable becomes an alloca in the entry block,
54 // unless:
55 // - it's an NRVO variable.
56 // - we are compiling OpenMP and it's an OpenMP local variable.
57 if (nrvo) {
58 // The named return value optimization: allocate this variable in the
59 // return slot, so that we can elide the copy when returning this
60 // variable (C++0x [class.copy]p34).
61 address = returnValue;
62
63 if (const RecordDecl *rd = ty->getAsRecordDecl()) {
64 if (const auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
65 (cxxrd && !cxxrd->hasTrivialDestructor()) ||
66 rd->isNonTrivialToPrimitiveDestroy())
67 cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: set NRVO flag");
68 }
69 } else {
70 // A normal fixed sized variable becomes an alloca in the entry block,
71 mlir::Type allocaTy = convertTypeForMem(ty);
72 // Create the temp alloca and declare variable using it.
73 address = createTempAlloca(allocaTy, alignment, loc, d.getName(),
74 /*arraySize=*/nullptr, /*alloca=*/nullptr, ip);
75 declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()),
76 alignment);
77 }
78 } else {
79 // Non-constant size type
81 if (!didCallStackSave) {
82 // Save the stack.
83 cir::PointerType defaultTy = allocaInt8PtrTy;
85 cgm.getDataLayout().getAlignment(defaultTy, false));
86 Address stack = createTempAlloca(defaultTy, align, loc, "saved_stack");
87
88 mlir::Value v = builder.createStackSave(loc, defaultTy);
89 assert(v.getType() == allocaInt8PtrTy);
90 builder.createStore(loc, v, stack);
91
92 didCallStackSave = true;
93
94 // Push a cleanup block and restore the stack there.
95 // FIXME: in general circumstances, this should be an EH cleanup.
97 }
98
99 VlaSizePair vlaSize = getVLASize(ty);
100 mlir::Type memTy = convertTypeForMem(vlaSize.type);
101
102 // Allocate memory for the array.
103 address =
104 createTempAlloca(memTy, alignment, loc, d.getName(), vlaSize.numElts,
105 /*alloca=*/nullptr, builder.saveInsertionPoint());
106
107 // If we have debug info enabled, properly describe the VLA dimensions for
108 // this type by registering the vla size expression for each of the
109 // dimensions.
111 }
112
113 emission.addr = address;
114 setAddrOfLocalVar(&d, address);
115
116 return emission;
117}
118
119/// Determine whether the given initializer is trivial in the sense
120/// that it requires no code to be generated.
122 if (!init)
123 return true;
124
125 if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(init))
126 if (CXXConstructorDecl *constructor = construct->getConstructor())
127 if (constructor->isTrivial() && constructor->isDefaultConstructor() &&
128 !construct->requiresZeroInitialization())
129 return true;
130
131 return false;
132}
133
135 const CIRGenFunction::AutoVarEmission &emission) {
136 assert(emission.variable && "emission was not valid!");
137
138 // If this was emitted as a global constant, we're done.
139 if (emission.wasEmittedAsGlobal())
140 return;
141
142 const VarDecl &d = *emission.variable;
143
144 QualType type = d.getType();
145
146 // If this local has an initializer, emit it now.
147 const Expr *init = d.getInit();
148
149 // Initialize the variable here if it doesn't have a initializer and it is a
150 // C struct that is non-trivial to initialize or an array containing such a
151 // struct.
152 if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() ==
154 cgm.errorNYI(d.getSourceRange(),
155 "emitAutoVarInit: non-trivial to default initialize");
156 return;
157 }
158
159 const Address addr = emission.addr;
160
161 // Check whether this is a byref variable that's potentially
162 // captured and moved by its own initializer. If so, we'll need to
163 // emit the initializer first, then copy into the variable.
165
166 // Note: constexpr already initializes everything correctly.
167 LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
168 (d.isConstexpr()
170 : (d.getAttr<UninitializedAttr>()
172 : getContext().getLangOpts().getTrivialAutoVarInit()));
173
174 auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) {
175 if (trivialAutoVarInit ==
177 return;
178
179 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization");
180 };
181
182 if (isTrivialInitializer(init)) {
183 initializeWhatIsTechnicallyUninitialized(addr);
184 return;
185 }
186
187 mlir::Attribute constant;
188 if (emission.isConstantAggregate ||
190 // FIXME: Differently from LLVM we try not to emit / lower too much
191 // here for CIR since we are interested in seeing the ctor in some
192 // analysis later on. So CIR's implementation of ConstantEmitter will
193 // frequently return an empty Attribute, to signal we want to codegen
194 // some trivial ctor calls and whatnots.
196 if (constant && !mlir::isa<cir::ZeroAttr>(constant) &&
197 (trivialAutoVarInit !=
199 cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate");
200 return;
201 }
202 }
203
204 // NOTE(cir): In case we have a constant initializer, we can just emit a
205 // store. But, in CIR, we wish to retain any ctor calls, so if it is a
206 // CXX temporary object creation, we ensure the ctor call is used deferring
207 // its removal/optimization to the CIR lowering.
208 if (!constant || isa<CXXTemporaryObjectExpr>(init)) {
209 initializeWhatIsTechnicallyUninitialized(addr);
211 emitExprAsInit(init, &d, lv);
212
213 if (!emission.wasEmittedAsOffloadClause()) {
214 // In case lv has uses it means we indeed initialized something
215 // out of it while trying to build the expression, mark it as such.
216 mlir::Value val = lv.getAddress().getPointer();
217 assert(val && "Should have an address");
218 auto allocaOp = val.getDefiningOp<cir::AllocaOp>();
219 assert(allocaOp && "Address should come straight out of the alloca");
220
221 if (!allocaOp.use_empty())
222 allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext()));
223 }
224
225 return;
226 }
227
228 // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly.
229 auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant);
230 assert(typedConstant && "expected typed attribute");
231 if (!emission.isConstantAggregate) {
232 // For simple scalar/complex initialization, store the value directly.
233 LValue lv = makeAddrLValue(addr, type);
234 assert(init && "expected initializer");
235 mlir::Location initLoc = getLoc(init->getSourceRange());
236 // lv.setNonGC(true);
238 RValue::get(builder.getConstant(initLoc, typedConstant)), lv);
239 }
240}
241
243 const CIRGenFunction::AutoVarEmission &emission) {
244 const VarDecl &d = *emission.variable;
245
246 // Check the type for a cleanup.
248 emitAutoVarTypeCleanup(emission, dtorKind);
249
251
252 // Handle the cleanup attribute.
253 if (d.hasAttr<CleanupAttr>())
254 cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr");
255}
256
257/// Emit code and set up symbol table for a variable declaration with auto,
258/// register, or no storage class specifier. These turn into simple stack
259/// objects, globals depending on target.
265
267 // If the declaration has external storage, don't emit it now, allow it to be
268 // emitted lazily on its first use.
269 if (d.hasExternalStorage())
270 return;
271
272 if (d.getStorageDuration() != SD_Automatic) {
273 // Static sampler variables translated to function calls.
274 if (d.getType()->isSamplerT()) {
275 // Nothing needs to be done here, but let's flag it as an error until we
276 // have a test. It requires OpenCL support.
277 cgm.errorNYI(d.getSourceRange(), "emitVarDecl static sampler type");
278 return;
279 }
280
281 cir::GlobalLinkageKind linkage =
282 cgm.getCIRLinkageVarDefinition(&d, /*IsConstant=*/false);
283
284 // FIXME: We need to force the emission/use of a guard variable for
285 // some variables even if we can constant-evaluate them because
286 // we can't guarantee every translation unit will constant-evaluate them.
287
288 return emitStaticVarDecl(d, linkage);
289 }
290
292 cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space");
293
294 assert(d.hasLocalStorage());
295
296 CIRGenFunction::VarDeclContext varDeclCtx{*this, &d};
297 return emitAutoVarDecl(d);
298}
299
300static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
301 if (cgm.getLangOpts().CPlusPlus)
302 return cgm.getMangledName(&d).str();
303
304 // If this isn't C++, we don't need a mangled name, just a pretty one.
305 assert(!d.isExternallyVisible() && "name shouldn't matter");
306 std::string contextName;
307 const DeclContext *dc = d.getDeclContext();
308 if (auto *cd = dyn_cast<CapturedDecl>(dc))
309 dc = cast<DeclContext>(cd->getNonClosureContext());
310 if (const auto *fd = dyn_cast<FunctionDecl>(dc))
311 contextName = std::string(cgm.getMangledName(fd));
312 else if (isa<BlockDecl>(dc))
313 cgm.errorNYI(d.getSourceRange(), "block decl context for static var");
314 else if (isa<ObjCMethodDecl>(dc))
315 cgm.errorNYI(d.getSourceRange(), "ObjC decl context for static var");
316 else
317 cgm.errorNYI(d.getSourceRange(), "Unknown context for static var decl");
318
319 contextName += "." + d.getNameAsString();
320 return contextName;
321}
322
323// TODO(cir): LLVM uses a Constant base class. Maybe CIR could leverage an
324// interface for all constants?
325cir::GlobalOp
327 cir::GlobalLinkageKind linkage) {
328 // In general, we don't always emit static var decls once before we reference
329 // them. It is possible to reference them before emitting the function that
330 // contains them, and it is possible to emit the containing function multiple
331 // times.
332 if (cir::GlobalOp existingGV = getStaticLocalDeclAddress(&d))
333 return existingGV;
334
335 QualType ty = d.getType();
336 assert(ty->isConstantSizeType() && "VLAs can't be static");
337
338 // Use the label if the variable is renamed with the asm-label extension.
339 if (d.hasAttr<AsmLabelAttr>())
340 errorNYI(d.getSourceRange(), "getOrCreateStaticVarDecl: asm label");
341
342 std::string name = getStaticDeclName(*this, d);
343
344 mlir::Type lty = getTypes().convertTypeForMem(ty);
346
347 if (d.hasAttr<LoaderUninitializedAttr>() || d.hasAttr<CUDASharedAttr>())
349 "getOrCreateStaticVarDecl: LoaderUninitializedAttr");
351
352 mlir::Attribute init = builder.getZeroInitAttr(convertType(ty));
353
354 cir::GlobalOp gv = builder.createVersionedGlobal(
355 getModule(), getLoc(d.getLocation()), name, lty, false, linkage);
356 // TODO(cir): infer visibility from linkage in global op builder.
357 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
358 gv.setInitialValueAttr(init);
359 gv.setAlignment(getASTContext().getDeclAlign(&d).getAsAlign().value());
360
361 if (supportsCOMDAT() && gv.isWeakForLinker())
362 gv.setComdat(true);
363
365
366 setGVProperties(gv, &d);
367
368 // OG checks if the expected address space, denoted by the type, is the
369 // same as the actual address space indicated by attributes. If they aren't
370 // the same, an addrspacecast is emitted when this variable is accessed.
371 // In CIR however, cir.get_global already carries that information in
372 // !cir.ptr type - if this global is in OpenCL local address space, then its
373 // type would be !cir.ptr<..., addrspace(offload_local)>. Therefore we don't
374 // need an explicit address space cast in CIR: they will get emitted when
375 // lowering to LLVM IR.
376
377 // Ensure that the static local gets initialized by making sure the parent
378 // function gets emitted eventually.
379 const Decl *dc = cast<Decl>(d.getDeclContext());
380
381 // We can't name blocks or captured statements directly, so try to emit their
382 // parents.
383 if (isa<BlockDecl>(dc) || isa<CapturedDecl>(dc)) {
384 dc = dc->getNonClosureContext();
385 // FIXME: Ensure that global blocks get emitted.
386 if (!dc)
387 errorNYI(d.getSourceRange(), "non-closure context");
388 }
389
390 GlobalDecl gd;
392 errorNYI(d.getSourceRange(), "C++ constructors static var context");
393 else if (isa<CXXDestructorDecl>(dc))
394 errorNYI(d.getSourceRange(), "C++ destructors static var context");
395 else if (const auto *fd = dyn_cast<FunctionDecl>(dc))
396 gd = GlobalDecl(fd);
397 else {
398 // Don't do anything for Obj-C method decls or global closures. We should
399 // never defer them.
400 assert(isa<ObjCMethodDecl>(dc) && "unexpected parent code decl");
401 }
403 // Disable emission of the parent function for the OpenMP device codegen.
404 errorNYI(d.getSourceRange(), "OpenMP");
405 }
406
407 return gv;
408}
409
410/// Add the initializer for 'd' to the global variable that has already been
411/// created for it. If the initializer has a different type than gv does, this
412/// may free gv and return a different one. Otherwise it just returns gv.
414 const VarDecl &d, cir::GlobalOp gv, cir::GetGlobalOp gvAddr) {
415 ConstantEmitter emitter(*this);
416 mlir::TypedAttr init =
417 mlir::cast<mlir::TypedAttr>(emitter.tryEmitForInitializer(d));
418
419 // If constant emission failed, then this should be a C++ static
420 // initializer.
421 if (!init) {
422 cgm.errorNYI(d.getSourceRange(), "static var without initializer");
423 return gv;
424 }
425
426 // TODO(cir): There should be debug code here to assert that the decl size
427 // matches the CIR data layout type alloc size, but the code for calculating
428 // the type alloc size is not implemented yet.
430
431 // The initializer may differ in type from the global. Rewrite
432 // the global to match the initializer. (We have to do this
433 // because some types, like unions, can't be completely represented
434 // in the LLVM type system.)
435 if (gv.getSymType() != init.getType()) {
436 gv.setSymType(init.getType());
437
438 // Normally this should be done with a call to cgm.replaceGlobal(oldGV, gv),
439 // but since at this point the current block hasn't been really attached,
440 // there's no visibility into the GetGlobalOp corresponding to this Global.
441 // Given those constraints, thread in the GetGlobalOp and update it
442 // directly.
444 gvAddr.getAddr().setType(builder.getPointerTo(init.getType()));
445 }
446
447 bool needsDtor =
449
451 gv.setInitialValueAttr(init);
452
453 emitter.finalize(gv);
454
455 if (needsDtor) {
456 // We have a constant initializer, but a nontrivial destructor. We still
457 // need to perform a guarded "initialization" in order to register the
458 // destructor.
459 cgm.errorNYI(d.getSourceRange(), "C++ guarded init");
460 }
461
462 return gv;
463}
464
466 cir::GlobalLinkageKind linkage) {
467 // Check to see if we already have a global variable for this
468 // declaration. This can happen when double-emitting function
469 // bodies, e.g. with complete and base constructors.
470 cir::GlobalOp globalOp = cgm.getOrCreateStaticVarDecl(d, linkage);
471 // TODO(cir): we should have a way to represent global ops as values without
472 // having to emit a get global op. Sometimes these emissions are not used.
473 mlir::Value addr = builder.createGetGlobal(globalOp);
474 auto getAddrOp = addr.getDefiningOp<cir::GetGlobalOp>();
475 assert(getAddrOp && "expected cir::GetGlobalOp");
476
477 CharUnits alignment = getContext().getDeclAlign(&d);
478
479 // Store into LocalDeclMap before generating initializer to handle
480 // circular references.
481 mlir::Type elemTy = convertTypeForMem(d.getType());
482 setAddrOfLocalVar(&d, Address(addr, elemTy, alignment));
483
484 // We can't have a VLA here, but we can have a pointer to a VLA,
485 // even though that doesn't really make any sense.
486 // Make sure to evaluate VLA bounds now so that we have them for later.
487 if (d.getType()->isVariablyModifiedType()) {
488 cgm.errorNYI(d.getSourceRange(),
489 "emitStaticVarDecl: variably modified type");
490 }
491
492 // Save the type in case adding the initializer forces a type change.
493 mlir::Type expectedType = addr.getType();
494
495 cir::GlobalOp var = globalOp;
496
498
499 // If this value has an initializer, emit it.
500 if (d.getInit())
501 var = addInitializerToStaticVarDecl(d, var, getAddrOp);
502
503 var.setAlignment(alignment.getAsAlign().value());
504
505 // There are a lot of attributes that need to be handled here. Until
506 // we start to support them, we just report an error if there are any.
507 if (d.hasAttrs())
508 cgm.errorNYI(d.getSourceRange(), "static var with attrs");
509
510 if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
511 cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
512
513 // From traditional codegen:
514 // We may have to cast the constant because of the initializer
515 // mismatch above.
516 //
517 // FIXME: It is really dangerous to store this in the map; if anyone
518 // RAUW's the GV uses of this constant will be invalid.
519 mlir::Value castedAddr =
520 builder.createBitcast(getAddrOp.getAddr(), expectedType);
521 localDeclMap.find(&d)->second = Address(castedAddr, elemTy, alignment);
522 cgm.setStaticLocalDeclAddress(&d, var);
523
526}
527
528void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc,
529 LValue lvalue, bool capturedByInit) {
531
532 SourceLocRAIIObject locRAII{*this, loc};
533 mlir::Value value = emitScalarExpr(init);
534 if (capturedByInit) {
535 cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init");
536 return;
537 }
539 emitStoreThroughLValue(RValue::get(value), lvalue, true);
540}
541
543 LValue lvalue, bool capturedByInit) {
544 SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())};
545 if (capturedByInit) {
546 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
547 return;
548 }
549
550 QualType type = d->getType();
551
552 if (type->isReferenceType()) {
553 RValue rvalue = emitReferenceBindingToExpr(init);
554 if (capturedByInit)
555 cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init");
556 emitStoreThroughLValue(rvalue, lvalue);
557 return;
558 }
560 case cir::TEK_Scalar:
561 emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
562 return;
563 case cir::TEK_Complex: {
564 mlir::Value complex = emitComplexExpr(init);
565 if (capturedByInit)
566 cgm.errorNYI(init->getSourceRange(),
567 "emitExprAsInit: complex type captured by init");
568 mlir::Location loc = getLoc(init->getExprLoc());
569 emitStoreOfComplex(loc, complex, lvalue,
570 /*isInit*/ true);
571 return;
572 }
574 // The overlap flag here should be calculated.
576 emitAggExpr(init,
580 return;
581 }
582 llvm_unreachable("bad evaluation kind");
583}
584
585void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) {
586 switch (d.getKind()) {
587 case Decl::BuiltinTemplate:
588 case Decl::TranslationUnit:
589 case Decl::ExternCContext:
590 case Decl::Namespace:
591 case Decl::UnresolvedUsingTypename:
592 case Decl::ClassTemplateSpecialization:
593 case Decl::ClassTemplatePartialSpecialization:
594 case Decl::VarTemplateSpecialization:
595 case Decl::VarTemplatePartialSpecialization:
596 case Decl::TemplateTypeParm:
597 case Decl::UnresolvedUsingValue:
598 case Decl::NonTypeTemplateParm:
599 case Decl::CXXDeductionGuide:
600 case Decl::CXXMethod:
601 case Decl::CXXConstructor:
602 case Decl::CXXDestructor:
603 case Decl::CXXConversion:
604 case Decl::Field:
605 case Decl::MSProperty:
606 case Decl::IndirectField:
607 case Decl::ObjCIvar:
608 case Decl::ObjCAtDefsField:
609 case Decl::ParmVar:
610 case Decl::ImplicitParam:
611 case Decl::ClassTemplate:
612 case Decl::VarTemplate:
613 case Decl::FunctionTemplate:
614 case Decl::TypeAliasTemplate:
615 case Decl::TemplateTemplateParm:
616 case Decl::ObjCMethod:
617 case Decl::ObjCCategory:
618 case Decl::ObjCProtocol:
619 case Decl::ObjCInterface:
620 case Decl::ObjCCategoryImpl:
621 case Decl::ObjCImplementation:
622 case Decl::ObjCProperty:
623 case Decl::ObjCCompatibleAlias:
624 case Decl::PragmaComment:
625 case Decl::PragmaDetectMismatch:
626 case Decl::AccessSpec:
627 case Decl::LinkageSpec:
628 case Decl::Export:
629 case Decl::ObjCPropertyImpl:
630 case Decl::FileScopeAsm:
631 case Decl::Friend:
632 case Decl::FriendTemplate:
633 case Decl::Block:
634 case Decl::OutlinedFunction:
635 case Decl::Captured:
636 case Decl::UsingShadow:
637 case Decl::ConstructorUsingShadow:
638 case Decl::ObjCTypeParam:
639 case Decl::Binding:
640 case Decl::UnresolvedUsingIfExists:
641 case Decl::HLSLBuffer:
642 case Decl::HLSLRootSignature:
643 llvm_unreachable("Declaration should not be in declstmts!");
644
645 case Decl::Function: // void X();
646 case Decl::EnumConstant: // enum ? { X = ? }
647 case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
648 case Decl::Label: // __label__ x;
649 case Decl::Import:
650 case Decl::MSGuid: // __declspec(uuid("..."))
651 case Decl::TemplateParamObject:
652 case Decl::OMPThreadPrivate:
653 case Decl::OMPGroupPrivate:
654 case Decl::OMPAllocate:
655 case Decl::OMPCapturedExpr:
656 case Decl::OMPRequires:
657 case Decl::Empty:
658 case Decl::Concept:
659 case Decl::LifetimeExtendedTemporary:
660 case Decl::RequiresExprBody:
661 case Decl::UnnamedGlobalConstant:
662 // None of these decls require codegen support.
663 return;
664
665 case Decl::Enum: // enum X;
666 case Decl::Record: // struct/union/class X;
667 case Decl::CXXRecord: // struct/union/class X; [C++]
668 case Decl::NamespaceAlias:
669 case Decl::Using: // using X; [C++]
670 case Decl::UsingEnum: // using enum X; [C++]
671 case Decl::UsingDirective: // using namespace X; [C++]
673 return;
674 case Decl::Var:
675 case Decl::Decomposition: {
676 const VarDecl &vd = cast<VarDecl>(d);
677 assert(vd.isLocalVarDecl() &&
678 "Should not see file-scope variables inside a function!");
679 emitVarDecl(vd);
680 if (evaluateConditionDecl)
682 return;
683 }
684 case Decl::OpenACCDeclare:
686 return;
687 case Decl::OpenACCRoutine:
689 return;
690 case Decl::Typedef: // typedef int X;
691 case Decl::TypeAlias: { // using X = int; [C++0x]
692 QualType ty = cast<TypedefNameDecl>(d).getUnderlyingType();
694 if (ty->isVariablyModifiedType())
695 cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type");
696 return;
697 }
698 case Decl::ImplicitConceptSpecialization:
699 case Decl::TopLevelStmt:
700 case Decl::UsingPack:
701 case Decl::OMPDeclareMapper:
702 case Decl::OMPDeclareReduction:
703 cgm.errorNYI(d.getSourceRange(),
704 std::string("emitDecl: unhandled decl type: ") +
705 d.getDeclKindName());
706 }
707}
708
710 SourceLocation loc) {
711 if (!sanOpts.has(SanitizerKind::NullabilityAssign))
712 return;
713
715}
716
717namespace {
718struct DestroyObject final : EHScopeStack::Cleanup {
719 DestroyObject(Address addr, QualType type,
720 CIRGenFunction::Destroyer *destroyer)
721 : addr(addr), type(type), destroyer(destroyer) {}
722
723 Address addr;
725 CIRGenFunction::Destroyer *destroyer;
726
727 void emit(CIRGenFunction &cgf) override {
728 cgf.emitDestroy(addr, type, destroyer);
729 }
730};
731
732struct CallStackRestore final : EHScopeStack::Cleanup {
733 Address stack;
734 CallStackRestore(Address stack) : stack(stack) {}
735 void emit(CIRGenFunction &cgf) override {
736 mlir::Location loc = stack.getPointer().getLoc();
737 mlir::Value v = cgf.getBuilder().createLoad(loc, stack);
738 cgf.getBuilder().createStackRestore(loc, v);
739 }
740};
741} // namespace
742
743/// Push the standard destructor for the given type as
744/// at least a normal cleanup.
746 Address addr, QualType type) {
747 assert(dtorKind && "cannot push destructor for trivial type");
748
749 CleanupKind cleanupKind = getCleanupKind(dtorKind);
750 pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind));
751}
752
754 QualType type, Destroyer *destroyer) {
755 pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
756}
757
758/// Destroys all the elements of the given array, beginning from last to first.
759/// The array cannot be zero-length.
760///
761/// \param begin - a type* denoting the first element of the array
762/// \param numElements - the number of elements in the array
763/// \param elementType - the element type of the array
764/// \param destroyer - the function to call to destroy elements
765void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
766 mlir::Value numElements,
767 QualType elementType,
768 CharUnits elementAlign,
769 Destroyer *destroyer) {
770 assert(!elementType->isArrayType());
771
772 // Differently from LLVM traditional codegen, use a higher level
773 // representation instead of lowering directly to a loop.
774 mlir::Type cirElementType = convertTypeForMem(elementType);
775 cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
776
777 uint64_t size = 0;
778
779 // Optimize for a constant array size.
780 if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
781 if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>())
782 size = constIntAttr.getUInt();
783 } else {
784 cgm.errorNYI(begin.getDefiningOp()->getLoc(),
785 "dynamic-length array expression");
786 }
787
788 auto arrayTy = cir::ArrayType::get(cirElementType, size);
789 mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
790
791 // Emit the dtor call that will execute for every array element.
792 cir::ArrayDtor::create(
793 builder, *currSrcLoc, arrayOp,
794 [&](mlir::OpBuilder &b, mlir::Location loc) {
795 auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
796 Address curAddr = Address(arg, cirElementType, elementAlign);
798
799 // Perform the actual destruction there.
800 destroyer(*this, curAddr, elementType);
801
802 cir::YieldOp::create(builder, loc);
803 });
804}
805
806/// Immediately perform the destruction of the given object.
807///
808/// \param addr - the address of the object; a type*
809/// \param type - the type of the object; if an array type, all
810/// objects are destroyed in reverse order
811/// \param destroyer - the function to call to destroy individual
812/// elements
814 Destroyer *destroyer) {
816 if (!arrayType)
817 return destroyer(*this, addr, type);
818
819 mlir::Value length = emitArrayLength(arrayType, type, addr);
820
821 CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
822 getContext().getTypeSizeInChars(type));
823
824 auto constantCount = length.getDefiningOp<cir::ConstantOp>();
825 if (!constantCount) {
827 cgm.errorNYI("emitDestroy: variable length array");
828 return;
829 }
830
831 auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue());
832 // If it's constant zero, we can just skip the entire thing.
833 if (constIntAttr && constIntAttr.getUInt() == 0)
834 return;
835
836 mlir::Value begin = addr.getPointer();
837 emitArrayDestroy(begin, length, type, elementAlign, destroyer);
838
839 // If the array destroy didn't use the length op, we can erase it.
840 if (constantCount.use_empty())
841 constantCount.erase();
842}
843
846 switch (kind) {
848 llvm_unreachable("no destroyer for trivial dtor");
850 return destroyCXXObject;
854 cgm.errorNYI("getDestroyer: other destruction kind");
855 return nullptr;
856 }
857 llvm_unreachable("Unknown DestructionKind");
858}
859
861 ehStack.pushCleanup<CallStackRestore>(kind, spMem);
862}
863
864/// Enter a destroy cleanup for the given local variable.
866 const CIRGenFunction::AutoVarEmission &emission,
867 QualType::DestructionKind dtorKind) {
868 assert(dtorKind != QualType::DK_none);
869
870 // Note that for __block variables, we want to destroy the
871 // original stack object, not the possibly forwarded object.
872 Address addr = emission.getObjectAddress(*this);
873
874 const VarDecl *var = emission.variable;
875 QualType type = var->getType();
876
877 CleanupKind cleanupKind = NormalAndEHCleanup;
878 CIRGenFunction::Destroyer *destroyer = nullptr;
879
880 switch (dtorKind) {
882 llvm_unreachable("no cleanup for trivially-destructible variable");
883
885 // If there's an NRVO flag on the emission, we need a different
886 // cleanup.
887 if (emission.nrvoFlag) {
888 cgm.errorNYI(var->getSourceRange(), "emitAutoVarTypeCleanup: NRVO");
889 return;
890 }
891 // Otherwise, this is handled below.
892 break;
893
897 cgm.errorNYI(var->getSourceRange(),
898 "emitAutoVarTypeCleanup: other dtor kind");
899 return;
900 }
901
902 // If we haven't chosen a more specific destroyer, use the default.
903 if (!destroyer)
904 destroyer = getDestroyer(dtorKind);
905
907 ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
908}
909
911 if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) {
912 for (auto *b : dd->flat_bindings())
913 if (auto *hd = b->getHoldingVar())
914 emitVarDecl(*hd);
915 }
916}
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 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.
__device__ __2f16 b
const LangOptions & getLangOpts() const
Definition ASTContext.h:926
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:3722
mlir::Value getPointer() const
Definition Address.h:82
static Address invalid()
Definition Address.h:67
clang::CharUnits getAlignment() const
Definition Address.h:117
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::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,...
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 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.
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)
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)
mlir::Value emitScalarExpr(const clang::Expr *e)
Emit the computation of the specified expression of scalar type.
void emitAutoVarInit(const AutoVarEmission &emission)
Emit the initializer for an allocated variable.
void maybeEmitDeferredVarDeclInit(const VarDecl *vd)
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.
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.
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
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 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)
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
cir::GlobalOp getStaticLocalDeclAddress(const VarDecl *d)
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:82
Represents a call to a C++ constructor.
Definition ExprCXX.h:1549
Represents a C++ constructor within a class.
Definition DeclCXX.h:2604
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
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
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
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:273
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:1478
LangAS getAddressSpace() const
Return the address space of this type.
Definition TypeBase.h:8404
Represents a struct/union/class.
Definition Decl.h:4312
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:338
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:2425
bool isArrayType() const
Definition TypeBase.h:8614
bool isVariablyModifiedType() const
Whether this type is a variably-modified type (C99 6.7.5).
Definition TypeBase.h:2800
bool isSamplerT() const
Definition TypeBase.h:8749
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
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2190
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:2486
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:2851
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:2698
@ 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
@ SD_Automatic
Automatic storage duration (most local variables).
Definition Specifiers.h:341
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 opGlobalConstant()
static bool objCLifetime()
static bool addressSpace()
static bool emitNullabilityCheck()
static bool ehCleanupFlags()
static bool opGlobalThreadLocal()
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