diff options
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 97 |
1 files changed, 50 insertions, 47 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0c002b5..71192cb 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3796,8 +3796,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Forward declarations are emitted lazily on first use. if (!FD->doesThisDeclarationHaveABody()) { if (!FD->doesDeclarationForceExternallyVisibleDefinition() && - (!FD->isMultiVersion() || - !FD->getASTContext().getTargetInfo().getTriple().isAArch64())) + (!FD->isMultiVersion() || !getTarget().getTriple().isAArch64())) return; StringRef MangledName = getMangledName(GD); @@ -4191,23 +4190,6 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, return llvm::GlobalValue::WeakODRLinkage; } -static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) { - auto *DeclCtx = const_cast<DeclContext *>(FD->getDeclContext()); - TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); - StorageClass SC = FD->getStorageClass(); - DeclarationName Name = FD->getNameInfo().getName(); - - FunctionDecl *NewDecl = - FunctionDecl::Create(FD->getASTContext(), DeclCtx, FD->getBeginLoc(), - FD->getEndLoc(), Name, TInfo->getType(), TInfo, SC); - - NewDecl->setIsMultiVersion(); - NewDecl->addAttr(TargetVersionAttr::CreateImplicit( - NewDecl->getASTContext(), "default", NewDecl->getSourceRange())); - - return NewDecl; -} - void CodeGenModule::emitMultiVersionFunctions() { std::vector<GlobalDecl> MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); @@ -4234,29 +4216,30 @@ void CodeGenModule::emitMultiVersionFunctions() { return cast<llvm::Function>(Func); }; - bool HasDefaultDecl = !FD->isTargetVersionMultiVersion(); - bool ShouldEmitResolver = - !getContext().getTargetInfo().getTriple().isAArch64(); + // For AArch64, a resolver is only emitted if a function marked with + // target_version("default")) or target_clones() is present and defined + // in this TU. For other architectures it is always emitted. + bool ShouldEmitResolver = !getTarget().getTriple().isAArch64(); SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options; getContext().forEachMultiversionedFunctionVersion( FD, [&](const FunctionDecl *CurFD) { llvm::SmallVector<StringRef, 8> Feats; + bool IsDefined = CurFD->doesThisDeclarationHaveABody(); if (const auto *TA = CurFD->getAttr<TargetAttr>()) { TA->getAddedFeatures(Feats); llvm::Function *Func = createFunction(CurFD); Options.emplace_back(Func, TA->getArchitecture(), Feats); } else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) { - bool HasDefaultDef = TVA->isDefaultVersion() && - CurFD->doesThisDeclarationHaveABody(); - HasDefaultDecl |= TVA->isDefaultVersion(); - ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef); + if (TVA->isDefaultVersion() && IsDefined) + ShouldEmitResolver = true; TVA->getFeatures(Feats); llvm::Function *Func = createFunction(CurFD); Options.emplace_back(Func, /*Architecture*/ "", Feats); } else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) { - ShouldEmitResolver |= CurFD->doesThisDeclarationHaveABody(); + if (IsDefined) + ShouldEmitResolver = true; for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) { if (!TC->isFirstOfVersion(I)) continue; @@ -4282,13 +4265,6 @@ void CodeGenModule::emitMultiVersionFunctions() { if (!ShouldEmitResolver) continue; - if (!HasDefaultDecl) { - FunctionDecl *NewFD = createDefaultTargetVersionFrom(FD); - llvm::Function *Func = createFunction(NewFD); - llvm::SmallVector<StringRef, 1> Feats; - Options.emplace_back(Func, /*Architecture*/ "", Feats); - } - llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD); if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) { ResolverConstant = IFunc->getResolver(); @@ -4339,6 +4315,14 @@ void CodeGenModule::emitMultiVersionFunctions() { emitMultiVersionFunctions(); } +static void replaceDeclarationWith(llvm::GlobalValue *Old, + llvm::Constant *New) { + assert(cast<llvm::Function>(Old)->isDeclaration() && "Not a declaration"); + New->takeName(Old); + Old->replaceAllUsesWith(New); + Old->eraseFromParent(); +} + void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { const auto *FD = cast<FunctionDecl>(GD.getDecl()); assert(FD && "Not a FunctionDecl?"); @@ -4443,12 +4427,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { // Fix up function declarations that were created for cpu_specific before // cpu_dispatch was known if (!isa<llvm::GlobalIFunc>(IFunc)) { - assert(cast<llvm::Function>(IFunc)->isDeclaration()); auto *GI = llvm::GlobalIFunc::create(DeclTy, 0, Linkage, "", ResolverFunc, &getModule()); - GI->takeName(IFunc); - IFunc->replaceAllUsesWith(GI); - IFunc->eraseFromParent(); + replaceDeclarationWith(IFunc, GI); IFunc = GI; } @@ -4478,7 +4459,8 @@ void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) { } /// If a dispatcher for the specified mangled name is not in the module, create -/// and return an llvm Function with the specified type. +/// and return it. The dispatcher is either an llvm Function with the specified +/// type, or a global ifunc. llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { const auto *FD = cast<FunctionDecl>(GD.getDecl()); assert(FD && "Not a FunctionDecl?"); @@ -4506,8 +4488,15 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { ResolverName += ".resolver"; } - // If the resolver has already been created, just return it. - if (llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName)) + // If the resolver has already been created, just return it. This lookup may + // yield a function declaration instead of a resolver on AArch64. That is + // because we didn't know whether a resolver will be generated when we first + // encountered a use of the symbol named after this resolver. Therefore, + // targets which support ifuncs should not return here unless we actually + // found an ifunc. + llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName); + if (ResolverGV && + (isa<llvm::GlobalIFunc>(ResolverGV) || !getTarget().supportsIFunc())) return ResolverGV; const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); @@ -4533,7 +4522,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); - + if (ResolverGV) + replaceDeclarationWith(ResolverGV, GIF); return GIF; } @@ -4542,6 +4532,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) { assert(isa<llvm::GlobalValue>(Resolver) && "Resolver should be created for the first time"); SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver)); + if (ResolverGV) + replaceDeclarationWith(ResolverGV, Resolver); return Resolver; } @@ -4571,6 +4563,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( ForDefinition_t IsForDefinition) { const Decl *D = GD.getDecl(); + std::string NameWithoutMultiVersionMangling; // 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)) { @@ -4592,14 +4585,24 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( if (FD->isMultiVersion()) { UpdateMultiVersionNames(GD, FD, MangledName); - if (FD->getASTContext().getTargetInfo().getTriple().isAArch64() && - !FD->isUsed()) - AddDeferredMultiVersionResolverToEmit(GD); - else if (!IsForDefinition) - return GetOrCreateMultiVersionResolver(GD); + if (!IsForDefinition) { + // On AArch64 we do not immediatelly emit an ifunc resolver when a + // function is used. Instead we defer the emission until we see a + // default definition. In the meantime we just reference the symbol + // without FMV mangling (it may or may not be replaced later). + if (getTarget().getTriple().isAArch64()) { + AddDeferredMultiVersionResolverToEmit(GD); + NameWithoutMultiVersionMangling = getMangledNameImpl( + *this, GD, FD, /*OmitMultiVersionMangling=*/true); + } else + return GetOrCreateMultiVersionResolver(GD); + } } } + if (!NameWithoutMultiVersionMangling.empty()) + MangledName = NameWithoutMultiVersionMangling; + // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { |