diff options
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 199 |
1 files changed, 175 insertions, 24 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index df33fc3e8200..85bd53741e18 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -395,6 +395,7 @@ void CodeGenModule::Release() { applyGlobalValReplacements(); applyReplacements(); checkAliases(); + emitMultiVersionFunctions(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); EmitCXXThreadLocalInitFunc(); @@ -725,36 +726,48 @@ void CodeGenModule::setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const { GV->setThreadLocalMode(TLM); } -StringRef CodeGenModule::getMangledName(GlobalDecl GD) { - GlobalDecl CanonicalGD = GD.getCanonicalDecl(); +static void AppendTargetMangling(const CodeGenModule &CGM, + const TargetAttr *Attr, raw_ostream &Out) { + if (Attr->isDefaultVersion()) + return; - // Some ABIs don't have constructor variants. Make sure that base and - // complete constructors get mangled the same. - if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) { - if (!getTarget().getCXXABI().hasConstructorVariants()) { - CXXCtorType OrigCtorType = GD.getCtorType(); - assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete); - if (OrigCtorType == Ctor_Base) - CanonicalGD = GlobalDecl(CD, Ctor_Complete); - } + Out << '.'; + const auto &Target = CGM.getTarget(); + TargetAttr::ParsedTargetAttr Info = + Attr->parse([&Target](StringRef LHS, StringRef RHS) { + return Target.multiVersionSortPriority(LHS) > + Target.multiVersionSortPriority(RHS); + }); + + bool IsFirst = true; + + if (!Info.Architecture.empty()) { + IsFirst = false; + Out << "arch_" << Info.Architecture; } - auto FoundName = MangledDeclNames.find(CanonicalGD); - if (FoundName != MangledDeclNames.end()) - return FoundName->second; + for (StringRef Feat : Info.Features) { + if (!IsFirst) + Out << '_'; + IsFirst = false; + Out << Feat.substr(1); + } +} - const auto *ND = cast<NamedDecl>(GD.getDecl()); +static std::string getMangledNameImpl(const CodeGenModule &CGM, GlobalDecl GD, + const NamedDecl *ND, + bool OmitTargetMangling = false) { SmallString<256> Buffer; - StringRef Str; - if (getCXXABI().getMangleContext().shouldMangleDeclName(ND)) { + llvm::raw_svector_ostream Out(Buffer); + MangleContext &MC = CGM.getCXXABI().getMangleContext(); + if (MC.shouldMangleDeclName(ND)) { llvm::raw_svector_ostream Out(Buffer); if (const auto *D = dyn_cast<CXXConstructorDecl>(ND)) - getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out); + MC.mangleCXXCtor(D, GD.getCtorType(), Out); else if (const auto *D = dyn_cast<CXXDestructorDecl>(ND)) - getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out); + MC.mangleCXXDtor(D, GD.getDtorType(), Out); else - getCXXABI().getMangleContext().mangleName(ND, Out); - Str = Out.str(); + MC.mangleName(ND, Out); } else { IdentifierInfo *II = ND->getIdentifier(); assert(II && "Attempt to mangle unnamed decl."); @@ -764,14 +777,74 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) { FD->getType()->castAs<FunctionType>()->getCallConv() == CC_X86RegCall) { llvm::raw_svector_ostream Out(Buffer); Out << "__regcall3__" << II->getName(); - Str = Out.str(); } else { - Str = II->getName(); + Out << II->getName(); + } + } + + if (const auto *FD = dyn_cast<FunctionDecl>(ND)) + if (FD->isMultiVersion() && !OmitTargetMangling) + AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out); + return Out.str(); +} + +void CodeGenModule::UpdateMultiVersionNames(GlobalDecl GD, + const FunctionDecl *FD) { + if (!FD->isMultiVersion()) + return; + + // Get the name of what this would be without the 'target' attribute. This + // allows us to lookup the version that was emitted when this wasn't a + // multiversion function. + std::string NonTargetName = + getMangledNameImpl(*this, GD, FD, /*OmitTargetMangling=*/true); + GlobalDecl OtherGD; + if (lookupRepresentativeDecl(NonTargetName, OtherGD)) { + assert(OtherGD.getCanonicalDecl() + .getDecl() + ->getAsFunction() + ->isMultiVersion() && + "Other GD should now be a multiversioned function"); + // OtherFD is the version of this function that was mangled BEFORE + // becoming a MultiVersion function. It potentially needs to be updated. + const FunctionDecl *OtherFD = + OtherGD.getCanonicalDecl().getDecl()->getAsFunction(); + std::string OtherName = getMangledNameImpl(*this, OtherGD, OtherFD); + // This is so that if the initial version was already the 'default' + // version, we don't try to update it. + if (OtherName != NonTargetName) { + Manglings.erase(NonTargetName); + auto Result = Manglings.insert(std::make_pair(OtherName, OtherGD)); + MangledDeclNames[OtherGD.getCanonicalDecl()] = Result.first->first(); + if (llvm::GlobalValue *Entry = GetGlobalValue(NonTargetName)) + Entry->setName(OtherName); } } +} + +StringRef CodeGenModule::getMangledName(GlobalDecl GD) { + GlobalDecl CanonicalGD = GD.getCanonicalDecl(); + + // Some ABIs don't have constructor variants. Make sure that base and + // complete constructors get mangled the same. + if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) { + if (!getTarget().getCXXABI().hasConstructorVariants()) { + CXXCtorType OrigCtorType = GD.getCtorType(); + assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete); + if (OrigCtorType == Ctor_Base) + CanonicalGD = GlobalDecl(CD, Ctor_Complete); + } + } + + auto FoundName = MangledDeclNames.find(CanonicalGD); + if (FoundName != MangledDeclNames.end()) + return FoundName->second; + // Keep the first result in the case of a mangling collision. - auto Result = Manglings.insert(std::make_pair(Str, GD)); + const auto *ND = cast<NamedDecl>(GD.getDecl()); + auto Result = + Manglings.insert(std::make_pair(getMangledNameImpl(*this, GD, ND), GD)); return MangledDeclNames[CanonicalGD] = Result.first->first(); } @@ -2061,6 +2134,74 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Function *NewFn); +void CodeGenModule::emitMultiVersionFunctions() { + for (GlobalDecl GD : MultiVersionFuncs) { + SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options; + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + getContext().forEachMultiversionedFunctionVersion( + FD, [this, &GD, &Options](const FunctionDecl *CurFD) { + GlobalDecl CurGD{ + (CurFD->isDefined() ? CurFD->getDefinition() : CurFD)}; + StringRef MangledName = getMangledName(CurGD); + llvm::Constant *Func = GetGlobalValue(MangledName); + if (!Func) { + if (CurFD->isDefined()) { + EmitGlobalFunctionDefinition(CurGD, nullptr); + Func = GetGlobalValue(MangledName); + } else { + const CGFunctionInfo &FI = + getTypes().arrangeGlobalDeclaration(GD); + llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); + Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false, + /*DontDefer=*/false, ForDefinition); + } + assert(Func && "This should have just been created"); + } + Options.emplace_back(getTarget(), cast<llvm::Function>(Func), + CurFD->getAttr<TargetAttr>()->parse()); + }); + + llvm::Function *ResolverFunc = cast<llvm::Function>( + GetGlobalValue((getMangledName(GD) + ".resolver").str())); + std::stable_sort( + Options.begin(), Options.end(), + std::greater<CodeGenFunction::MultiVersionResolverOption>()); + CodeGenFunction CGF(*this); + CGF.EmitMultiVersionResolver(ResolverFunc, Options); + } +} + +/// If an ifunc for the specified mangled name is not in the module, create and +/// return an llvm IFunc Function with the specified type. +llvm::Constant * +CodeGenModule::GetOrCreateMultiVersionIFunc(GlobalDecl GD, llvm::Type *DeclTy, + StringRef MangledName, + const FunctionDecl *FD) { + std::string IFuncName = (MangledName + ".ifunc").str(); + if (llvm::GlobalValue *IFuncGV = GetGlobalValue(IFuncName)) + return IFuncGV; + + // Since this is the first time we've created this IFunc, make sure + // that we put this multiversioned function into the list to be + // replaced later. + MultiVersionFuncs.push_back(GD); + + std::string ResolverName = (MangledName + ".resolver").str(); + llvm::Type *ResolverType = llvm::FunctionType::get( + llvm::PointerType::get(DeclTy, + Context.getTargetAddressSpace(FD->getType())), + false); + llvm::Constant *Resolver = + GetOrCreateLLVMFunction(ResolverName, ResolverType, GlobalDecl{}, + /*ForVTable=*/false); + llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create( + DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule()); + GIF->setName(IFuncName); + SetCommonAttributes(FD, GIF); + + return GIF; +} + /// GetOrCreateLLVMFunction - If the specified mangled name is not in the /// module, create and return an llvm Function with the specified type. If there /// is something in the module with the specified name, return it potentially @@ -2074,6 +2215,16 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( ForDefinition_t IsForDefinition) { const Decl *D = GD.getDecl(); + // Any attempts to use a MultiVersion function should result in retrieving + // the iFunc instead. Name Mangling will handle the rest of the changes. + if (const FunctionDecl *FD = cast_or_null<FunctionDecl>(D)) { + if (FD->isMultiVersion() && FD->getAttr<TargetAttr>()->isDefaultVersion()) { + UpdateMultiVersionNames(GD, FD); + if (!IsForDefinition) + return GetOrCreateMultiVersionIFunc(GD, Ty, MangledName, FD); + } + } + // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { |
