| 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 | |