diff options
author | Dmitry Polukhin <dmitry.polukhin@gmail.com> | 2016-04-11 07:48:59 +0000 |
---|---|---|
committer | Dmitry Polukhin <dmitry.polukhin@gmail.com> | 2016-04-11 07:48:59 +0000 |
commit | 85eda12d093714bfc9f266d50254e82888c9e8c3 (patch) | |
tree | 9216c6a571a665d295ab1d8f783c27e121c349a4 /clang/lib/CodeGen/CodeGenModule.cpp | |
parent | bbffeac569e89a61201ce159790f68b8493042b6 (diff) | |
download | llvm-85eda12d093714bfc9f266d50254e82888c9e8c3.zip llvm-85eda12d093714bfc9f266d50254e82888c9e8c3.tar.gz llvm-85eda12d093714bfc9f266d50254e82888c9e8c3.tar.bz2 |
[GCC] Attribute ifunc support in clang
This patch add support for GCC attribute((ifunc("resolver"))) for
targets that use ELF as object file format. In general ifunc is a
special kind of function alias with type @gnu_indirect_function. LLVM
patch http://reviews.llvm.org/D15525
Differential Revision: http://reviews.llvm.org/D15524
llvm-svn: 265917
Diffstat (limited to 'clang/lib/CodeGen/CodeGenModule.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 121 |
1 files changed, 100 insertions, 21 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 7e522f2..e4ae5bb 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -274,20 +274,21 @@ void CodeGenModule::applyGlobalValReplacements() { // This is only used in aliases that we created and we know they have a // linear structure. -static const llvm::GlobalObject *getAliasedGlobal(const llvm::GlobalAlias &GA) { - llvm::SmallPtrSet<const llvm::GlobalAlias*, 4> Visited; - const llvm::Constant *C = &GA; +static const llvm::GlobalObject *getAliasedGlobal( + const llvm::GlobalIndirectSymbol &GIS) { + llvm::SmallPtrSet<const llvm::GlobalIndirectSymbol*, 4> Visited; + const llvm::Constant *C = &GIS; for (;;) { C = C->stripPointerCasts(); if (auto *GO = dyn_cast<llvm::GlobalObject>(C)) return GO; // stripPointerCasts will not walk over weak aliases. - auto *GA2 = dyn_cast<llvm::GlobalAlias>(C); - if (!GA2) + auto *GIS2 = dyn_cast<llvm::GlobalIndirectSymbol>(C); + if (!GIS2) return nullptr; - if (!Visited.insert(GA2).second) + if (!Visited.insert(GIS2).second) return nullptr; - C = GA2->getAliasee(); + C = GIS2->getIndirectSymbol(); } } @@ -299,20 +300,35 @@ void CodeGenModule::checkAliases() { DiagnosticsEngine &Diags = getDiags(); for (const GlobalDecl &GD : Aliases) { const auto *D = cast<ValueDecl>(GD.getDecl()); - const AliasAttr *AA = D->getAttr<AliasAttr>(); + SourceLocation Location; + bool IsIFunc = D->hasAttr<IFuncAttr>(); + if (const Attr *A = D->getDefiningAttr()) + Location = A->getLocation(); + else + llvm_unreachable("Not an alias or ifunc?"); StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); - auto *Alias = cast<llvm::GlobalAlias>(Entry); + auto *Alias = cast<llvm::GlobalIndirectSymbol>(Entry); const llvm::GlobalValue *GV = getAliasedGlobal(*Alias); if (!GV) { Error = true; - Diags.Report(AA->getLocation(), diag::err_cyclic_alias); + Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; } else if (GV->isDeclaration()) { Error = true; - Diags.Report(AA->getLocation(), diag::err_alias_to_undefined); + Diags.Report(Location, diag::err_alias_to_undefined) + << IsIFunc << IsIFunc; + } else if (IsIFunc) { + // Check resolver function type. + llvm::FunctionType *FTy = dyn_cast<llvm::FunctionType>( + GV->getType()->getPointerElementType()); + assert(FTy); + if (!FTy->getReturnType()->isPointerTy()) + Diags.Report(Location, diag::err_ifunc_resolver_return); + if (FTy->getNumParams()) + Diags.Report(Location, diag::err_ifunc_resolver_params); } - llvm::Constant *Aliasee = Alias->getAliasee(); + llvm::Constant *Aliasee = Alias->getIndirectSymbol(); llvm::GlobalValue *AliaseeGV; if (auto CE = dyn_cast<llvm::ConstantExpr>(Aliasee)) AliaseeGV = cast<llvm::GlobalValue>(CE->getOperand(0)); @@ -323,7 +339,7 @@ void CodeGenModule::checkAliases() { StringRef AliasSection = SA->getName(); if (AliasSection != AliaseeGV->getSection()) Diags.Report(SA->getLocation(), diag::warn_alias_with_section) - << AliasSection; + << AliasSection << IsIFunc << IsIFunc; } // We have to handle alias to weak aliases in here. LLVM itself disallows @@ -331,13 +347,13 @@ void CodeGenModule::checkAliases() { // compatibility with gcc we implement it by just pointing the alias // to its aliasee's aliasee. We also warn, since the user is probably // expecting the link to be weak. - if (auto GA = dyn_cast<llvm::GlobalAlias>(AliaseeGV)) { + if (auto GA = dyn_cast<llvm::GlobalIndirectSymbol>(AliaseeGV)) { if (GA->isInterposable()) { - Diags.Report(AA->getLocation(), diag::warn_alias_to_weak_alias) - << GV->getName() << GA->getName(); + Diags.Report(Location, diag::warn_alias_to_weak_alias) + << GV->getName() << GA->getName() << IsIFunc; Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( - GA->getAliasee(), Alias->getType()); - Alias->setAliasee(Aliasee); + GA->getIndirectSymbol(), Alias->getType()); + Alias->setIndirectSymbol(Aliasee); } } } @@ -347,7 +363,7 @@ void CodeGenModule::checkAliases() { for (const GlobalDecl &GD : Aliases) { StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); - auto *Alias = cast<llvm::GlobalAlias>(Entry); + auto *Alias = dyn_cast<llvm::GlobalIndirectSymbol>(Entry); Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType())); Alias->eraseFromParent(); } @@ -1538,6 +1554,10 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { if (Global->hasAttr<AliasAttr>()) return EmitAliasDefinition(GD); + // IFunc like an alias whose value is resolved at runtime by calling resolver. + if (Global->hasAttr<IFuncAttr>()) + return emitIFuncDefinition(GD); + // If this is CUDA, be selective about which declarations we emit. if (LangOpts.CUDA) { if (LangOpts.CUDAIsDevice) { @@ -2901,7 +2921,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { StringRef MangledName = getMangledName(GD); if (AA->getAliasee() == MangledName) { - Diags.Report(AA->getLocation(), diag::err_cyclic_alias); + Diags.Report(AA->getLocation(), diag::err_cyclic_alias) << 0; return; } @@ -2932,7 +2952,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { if (Entry) { if (GA->getAliasee() == Entry) { - Diags.Report(AA->getLocation(), diag::err_cyclic_alias); + Diags.Report(AA->getLocation(), diag::err_cyclic_alias) << 0; return; } @@ -2969,6 +2989,65 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { setAliasAttributes(D, GA); } +void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) { + const auto *D = cast<ValueDecl>(GD.getDecl()); + const IFuncAttr *IFA = D->getAttr<IFuncAttr>(); + assert(IFA && "Not an ifunc?"); + + StringRef MangledName = getMangledName(GD); + + if (IFA->getResolver() == MangledName) { + Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1; + return; + } + + // Report an error if some definition overrides ifunc. + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + if (Entry && !Entry->isDeclaration()) { + GlobalDecl OtherGD; + if (lookupRepresentativeDecl(MangledName, OtherGD) && + DiagnosedConflictingDefinitions.insert(GD).second) { + Diags.Report(D->getLocation(), diag::err_duplicate_mangled_name); + Diags.Report(OtherGD.getDecl()->getLocation(), + diag::note_previous_definition); + } + return; + } + + Aliases.push_back(GD); + + llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); + llvm::Constant *Resolver = + GetOrCreateLLVMFunction(IFA->getResolver(), DeclTy, GD, + /*ForVTable=*/false); + llvm::GlobalIFunc *GIF = + llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage, + "", Resolver, &getModule()); + if (Entry) { + if (GIF->getResolver() == Entry) { + Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1; + return; + } + assert(Entry->isDeclaration()); + + // If there is a declaration in the module, then we had an extern followed + // by the ifunc, as in: + // extern int test(); + // ... + // int test() __attribute__((ifunc("resolver"))); + // + // Remove it and replace uses of it with the ifunc. + GIF->takeName(Entry); + + Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GIF, + Entry->getType())); + Entry->eraseFromParent(); + } else + GIF->setName(MangledName); + + SetCommonAttributes(D, GIF); +} + llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys) { return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, |