//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This contains code dealing with code generation of C++ declarations // //===----------------------------------------------------------------------===// #include "CIRGenCXXABI.h" #include "CIRGenFunction.h" #include "CIRGenModule.h" #include "clang/AST/Attr.h" #include "clang/AST/Mangle.h" #include "clang/Basic/LangOptions.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" using namespace clang; using namespace clang::CIRGen; void CIRGenFunction::emitCXXGuardedInit(const VarDecl &varDecl, cir::GlobalOp globalOp, bool performInit) { // If we've been asked to forbid guard variables, emit an error now. // This diagnostic is hard-coded for Darwin's use case; we can find // better phrasing if someone else needs it. if (cgm.getCodeGenOpts().ForbidGuardVariables) cgm.error(varDecl.getLocation(), "guard variables are forbidden"); // Compute the mangled guard variable name and set the static_local attribute // BEFORE emitting initialization. This ensures that GetGlobalOps created // during initialization (e.g., in the ctor region) will see the attribute // and be marked with static_local accordingly. llvm::SmallString<256> guardName; { llvm::raw_svector_ostream out(guardName); cgm.getCXXABI().getMangleContext().mangleStaticGuardVariable(&varDecl, out); } // Mark the global as static local with the guard name. The emission of the // guard/acquire is done during LoweringPrepare. auto guardAttr = mlir::StringAttr::get(&cgm.getMLIRContext(), guardName); if (!varDecl.isStaticLocal()) cgm.errorNYI( varDecl.getSourceRange(), "Static local guard attr only valid on static local variables"); globalOp.setStaticLocalGuardAttr( cir::StaticLocalGuardAttr::get(&cgm.getMLIRContext(), guardAttr)); // Emit the initializer and add a global destructor if appropriate. // TODO(cir): classic codegen calls emitCXXGlobalVarDeclInit for this as well, // and this is meant to handle cases with weak linkage (see comment in // emitCXXGlobalVarDeclInitFunc). At one point we'll have to do some level of // split here depending on whether this is a global (which should/can have // ctor/dtor regions), or should have in-function initialization. cgm.emitCXXStaticLocalVarDeclInit(&varDecl, globalOp, performInit); } void CIRGenModule::setGlobalTlsReferences(const VarDecl &vd, cir::GlobalOp globalOp) { assert(!vd.isStaticLocal() && vd.getTLSKind()); // C doesn't need guarded thread-local init, because it can't have // non-constant init. if (!getLangOpts().CPlusPlus) return; if (globalOp.getTlsModel() != cir::TLS_Model::GeneralDynamic) return; llvm::SmallString<256> wrapperFuncName; llvm::SmallString<256> initFuncName; llvm::SmallString<256> guardName; if (getCXXABI().getMangleContext().getKind() == MangleContext::MK_Itanium) { llvm::raw_svector_ostream wrapperOut(wrapperFuncName); llvm::raw_svector_ostream initOut(initFuncName); llvm::raw_svector_ostream guardStream(guardName); auto &mc = cast(getCXXABI().getMangleContext()); mc.mangleItaniumThreadLocalWrapper(&vd, wrapperOut); mc.mangleItaniumThreadLocalInit(&vd, initOut); if (globalOp.hasWeakLinkage() || globalOp.hasLinkOnceLinkage() || isTemplateInstantiation(vd.getTemplateSpecializationKind())) { getCXXABI().getMangleContext().mangleStaticGuardVariable(&vd, guardStream); } } else { errorNYI(vd.getSourceRange(), "setGlobalTlsReferences: non-itanium mangler"); return; } globalOp.setDynTlsRefsAttr(cir::ThreadLocalGlobalWrapperInitAttr::get( &getMLIRContext(), wrapperFuncName, initFuncName, guardName)); } void CIRGenModule::emitCXXGlobalVarDeclInitFunc(const VarDecl *vd, cir::GlobalOp addr, bool performInit) { assert(!cir::MissingFeatures::cudaSupport()); assert(!cir::MissingFeatures::deferredCXXGlobalInit()); // TODO(cir): Classic codegen calls emitCXXGuardedInit in the following case: // template struct Templ { // static T f; // }; // template T Templ::f = get_i(); // auto func() { // Templ t; // return decltype(t)::f; // } // // However, at the moment it is only suitable for static-local variables, so // we will have to modify it to work for this case as well. emitCXXGlobalVarDeclInit(vd, addr, performInit); }