2499 lines · cpp
1//===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This is the internal per-translation-unit state used for CIR translation.10//11//===----------------------------------------------------------------------===//12 13#include "CIRGenModule.h"14#include "CIRGenCXXABI.h"15#include "CIRGenConstantEmitter.h"16#include "CIRGenFunction.h"17 18#include "clang/AST/ASTContext.h"19#include "clang/AST/DeclBase.h"20#include "clang/AST/DeclOpenACC.h"21#include "clang/AST/GlobalDecl.h"22#include "clang/AST/RecordLayout.h"23#include "clang/Basic/SourceManager.h"24#include "clang/CIR/Dialect/IR/CIRDialect.h"25#include "clang/CIR/Interfaces/CIROpInterfaces.h"26#include "clang/CIR/MissingFeatures.h"27 28#include "CIRGenFunctionInfo.h"29#include "mlir/IR/BuiltinOps.h"30#include "mlir/IR/Location.h"31#include "mlir/IR/MLIRContext.h"32#include "mlir/IR/Verifier.h"33 34using namespace clang;35using namespace clang::CIRGen;36 37static CIRGenCXXABI *createCXXABI(CIRGenModule &cgm) {38 switch (cgm.getASTContext().getCXXABIKind()) {39 case TargetCXXABI::GenericItanium:40 case TargetCXXABI::GenericAArch64:41 case TargetCXXABI::AppleARM64:42 return CreateCIRGenItaniumCXXABI(cgm);43 44 case TargetCXXABI::Fuchsia:45 case TargetCXXABI::GenericARM:46 case TargetCXXABI::iOS:47 case TargetCXXABI::WatchOS:48 case TargetCXXABI::GenericMIPS:49 case TargetCXXABI::WebAssembly:50 case TargetCXXABI::XL:51 case TargetCXXABI::Microsoft:52 cgm.errorNYI("C++ ABI kind not yet implemented");53 return nullptr;54 }55 56 llvm_unreachable("invalid C++ ABI kind");57}58 59CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,60 clang::ASTContext &astContext,61 const clang::CodeGenOptions &cgo,62 DiagnosticsEngine &diags)63 : builder(mlirContext, *this), astContext(astContext),64 langOpts(astContext.getLangOpts()), codeGenOpts(cgo),65 theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))},66 diags(diags), target(astContext.getTargetInfo()),67 abi(createCXXABI(*this)), genTypes(*this), vtables(*this) {68 69 // Initialize cached types70 voidTy = cir::VoidType::get(&getMLIRContext());71 voidPtrTy = cir::PointerType::get(voidTy);72 sInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/true);73 sInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/true);74 sInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/true);75 sInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/true);76 sInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/true);77 uInt8Ty = cir::IntType::get(&getMLIRContext(), 8, /*isSigned=*/false);78 uInt8PtrTy = cir::PointerType::get(uInt8Ty);79 cirAllocaAddressSpace = getTargetCIRGenInfo().getCIRAllocaAddressSpace();80 uInt16Ty = cir::IntType::get(&getMLIRContext(), 16, /*isSigned=*/false);81 uInt32Ty = cir::IntType::get(&getMLIRContext(), 32, /*isSigned=*/false);82 uInt64Ty = cir::IntType::get(&getMLIRContext(), 64, /*isSigned=*/false);83 uInt128Ty = cir::IntType::get(&getMLIRContext(), 128, /*isSigned=*/false);84 fP16Ty = cir::FP16Type::get(&getMLIRContext());85 bFloat16Ty = cir::BF16Type::get(&getMLIRContext());86 floatTy = cir::SingleType::get(&getMLIRContext());87 doubleTy = cir::DoubleType::get(&getMLIRContext());88 fP80Ty = cir::FP80Type::get(&getMLIRContext());89 fP128Ty = cir::FP128Type::get(&getMLIRContext());90 91 allocaInt8PtrTy = cir::PointerType::get(uInt8Ty, cirAllocaAddressSpace);92 93 PointerAlignInBytes =94 astContext95 .toCharUnitsFromBits(96 astContext.getTargetInfo().getPointerAlign(LangAS::Default))97 .getQuantity();98 99 const unsigned charSize = astContext.getTargetInfo().getCharWidth();100 uCharTy = cir::IntType::get(&getMLIRContext(), charSize, /*isSigned=*/false);101 102 // TODO(CIR): Should be updated once TypeSizeInfoAttr is upstreamed103 const unsigned sizeTypeSize =104 astContext.getTypeSize(astContext.getSignedSizeType());105 SizeSizeInBytes = astContext.toCharUnitsFromBits(sizeTypeSize).getQuantity();106 // In CIRGenTypeCache, UIntPtrTy and SizeType are fields of the same union107 uIntPtrTy =108 cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/false);109 ptrDiffTy =110 cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/true);111 112 std::optional<cir::SourceLanguage> sourceLanguage = getCIRSourceLanguage();113 if (sourceLanguage)114 theModule->setAttr(115 cir::CIRDialect::getSourceLanguageAttrName(),116 cir::SourceLanguageAttr::get(&mlirContext, *sourceLanguage));117 theModule->setAttr(cir::CIRDialect::getTripleAttrName(),118 builder.getStringAttr(getTriple().str()));119 120 if (cgo.OptimizationLevel > 0 || cgo.OptimizeSize > 0)121 theModule->setAttr(cir::CIRDialect::getOptInfoAttrName(),122 cir::OptInfoAttr::get(&mlirContext,123 cgo.OptimizationLevel,124 cgo.OptimizeSize));125 // Set the module name to be the name of the main file. TranslationUnitDecl126 // often contains invalid source locations and isn't a reliable source for the127 // module location.128 FileID mainFileId = astContext.getSourceManager().getMainFileID();129 const FileEntry &mainFile =130 *astContext.getSourceManager().getFileEntryForID(mainFileId);131 StringRef path = mainFile.tryGetRealPathName();132 if (!path.empty()) {133 theModule.setSymName(path);134 theModule->setLoc(mlir::FileLineColLoc::get(&mlirContext, path,135 /*line=*/0,136 /*column=*/0));137 }138}139 140CIRGenModule::~CIRGenModule() = default;141 142/// FIXME: this could likely be a common helper and not necessarily related143/// with codegen.144/// Return the best known alignment for an unknown pointer to a145/// particular class.146CharUnits CIRGenModule::getClassPointerAlignment(const CXXRecordDecl *rd) {147 if (!rd->hasDefinition())148 return CharUnits::One(); // Hopefully won't be used anywhere.149 150 auto &layout = astContext.getASTRecordLayout(rd);151 152 // If the class is final, then we know that the pointer points to an153 // object of that type and can use the full alignment.154 if (rd->isEffectivelyFinal())155 return layout.getAlignment();156 157 // Otherwise, we have to assume it could be a subclass.158 return layout.getNonVirtualAlignment();159}160 161CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t,162 LValueBaseInfo *baseInfo) {163 assert(!cir::MissingFeatures::opTBAA());164 165 // FIXME: This duplicates logic in ASTContext::getTypeAlignIfKnown, but166 // that doesn't return the information we need to compute baseInfo.167 168 // Honor alignment typedef attributes even on incomplete types.169 // We also honor them straight for C++ class types, even as pointees;170 // there's an expressivity gap here.171 if (const auto *tt = t->getAs<TypedefType>()) {172 if (unsigned align = tt->getDecl()->getMaxAlignment()) {173 if (baseInfo)174 *baseInfo = LValueBaseInfo(AlignmentSource::AttributedType);175 return astContext.toCharUnitsFromBits(align);176 }177 }178 179 // Analyze the base element type, so we don't get confused by incomplete180 // array types.181 t = astContext.getBaseElementType(t);182 183 if (t->isIncompleteType()) {184 // We could try to replicate the logic from185 // ASTContext::getTypeAlignIfKnown, but nothing uses the alignment if the186 // type is incomplete, so it's impossible to test. We could try to reuse187 // getTypeAlignIfKnown, but that doesn't return the information we need188 // to set baseInfo. So just ignore the possibility that the alignment is189 // greater than one.190 if (baseInfo)191 *baseInfo = LValueBaseInfo(AlignmentSource::Type);192 return CharUnits::One();193 }194 195 if (baseInfo)196 *baseInfo = LValueBaseInfo(AlignmentSource::Type);197 198 CharUnits alignment;199 if (t.getQualifiers().hasUnaligned()) {200 alignment = CharUnits::One();201 } else {202 assert(!cir::MissingFeatures::alignCXXRecordDecl());203 alignment = astContext.getTypeAlignInChars(t);204 }205 206 // Cap to the global maximum type alignment unless the alignment207 // was somehow explicit on the type.208 if (unsigned maxAlign = astContext.getLangOpts().MaxTypeAlign) {209 if (alignment.getQuantity() > maxAlign &&210 !astContext.isAlignmentRequired(t))211 alignment = CharUnits::fromQuantity(maxAlign);212 }213 return alignment;214}215 216const TargetCIRGenInfo &CIRGenModule::getTargetCIRGenInfo() {217 if (theTargetCIRGenInfo)218 return *theTargetCIRGenInfo;219 220 const llvm::Triple &triple = getTarget().getTriple();221 switch (triple.getArch()) {222 default:223 assert(!cir::MissingFeatures::targetCIRGenInfoArch());224 225 // Currently we just fall through to x86_64.226 [[fallthrough]];227 228 case llvm::Triple::x86_64: {229 switch (triple.getOS()) {230 default:231 assert(!cir::MissingFeatures::targetCIRGenInfoOS());232 233 // Currently we just fall through to x86_64.234 [[fallthrough]];235 236 case llvm::Triple::Linux:237 theTargetCIRGenInfo = createX8664TargetCIRGenInfo(genTypes);238 return *theTargetCIRGenInfo;239 }240 }241 }242}243 244mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {245 assert(cLoc.isValid() && "expected valid source location");246 const SourceManager &sm = astContext.getSourceManager();247 PresumedLoc pLoc = sm.getPresumedLoc(cLoc);248 StringRef filename = pLoc.getFilename();249 return mlir::FileLineColLoc::get(builder.getStringAttr(filename),250 pLoc.getLine(), pLoc.getColumn());251}252 253mlir::Location CIRGenModule::getLoc(SourceRange cRange) {254 assert(cRange.isValid() && "expected a valid source range");255 mlir::Location begin = getLoc(cRange.getBegin());256 mlir::Location end = getLoc(cRange.getEnd());257 mlir::Attribute metadata;258 return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext());259}260 261mlir::Operation *262CIRGenModule::getAddrOfGlobal(GlobalDecl gd, ForDefinition_t isForDefinition) {263 const Decl *d = gd.getDecl();264 265 if (isa<CXXConstructorDecl>(d) || isa<CXXDestructorDecl>(d))266 return getAddrOfCXXStructor(gd, /*FnInfo=*/nullptr, /*FnType=*/nullptr,267 /*DontDefer=*/false, isForDefinition);268 269 if (isa<CXXMethodDecl>(d)) {270 const CIRGenFunctionInfo &fi =271 getTypes().arrangeCXXMethodDeclaration(cast<CXXMethodDecl>(d));272 cir::FuncType ty = getTypes().getFunctionType(fi);273 return getAddrOfFunction(gd, ty, /*ForVTable=*/false, /*DontDefer=*/false,274 isForDefinition);275 }276 277 if (isa<FunctionDecl>(d)) {278 const CIRGenFunctionInfo &fi = getTypes().arrangeGlobalDeclaration(gd);279 cir::FuncType ty = getTypes().getFunctionType(fi);280 return getAddrOfFunction(gd, ty, /*ForVTable=*/false, /*DontDefer=*/false,281 isForDefinition);282 }283 284 return getAddrOfGlobalVar(cast<VarDecl>(d), /*ty=*/nullptr, isForDefinition)285 .getDefiningOp();286}287 288void CIRGenModule::emitGlobalDecl(const clang::GlobalDecl &d) {289 // We call getAddrOfGlobal with isForDefinition set to ForDefinition in290 // order to get a Value with exactly the type we need, not something that291 // might have been created for another decl with the same mangled name but292 // different type.293 mlir::Operation *op = getAddrOfGlobal(d, ForDefinition);294 295 // In case of different address spaces, we may still get a cast, even with296 // IsForDefinition equal to ForDefinition. Query mangled names table to get297 // GlobalValue.298 if (!op)299 op = getGlobalValue(getMangledName(d));300 301 assert(op && "expected a valid global op");302 303 // Check to see if we've already emitted this. This is necessary for a304 // couple of reasons: first, decls can end up in deferred-decls queue305 // multiple times, and second, decls can end up with definitions in unusual306 // ways (e.g. by an extern inline function acquiring a strong function307 // redefinition). Just ignore those cases.308 // TODO: Not sure what to map this to for MLIR309 mlir::Operation *globalValueOp = op;310 if (auto gv = dyn_cast<cir::GetGlobalOp>(op))311 globalValueOp =312 mlir::SymbolTable::lookupSymbolIn(getModule(), gv.getNameAttr());313 314 if (auto cirGlobalValue =315 dyn_cast<cir::CIRGlobalValueInterface>(globalValueOp))316 if (!cirGlobalValue.isDeclaration())317 return;318 319 // If this is OpenMP, check if it is legal to emit this global normally.320 assert(!cir::MissingFeatures::openMP());321 322 // Otherwise, emit the definition and move on to the next one.323 emitGlobalDefinition(d, op);324}325 326void CIRGenModule::emitDeferred() {327 // Emit code for any potentially referenced deferred decls. Since a previously328 // unused static decl may become used during the generation of code for a329 // static function, iterate until no changes are made.330 331 assert(!cir::MissingFeatures::openMP());332 assert(!cir::MissingFeatures::deferredVtables());333 assert(!cir::MissingFeatures::cudaSupport());334 335 // Stop if we're out of both deferred vtables and deferred declarations.336 if (deferredDeclsToEmit.empty())337 return;338 339 // Grab the list of decls to emit. If emitGlobalDefinition schedules more340 // work, it will not interfere with this.341 std::vector<GlobalDecl> curDeclsToEmit;342 curDeclsToEmit.swap(deferredDeclsToEmit);343 344 for (const GlobalDecl &d : curDeclsToEmit) {345 emitGlobalDecl(d);346 347 // If we found out that we need to emit more decls, do that recursively.348 // This has the advantage that the decls are emitted in a DFS and related349 // ones are close together, which is convenient for testing.350 if (!deferredDeclsToEmit.empty()) {351 emitDeferred();352 assert(deferredDeclsToEmit.empty());353 }354 }355}356 357void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {358 if (const auto *cd = dyn_cast<clang::OpenACCConstructDecl>(gd.getDecl())) {359 emitGlobalOpenACCDecl(cd);360 return;361 }362 363 const auto *global = cast<ValueDecl>(gd.getDecl());364 365 if (const auto *fd = dyn_cast<FunctionDecl>(global)) {366 // Update deferred annotations with the latest declaration if the function367 // was already used or defined.368 if (fd->hasAttr<AnnotateAttr>())369 errorNYI(fd->getSourceRange(), "deferredAnnotations");370 if (!fd->doesThisDeclarationHaveABody()) {371 if (!fd->doesDeclarationForceExternallyVisibleDefinition())372 return;373 374 errorNYI(fd->getSourceRange(),375 "function declaration that forces code gen");376 return;377 }378 } else {379 const auto *vd = cast<VarDecl>(global);380 assert(vd->isFileVarDecl() && "Cannot emit local var decl as global.");381 if (vd->isThisDeclarationADefinition() != VarDecl::Definition &&382 !astContext.isMSStaticDataMemberInlineDefinition(vd)) {383 assert(!cir::MissingFeatures::openMP());384 // If this declaration may have caused an inline variable definition to385 // change linkage, make sure that it's emitted.386 if (astContext.getInlineVariableDefinitionKind(vd) ==387 ASTContext::InlineVariableDefinitionKind::Strong)388 getAddrOfGlobalVar(vd);389 // Otherwise, we can ignore this declaration. The variable will be emitted390 // on its first use.391 return;392 }393 }394 395 // Defer code generation to first use when possible, e.g. if this is an inline396 // function. If the global must always be emitted, do it eagerly if possible397 // to benefit from cache locality. Deferring code generation is necessary to398 // avoid adding initializers to external declarations.399 if (mustBeEmitted(global) && mayBeEmittedEagerly(global)) {400 // Emit the definition if it can't be deferred.401 emitGlobalDefinition(gd);402 return;403 }404 405 // If we're deferring emission of a C++ variable with an initializer, remember406 // the order in which it appeared on the file.407 assert(!cir::MissingFeatures::deferredCXXGlobalInit());408 409 llvm::StringRef mangledName = getMangledName(gd);410 if (getGlobalValue(mangledName) != nullptr) {411 // The value has already been used and should therefore be emitted.412 addDeferredDeclToEmit(gd);413 } else if (mustBeEmitted(global)) {414 // The value must be emitted, but cannot be emitted eagerly.415 assert(!mayBeEmittedEagerly(global));416 addDeferredDeclToEmit(gd);417 } else {418 // Otherwise, remember that we saw a deferred decl with this name. The first419 // use of the mangled name will cause it to move into deferredDeclsToEmit.420 deferredDecls[mangledName] = gd;421 }422}423 424void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,425 mlir::Operation *op) {426 auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());427 const CIRGenFunctionInfo &fi = getTypes().arrangeGlobalDeclaration(gd);428 cir::FuncType funcType = getTypes().getFunctionType(fi);429 cir::FuncOp funcOp = dyn_cast_if_present<cir::FuncOp>(op);430 if (!funcOp || funcOp.getFunctionType() != funcType) {431 funcOp = getAddrOfFunction(gd, funcType, /*ForVTable=*/false,432 /*DontDefer=*/true, ForDefinition);433 }434 435 // Already emitted.436 if (!funcOp.isDeclaration())437 return;438 439 setFunctionLinkage(gd, funcOp);440 setGVProperties(funcOp, funcDecl);441 assert(!cir::MissingFeatures::opFuncMaybeHandleStaticInExternC());442 maybeSetTrivialComdat(*funcDecl, funcOp);443 assert(!cir::MissingFeatures::setLLVMFunctionFEnvAttributes());444 445 CIRGenFunction cgf(*this, builder);446 curCGF = &cgf;447 {448 mlir::OpBuilder::InsertionGuard guard(builder);449 cgf.generateCode(gd, funcOp, funcType);450 }451 curCGF = nullptr;452 453 setNonAliasAttributes(gd, funcOp);454 setCIRFunctionAttributesForDefinition(funcDecl, funcOp);455 456 auto getPriority = [this](const auto *attr) -> int {457 Expr *e = attr->getPriority();458 if (e)459 return e->EvaluateKnownConstInt(this->getASTContext()).getExtValue();460 return attr->DefaultPriority;461 };462 463 if (const ConstructorAttr *ca = funcDecl->getAttr<ConstructorAttr>())464 addGlobalCtor(funcOp, getPriority(ca));465 if (const DestructorAttr *da = funcDecl->getAttr<DestructorAttr>())466 addGlobalDtor(funcOp, getPriority(da));467 468 if (funcDecl->getAttr<AnnotateAttr>())469 errorNYI(funcDecl->getSourceRange(), "deferredAnnotations");470}471 472/// Track functions to be called before main() runs.473void CIRGenModule::addGlobalCtor(cir::FuncOp ctor,474 std::optional<int> priority) {475 assert(!cir::MissingFeatures::globalCtorLexOrder());476 assert(!cir::MissingFeatures::globalCtorAssociatedData());477 478 // Traditional LLVM codegen directly adds the function to the list of global479 // ctors. In CIR we just add a global_ctor attribute to the function. The480 // global list is created in LoweringPrepare.481 //482 // FIXME(from traditional LLVM): Type coercion of void()* types.483 ctor.setGlobalCtorPriority(priority);484}485 486/// Add a function to the list that will be called when the module is unloaded.487void CIRGenModule::addGlobalDtor(cir::FuncOp dtor,488 std::optional<int> priority) {489 if (codeGenOpts.RegisterGlobalDtorsWithAtExit &&490 (!getASTContext().getTargetInfo().getTriple().isOSAIX()))491 errorNYI(dtor.getLoc(), "registerGlobalDtorsWithAtExit");492 493 // FIXME(from traditional LLVM): Type coercion of void()* types.494 dtor.setGlobalDtorPriority(priority);495}496 497void CIRGenModule::handleCXXStaticMemberVarInstantiation(VarDecl *vd) {498 VarDecl::DefinitionKind dk = vd->isThisDeclarationADefinition();499 if (dk == VarDecl::Definition && vd->hasAttr<DLLImportAttr>())500 return;501 502 TemplateSpecializationKind tsk = vd->getTemplateSpecializationKind();503 // If we have a definition, this might be a deferred decl. If the504 // instantiation is explicit, make sure we emit it at the end.505 if (vd->getDefinition() && tsk == TSK_ExplicitInstantiationDefinition)506 getAddrOfGlobalVar(vd);507 508 emitTopLevelDecl(vd);509}510 511mlir::Operation *CIRGenModule::getGlobalValue(StringRef name) {512 return mlir::SymbolTable::lookupSymbolIn(theModule, name);513}514 515cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &cgm,516 mlir::Location loc, StringRef name,517 mlir::Type t, bool isConstant,518 mlir::Operation *insertPoint) {519 cir::GlobalOp g;520 CIRGenBuilderTy &builder = cgm.getBuilder();521 522 {523 mlir::OpBuilder::InsertionGuard guard(builder);524 525 // If an insertion point is provided, we're replacing an existing global,526 // otherwise, create the new global immediately after the last gloabl we527 // emitted.528 if (insertPoint) {529 builder.setInsertionPoint(insertPoint);530 } else {531 // Group global operations together at the top of the module.532 if (cgm.lastGlobalOp)533 builder.setInsertionPointAfter(cgm.lastGlobalOp);534 else535 builder.setInsertionPointToStart(cgm.getModule().getBody());536 }537 538 g = cir::GlobalOp::create(builder, loc, name, t, isConstant);539 if (!insertPoint)540 cgm.lastGlobalOp = g;541 542 // Default to private until we can judge based on the initializer,543 // since MLIR doesn't allow public declarations.544 mlir::SymbolTable::setSymbolVisibility(545 g, mlir::SymbolTable::Visibility::Private);546 }547 return g;548}549 550void CIRGenModule::setCommonAttributes(GlobalDecl gd, mlir::Operation *gv) {551 const Decl *d = gd.getDecl();552 if (isa_and_nonnull<NamedDecl>(d))553 setGVProperties(gv, dyn_cast<NamedDecl>(d));554 assert(!cir::MissingFeatures::defaultVisibility());555 assert(!cir::MissingFeatures::opGlobalUsedOrCompilerUsed());556}557 558void CIRGenModule::setNonAliasAttributes(GlobalDecl gd, mlir::Operation *op) {559 setCommonAttributes(gd, op);560 561 assert(!cir::MissingFeatures::opGlobalUsedOrCompilerUsed());562 assert(!cir::MissingFeatures::opGlobalSection());563 assert(!cir::MissingFeatures::opFuncCPUAndFeaturesAttributes());564 assert(!cir::MissingFeatures::opFuncSection());565 566 assert(!cir::MissingFeatures::setTargetAttributes());567}568 569std::optional<cir::SourceLanguage> CIRGenModule::getCIRSourceLanguage() const {570 using ClangStd = clang::LangStandard;571 using CIRLang = cir::SourceLanguage;572 auto opts = getLangOpts();573 574 if (opts.CPlusPlus)575 return CIRLang::CXX;576 if (opts.C99 || opts.C11 || opts.C17 || opts.C23 || opts.C2y ||577 opts.LangStd == ClangStd::lang_c89 ||578 opts.LangStd == ClangStd::lang_gnu89)579 return CIRLang::C;580 581 // TODO(cir): support remaining source languages.582 assert(!cir::MissingFeatures::sourceLanguageCases());583 errorNYI("CIR does not yet support the given source language");584 return std::nullopt;585}586 587static void setLinkageForGV(cir::GlobalOp &gv, const NamedDecl *nd) {588 // Set linkage and visibility in case we never see a definition.589 LinkageInfo lv = nd->getLinkageAndVisibility();590 // Don't set internal linkage on declarations.591 // "extern_weak" is overloaded in LLVM; we probably should have592 // separate linkage types for this.593 if (isExternallyVisible(lv.getLinkage()) &&594 (nd->hasAttr<WeakAttr>() || nd->isWeakImported()))595 gv.setLinkage(cir::GlobalLinkageKind::ExternalWeakLinkage);596}597 598/// If the specified mangled name is not in the module,599/// create and return an mlir GlobalOp with the specified type (TODO(cir):600/// address space).601///602/// TODO(cir):603/// 1. If there is something in the module with the specified name, return604/// it potentially bitcasted to the right type.605///606/// 2. If \p d is non-null, it specifies a decl that correspond to this. This607/// is used to set the attributes on the global when it is first created.608///609/// 3. If \p isForDefinition is true, it is guaranteed that an actual global610/// with type \p ty will be returned, not conversion of a variable with the same611/// mangled name but some other type.612cir::GlobalOp613CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,614 LangAS langAS, const VarDecl *d,615 ForDefinition_t isForDefinition) {616 // Lookup the entry, lazily creating it if necessary.617 cir::GlobalOp entry;618 if (mlir::Operation *v = getGlobalValue(mangledName)) {619 if (!isa<cir::GlobalOp>(v))620 errorNYI(d->getSourceRange(), "global with non-GlobalOp type");621 entry = cast<cir::GlobalOp>(v);622 }623 624 if (entry) {625 assert(!cir::MissingFeatures::addressSpace());626 assert(!cir::MissingFeatures::opGlobalWeakRef());627 628 assert(!cir::MissingFeatures::setDLLStorageClass());629 assert(!cir::MissingFeatures::openMP());630 631 if (entry.getSymType() == ty)632 return entry;633 634 // If there are two attempts to define the same mangled name, issue an635 // error.636 //637 // TODO(cir): look at mlir::GlobalValue::isDeclaration for all aspects of638 // recognizing the global as a declaration, for now only check if639 // initializer is present.640 if (isForDefinition && !entry.isDeclaration()) {641 errorNYI(d->getSourceRange(), "global with conflicting type");642 }643 644 // Address space check removed because it is unnecessary because CIR records645 // address space info in types.646 647 // (If global is requested for a definition, we always need to create a new648 // global, not just return a bitcast.)649 if (!isForDefinition)650 return entry;651 }652 653 mlir::Location loc = getLoc(d->getSourceRange());654 655 // mlir::SymbolTable::Visibility::Public is the default, no need to explicitly656 // mark it as such.657 cir::GlobalOp gv =658 CIRGenModule::createGlobalOp(*this, loc, mangledName, ty, false,659 /*insertPoint=*/entry.getOperation());660 661 // This is the first use or definition of a mangled name. If there is a662 // deferred decl with this name, remember that we need to emit it at the end663 // of the file.664 auto ddi = deferredDecls.find(mangledName);665 if (ddi != deferredDecls.end()) {666 // Move the potentially referenced deferred decl to the DeferredDeclsToEmit667 // list, and remove it from DeferredDecls (since we don't need it anymore).668 addDeferredDeclToEmit(ddi->second);669 deferredDecls.erase(ddi);670 }671 672 // Handle things which are present even on external declarations.673 if (d) {674 if (langOpts.OpenMP && !langOpts.OpenMPSimd)675 errorNYI(d->getSourceRange(), "OpenMP target global variable");676 677 gv.setAlignmentAttr(getSize(astContext.getDeclAlign(d)));678 // FIXME: This code is overly simple and should be merged with other global679 // handling.680 gv.setConstant(d->getType().isConstantStorage(681 astContext, /*ExcludeCtor=*/false, /*ExcludeDtor=*/false));682 683 setLinkageForGV(gv, d);684 685 if (d->getTLSKind())686 errorNYI(d->getSourceRange(), "thread local global variable");687 688 setGVProperties(gv, d);689 690 // If required by the ABI, treat declarations of static data members with691 // inline initializers as definitions.692 if (astContext.isMSStaticDataMemberInlineDefinition(d))693 errorNYI(d->getSourceRange(), "MS static data member inline definition");694 695 assert(!cir::MissingFeatures::opGlobalSection());696 gv.setGlobalVisibilityAttr(getGlobalVisibilityAttrFromDecl(d));697 698 // Handle XCore specific ABI requirements.699 if (getTriple().getArch() == llvm::Triple::xcore)700 errorNYI(d->getSourceRange(), "XCore specific ABI requirements");701 702 // Check if we a have a const declaration with an initializer, we may be703 // able to emit it as available_externally to expose it's value to the704 // optimizer.705 if (getLangOpts().CPlusPlus && gv.isPublic() &&706 d->getType().isConstQualified() && gv.isDeclaration() &&707 !d->hasDefinition() && d->hasInit() && !d->hasAttr<DLLImportAttr>())708 errorNYI(d->getSourceRange(),709 "external const declaration with initializer");710 }711 712 return gv;713}714 715cir::GlobalOp716CIRGenModule::getOrCreateCIRGlobal(const VarDecl *d, mlir::Type ty,717 ForDefinition_t isForDefinition) {718 assert(d->hasGlobalStorage() && "Not a global variable");719 QualType astTy = d->getType();720 if (!ty)721 ty = getTypes().convertTypeForMem(astTy);722 723 StringRef mangledName = getMangledName(d);724 return getOrCreateCIRGlobal(mangledName, ty, astTy.getAddressSpace(), d,725 isForDefinition);726}727 728/// Return the mlir::Value for the address of the given global variable. If729/// \p ty is non-null and if the global doesn't exist, then it will be created730/// with the specified type instead of whatever the normal requested type would731/// be. If \p isForDefinition is true, it is guaranteed that an actual global732/// with type \p ty will be returned, not conversion of a variable with the same733/// mangled name but some other type.734mlir::Value CIRGenModule::getAddrOfGlobalVar(const VarDecl *d, mlir::Type ty,735 ForDefinition_t isForDefinition) {736 assert(d->hasGlobalStorage() && "Not a global variable");737 QualType astTy = d->getType();738 if (!ty)739 ty = getTypes().convertTypeForMem(astTy);740 741 assert(!cir::MissingFeatures::opGlobalThreadLocal());742 743 cir::GlobalOp g = getOrCreateCIRGlobal(d, ty, isForDefinition);744 mlir::Type ptrTy = builder.getPointerTo(g.getSymType());745 return cir::GetGlobalOp::create(builder, getLoc(d->getSourceRange()), ptrTy,746 g.getSymName());747}748 749cir::GlobalViewAttr CIRGenModule::getAddrOfGlobalVarAttr(const VarDecl *d) {750 assert(d->hasGlobalStorage() && "Not a global variable");751 mlir::Type ty = getTypes().convertTypeForMem(d->getType());752 753 cir::GlobalOp globalOp = getOrCreateCIRGlobal(d, ty, NotForDefinition);754 assert(!cir::MissingFeatures::addressSpace());755 cir::PointerType ptrTy = builder.getPointerTo(globalOp.getSymType());756 return builder.getGlobalViewAttr(ptrTy, globalOp);757}758 759void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,760 bool isTentative) {761 if (getLangOpts().OpenCL || getLangOpts().OpenMPIsTargetDevice) {762 errorNYI(vd->getSourceRange(), "emit OpenCL/OpenMP global variable");763 return;764 }765 766 // Whether the definition of the variable is available externally.767 // If yes, we shouldn't emit the GloablCtor and GlobalDtor for the variable768 // since this is the job for its original source.769 bool isDefinitionAvailableExternally =770 astContext.GetGVALinkageForVariable(vd) == GVA_AvailableExternally;771 772 // It is useless to emit the definition for an available_externally variable773 // which can't be marked as const.774 if (isDefinitionAvailableExternally &&775 (!vd->hasConstantInitialization() ||776 // TODO: Update this when we have interface to check constexpr777 // destructor.778 vd->needsDestruction(astContext) ||779 !vd->getType().isConstantStorage(astContext, true, true)))780 return;781 782 mlir::Attribute init;783 bool needsGlobalCtor = false;784 bool needsGlobalDtor =785 !isDefinitionAvailableExternally &&786 vd->needsDestruction(astContext) == QualType::DK_cxx_destructor;787 const VarDecl *initDecl;788 const Expr *initExpr = vd->getAnyInitializer(initDecl);789 790 std::optional<ConstantEmitter> emitter;791 792 assert(!cir::MissingFeatures::cudaSupport());793 794 if (vd->hasAttr<LoaderUninitializedAttr>()) {795 errorNYI(vd->getSourceRange(), "loader uninitialized attribute");796 return;797 } else if (!initExpr) {798 // This is a tentative definition; tentative definitions are799 // implicitly initialized with { 0 }.800 //801 // Note that tentative definitions are only emitted at the end of802 // a translation unit, so they should never have incomplete803 // type. In addition, EmitTentativeDefinition makes sure that we804 // never attempt to emit a tentative definition if a real one805 // exists. A use may still exists, however, so we still may need806 // to do a RAUW.807 assert(!vd->getType()->isIncompleteType() && "Unexpected incomplete type");808 init = builder.getZeroInitAttr(convertType(vd->getType()));809 } else {810 emitter.emplace(*this);811 mlir::Attribute initializer = emitter->tryEmitForInitializer(*initDecl);812 if (!initializer) {813 QualType qt = initExpr->getType();814 if (vd->getType()->isReferenceType())815 qt = vd->getType();816 817 if (getLangOpts().CPlusPlus) {818 if (initDecl->hasFlexibleArrayInit(astContext))819 errorNYI(vd->getSourceRange(), "flexible array initializer");820 init = builder.getZeroInitAttr(convertType(qt));821 if (!isDefinitionAvailableExternally)822 needsGlobalCtor = true;823 } else {824 errorNYI(vd->getSourceRange(), "static initializer");825 }826 } else {827 init = initializer;828 // We don't need an initializer, so remove the entry for the delayed829 // initializer position (just in case this entry was delayed) if we830 // also don't need to register a destructor.831 assert(!cir::MissingFeatures::deferredCXXGlobalInit());832 }833 }834 835 mlir::Type initType;836 if (mlir::isa<mlir::SymbolRefAttr>(init)) {837 errorNYI(vd->getSourceRange(), "global initializer is a symbol reference");838 return;839 } else {840 assert(mlir::isa<mlir::TypedAttr>(init) && "This should have a type");841 auto typedInitAttr = mlir::cast<mlir::TypedAttr>(init);842 initType = typedInitAttr.getType();843 }844 assert(!mlir::isa<mlir::NoneType>(initType) && "Should have a type by now");845 846 cir::GlobalOp gv =847 getOrCreateCIRGlobal(vd, initType, ForDefinition_t(!isTentative));848 // TODO(cir): Strip off pointer casts from Entry if we get them?849 850 if (!gv || gv.getSymType() != initType) {851 errorNYI(vd->getSourceRange(), "global initializer with type mismatch");852 return;853 }854 855 assert(!cir::MissingFeatures::maybeHandleStaticInExternC());856 857 if (vd->hasAttr<AnnotateAttr>()) {858 errorNYI(vd->getSourceRange(), "annotate global variable");859 }860 861 if (langOpts.CUDA) {862 errorNYI(vd->getSourceRange(), "CUDA global variable");863 }864 865 // Set initializer and finalize emission866 CIRGenModule::setInitializer(gv, init);867 if (emitter)868 emitter->finalize(gv);869 870 // If it is safe to mark the global 'constant', do so now.871 gv.setConstant((vd->hasAttr<CUDAConstantAttr>() && langOpts.CUDAIsDevice) ||872 (!needsGlobalCtor && !needsGlobalDtor &&873 vd->getType().isConstantStorage(874 astContext, /*ExcludeCtor=*/true, /*ExcludeDtor=*/true)));875 assert(!cir::MissingFeatures::opGlobalSection());876 877 // Set CIR's linkage type as appropriate.878 cir::GlobalLinkageKind linkage =879 getCIRLinkageVarDefinition(vd, /*IsConstant=*/false);880 881 // Set CIR linkage and DLL storage class.882 gv.setLinkage(linkage);883 // FIXME(cir): setLinkage should likely set MLIR's visibility automatically.884 gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));885 assert(!cir::MissingFeatures::opGlobalDLLImportExport());886 if (linkage == cir::GlobalLinkageKind::CommonLinkage) {887 // common vars aren't constant even if declared const.888 gv.setConstant(false);889 // Tentative definition of global variables may be initialized with890 // non-zero null pointers. In this case they should have weak linkage891 // since common linkage must have zero initializer and must not have892 // explicit section therefore cannot have non-zero initial value.893 std::optional<mlir::Attribute> initializer = gv.getInitialValue();894 if (initializer && !getBuilder().isNullValue(*initializer))895 gv.setLinkage(cir::GlobalLinkageKind::WeakAnyLinkage);896 }897 898 setNonAliasAttributes(vd, gv);899 900 assert(!cir::MissingFeatures::opGlobalThreadLocal());901 902 maybeSetTrivialComdat(*vd, gv);903 904 // Emit the initializer function if necessary.905 if (needsGlobalCtor || needsGlobalDtor)906 emitCXXGlobalVarDeclInitFunc(vd, gv, needsGlobalCtor);907}908 909void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,910 mlir::Operation *op) {911 const auto *decl = cast<ValueDecl>(gd.getDecl());912 if (const auto *fd = dyn_cast<FunctionDecl>(decl)) {913 // TODO(CIR): Skip generation of CIR for functions with available_externally914 // linkage at -O0.915 916 if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) {917 // Make sure to emit the definition(s) before we emit the thunks. This is918 // necessary for the generation of certain thunks.919 if (isa<CXXConstructorDecl>(method) || isa<CXXDestructorDecl>(method))920 abi->emitCXXStructor(gd);921 else if (fd->isMultiVersion())922 errorNYI(method->getSourceRange(), "multiversion functions");923 else924 emitGlobalFunctionDefinition(gd, op);925 926 if (method->isVirtual())927 getVTables().emitThunks(gd);928 929 return;930 }931 932 if (fd->isMultiVersion())933 errorNYI(fd->getSourceRange(), "multiversion functions");934 emitGlobalFunctionDefinition(gd, op);935 return;936 }937 938 if (const auto *vd = dyn_cast<VarDecl>(decl))939 return emitGlobalVarDefinition(vd, !vd->hasDefinition());940 941 llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");942}943 944mlir::Attribute945CIRGenModule::getConstantArrayFromStringLiteral(const StringLiteral *e) {946 assert(!e->getType()->isPointerType() && "Strings are always arrays");947 948 // Don't emit it as the address of the string, emit the string data itself949 // as an inline array.950 if (e->getCharByteWidth() == 1) {951 SmallString<64> str(e->getString());952 953 // Resize the string to the right size, which is indicated by its type.954 const ConstantArrayType *cat =955 astContext.getAsConstantArrayType(e->getType());956 uint64_t finalSize = cat->getZExtSize();957 str.resize(finalSize);958 959 mlir::Type eltTy = convertType(cat->getElementType());960 return builder.getString(str, eltTy, finalSize);961 }962 963 errorNYI(e->getSourceRange(),964 "getConstantArrayFromStringLiteral: wide characters");965 return mlir::Attribute();966}967 968bool CIRGenModule::supportsCOMDAT() const {969 return getTriple().supportsCOMDAT();970}971 972static bool shouldBeInCOMDAT(CIRGenModule &cgm, const Decl &d) {973 if (!cgm.supportsCOMDAT())974 return false;975 976 if (d.hasAttr<SelectAnyAttr>())977 return true;978 979 GVALinkage linkage;980 if (auto *vd = dyn_cast<VarDecl>(&d))981 linkage = cgm.getASTContext().GetGVALinkageForVariable(vd);982 else983 linkage =984 cgm.getASTContext().GetGVALinkageForFunction(cast<FunctionDecl>(&d));985 986 switch (linkage) {987 case clang::GVA_Internal:988 case clang::GVA_AvailableExternally:989 case clang::GVA_StrongExternal:990 return false;991 case clang::GVA_DiscardableODR:992 case clang::GVA_StrongODR:993 return true;994 }995 llvm_unreachable("No such linkage");996}997 998void CIRGenModule::maybeSetTrivialComdat(const Decl &d, mlir::Operation *op) {999 if (!shouldBeInCOMDAT(*this, d))1000 return;1001 if (auto globalOp = dyn_cast_or_null<cir::GlobalOp>(op)) {1002 globalOp.setComdat(true);1003 } else {1004 auto funcOp = cast<cir::FuncOp>(op);1005 funcOp.setComdat(true);1006 }1007}1008 1009void CIRGenModule::updateCompletedType(const TagDecl *td) {1010 // Make sure that this type is translated.1011 genTypes.updateCompletedType(td);1012}1013 1014void CIRGenModule::addReplacement(StringRef name, mlir::Operation *op) {1015 replacements[name] = op;1016}1017 1018void CIRGenModule::replacePointerTypeArgs(cir::FuncOp oldF, cir::FuncOp newF) {1019 std::optional<mlir::SymbolTable::UseRange> optionalUseRange =1020 oldF.getSymbolUses(theModule);1021 if (!optionalUseRange)1022 return;1023 1024 for (const mlir::SymbolTable::SymbolUse &u : *optionalUseRange) {1025 // CallTryOp only shows up after FlattenCFG.1026 auto call = mlir::dyn_cast<cir::CallOp>(u.getUser());1027 if (!call)1028 continue;1029 1030 for (const auto [argOp, fnArgType] :1031 llvm::zip(call.getArgs(), newF.getFunctionType().getInputs())) {1032 if (argOp.getType() == fnArgType)1033 continue;1034 1035 // The purpose of this entire function is to insert bitcasts in the case1036 // where these types don't match, but I haven't seen a case where that1037 // happens.1038 errorNYI(call.getLoc(), "replace call with mismatched types");1039 }1040 }1041}1042 1043void CIRGenModule::applyReplacements() {1044 for (auto &i : replacements) {1045 StringRef mangledName = i.first();1046 mlir::Operation *replacement = i.second;1047 mlir::Operation *entry = getGlobalValue(mangledName);1048 if (!entry)1049 continue;1050 assert(isa<cir::FuncOp>(entry) && "expected function");1051 auto oldF = cast<cir::FuncOp>(entry);1052 auto newF = dyn_cast<cir::FuncOp>(replacement);1053 if (!newF) {1054 // In classic codegen, this can be a global alias, a bitcast, or a GEP.1055 errorNYI(replacement->getLoc(), "replacement is not a function");1056 continue;1057 }1058 1059 // LLVM has opaque pointer but CIR not. So we may have to handle these1060 // different pointer types when performing replacement.1061 replacePointerTypeArgs(oldF, newF);1062 1063 // Replace old with new, but keep the old order.1064 if (oldF.replaceAllSymbolUses(newF.getSymNameAttr(), theModule).failed())1065 llvm_unreachable("internal error, cannot RAUW symbol");1066 if (newF) {1067 newF->moveBefore(oldF);1068 oldF->erase();1069 }1070 }1071}1072 1073cir::GlobalOp CIRGenModule::createOrReplaceCXXRuntimeVariable(1074 mlir::Location loc, StringRef name, mlir::Type ty,1075 cir::GlobalLinkageKind linkage, clang::CharUnits alignment) {1076 auto gv = mlir::dyn_cast_or_null<cir::GlobalOp>(1077 mlir::SymbolTable::lookupSymbolIn(theModule, name));1078 1079 if (gv) {1080 // Check if the variable has the right type.1081 if (gv.getSymType() == ty)1082 return gv;1083 1084 // Because of C++ name mangling, the only way we can end up with an already1085 // existing global with the same name is if it has been declared extern1086 // "C".1087 assert(gv.isDeclaration() && "Declaration has wrong type!");1088 1089 errorNYI(loc, "createOrReplaceCXXRuntimeVariable: declaration exists with "1090 "wrong type");1091 return gv;1092 }1093 1094 // Create a new variable.1095 gv = createGlobalOp(*this, loc, name, ty);1096 1097 // Set up extra information and add to the module1098 gv.setLinkageAttr(1099 cir::GlobalLinkageKindAttr::get(&getMLIRContext(), linkage));1100 mlir::SymbolTable::setSymbolVisibility(gv,1101 CIRGenModule::getMLIRVisibility(gv));1102 1103 if (supportsCOMDAT() && cir::isWeakForLinker(linkage) &&1104 !gv.hasAvailableExternallyLinkage()) {1105 gv.setComdat(true);1106 }1107 1108 gv.setAlignmentAttr(getSize(alignment));1109 setDSOLocal(static_cast<mlir::Operation *>(gv));1110 return gv;1111}1112 1113// TODO(CIR): this could be a common method between LLVM codegen.1114static bool isVarDeclStrongDefinition(const ASTContext &astContext,1115 CIRGenModule &cgm, const VarDecl *vd,1116 bool noCommon) {1117 // Don't give variables common linkage if -fno-common was specified unless it1118 // was overridden by a NoCommon attribute.1119 if ((noCommon || vd->hasAttr<NoCommonAttr>()) && !vd->hasAttr<CommonAttr>())1120 return true;1121 1122 // C11 6.9.2/2:1123 // A declaration of an identifier for an object that has file scope without1124 // an initializer, and without a storage-class specifier or with the1125 // storage-class specifier static, constitutes a tentative definition.1126 if (vd->getInit() || vd->hasExternalStorage())1127 return true;1128 1129 // A variable cannot be both common and exist in a section.1130 if (vd->hasAttr<SectionAttr>())1131 return true;1132 1133 // A variable cannot be both common and exist in a section.1134 // We don't try to determine which is the right section in the front-end.1135 // If no specialized section name is applicable, it will resort to default.1136 if (vd->hasAttr<PragmaClangBSSSectionAttr>() ||1137 vd->hasAttr<PragmaClangDataSectionAttr>() ||1138 vd->hasAttr<PragmaClangRelroSectionAttr>() ||1139 vd->hasAttr<PragmaClangRodataSectionAttr>())1140 return true;1141 1142 // Thread local vars aren't considered common linkage.1143 if (vd->getTLSKind())1144 return true;1145 1146 // Tentative definitions marked with WeakImportAttr are true definitions.1147 if (vd->hasAttr<WeakImportAttr>())1148 return true;1149 1150 // A variable cannot be both common and exist in a comdat.1151 if (shouldBeInCOMDAT(cgm, *vd))1152 return true;1153 1154 // Declarations with a required alignment do not have common linkage in MSVC1155 // mode.1156 if (astContext.getTargetInfo().getCXXABI().isMicrosoft()) {1157 if (vd->hasAttr<AlignedAttr>())1158 return true;1159 QualType varType = vd->getType();1160 if (astContext.isAlignmentRequired(varType))1161 return true;1162 1163 if (const auto *rd = varType->getAsRecordDecl()) {1164 for (const FieldDecl *fd : rd->fields()) {1165 if (fd->isBitField())1166 continue;1167 if (fd->hasAttr<AlignedAttr>())1168 return true;1169 if (astContext.isAlignmentRequired(fd->getType()))1170 return true;1171 }1172 }1173 }1174 1175 // Microsoft's link.exe doesn't support alignments greater than 32 bytes for1176 // common symbols, so symbols with greater alignment requirements cannot be1177 // common.1178 // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two1179 // alignments for common symbols via the aligncomm directive, so this1180 // restriction only applies to MSVC environments.1181 if (astContext.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() &&1182 astContext.getTypeAlignIfKnown(vd->getType()) >1183 astContext.toBits(CharUnits::fromQuantity(32)))1184 return true;1185 1186 return false;1187}1188 1189cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator(1190 const DeclaratorDecl *dd, GVALinkage linkage, bool isConstantVariable) {1191 if (linkage == GVA_Internal)1192 return cir::GlobalLinkageKind::InternalLinkage;1193 1194 if (dd->hasAttr<WeakAttr>()) {1195 if (isConstantVariable)1196 return cir::GlobalLinkageKind::WeakODRLinkage;1197 return cir::GlobalLinkageKind::WeakAnyLinkage;1198 }1199 1200 if (const auto *fd = dd->getAsFunction())1201 if (fd->isMultiVersion() && linkage == GVA_AvailableExternally)1202 return cir::GlobalLinkageKind::LinkOnceAnyLinkage;1203 1204 // We are guaranteed to have a strong definition somewhere else,1205 // so we can use available_externally linkage.1206 if (linkage == GVA_AvailableExternally)1207 return cir::GlobalLinkageKind::AvailableExternallyLinkage;1208 1209 // Note that Apple's kernel linker doesn't support symbol1210 // coalescing, so we need to avoid linkonce and weak linkages there.1211 // Normally, this means we just map to internal, but for explicit1212 // instantiations we'll map to external.1213 1214 // In C++, the compiler has to emit a definition in every translation unit1215 // that references the function. We should use linkonce_odr because1216 // a) if all references in this translation unit are optimized away, we1217 // don't need to codegen it. b) if the function persists, it needs to be1218 // merged with other definitions. c) C++ has the ODR, so we know the1219 // definition is dependable.1220 if (linkage == GVA_DiscardableODR)1221 return !astContext.getLangOpts().AppleKext1222 ? cir::GlobalLinkageKind::LinkOnceODRLinkage1223 : cir::GlobalLinkageKind::InternalLinkage;1224 1225 // An explicit instantiation of a template has weak linkage, since1226 // explicit instantiations can occur in multiple translation units1227 // and must all be equivalent. However, we are not allowed to1228 // throw away these explicit instantiations.1229 //1230 // CUDA/HIP: For -fno-gpu-rdc case, device code is limited to one TU,1231 // so say that CUDA templates are either external (for kernels) or internal.1232 // This lets llvm perform aggressive inter-procedural optimizations. For1233 // -fgpu-rdc case, device function calls across multiple TU's are allowed,1234 // therefore we need to follow the normal linkage paradigm.1235 if (linkage == GVA_StrongODR) {1236 if (getLangOpts().AppleKext)1237 return cir::GlobalLinkageKind::ExternalLinkage;1238 if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&1239 !getLangOpts().GPURelocatableDeviceCode)1240 return dd->hasAttr<CUDAGlobalAttr>()1241 ? cir::GlobalLinkageKind::ExternalLinkage1242 : cir::GlobalLinkageKind::InternalLinkage;1243 return cir::GlobalLinkageKind::WeakODRLinkage;1244 }1245 1246 // C++ doesn't have tentative definitions and thus cannot have common1247 // linkage.1248 if (!getLangOpts().CPlusPlus && isa<VarDecl>(dd) &&1249 !isVarDeclStrongDefinition(astContext, *this, cast<VarDecl>(dd),1250 getCodeGenOpts().NoCommon))1251 return cir::GlobalLinkageKind::CommonLinkage;1252 1253 // selectany symbols are externally visible, so use weak instead of1254 // linkonce. MSVC optimizes away references to const selectany globals, so1255 // all definitions should be the same and ODR linkage should be used.1256 // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx1257 if (dd->hasAttr<SelectAnyAttr>())1258 return cir::GlobalLinkageKind::WeakODRLinkage;1259 1260 // Otherwise, we have strong external linkage.1261 assert(linkage == GVA_StrongExternal);1262 return cir::GlobalLinkageKind::ExternalLinkage;1263}1264 1265/// This function is called when we implement a function with no prototype, e.g.1266/// "int foo() {}". If there are existing call uses of the old function in the1267/// module, this adjusts them to call the new function directly.1268///1269/// This is not just a cleanup: the always_inline pass requires direct calls to1270/// functions to be able to inline them. If there is a bitcast in the way, it1271/// won't inline them. Instcombine normally deletes these calls, but it isn't1272/// run at -O0.1273void CIRGenModule::replaceUsesOfNonProtoTypeWithRealFunction(1274 mlir::Operation *old, cir::FuncOp newFn) {1275 // If we're redefining a global as a function, don't transform it.1276 auto oldFn = mlir::dyn_cast<cir::FuncOp>(old);1277 if (!oldFn)1278 return;1279 1280 // TODO(cir): this RAUW ignores the features below.1281 assert(!cir::MissingFeatures::opFuncExceptions());1282 assert(!cir::MissingFeatures::opFuncParameterAttributes());1283 assert(!cir::MissingFeatures::opFuncOperandBundles());1284 if (oldFn->getAttrs().size() <= 1)1285 errorNYI(old->getLoc(),1286 "replaceUsesOfNonProtoTypeWithRealFunction: Attribute forwarding");1287 1288 // Mark new function as originated from a no-proto declaration.1289 newFn.setNoProto(oldFn.getNoProto());1290 1291 // Iterate through all calls of the no-proto function.1292 std::optional<mlir::SymbolTable::UseRange> symUses =1293 oldFn.getSymbolUses(oldFn->getParentOp());1294 for (const mlir::SymbolTable::SymbolUse &use : symUses.value()) {1295 mlir::OpBuilder::InsertionGuard guard(builder);1296 1297 if (auto noProtoCallOp = mlir::dyn_cast<cir::CallOp>(use.getUser())) {1298 builder.setInsertionPoint(noProtoCallOp);1299 1300 // Patch call type with the real function type.1301 cir::CallOp realCallOp = builder.createCallOp(1302 noProtoCallOp.getLoc(), newFn, noProtoCallOp.getOperands());1303 1304 // Replace old no proto call with fixed call.1305 noProtoCallOp.replaceAllUsesWith(realCallOp);1306 noProtoCallOp.erase();1307 } else if (auto getGlobalOp =1308 mlir::dyn_cast<cir::GetGlobalOp>(use.getUser())) {1309 // Replace type1310 getGlobalOp.getAddr().setType(1311 cir::PointerType::get(newFn.getFunctionType()));1312 } else {1313 errorNYI(use.getUser()->getLoc(),1314 "replaceUsesOfNonProtoTypeWithRealFunction: unexpected use");1315 }1316 }1317}1318 1319cir::GlobalLinkageKind1320CIRGenModule::getCIRLinkageVarDefinition(const VarDecl *vd, bool isConstant) {1321 assert(!isConstant && "constant variables NYI");1322 GVALinkage linkage = astContext.GetGVALinkageForVariable(vd);1323 return getCIRLinkageForDeclarator(vd, linkage, isConstant);1324}1325 1326cir::GlobalLinkageKind CIRGenModule::getFunctionLinkage(GlobalDecl gd) {1327 const auto *d = cast<FunctionDecl>(gd.getDecl());1328 1329 GVALinkage linkage = astContext.GetGVALinkageForFunction(d);1330 1331 if (const auto *dtor = dyn_cast<CXXDestructorDecl>(d))1332 return getCXXABI().getCXXDestructorLinkage(linkage, dtor, gd.getDtorType());1333 1334 return getCIRLinkageForDeclarator(d, linkage, /*isConstantVariable=*/false);1335}1336 1337static cir::GlobalOp1338generateStringLiteral(mlir::Location loc, mlir::TypedAttr c,1339 cir::GlobalLinkageKind lt, CIRGenModule &cgm,1340 StringRef globalName, CharUnits alignment) {1341 assert(!cir::MissingFeatures::addressSpace());1342 1343 // Create a global variable for this string1344 // FIXME(cir): check for insertion point in module level.1345 cir::GlobalOp gv = CIRGenModule::createGlobalOp(1346 cgm, loc, globalName, c.getType(), !cgm.getLangOpts().WritableStrings);1347 1348 // Set up extra information and add to the module1349 gv.setAlignmentAttr(cgm.getSize(alignment));1350 gv.setLinkageAttr(1351 cir::GlobalLinkageKindAttr::get(cgm.getBuilder().getContext(), lt));1352 assert(!cir::MissingFeatures::opGlobalThreadLocal());1353 assert(!cir::MissingFeatures::opGlobalUnnamedAddr());1354 CIRGenModule::setInitializer(gv, c);1355 if (gv.isWeakForLinker()) {1356 assert(cgm.supportsCOMDAT() && "Only COFF uses weak string literals");1357 gv.setComdat(true);1358 }1359 cgm.setDSOLocal(static_cast<mlir::Operation *>(gv));1360 return gv;1361}1362 1363// LLVM IR automatically uniques names when new llvm::GlobalVariables are1364// created. This is handy, for example, when creating globals for string1365// literals. Since we don't do that when creating cir::GlobalOp's, we need1366// a mechanism to generate a unique name in advance.1367//1368// For now, this mechanism is only used in cases where we know that the1369// name is compiler-generated, so we don't use the MLIR symbol table for1370// the lookup.1371std::string CIRGenModule::getUniqueGlobalName(const std::string &baseName) {1372 // If this is the first time we've generated a name for this basename, use1373 // it as is and start a counter for this base name.1374 auto it = cgGlobalNames.find(baseName);1375 if (it == cgGlobalNames.end()) {1376 cgGlobalNames[baseName] = 1;1377 return baseName;1378 }1379 1380 std::string result =1381 baseName + "." + std::to_string(cgGlobalNames[baseName]++);1382 // There should not be any symbol with this name in the module.1383 assert(!mlir::SymbolTable::lookupSymbolIn(theModule, result));1384 return result;1385}1386 1387/// Return a pointer to a constant array for the given string literal.1388cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s,1389 StringRef name) {1390 CharUnits alignment =1391 astContext.getAlignOfGlobalVarInChars(s->getType(), /*VD=*/nullptr);1392 1393 mlir::Attribute c = getConstantArrayFromStringLiteral(s);1394 1395 cir::GlobalOp gv;1396 if (!getLangOpts().WritableStrings && constantStringMap.count(c)) {1397 gv = constantStringMap[c];1398 // The bigger alignment always wins.1399 if (!gv.getAlignment() ||1400 uint64_t(alignment.getQuantity()) > *gv.getAlignment())1401 gv.setAlignmentAttr(getSize(alignment));1402 } else {1403 // Mangle the string literal if that's how the ABI merges duplicate strings.1404 // Don't do it if they are writable, since we don't want writes in one TU to1405 // affect strings in another.1406 if (getCXXABI().getMangleContext().shouldMangleStringLiteral(s) &&1407 !getLangOpts().WritableStrings) {1408 errorNYI(s->getSourceRange(),1409 "getGlobalForStringLiteral: mangle string literals");1410 }1411 1412 // Unlike LLVM IR, CIR doesn't automatically unique names for globals, so1413 // we need to do that explicitly.1414 std::string uniqueName = getUniqueGlobalName(name.str());1415 mlir::Location loc = getLoc(s->getSourceRange());1416 auto typedC = llvm::cast<mlir::TypedAttr>(c);1417 gv = generateStringLiteral(loc, typedC,1418 cir::GlobalLinkageKind::PrivateLinkage, *this,1419 uniqueName, alignment);1420 setDSOLocal(static_cast<mlir::Operation *>(gv));1421 constantStringMap[c] = gv;1422 1423 assert(!cir::MissingFeatures::sanitizers());1424 }1425 return gv;1426}1427 1428/// Return a pointer to a constant array for the given string literal.1429cir::GlobalViewAttr1430CIRGenModule::getAddrOfConstantStringFromLiteral(const StringLiteral *s,1431 StringRef name) {1432 cir::GlobalOp gv = getGlobalForStringLiteral(s, name);1433 auto arrayTy = mlir::dyn_cast<cir::ArrayType>(gv.getSymType());1434 assert(arrayTy && "String literal must be array");1435 assert(!cir::MissingFeatures::addressSpace());1436 cir::PointerType ptrTy = getBuilder().getPointerTo(arrayTy.getElementType());1437 1438 return builder.getGlobalViewAttr(ptrTy, gv);1439}1440 1441// TODO(cir): this could be a common AST helper for both CIR and LLVM codegen.1442LangAS CIRGenModule::getLangTempAllocaAddressSpace() const {1443 if (getLangOpts().OpenCL)1444 return LangAS::opencl_private;1445 1446 // For temporaries inside functions, CUDA treats them as normal variables.1447 // LangAS::cuda_device, on the other hand, is reserved for those variables1448 // explicitly marked with __device__.1449 if (getLangOpts().CUDAIsDevice)1450 return LangAS::Default;1451 1452 if (getLangOpts().SYCLIsDevice ||1453 (getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice))1454 errorNYI("SYCL or OpenMP temp address space");1455 return LangAS::Default;1456}1457 1458void CIRGenModule::emitExplicitCastExprType(const ExplicitCastExpr *e,1459 CIRGenFunction *cgf) {1460 if (cgf && e->getType()->isVariablyModifiedType())1461 cgf->emitVariablyModifiedType(e->getType());1462 1463 assert(!cir::MissingFeatures::generateDebugInfo() &&1464 "emitExplicitCastExprType");1465}1466 1467void CIRGenModule::emitDeclContext(const DeclContext *dc) {1468 for (Decl *decl : dc->decls()) {1469 // Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope1470 // are themselves considered "top-level", so EmitTopLevelDecl on an1471 // ObjCImplDecl does not recursively visit them. We need to do that in1472 // case they're nested inside another construct (LinkageSpecDecl /1473 // ExportDecl) that does stop them from being considered "top-level".1474 if (auto *oid = dyn_cast<ObjCImplDecl>(decl))1475 errorNYI(oid->getSourceRange(), "emitDeclConext: ObjCImplDecl");1476 1477 emitTopLevelDecl(decl);1478 }1479}1480 1481// Emit code for a single top level declaration.1482void CIRGenModule::emitTopLevelDecl(Decl *decl) {1483 1484 // Ignore dependent declarations.1485 if (decl->isTemplated())1486 return;1487 1488 switch (decl->getKind()) {1489 default:1490 errorNYI(decl->getBeginLoc(), "declaration of kind",1491 decl->getDeclKindName());1492 break;1493 1494 case Decl::CXXConversion:1495 case Decl::CXXMethod:1496 case Decl::Function: {1497 auto *fd = cast<FunctionDecl>(decl);1498 // Consteval functions shouldn't be emitted.1499 if (!fd->isConsteval())1500 emitGlobal(fd);1501 break;1502 }1503 1504 case Decl::Var:1505 case Decl::Decomposition:1506 case Decl::VarTemplateSpecialization: {1507 auto *vd = cast<VarDecl>(decl);1508 if (isa<DecompositionDecl>(decl)) {1509 errorNYI(decl->getSourceRange(), "global variable decompositions");1510 break;1511 }1512 emitGlobal(vd);1513 break;1514 }1515 case Decl::OpenACCRoutine:1516 emitGlobalOpenACCRoutineDecl(cast<OpenACCRoutineDecl>(decl));1517 break;1518 case Decl::OpenACCDeclare:1519 emitGlobalOpenACCDeclareDecl(cast<OpenACCDeclareDecl>(decl));1520 break;1521 case Decl::Enum:1522 case Decl::Using: // using X; [C++]1523 case Decl::UsingDirective: // using namespace X; [C++]1524 case Decl::UsingEnum: // using enum X; [C++]1525 case Decl::NamespaceAlias:1526 case Decl::Typedef:1527 case Decl::TypeAlias: // using foo = bar; [C++11]1528 case Decl::Record:1529 assert(!cir::MissingFeatures::generateDebugInfo());1530 break;1531 1532 // No code generation needed.1533 case Decl::ClassTemplate:1534 case Decl::Concept:1535 case Decl::CXXDeductionGuide:1536 case Decl::Empty:1537 case Decl::FunctionTemplate:1538 case Decl::StaticAssert:1539 case Decl::TypeAliasTemplate:1540 case Decl::UsingShadow:1541 case Decl::VarTemplate:1542 case Decl::VarTemplatePartialSpecialization:1543 break;1544 1545 case Decl::CXXConstructor:1546 getCXXABI().emitCXXConstructors(cast<CXXConstructorDecl>(decl));1547 break;1548 case Decl::CXXDestructor:1549 getCXXABI().emitCXXDestructors(cast<CXXDestructorDecl>(decl));1550 break;1551 1552 // C++ Decls1553 case Decl::LinkageSpec:1554 case Decl::Namespace:1555 emitDeclContext(Decl::castToDeclContext(decl));1556 break;1557 1558 case Decl::ClassTemplateSpecialization:1559 case Decl::CXXRecord: {1560 CXXRecordDecl *crd = cast<CXXRecordDecl>(decl);1561 assert(!cir::MissingFeatures::generateDebugInfo());1562 for (auto *childDecl : crd->decls())1563 if (isa<VarDecl, CXXRecordDecl, EnumDecl, OpenACCDeclareDecl>(childDecl))1564 emitTopLevelDecl(childDecl);1565 break;1566 }1567 1568 case Decl::FileScopeAsm:1569 // File-scope asm is ignored during device-side CUDA compilation.1570 if (langOpts.CUDA && langOpts.CUDAIsDevice)1571 break;1572 // File-scope asm is ignored during device-side OpenMP compilation.1573 if (langOpts.OpenMPIsTargetDevice)1574 break;1575 // File-scope asm is ignored during device-side SYCL compilation.1576 if (langOpts.SYCLIsDevice)1577 break;1578 auto *file_asm = cast<FileScopeAsmDecl>(decl);1579 std::string line = file_asm->getAsmString();1580 globalScopeAsm.push_back(builder.getStringAttr(line));1581 break;1582 }1583}1584 1585void CIRGenModule::setInitializer(cir::GlobalOp &op, mlir::Attribute value) {1586 // Recompute visibility when updating initializer.1587 op.setInitialValueAttr(value);1588 assert(!cir::MissingFeatures::opGlobalVisibility());1589}1590 1591std::pair<cir::FuncType, cir::FuncOp> CIRGenModule::getAddrAndTypeOfCXXStructor(1592 GlobalDecl gd, const CIRGenFunctionInfo *fnInfo, cir::FuncType fnType,1593 bool dontDefer, ForDefinition_t isForDefinition) {1594 auto *md = cast<CXXMethodDecl>(gd.getDecl());1595 1596 if (isa<CXXDestructorDecl>(md)) {1597 // Always alias equivalent complete destructors to base destructors in the1598 // MS ABI.1599 if (getTarget().getCXXABI().isMicrosoft() &&1600 gd.getDtorType() == Dtor_Complete &&1601 md->getParent()->getNumVBases() == 0)1602 errorNYI(md->getSourceRange(),1603 "getAddrAndTypeOfCXXStructor: MS ABI complete destructor");1604 }1605 1606 if (!fnType) {1607 if (!fnInfo)1608 fnInfo = &getTypes().arrangeCXXStructorDeclaration(gd);1609 fnType = getTypes().getFunctionType(*fnInfo);1610 }1611 1612 auto fn = getOrCreateCIRFunction(getMangledName(gd), fnType, gd,1613 /*ForVtable=*/false, dontDefer,1614 /*IsThunk=*/false, isForDefinition);1615 1616 return {fnType, fn};1617}1618 1619cir::FuncOp CIRGenModule::getAddrOfFunction(clang::GlobalDecl gd,1620 mlir::Type funcType, bool forVTable,1621 bool dontDefer,1622 ForDefinition_t isForDefinition) {1623 assert(!cast<FunctionDecl>(gd.getDecl())->isConsteval() &&1624 "consteval function should never be emitted");1625 1626 if (!funcType) {1627 const auto *fd = cast<FunctionDecl>(gd.getDecl());1628 funcType = convertType(fd->getType());1629 }1630 1631 // Devirtualized destructor calls may come through here instead of via1632 // getAddrOfCXXStructor. Make sure we use the MS ABI base destructor instead1633 // of the complete destructor when necessary.1634 if (const auto *dd = dyn_cast<CXXDestructorDecl>(gd.getDecl())) {1635 if (getTarget().getCXXABI().isMicrosoft() &&1636 gd.getDtorType() == Dtor_Complete &&1637 dd->getParent()->getNumVBases() == 0)1638 errorNYI(dd->getSourceRange(),1639 "getAddrOfFunction: MS ABI complete destructor");1640 }1641 1642 StringRef mangledName = getMangledName(gd);1643 cir::FuncOp func =1644 getOrCreateCIRFunction(mangledName, funcType, gd, forVTable, dontDefer,1645 /*isThunk=*/false, isForDefinition);1646 return func;1647}1648 1649static std::string getMangledNameImpl(CIRGenModule &cgm, GlobalDecl gd,1650 const NamedDecl *nd) {1651 SmallString<256> buffer;1652 1653 llvm::raw_svector_ostream out(buffer);1654 MangleContext &mc = cgm.getCXXABI().getMangleContext();1655 1656 assert(!cir::MissingFeatures::moduleNameHash());1657 1658 if (mc.shouldMangleDeclName(nd)) {1659 mc.mangleName(gd.getWithDecl(nd), out);1660 } else {1661 IdentifierInfo *ii = nd->getIdentifier();1662 assert(ii && "Attempt to mangle unnamed decl.");1663 1664 const auto *fd = dyn_cast<FunctionDecl>(nd);1665 if (fd &&1666 fd->getType()->castAs<FunctionType>()->getCallConv() == CC_X86RegCall) {1667 cgm.errorNYI(nd->getSourceRange(), "getMangledName: X86RegCall");1668 } else if (fd && fd->hasAttr<CUDAGlobalAttr>() &&1669 gd.getKernelReferenceKind() == KernelReferenceKind::Stub) {1670 cgm.errorNYI(nd->getSourceRange(), "getMangledName: CUDA device stub");1671 }1672 out << ii->getName();1673 }1674 1675 // Check if the module name hash should be appended for internal linkage1676 // symbols. This should come before multi-version target suffixes are1677 // appendded. This is to keep the name and module hash suffix of the internal1678 // linkage function together. The unique suffix should only be added when name1679 // mangling is done to make sure that the final name can be properly1680 // demangled. For example, for C functions without prototypes, name mangling1681 // is not done and the unique suffix should not be appended then.1682 assert(!cir::MissingFeatures::moduleNameHash());1683 1684 if (const auto *fd = dyn_cast<FunctionDecl>(nd)) {1685 if (fd->isMultiVersion()) {1686 cgm.errorNYI(nd->getSourceRange(),1687 "getMangledName: multi-version functions");1688 }1689 }1690 if (cgm.getLangOpts().GPURelocatableDeviceCode) {1691 cgm.errorNYI(nd->getSourceRange(),1692 "getMangledName: GPU relocatable device code");1693 }1694 1695 return std::string(out.str());1696}1697 1698StringRef CIRGenModule::getMangledName(GlobalDecl gd) {1699 GlobalDecl canonicalGd = gd.getCanonicalDecl();1700 1701 // Some ABIs don't have constructor variants. Make sure that base and complete1702 // constructors get mangled the same.1703 if (const auto *cd = dyn_cast<CXXConstructorDecl>(canonicalGd.getDecl())) {1704 if (!getTarget().getCXXABI().hasConstructorVariants()) {1705 errorNYI(cd->getSourceRange(),1706 "getMangledName: C++ constructor without variants");1707 return cast<NamedDecl>(gd.getDecl())->getIdentifier()->getName();1708 }1709 }1710 1711 // Keep the first result in the case of a mangling collision.1712 const auto *nd = cast<NamedDecl>(gd.getDecl());1713 std::string mangledName = getMangledNameImpl(*this, gd, nd);1714 1715 auto result = manglings.insert(std::make_pair(mangledName, gd));1716 return mangledDeclNames[canonicalGd] = result.first->first();1717}1718 1719void CIRGenModule::emitTentativeDefinition(const VarDecl *d) {1720 assert(!d->getInit() && "Cannot emit definite definitions here!");1721 1722 StringRef mangledName = getMangledName(d);1723 mlir::Operation *gv = getGlobalValue(mangledName);1724 1725 // If we already have a definition, not declaration, with the same mangled1726 // name, emitting of declaration is not required (and would actually overwrite1727 // the emitted definition).1728 if (gv && !mlir::cast<cir::GlobalOp>(gv).isDeclaration())1729 return;1730 1731 // If we have not seen a reference to this variable yet, place it into the1732 // deferred declarations table to be emitted if needed later.1733 if (!mustBeEmitted(d) && !gv) {1734 deferredDecls[mangledName] = d;1735 return;1736 }1737 1738 // The tentative definition is the only definition.1739 emitGlobalVarDefinition(d);1740}1741 1742bool CIRGenModule::mustBeEmitted(const ValueDecl *global) {1743 // Never defer when EmitAllDecls is specified.1744 if (langOpts.EmitAllDecls)1745 return true;1746 1747 const auto *vd = dyn_cast<VarDecl>(global);1748 if (vd &&1749 ((codeGenOpts.KeepPersistentStorageVariables &&1750 (vd->getStorageDuration() == SD_Static ||1751 vd->getStorageDuration() == SD_Thread)) ||1752 (codeGenOpts.KeepStaticConsts && vd->getStorageDuration() == SD_Static &&1753 vd->getType().isConstQualified())))1754 return true;1755 1756 return getASTContext().DeclMustBeEmitted(global);1757}1758 1759bool CIRGenModule::mayBeEmittedEagerly(const ValueDecl *global) {1760 // In OpenMP 5.0 variables and function may be marked as1761 // device_type(host/nohost) and we should not emit them eagerly unless we sure1762 // that they must be emitted on the host/device. To be sure we need to have1763 // seen a declare target with an explicit mentioning of the function, we know1764 // we have if the level of the declare target attribute is -1. Note that we1765 // check somewhere else if we should emit this at all.1766 if (langOpts.OpenMP >= 50 && !langOpts.OpenMPSimd) {1767 std::optional<OMPDeclareTargetDeclAttr *> activeAttr =1768 OMPDeclareTargetDeclAttr::getActiveAttr(global);1769 if (!activeAttr || (*activeAttr)->getLevel() != (unsigned)-1)1770 return false;1771 }1772 1773 const auto *fd = dyn_cast<FunctionDecl>(global);1774 if (fd) {1775 // Implicit template instantiations may change linkage if they are later1776 // explicitly instantiated, so they should not be emitted eagerly.1777 if (fd->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)1778 return false;1779 // Defer until all versions have been semantically checked.1780 if (fd->hasAttr<TargetVersionAttr>() && !fd->isMultiVersion())1781 return false;1782 if (langOpts.SYCLIsDevice) {1783 errorNYI(fd->getSourceRange(), "mayBeEmittedEagerly: SYCL");1784 return false;1785 }1786 }1787 const auto *vd = dyn_cast<VarDecl>(global);1788 if (vd)1789 if (astContext.getInlineVariableDefinitionKind(vd) ==1790 ASTContext::InlineVariableDefinitionKind::WeakUnknown)1791 // A definition of an inline constexpr static data member may change1792 // linkage later if it's redeclared outside the class.1793 return false;1794 1795 // If OpenMP is enabled and threadprivates must be generated like TLS, delay1796 // codegen for global variables, because they may be marked as threadprivate.1797 if (langOpts.OpenMP && langOpts.OpenMPUseTLS &&1798 astContext.getTargetInfo().isTLSSupported() && isa<VarDecl>(global) &&1799 !global->getType().isConstantStorage(astContext, false, false) &&1800 !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(global))1801 return false;1802 1803 assert((fd || vd) &&1804 "Only FunctionDecl and VarDecl should hit this path so far.");1805 return true;1806}1807 1808static bool shouldAssumeDSOLocal(const CIRGenModule &cgm,1809 cir::CIRGlobalValueInterface gv) {1810 if (gv.hasLocalLinkage())1811 return true;1812 1813 if (!gv.hasDefaultVisibility() && !gv.hasExternalWeakLinkage())1814 return true;1815 1816 // DLLImport explicitly marks the GV as external.1817 // so it shouldn't be dso_local1818 // But we don't have the info set now1819 assert(!cir::MissingFeatures::opGlobalDLLImportExport());1820 1821 const llvm::Triple &tt = cgm.getTriple();1822 const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();1823 if (tt.isOSCygMing()) {1824 // In MinGW and Cygwin, variables without DLLImport can still be1825 // automatically imported from a DLL by the linker; don't mark variables1826 // that potentially could come from another DLL as DSO local.1827 1828 // With EmulatedTLS, TLS variables can be autoimported from other DLLs1829 // (and this actually happens in the public interface of libstdc++), so1830 // such variables can't be marked as DSO local. (Native TLS variables1831 // can't be dllimported at all, though.)1832 cgm.errorNYI("shouldAssumeDSOLocal: MinGW");1833 }1834 1835 // On COFF, don't mark 'extern_weak' symbols as DSO local. If these symbols1836 // remain unresolved in the link, they can be resolved to zero, which is1837 // outside the current DSO.1838 if (tt.isOSBinFormatCOFF() && gv.hasExternalWeakLinkage())1839 return false;1840 1841 // Every other GV is local on COFF.1842 // Make an exception for windows OS in the triple: Some firmware builds use1843 // *-win32-macho triples. This (accidentally?) produced windows relocations1844 // without GOT tables in older clang versions; Keep this behaviour.1845 // FIXME: even thread local variables?1846 if (tt.isOSBinFormatCOFF() || (tt.isOSWindows() && tt.isOSBinFormatMachO()))1847 return true;1848 1849 // Only handle COFF and ELF for now.1850 if (!tt.isOSBinFormatELF())1851 return false;1852 1853 llvm::Reloc::Model rm = cgOpts.RelocationModel;1854 const LangOptions &lOpts = cgm.getLangOpts();1855 if (rm != llvm::Reloc::Static && !lOpts.PIE) {1856 // On ELF, if -fno-semantic-interposition is specified and the target1857 // supports local aliases, there will be neither CC11858 // -fsemantic-interposition nor -fhalf-no-semantic-interposition. Set1859 // dso_local on the function if using a local alias is preferable (can avoid1860 // PLT indirection).1861 if (!(isa<cir::FuncOp>(gv) && gv.canBenefitFromLocalAlias()))1862 return false;1863 return !(lOpts.SemanticInterposition || lOpts.HalfNoSemanticInterposition);1864 }1865 1866 // A definition cannot be preempted from an executable.1867 if (!gv.isDeclarationForLinker())1868 return true;1869 1870 // Most PIC code sequences that assume that a symbol is local cannot produce a1871 // 0 if it turns out the symbol is undefined. While this is ABI and relocation1872 // depended, it seems worth it to handle it here.1873 if (rm == llvm::Reloc::PIC_ && gv.hasExternalWeakLinkage())1874 return false;1875 1876 // PowerPC64 prefers TOC indirection to avoid copy relocations.1877 if (tt.isPPC64())1878 return false;1879 1880 if (cgOpts.DirectAccessExternalData) {1881 // If -fdirect-access-external-data (default for -fno-pic), set dso_local1882 // for non-thread-local variables. If the symbol is not defined in the1883 // executable, a copy relocation will be needed at link time. dso_local is1884 // excluded for thread-local variables because they generally don't support1885 // copy relocations.1886 if (auto globalOp = dyn_cast<cir::GlobalOp>(gv.getOperation())) {1887 // Assume variables are not thread-local until that support is added.1888 assert(!cir::MissingFeatures::opGlobalThreadLocal());1889 return true;1890 }1891 1892 // -fno-pic sets dso_local on a function declaration to allow direct1893 // accesses when taking its address (similar to a data symbol). If the1894 // function is not defined in the executable, a canonical PLT entry will be1895 // needed at link time. -fno-direct-access-external-data can avoid the1896 // canonical PLT entry. We don't generalize this condition to -fpie/-fpic as1897 // it could just cause trouble without providing perceptible benefits.1898 if (isa<cir::FuncOp>(gv) && !cgOpts.NoPLT && rm == llvm::Reloc::Static)1899 return true;1900 }1901 1902 // If we can use copy relocations we can assume it is local.1903 1904 // Otherwise don't assume it is local.1905 1906 return false;1907}1908 1909void CIRGenModule::setGlobalVisibility(mlir::Operation *gv,1910 const NamedDecl *d) const {1911 assert(!cir::MissingFeatures::opGlobalVisibility());1912}1913 1914void CIRGenModule::setDSOLocal(cir::CIRGlobalValueInterface gv) const {1915 gv.setDSOLocal(shouldAssumeDSOLocal(*this, gv));1916}1917 1918void CIRGenModule::setDSOLocal(mlir::Operation *op) const {1919 if (auto globalValue = dyn_cast<cir::CIRGlobalValueInterface>(op))1920 setDSOLocal(globalValue);1921}1922 1923void CIRGenModule::setGVProperties(mlir::Operation *op,1924 const NamedDecl *d) const {1925 assert(!cir::MissingFeatures::opGlobalDLLImportExport());1926 setGVPropertiesAux(op, d);1927}1928 1929void CIRGenModule::setGVPropertiesAux(mlir::Operation *op,1930 const NamedDecl *d) const {1931 setGlobalVisibility(op, d);1932 setDSOLocal(op);1933 assert(!cir::MissingFeatures::opGlobalPartition());1934}1935 1936void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl,1937 cir::FuncOp func,1938 bool isIncompleteFunction,1939 bool isThunk) {1940 // NOTE(cir): Original CodeGen checks if this is an intrinsic. In CIR we1941 // represent them in dedicated ops. The correct attributes are ensured during1942 // translation to LLVM. Thus, we don't need to check for them here.1943 1944 assert(!cir::MissingFeatures::setFunctionAttributes());1945 assert(!cir::MissingFeatures::setTargetAttributes());1946 1947 // TODO(cir): This needs a lot of work to better match CodeGen. That1948 // ultimately ends up in setGlobalVisibility, which already has the linkage of1949 // the LLVM GV (corresponding to our FuncOp) computed, so it doesn't have to1950 // recompute it here. This is a minimal fix for now.1951 if (!isLocalLinkage(getFunctionLinkage(globalDecl))) {1952 const Decl *decl = globalDecl.getDecl();1953 func.setGlobalVisibilityAttr(getGlobalVisibilityAttrFromDecl(decl));1954 }1955 1956 // If we plan on emitting this inline builtin, we can't treat it as a builtin.1957 const auto *fd = cast<FunctionDecl>(globalDecl.getDecl());1958 if (fd->isInlineBuiltinDeclaration()) {1959 const FunctionDecl *fdBody;1960 bool hasBody = fd->hasBody(fdBody);1961 (void)hasBody;1962 assert(hasBody && "Inline builtin declarations should always have an "1963 "available body!");1964 assert(!cir::MissingFeatures::attributeNoBuiltin());1965 }1966}1967 1968void CIRGenModule::setCIRFunctionAttributesForDefinition(1969 const clang::FunctionDecl *decl, cir::FuncOp f) {1970 assert(!cir::MissingFeatures::opFuncUnwindTablesAttr());1971 assert(!cir::MissingFeatures::stackProtector());1972 1973 std::optional<cir::InlineKind> existingInlineKind = f.getInlineKind();1974 bool isNoInline =1975 existingInlineKind && *existingInlineKind == cir::InlineKind::NoInline;1976 bool isAlwaysInline = existingInlineKind &&1977 *existingInlineKind == cir::InlineKind::AlwaysInline;1978 1979 if (!decl) {1980 assert(!cir::MissingFeatures::hlsl());1981 1982 if (!isAlwaysInline &&1983 codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {1984 // If inlining is disabled and we don't have a declaration to control1985 // inlining, mark the function as 'noinline' unless it is explicitly1986 // marked as 'alwaysinline'.1987 f.setInlineKindAttr(1988 cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));1989 }1990 1991 return;1992 }1993 1994 assert(!cir::MissingFeatures::opFuncArmStreamingAttr());1995 assert(!cir::MissingFeatures::opFuncArmNewAttr());1996 assert(!cir::MissingFeatures::opFuncOptNoneAttr());1997 assert(!cir::MissingFeatures::opFuncMinSizeAttr());1998 assert(!cir::MissingFeatures::opFuncNakedAttr());1999 assert(!cir::MissingFeatures::opFuncNoDuplicateAttr());2000 assert(!cir::MissingFeatures::hlsl());2001 2002 // Handle inline attributes2003 if (decl->hasAttr<NoInlineAttr>() && !isAlwaysInline) {2004 // Add noinline if the function isn't always_inline.2005 f.setInlineKindAttr(2006 cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));2007 } else if (decl->hasAttr<AlwaysInlineAttr>() && !isNoInline) {2008 // Don't override AlwaysInline with NoInline, or vice versa, since we can't2009 // specify both in IR.2010 f.setInlineKindAttr(2011 cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline));2012 } else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {2013 // If inlining is disabled, force everything that isn't always_inline2014 // to carry an explicit noinline attribute.2015 if (!isAlwaysInline) {2016 f.setInlineKindAttr(2017 cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));2018 }2019 } else {2020 // Otherwise, propagate the inline hint attribute and potentially use its2021 // absence to mark things as noinline.2022 // Search function and template pattern redeclarations for inline.2023 if (auto *fd = dyn_cast<FunctionDecl>(decl)) {2024 // TODO: Share this checkForInline implementation with classic codegen.2025 // This logic is likely to change over time, so sharing would help ensure2026 // consistency.2027 auto checkForInline = [](const FunctionDecl *decl) {2028 auto checkRedeclForInline = [](const FunctionDecl *redecl) {2029 return redecl->isInlineSpecified();2030 };2031 if (any_of(decl->redecls(), checkRedeclForInline))2032 return true;2033 const FunctionDecl *pattern = decl->getTemplateInstantiationPattern();2034 if (!pattern)2035 return false;2036 return any_of(pattern->redecls(), checkRedeclForInline);2037 };2038 if (checkForInline(fd)) {2039 f.setInlineKindAttr(cir::InlineAttr::get(&getMLIRContext(),2040 cir::InlineKind::InlineHint));2041 } else if (codeGenOpts.getInlining() ==2042 CodeGenOptions::OnlyHintInlining &&2043 !fd->isInlined() && !isAlwaysInline) {2044 f.setInlineKindAttr(2045 cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));2046 }2047 }2048 }2049 2050 assert(!cir::MissingFeatures::opFuncColdHotAttr());2051}2052 2053cir::FuncOp CIRGenModule::getOrCreateCIRFunction(2054 StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable,2055 bool dontDefer, bool isThunk, ForDefinition_t isForDefinition,2056 mlir::ArrayAttr extraAttrs) {2057 const Decl *d = gd.getDecl();2058 2059 if (isThunk)2060 errorNYI(d->getSourceRange(), "getOrCreateCIRFunction: thunk");2061 2062 // In what follows, we continue past 'errorNYI' as if nothing happened because2063 // the rest of the implementation is better than doing nothing.2064 2065 if (const auto *fd = cast_or_null<FunctionDecl>(d)) {2066 // For the device mark the function as one that should be emitted.2067 if (getLangOpts().OpenMPIsTargetDevice && fd->isDefined() && !dontDefer &&2068 !isForDefinition)2069 errorNYI(fd->getSourceRange(),2070 "getOrCreateCIRFunction: OpenMP target function");2071 2072 // Any attempts to use a MultiVersion function should result in retrieving2073 // the iFunc instead. Name mangling will handle the rest of the changes.2074 if (fd->isMultiVersion())2075 errorNYI(fd->getSourceRange(), "getOrCreateCIRFunction: multi-version");2076 }2077 2078 // Lookup the entry, lazily creating it if necessary.2079 mlir::Operation *entry = getGlobalValue(mangledName);2080 if (entry) {2081 assert(mlir::isa<cir::FuncOp>(entry));2082 2083 assert(!cir::MissingFeatures::weakRefReference());2084 2085 // Handle dropped DLL attributes.2086 if (d && !d->hasAttr<DLLImportAttr>() && !d->hasAttr<DLLExportAttr>()) {2087 assert(!cir::MissingFeatures::setDLLStorageClass());2088 setDSOLocal(entry);2089 }2090 2091 // If there are two attempts to define the same mangled name, issue an2092 // error.2093 auto fn = cast<cir::FuncOp>(entry);2094 if (isForDefinition && fn && !fn.isDeclaration()) {2095 errorNYI(d->getSourceRange(), "Duplicate function definition");2096 }2097 if (fn && fn.getFunctionType() == funcType) {2098 return fn;2099 }2100 2101 if (!isForDefinition) {2102 return fn;2103 }2104 2105 // TODO(cir): classic codegen checks here if this is a llvm::GlobalAlias.2106 // How will we support this?2107 }2108 2109 auto *funcDecl = llvm::cast_or_null<FunctionDecl>(gd.getDecl());2110 bool invalidLoc = !funcDecl ||2111 funcDecl->getSourceRange().getBegin().isInvalid() ||2112 funcDecl->getSourceRange().getEnd().isInvalid();2113 cir::FuncOp funcOp = createCIRFunction(2114 invalidLoc ? theModule->getLoc() : getLoc(funcDecl->getSourceRange()),2115 mangledName, mlir::cast<cir::FuncType>(funcType), funcDecl);2116 2117 // If we already created a function with the same mangled name (but different2118 // type) before, take its name and add it to the list of functions to be2119 // replaced with F at the end of CodeGen.2120 //2121 // This happens if there is a prototype for a function (e.g. "int f()") and2122 // then a definition of a different type (e.g. "int f(int x)").2123 if (entry) {2124 2125 // Fetch a generic symbol-defining operation and its uses.2126 auto symbolOp = mlir::cast<mlir::SymbolOpInterface>(entry);2127 2128 // This might be an implementation of a function without a prototype, in2129 // which case, try to do special replacement of calls which match the new2130 // prototype. The really key thing here is that we also potentially drop2131 // arguments from the call site so as to make a direct call, which makes the2132 // inliner happier and suppresses a number of optimizer warnings (!) about2133 // dropping arguments.2134 if (symbolOp.getSymbolUses(symbolOp->getParentOp()))2135 replaceUsesOfNonProtoTypeWithRealFunction(entry, funcOp);2136 2137 // Obliterate no-proto declaration.2138 entry->erase();2139 }2140 2141 if (d)2142 setFunctionAttributes(gd, funcOp, /*isIncompleteFunction=*/false, isThunk);2143 2144 // 'dontDefer' actually means don't move this to the deferredDeclsToEmit list.2145 if (dontDefer) {2146 // TODO(cir): This assertion will need an additional condition when we2147 // support incomplete functions.2148 assert(funcOp.getFunctionType() == funcType);2149 return funcOp;2150 }2151 2152 // All MSVC dtors other than the base dtor are linkonce_odr and delegate to2153 // each other bottoming out wiht the base dtor. Therefore we emit non-base2154 // dtors on usage, even if there is no dtor definition in the TU.2155 if (isa_and_nonnull<CXXDestructorDecl>(d) &&2156 getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(d),2157 gd.getDtorType()))2158 errorNYI(d->getSourceRange(), "getOrCreateCIRFunction: dtor");2159 2160 // This is the first use or definition of a mangled name. If there is a2161 // deferred decl with this name, remember that we need to emit it at the end2162 // of the file.2163 auto ddi = deferredDecls.find(mangledName);2164 if (ddi != deferredDecls.end()) {2165 // Move the potentially referenced deferred decl to the2166 // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we2167 // don't need it anymore).2168 addDeferredDeclToEmit(ddi->second);2169 deferredDecls.erase(ddi);2170 2171 // Otherwise, there are cases we have to worry about where we're using a2172 // declaration for which we must emit a definition but where we might not2173 // find a top-level definition.2174 // - member functions defined inline in their classes2175 // - friend functions defined inline in some class2176 // - special member functions with implicit definitions2177 // If we ever change our AST traversal to walk into class methods, this2178 // will be unnecessary.2179 //2180 // We also don't emit a definition for a function if it's going to be an2181 // entry in a vtable, unless it's already marked as used.2182 } else if (getLangOpts().CPlusPlus && d) {2183 // Look for a declaration that's lexically in a record.2184 for (const auto *fd = cast<FunctionDecl>(d)->getMostRecentDecl(); fd;2185 fd = fd->getPreviousDecl()) {2186 if (isa<CXXRecordDecl>(fd->getLexicalDeclContext())) {2187 if (fd->doesThisDeclarationHaveABody()) {2188 addDeferredDeclToEmit(gd.getWithDecl(fd));2189 break;2190 }2191 }2192 }2193 }2194 2195 return funcOp;2196}2197 2198cir::FuncOp2199CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,2200 cir::FuncType funcType,2201 const clang::FunctionDecl *funcDecl) {2202 cir::FuncOp func;2203 {2204 mlir::OpBuilder::InsertionGuard guard(builder);2205 2206 // Some global emissions are triggered while emitting a function, e.g.2207 // void s() { x.method() }2208 //2209 // Be sure to insert a new function before a current one.2210 CIRGenFunction *cgf = this->curCGF;2211 if (cgf)2212 builder.setInsertionPoint(cgf->curFn);2213 2214 func = cir::FuncOp::create(builder, loc, name, funcType);2215 2216 assert(!cir::MissingFeatures::opFuncAstDeclAttr());2217 2218 if (funcDecl && !funcDecl->hasPrototype())2219 func.setNoProto(true);2220 2221 assert(func.isDeclaration() && "expected empty body");2222 2223 // A declaration gets private visibility by default, but external linkage2224 // as the default linkage.2225 func.setLinkageAttr(cir::GlobalLinkageKindAttr::get(2226 &getMLIRContext(), cir::GlobalLinkageKind::ExternalLinkage));2227 mlir::SymbolTable::setSymbolVisibility(2228 func, mlir::SymbolTable::Visibility::Private);2229 2230 assert(!cir::MissingFeatures::opFuncExtraAttrs());2231 2232 // Mark C++ special member functions (Constructor, Destructor etc.)2233 setCXXSpecialMemberAttr(func, funcDecl);2234 2235 if (!cgf)2236 theModule.push_back(func);2237 }2238 return func;2239}2240 2241cir::FuncOp2242CIRGenModule::createCIRBuiltinFunction(mlir::Location loc, StringRef name,2243 cir::FuncType ty,2244 const clang::FunctionDecl *fd) {2245 cir::FuncOp fnOp = createCIRFunction(loc, name, ty, fd);2246 fnOp.setBuiltin(true);2247 return fnOp;2248}2249 2250static cir::CtorKind getCtorKindFromDecl(const CXXConstructorDecl *ctor) {2251 if (ctor->isDefaultConstructor())2252 return cir::CtorKind::Default;2253 if (ctor->isCopyConstructor())2254 return cir::CtorKind::Copy;2255 if (ctor->isMoveConstructor())2256 return cir::CtorKind::Move;2257 return cir::CtorKind::Custom;2258}2259 2260static cir::AssignKind getAssignKindFromDecl(const CXXMethodDecl *method) {2261 if (method->isCopyAssignmentOperator())2262 return cir::AssignKind::Copy;2263 if (method->isMoveAssignmentOperator())2264 return cir::AssignKind::Move;2265 llvm_unreachable("not a copy or move assignment operator");2266}2267 2268void CIRGenModule::setCXXSpecialMemberAttr(2269 cir::FuncOp funcOp, const clang::FunctionDecl *funcDecl) {2270 if (!funcDecl)2271 return;2272 2273 if (const auto *dtor = dyn_cast<CXXDestructorDecl>(funcDecl)) {2274 auto cxxDtor = cir::CXXDtorAttr::get(2275 convertType(getASTContext().getCanonicalTagType(dtor->getParent())),2276 dtor->isTrivial());2277 funcOp.setCxxSpecialMemberAttr(cxxDtor);2278 return;2279 }2280 2281 if (const auto *ctor = dyn_cast<CXXConstructorDecl>(funcDecl)) {2282 cir::CtorKind kind = getCtorKindFromDecl(ctor);2283 auto cxxCtor = cir::CXXCtorAttr::get(2284 convertType(getASTContext().getCanonicalTagType(ctor->getParent())),2285 kind, ctor->isTrivial());2286 funcOp.setCxxSpecialMemberAttr(cxxCtor);2287 return;2288 }2289 2290 const auto *method = dyn_cast<CXXMethodDecl>(funcDecl);2291 if (method && (method->isCopyAssignmentOperator() ||2292 method->isMoveAssignmentOperator())) {2293 cir::AssignKind assignKind = getAssignKindFromDecl(method);2294 auto cxxAssign = cir::CXXAssignAttr::get(2295 convertType(getASTContext().getCanonicalTagType(method->getParent())),2296 assignKind, method->isTrivial());2297 funcOp.setCxxSpecialMemberAttr(cxxAssign);2298 return;2299 }2300}2301 2302cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty,2303 StringRef name, mlir::ArrayAttr,2304 [[maybe_unused]] bool isLocal,2305 bool assumeConvergent) {2306 if (assumeConvergent)2307 errorNYI("createRuntimeFunction: assumeConvergent");2308 if (isLocal)2309 errorNYI("createRuntimeFunction: local");2310 2311 cir::FuncOp entry = getOrCreateCIRFunction(name, ty, GlobalDecl(),2312 /*forVtable=*/false);2313 2314 if (entry) {2315 // TODO(cir): set the attributes of the function.2316 assert(!cir::MissingFeatures::setLLVMFunctionFEnvAttributes());2317 assert(!cir::MissingFeatures::opFuncCallingConv());2318 assert(!cir::MissingFeatures::opGlobalDLLImportExport());2319 entry.setDSOLocal(true);2320 }2321 2322 return entry;2323}2324 2325mlir::SymbolTable::Visibility2326CIRGenModule::getMLIRVisibility(cir::GlobalOp op) {2327 // MLIR doesn't accept public symbols declarations (only2328 // definitions).2329 if (op.isDeclaration())2330 return mlir::SymbolTable::Visibility::Private;2331 return getMLIRVisibilityFromCIRLinkage(op.getLinkage());2332}2333 2334mlir::SymbolTable::Visibility2335CIRGenModule::getMLIRVisibilityFromCIRLinkage(cir::GlobalLinkageKind glk) {2336 switch (glk) {2337 case cir::GlobalLinkageKind::InternalLinkage:2338 case cir::GlobalLinkageKind::PrivateLinkage:2339 return mlir::SymbolTable::Visibility::Private;2340 case cir::GlobalLinkageKind::ExternalLinkage:2341 case cir::GlobalLinkageKind::ExternalWeakLinkage:2342 case cir::GlobalLinkageKind::LinkOnceODRLinkage:2343 case cir::GlobalLinkageKind::AvailableExternallyLinkage:2344 case cir::GlobalLinkageKind::CommonLinkage:2345 case cir::GlobalLinkageKind::WeakAnyLinkage:2346 case cir::GlobalLinkageKind::WeakODRLinkage:2347 return mlir::SymbolTable::Visibility::Public;2348 default: {2349 llvm::errs() << "visibility not implemented for '"2350 << stringifyGlobalLinkageKind(glk) << "'\n";2351 assert(0 && "not implemented");2352 }2353 }2354 llvm_unreachable("linkage should be handled above!");2355}2356 2357cir::VisibilityKind CIRGenModule::getGlobalVisibilityKindFromClangVisibility(2358 clang::VisibilityAttr::VisibilityType visibility) {2359 switch (visibility) {2360 case clang::VisibilityAttr::VisibilityType::Default:2361 return cir::VisibilityKind::Default;2362 case clang::VisibilityAttr::VisibilityType::Hidden:2363 return cir::VisibilityKind::Hidden;2364 case clang::VisibilityAttr::VisibilityType::Protected:2365 return cir::VisibilityKind::Protected;2366 }2367 llvm_unreachable("unexpected visibility value");2368}2369 2370cir::VisibilityAttr2371CIRGenModule::getGlobalVisibilityAttrFromDecl(const Decl *decl) {2372 const clang::VisibilityAttr *va = decl->getAttr<clang::VisibilityAttr>();2373 cir::VisibilityAttr cirVisibility =2374 cir::VisibilityAttr::get(&getMLIRContext());2375 if (va) {2376 cirVisibility = cir::VisibilityAttr::get(2377 &getMLIRContext(),2378 getGlobalVisibilityKindFromClangVisibility(va->getVisibility()));2379 }2380 return cirVisibility;2381}2382 2383void CIRGenModule::release() {2384 emitDeferred();2385 applyReplacements();2386 2387 theModule->setAttr(cir::CIRDialect::getModuleLevelAsmAttrName(),2388 builder.getArrayAttr(globalScopeAsm));2389 2390 // There's a lot of code that is not implemented yet.2391 assert(!cir::MissingFeatures::cgmRelease());2392}2393 2394void CIRGenModule::emitAliasForGlobal(StringRef mangledName,2395 mlir::Operation *op, GlobalDecl aliasGD,2396 cir::FuncOp aliasee,2397 cir::GlobalLinkageKind linkage) {2398 2399 auto *aliasFD = dyn_cast<FunctionDecl>(aliasGD.getDecl());2400 assert(aliasFD && "expected FunctionDecl");2401 2402 // The aliasee function type is different from the alias one, this difference2403 // is specific to CIR because in LLVM the ptr types are already erased at this2404 // point.2405 const CIRGenFunctionInfo &fnInfo =2406 getTypes().arrangeCXXStructorDeclaration(aliasGD);2407 cir::FuncType fnType = getTypes().getFunctionType(fnInfo);2408 2409 cir::FuncOp alias =2410 createCIRFunction(getLoc(aliasGD.getDecl()->getSourceRange()),2411 mangledName, fnType, aliasFD);2412 alias.setAliasee(aliasee.getName());2413 alias.setLinkage(linkage);2414 // Declarations cannot have public MLIR visibility, just mark them private2415 // but this really should have no meaning since CIR should not be using2416 // this information to derive linkage information.2417 mlir::SymbolTable::setSymbolVisibility(2418 alias, mlir::SymbolTable::Visibility::Private);2419 2420 // Alias constructors and destructors are always unnamed_addr.2421 assert(!cir::MissingFeatures::opGlobalUnnamedAddr());2422 2423 // Switch any previous uses to the alias.2424 if (op) {2425 errorNYI(aliasFD->getSourceRange(), "emitAliasForGlobal: previous uses");2426 } else {2427 // Name already set by createCIRFunction2428 }2429 2430 // Finally, set up the alias with its proper name and attributes.2431 setCommonAttributes(aliasGD, alias);2432}2433 2434mlir::Type CIRGenModule::convertType(QualType type) {2435 return genTypes.convertType(type);2436}2437 2438bool CIRGenModule::verifyModule() const {2439 // Verify the module after we have finished constructing it, this will2440 // check the structural properties of the IR and invoke any specific2441 // verifiers we have on the CIR operations.2442 return mlir::verify(theModule).succeeded();2443}2444 2445mlir::Attribute CIRGenModule::getAddrOfRTTIDescriptor(mlir::Location loc,2446 QualType ty, bool forEh) {2447 // Return a bogus pointer if RTTI is disabled, unless it's for EH.2448 // FIXME: should we even be calling this method if RTTI is disabled2449 // and it's not for EH?2450 if (!shouldEmitRTTI(forEh))2451 return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());2452 2453 if (forEh && ty->isObjCObjectPointerType() &&2454 langOpts.ObjCRuntime.isGNUFamily()) {2455 errorNYI(loc, "getAddrOfRTTIDescriptor: Objc PtrType & Objc RT GUN");2456 return {};2457 }2458 2459 return getCXXABI().getAddrOfRTTIDescriptor(loc, ty);2460}2461 2462// TODO(cir): this can be shared with LLVM codegen.2463CharUnits CIRGenModule::computeNonVirtualBaseClassOffset(2464 const CXXRecordDecl *derivedClass,2465 llvm::iterator_range<CastExpr::path_const_iterator> path) {2466 CharUnits offset = CharUnits::Zero();2467 2468 const ASTContext &astContext = getASTContext();2469 const CXXRecordDecl *rd = derivedClass;2470 2471 for (const CXXBaseSpecifier *base : path) {2472 assert(!base->isVirtual() && "Should not see virtual bases here!");2473 2474 // Get the layout.2475 const ASTRecordLayout &layout = astContext.getASTRecordLayout(rd);2476 2477 const auto *baseDecl = base->getType()->castAsCXXRecordDecl();2478 2479 // Add the offset.2480 offset += layout.getBaseClassOffset(baseDecl);2481 2482 rd = baseDecl;2483 }2484 2485 return offset;2486}2487 2488DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,2489 llvm::StringRef feature) {2490 unsigned diagID = diags.getCustomDiagID(2491 DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");2492 return diags.Report(loc, diagID) << feature;2493}2494 2495DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,2496 llvm::StringRef feature) {2497 return errorNYI(loc.getBegin(), feature) << loc;2498}2499