1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This contains code to emit Decl nodes as CIR code. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "CIRGenConstantEmitter.h" |
14 | #include "CIRGenFunction.h" |
15 | #include "mlir/IR/Location.h" |
16 | #include "clang/AST/Attr.h" |
17 | #include "clang/AST/Decl.h" |
18 | #include "clang/AST/DeclOpenACC.h" |
19 | #include "clang/AST/Expr.h" |
20 | #include "clang/AST/ExprCXX.h" |
21 | #include "clang/CIR/MissingFeatures.h" |
22 | |
23 | using namespace clang; |
24 | using namespace clang::CIRGen; |
25 | |
26 | CIRGenFunction::AutoVarEmission |
27 | CIRGenFunction::emitAutoVarAlloca(const VarDecl &d) { |
28 | QualType ty = d.getType(); |
29 | if (ty.getAddressSpace() != LangAS::Default) |
30 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarAlloca: address space" ); |
31 | |
32 | mlir::Location loc = getLoc(d.getSourceRange()); |
33 | |
34 | CIRGenFunction::AutoVarEmission emission(d); |
35 | emission.IsEscapingByRef = d.isEscapingByref(); |
36 | if (emission.IsEscapingByRef) |
37 | cgm.errorNYI(d.getSourceRange(), |
38 | "emitAutoVarDecl: decl escaping by reference" ); |
39 | |
40 | CharUnits alignment = getContext().getDeclAlign(&d); |
41 | |
42 | // If the type is variably-modified, emit all the VLA sizes for it. |
43 | if (ty->isVariablyModifiedType()) |
44 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: variably modified type" ); |
45 | |
46 | Address address = Address::invalid(); |
47 | if (!ty->isConstantSizeType()) |
48 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarDecl: non-constant size type" ); |
49 | |
50 | // A normal fixed sized variable becomes an alloca in the entry block, |
51 | mlir::Type allocaTy = convertTypeForMem(ty); |
52 | // Create the temp alloca and declare variable using it. |
53 | address = createTempAlloca(allocaTy, alignment, loc, d.getName()); |
54 | declare(address.getPointer(), &d, ty, getLoc(d.getSourceRange()), alignment); |
55 | |
56 | emission.Addr = address; |
57 | setAddrOfLocalVar(vd: &d, addr: address); |
58 | |
59 | return emission; |
60 | } |
61 | |
62 | /// Determine whether the given initializer is trivial in the sense |
63 | /// that it requires no code to be generated. |
64 | bool CIRGenFunction::isTrivialInitializer(const Expr *init) { |
65 | if (!init) |
66 | return true; |
67 | |
68 | if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(Val: init)) |
69 | if (CXXConstructorDecl *constructor = construct->getConstructor()) |
70 | if (constructor->isTrivial() && constructor->isDefaultConstructor() && |
71 | !construct->requiresZeroInitialization()) |
72 | return true; |
73 | |
74 | return false; |
75 | } |
76 | |
77 | void CIRGenFunction::emitAutoVarInit( |
78 | const CIRGenFunction::AutoVarEmission &emission) { |
79 | assert(emission.Variable && "emission was not valid!" ); |
80 | |
81 | // If this was emitted as a global constant, we're done. |
82 | if (emission.wasEmittedAsGlobal()) |
83 | return; |
84 | |
85 | const VarDecl &d = *emission.Variable; |
86 | |
87 | QualType type = d.getType(); |
88 | |
89 | // If this local has an initializer, emit it now. |
90 | const Expr *init = d.getInit(); |
91 | |
92 | // Initialize the variable here if it doesn't have a initializer and it is a |
93 | // C struct that is non-trivial to initialize or an array containing such a |
94 | // struct. |
95 | if (!init && type.isNonTrivialToPrimitiveDefaultInitialize() == |
96 | QualType::PDIK_Struct) { |
97 | cgm.errorNYI(d.getSourceRange(), |
98 | "emitAutoVarInit: non-trivial to default initialize" ); |
99 | return; |
100 | } |
101 | |
102 | const Address addr = emission.Addr; |
103 | |
104 | // Check whether this is a byref variable that's potentially |
105 | // captured and moved by its own initializer. If so, we'll need to |
106 | // emit the initializer first, then copy into the variable. |
107 | assert(!cir::MissingFeatures::opAllocaCaptureByInit()); |
108 | |
109 | // Note: constexpr already initializes everything correctly. |
110 | LangOptions::TrivialAutoVarInitKind trivialAutoVarInit = |
111 | (d.isConstexpr() |
112 | ? LangOptions::TrivialAutoVarInitKind::Uninitialized |
113 | : (d.getAttr<UninitializedAttr>() |
114 | ? LangOptions::TrivialAutoVarInitKind::Uninitialized |
115 | : getContext().getLangOpts().getTrivialAutoVarInit())); |
116 | |
117 | auto initializeWhatIsTechnicallyUninitialized = [&](Address addr) { |
118 | if (trivialAutoVarInit == |
119 | LangOptions::TrivialAutoVarInitKind::Uninitialized) |
120 | return; |
121 | |
122 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: trivial initialization" ); |
123 | }; |
124 | |
125 | if (isTrivialInitializer(init)) { |
126 | initializeWhatIsTechnicallyUninitialized(addr); |
127 | return; |
128 | } |
129 | |
130 | mlir::Attribute constant; |
131 | if (emission.IsConstantAggregate || |
132 | d.mightBeUsableInConstantExpressions(C: getContext())) { |
133 | // FIXME: Differently from LLVM we try not to emit / lower too much |
134 | // here for CIR since we are interested in seeing the ctor in some |
135 | // analysis later on. So CIR's implementation of ConstantEmitter will |
136 | // frequently return an empty Attribute, to signal we want to codegen |
137 | // some trivial ctor calls and whatnots. |
138 | constant = ConstantEmitter(*this).tryEmitAbstractForInitializer(d); |
139 | if (constant && !mlir::isa<cir::ZeroAttr>(constant) && |
140 | (trivialAutoVarInit != |
141 | LangOptions::TrivialAutoVarInitKind::Uninitialized)) { |
142 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarInit: constant aggregate" ); |
143 | return; |
144 | } |
145 | } |
146 | |
147 | // NOTE(cir): In case we have a constant initializer, we can just emit a |
148 | // store. But, in CIR, we wish to retain any ctor calls, so if it is a |
149 | // CXX temporary object creation, we ensure the ctor call is used deferring |
150 | // its removal/optimization to the CIR lowering. |
151 | if (!constant || isa<CXXTemporaryObjectExpr>(Val: init)) { |
152 | initializeWhatIsTechnicallyUninitialized(addr); |
153 | LValue lv = makeAddrLValue(addr, ty: type, source: AlignmentSource::Decl); |
154 | emitExprAsInit(init, &d, lv); |
155 | // In case lv has uses it means we indeed initialized something |
156 | // out of it while trying to build the expression, mark it as such. |
157 | mlir::Value val = lv.getAddress().getPointer(); |
158 | assert(val && "Should have an address" ); |
159 | auto allocaOp = dyn_cast_or_null<cir::AllocaOp>(val.getDefiningOp()); |
160 | assert(allocaOp && "Address should come straight out of the alloca" ); |
161 | |
162 | if (!allocaOp.use_empty()) |
163 | allocaOp.setInitAttr(mlir::UnitAttr::get(&getMLIRContext())); |
164 | return; |
165 | } |
166 | |
167 | // FIXME(cir): migrate most of this file to use mlir::TypedAttr directly. |
168 | auto typedConstant = mlir::dyn_cast<mlir::TypedAttr>(constant); |
169 | assert(typedConstant && "expected typed attribute" ); |
170 | if (!emission.IsConstantAggregate) { |
171 | // For simple scalar/complex initialization, store the value directly. |
172 | LValue lv = makeAddrLValue(addr, ty: type); |
173 | assert(init && "expected initializer" ); |
174 | mlir::Location initLoc = getLoc(init->getSourceRange()); |
175 | // lv.setNonGC(true); |
176 | return emitStoreThroughLValue( |
177 | RValue::src: get(builder.getConstant(initLoc, typedConstant)), dst: lv); |
178 | } |
179 | } |
180 | |
181 | void CIRGenFunction::emitAutoVarCleanups( |
182 | const CIRGenFunction::AutoVarEmission &emission) { |
183 | const VarDecl &d = *emission.Variable; |
184 | |
185 | // Check the type for a cleanup. |
186 | if (d.needsDestruction(Ctx: getContext())) |
187 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: type cleanup" ); |
188 | |
189 | assert(!cir::MissingFeatures::opAllocaPreciseLifetime()); |
190 | |
191 | // Handle the cleanup attribute. |
192 | if (d.hasAttr<CleanupAttr>()) |
193 | cgm.errorNYI(d.getSourceRange(), "emitAutoVarCleanups: CleanupAttr" ); |
194 | } |
195 | |
196 | /// Emit code and set up symbol table for a variable declaration with auto, |
197 | /// register, or no storage class specifier. These turn into simple stack |
198 | /// objects, globals depending on target. |
199 | void CIRGenFunction::emitAutoVarDecl(const VarDecl &d) { |
200 | CIRGenFunction::AutoVarEmission emission = emitAutoVarAlloca(d); |
201 | emitAutoVarInit(emission); |
202 | emitAutoVarCleanups(emission); |
203 | } |
204 | |
205 | void CIRGenFunction::emitVarDecl(const VarDecl &d) { |
206 | // If the declaration has external storage, don't emit it now, allow it to be |
207 | // emitted lazily on its first use. |
208 | if (d.hasExternalStorage()) |
209 | return; |
210 | |
211 | if (d.getStorageDuration() != SD_Automatic) |
212 | cgm.errorNYI(d.getSourceRange(), "emitVarDecl automatic storage duration" ); |
213 | if (d.getType().getAddressSpace() == LangAS::opencl_local) |
214 | cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space" ); |
215 | |
216 | assert(d.hasLocalStorage()); |
217 | |
218 | CIRGenFunction::VarDeclContext varDeclCtx{*this, &d}; |
219 | return emitAutoVarDecl(d); |
220 | } |
221 | |
222 | void CIRGenFunction::emitScalarInit(const Expr *init, mlir::Location loc, |
223 | LValue lvalue, bool capturedByInit) { |
224 | assert(!cir::MissingFeatures::objCLifetime()); |
225 | |
226 | SourceLocRAIIObject locRAII{*this, loc}; |
227 | mlir::Value value = emitScalarExpr(init); |
228 | if (capturedByInit) { |
229 | cgm.errorNYI(init->getSourceRange(), "emitScalarInit: captured by init" ); |
230 | return; |
231 | } |
232 | assert(!cir::MissingFeatures::emitNullabilityCheck()); |
233 | emitStoreThroughLValue(RValue::src: get(value), dst: lvalue, isInit: true); |
234 | } |
235 | |
236 | void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d, |
237 | LValue lvalue, bool capturedByInit) { |
238 | SourceLocRAIIObject loc{*this, getLoc(init->getSourceRange())}; |
239 | if (capturedByInit) { |
240 | cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init" ); |
241 | return; |
242 | } |
243 | |
244 | QualType type = d->getType(); |
245 | |
246 | if (type->isReferenceType()) { |
247 | RValue rvalue = emitReferenceBindingToExpr(e: init); |
248 | if (capturedByInit) |
249 | cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: captured by init" ); |
250 | emitStoreThroughLValue(src: rvalue, dst: lvalue); |
251 | return; |
252 | } |
253 | switch (CIRGenFunction::getEvaluationKind(type)) { |
254 | case cir::TEK_Scalar: |
255 | emitScalarInit(init, getLoc(d->getSourceRange()), lvalue); |
256 | return; |
257 | case cir::TEK_Complex: { |
258 | cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: complex type" ); |
259 | return; |
260 | } |
261 | case cir::TEK_Aggregate: |
262 | emitAggExpr(e: init, slot: AggValueSlot::forLValue(lv: lvalue)); |
263 | return; |
264 | } |
265 | llvm_unreachable("bad evaluation kind" ); |
266 | } |
267 | |
268 | void CIRGenFunction::emitDecl(const Decl &d) { |
269 | switch (d.getKind()) { |
270 | case Decl::BuiltinTemplate: |
271 | case Decl::TranslationUnit: |
272 | case Decl::ExternCContext: |
273 | case Decl::Namespace: |
274 | case Decl::UnresolvedUsingTypename: |
275 | case Decl::ClassTemplateSpecialization: |
276 | case Decl::ClassTemplatePartialSpecialization: |
277 | case Decl::VarTemplateSpecialization: |
278 | case Decl::VarTemplatePartialSpecialization: |
279 | case Decl::TemplateTypeParm: |
280 | case Decl::UnresolvedUsingValue: |
281 | case Decl::NonTypeTemplateParm: |
282 | case Decl::CXXDeductionGuide: |
283 | case Decl::CXXMethod: |
284 | case Decl::CXXConstructor: |
285 | case Decl::CXXDestructor: |
286 | case Decl::CXXConversion: |
287 | case Decl::Field: |
288 | case Decl::MSProperty: |
289 | case Decl::IndirectField: |
290 | case Decl::ObjCIvar: |
291 | case Decl::ObjCAtDefsField: |
292 | case Decl::ParmVar: |
293 | case Decl::ImplicitParam: |
294 | case Decl::ClassTemplate: |
295 | case Decl::VarTemplate: |
296 | case Decl::FunctionTemplate: |
297 | case Decl::TypeAliasTemplate: |
298 | case Decl::TemplateTemplateParm: |
299 | case Decl::ObjCMethod: |
300 | case Decl::ObjCCategory: |
301 | case Decl::ObjCProtocol: |
302 | case Decl::ObjCInterface: |
303 | case Decl::ObjCCategoryImpl: |
304 | case Decl::ObjCImplementation: |
305 | case Decl::ObjCProperty: |
306 | case Decl::ObjCCompatibleAlias: |
307 | case Decl::PragmaComment: |
308 | case Decl::PragmaDetectMismatch: |
309 | case Decl::AccessSpec: |
310 | case Decl::LinkageSpec: |
311 | case Decl::Export: |
312 | case Decl::ObjCPropertyImpl: |
313 | case Decl::FileScopeAsm: |
314 | case Decl::Friend: |
315 | case Decl::FriendTemplate: |
316 | case Decl::Block: |
317 | case Decl::OutlinedFunction: |
318 | case Decl::Captured: |
319 | case Decl::UsingShadow: |
320 | case Decl::ConstructorUsingShadow: |
321 | case Decl::ObjCTypeParam: |
322 | case Decl::Binding: |
323 | case Decl::UnresolvedUsingIfExists: |
324 | case Decl::HLSLBuffer: |
325 | case Decl::HLSLRootSignature: |
326 | llvm_unreachable("Declaration should not be in declstmts!" ); |
327 | |
328 | case Decl::Function: // void X(); |
329 | case Decl::EnumConstant: // enum ? { X = ? } |
330 | case Decl::StaticAssert: // static_assert(X, ""); [C++0x] |
331 | case Decl::Label: // __label__ x; |
332 | case Decl::Import: |
333 | case Decl::MSGuid: // __declspec(uuid("...")) |
334 | case Decl::TemplateParamObject: |
335 | case Decl::OMPThreadPrivate: |
336 | case Decl::OMPAllocate: |
337 | case Decl::OMPCapturedExpr: |
338 | case Decl::OMPRequires: |
339 | case Decl::Empty: |
340 | case Decl::Concept: |
341 | case Decl::LifetimeExtendedTemporary: |
342 | case Decl::RequiresExprBody: |
343 | case Decl::UnnamedGlobalConstant: |
344 | // None of these decls require codegen support. |
345 | return; |
346 | |
347 | case Decl::Enum: // enum X; |
348 | case Decl::Record: // struct/union/class X; |
349 | case Decl::CXXRecord: // struct/union/class X; [C++] |
350 | case Decl::NamespaceAlias: |
351 | case Decl::Using: // using X; [C++] |
352 | case Decl::UsingEnum: // using enum X; [C++] |
353 | case Decl::UsingDirective: // using namespace X; [C++] |
354 | assert(!cir::MissingFeatures::generateDebugInfo()); |
355 | return; |
356 | case Decl::Var: { |
357 | const VarDecl &vd = cast<VarDecl>(Val: d); |
358 | assert(vd.isLocalVarDecl() && |
359 | "Should not see file-scope variables inside a function!" ); |
360 | emitVarDecl(d: vd); |
361 | return; |
362 | } |
363 | case Decl::OpenACCDeclare: |
364 | emitOpenACCDeclare(d: cast<OpenACCDeclareDecl>(Val: d)); |
365 | return; |
366 | case Decl::OpenACCRoutine: |
367 | emitOpenACCRoutine(d: cast<OpenACCRoutineDecl>(Val: d)); |
368 | return; |
369 | case Decl::Typedef: // typedef int X; |
370 | case Decl::TypeAlias: { // using X = int; [C++0x] |
371 | QualType ty = cast<TypedefNameDecl>(Val: d).getUnderlyingType(); |
372 | assert(!cir::MissingFeatures::generateDebugInfo()); |
373 | if (ty->isVariablyModifiedType()) |
374 | cgm.errorNYI(d.getSourceRange(), "emitDecl: variably modified type" ); |
375 | return; |
376 | } |
377 | case Decl::ImplicitConceptSpecialization: |
378 | case Decl::TopLevelStmt: |
379 | case Decl::UsingPack: |
380 | case Decl::Decomposition: // This could be moved to join Decl::Var |
381 | case Decl::OMPDeclareReduction: |
382 | case Decl::OMPDeclareMapper: |
383 | cgm.errorNYI(d.getSourceRange(), |
384 | std::string("emitDecl: unhandled decl type: " ) + |
385 | d.getDeclKindName()); |
386 | } |
387 | } |
388 | |
389 | void CIRGenFunction::emitNullabilityCheck(LValue lhs, mlir::Value rhs, |
390 | SourceLocation loc) { |
391 | if (!sanOpts.has(K: SanitizerKind::NullabilityAssign)) |
392 | return; |
393 | |
394 | assert(!cir::MissingFeatures::sanitizers()); |
395 | } |
396 | |