[GCC] Attribute ifunc support in llvm

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. Patch
for Clang http://reviews.llvm.org/D15524

Differential Revision: http://reviews.llvm.org/D15525

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265667 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dmitry Polukhin 2016-04-07 12:32:19 +00:00
parent 719a4bd1ab
commit ba4922356c
24 changed files with 369 additions and 22 deletions

View File

@ -764,6 +764,25 @@ some can only be checked when producing an object file:
* No global value in the expression can be a declaration, since that
would require a relocation, which is not possible.
.. _langref_ifunc:
IFuncs
-------
IFuncs, like as aliases, don't create any new data or func. They are just a new
symbol that dynamic linker resolves at runtime by calling a resolver function.
IFuncs have a name and a resolver that is a function called by dynamic linker
that returns address of another function associated with the name.
IFunc may have an optional :ref:`linkage type <linkage>` and an optional
:ref:`visibility style <visibility>`.
Syntax::
@<Name> = [Linkage] [Visibility] ifunc <IFuncTy>, <ResolverTy>* @<Resolver>
.. _langref_comdats:
Comdats

View File

@ -256,6 +256,7 @@ typedef enum {
LLVMFunctionValueKind,
LLVMGlobalAliasValueKind,
LLVMGlobalIFuncValueKind,
LLVMGlobalVariableValueKind,
LLVMBlockAddressValueKind,
LLVMConstantExprValueKind,

View File

@ -110,6 +110,9 @@ enum ModuleCodes {
// HASH: [5*i32]
MODULE_CODE_HASH = 17,
// IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility]
MODULE_CODE_IFUNC = 18,
};
/// PARAMATTR blocks have code for defining a parameter attribute set.

View File

@ -0,0 +1,76 @@
//===-------- llvm/GlobalIFunc.h - GlobalIFunc class ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \brief
/// This file contains the declaration of the GlobalIFunc class, which
/// represents a single indirect function in the IR. Indirect function uses
/// ELF symbol type extension to mark that the address of a declaration should
/// be resolved at runtime by calling a resolver function.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_GLOBALIFUNC_H
#define LLVM_IR_GLOBALIFUNC_H
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/IR/GlobalIndirectSymbol.h"
namespace llvm {
class Module;
// Traits class for using GlobalIFunc in symbol table in Module.
template <typename ValueSubClass> class SymbolTableListTraits;
class GlobalIFunc final : public GlobalIndirectSymbol,
public ilist_node<GlobalIFunc> {
friend class SymbolTableListTraits<GlobalIFunc>;
void operator=(const GlobalIFunc &) = delete;
GlobalIFunc(const GlobalIFunc &) = delete;
void setParent(Module *parent);
GlobalIFunc(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage,
const Twine &Name, Constant *Resolver, Module *Parent);
public:
/// If a parent module is specified, the ifunc is automatically inserted into
/// the end of the specified module's ifunc list.
static GlobalIFunc *create(Type *Ty, unsigned AddressSpace,
LinkageTypes Linkage, const Twine &Name,
Constant *Resolver, Module *Parent);
/// This method unlinks 'this' from the containing module, but does not
/// delete it.
void removeFromParent() final;
/// This method unlinks 'this' from the containing module and deletes it.
void eraseFromParent() final;
/// These methods retrieve and set ifunc resolver function.
void setResolver(Constant *Resolver) {
setIndirectSymbol(Resolver);
}
const Constant *getResolver() const {
return getIndirectSymbol();
}
Constant *getResolver() {
return getIndirectSymbol();
}
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Value *V) {
return V->getValueID() == Value::GlobalIFuncVal;
}
};
} // End llvm namespace
#endif

View File

@ -51,7 +51,8 @@ public:
// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const Value *V) {
return V->getValueID() == Value::GlobalAliasVal;
return V->getValueID() == Value::GlobalAliasVal ||
V->getValueID() == Value::GlobalIFuncVal;
}
};

View File

@ -388,7 +388,8 @@ public:
static bool classof(const Value *V) {
return V->getValueID() == Value::FunctionVal ||
V->getValueID() == Value::GlobalVariableVal ||
V->getValueID() == Value::GlobalAliasVal;
V->getValueID() == Value::GlobalAliasVal ||
V->getValueID() == Value::GlobalIFuncVal;
}
};

View File

@ -21,6 +21,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalIFunc.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/CBindingWrapping.h"
@ -75,6 +76,8 @@ public:
typedef SymbolTableList<Function> FunctionListType;
/// The type for the list of aliases.
typedef SymbolTableList<GlobalAlias> AliasListType;
/// The type for the list of ifuncs.
typedef SymbolTableList<GlobalIFunc> IFuncListType;
/// The type for the list of named metadata.
typedef ilist<NamedMDNode> NamedMDListType;
/// The type of the comdat "symbol" table.
@ -100,6 +103,11 @@ public:
/// The Global Alias constant iterator
typedef AliasListType::const_iterator const_alias_iterator;
/// The Global IFunc iterators.
typedef IFuncListType::iterator ifunc_iterator;
/// The Global IFunc constant iterator
typedef IFuncListType::const_iterator const_ifunc_iterator;
/// The named metadata iterators.
typedef NamedMDListType::iterator named_metadata_iterator;
/// The named metadata constant iterators.
@ -163,6 +171,7 @@ private:
GlobalListType GlobalList; ///< The Global Variables in the module
FunctionListType FunctionList; ///< The Functions in the module
AliasListType AliasList; ///< The Aliases in the module
IFuncListType IFuncList; ///< The IFuncs in the module
NamedMDListType NamedMDList; ///< The named metadata in the module
std::string GlobalScopeAsm; ///< Inline Asm at global scope.
ValueSymbolTable *ValSymTab; ///< Symbol table for values
@ -383,6 +392,15 @@ public:
/// name is not found.
GlobalAlias *getNamedAlias(StringRef Name) const;
/// @}
/// @name Global IFunc Accessors
/// @{
/// Return the global ifunc in the module with the specified name, of
/// arbitrary type. This method returns null if a global with the specified
/// name is not found.
GlobalIFunc *getNamedIFunc(StringRef Name) const;
/// @}
/// @name Named Metadata Accessors
/// @{
@ -486,6 +504,13 @@ public:
static AliasListType Module::*getSublistAccess(GlobalAlias*) {
return &Module::AliasList;
}
/// Get the Module's list of ifuncs (constant).
const IFuncListType &getIFuncList() const { return IFuncList; }
/// Get the Module's list of ifuncs.
IFuncListType &getIFuncList() { return IFuncList; }
static IFuncListType Module::*getSublistAccess(GlobalIFunc*) {
return &Module::IFuncList;
}
/// Get the Module's list of named metadata (constant).
const NamedMDListType &getNamedMDList() const { return NamedMDList; }
/// Get the Module's list of named metadata.
@ -559,6 +584,24 @@ public:
return make_range(alias_begin(), alias_end());
}
/// @}
/// @name IFunc Iteration
/// @{
ifunc_iterator ifunc_begin() { return IFuncList.begin(); }
const_ifunc_iterator ifunc_begin() const { return IFuncList.begin(); }
ifunc_iterator ifunc_end () { return IFuncList.end(); }
const_ifunc_iterator ifunc_end () const { return IFuncList.end(); }
size_t ifunc_size () const { return IFuncList.size(); }
bool ifunc_empty() const { return IFuncList.empty(); }
iterator_range<ifunc_iterator> ifuncs() {
return make_range(ifunc_begin(), ifunc_end());
}
iterator_range<const_ifunc_iterator> ifuncs() const {
return make_range(ifunc_begin(), ifunc_end());
}
/// @}
/// @name Named Metadata Iteration
/// @{

View File

@ -49,6 +49,7 @@ class Function;
class Instruction;
class GlobalVariable;
class GlobalAlias;
class GlobalIFunc;
class Module;
#define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \
template <> struct SymbolTableListParentType<NODE> { typedef PARENT type; };
@ -58,6 +59,7 @@ DEFINE_SYMBOL_TABLE_PARENT_TYPE(Argument, Function)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(Function, Module)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalVariable, Module)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalAlias, Module)
DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalIFunc, Module)
#undef DEFINE_SYMBOL_TABLE_PARENT_TYPE
template <typename NodeTy> class SymbolTableList;

View File

@ -60,6 +60,7 @@ HANDLE_VALUE(MemoryPhi)
HANDLE_GLOBAL_VALUE(Function)
HANDLE_GLOBAL_VALUE(GlobalAlias)
HANDLE_GLOBAL_VALUE(GlobalIFunc)
HANDLE_GLOBAL_VALUE(GlobalVariable)
HANDLE_CONSTANT(BlockAddress)
HANDLE_CONSTANT(ConstantExpr)

View File

@ -32,6 +32,7 @@ class ConstantAggregate;
class DataLayout;
class Function;
class GlobalAlias;
class GlobalIFunc;
class GlobalIndirectSymbol;
class GlobalObject;
class GlobalValue;
@ -751,9 +752,15 @@ template <> struct isa_impl<GlobalAlias, Value> {
}
};
template <> struct isa_impl<GlobalIFunc, Value> {
static inline bool doit(const Value &Val) {
return Val.getValueID() == Value::GlobalIFuncVal;
}
};
template <> struct isa_impl<GlobalIndirectSymbol, Value> {
static inline bool doit(const Value &Val) {
return isa<GlobalAlias>(Val);
return isa<GlobalAlias>(Val) || isa<GlobalIFunc>(Val);
}
};

View File

@ -39,6 +39,7 @@ class ValueSymbolTable {
friend class SymbolTableListTraits<Function>;
friend class SymbolTableListTraits<GlobalVariable>;
friend class SymbolTableListTraits<GlobalAlias>;
friend class SymbolTableListTraits<GlobalIFunc>;
/// @name Types
/// @{
public:

View File

@ -560,6 +560,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(addrspace);
KEYWORD(section);
KEYWORD(alias);
KEYWORD(ifunc);
KEYWORD(module);
KEYWORD(asm);
KEYWORD(sideeffect);

View File

@ -467,10 +467,10 @@ bool LLParser::ParseGlobalType(bool &IsConstant) {
}
/// ParseUnnamedGlobal:
/// OptionalVisibility ALIAS ...
/// OptionalVisibility (ALIAS | IFUNC) ...
/// OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// ... -> global variable
/// GlobalID '=' OptionalVisibility ALIAS ...
/// GlobalID '=' OptionalVisibility (ALIAS | IFUNC) ...
/// GlobalID '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// ... -> global variable
bool LLParser::ParseUnnamedGlobal() {
@ -500,7 +500,7 @@ bool LLParser::ParseUnnamedGlobal() {
parseOptionalUnnamedAddr(UnnamedAddr))
return true;
if (Lex.getKind() != lltok::kw_alias)
if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
@ -509,7 +509,7 @@ bool LLParser::ParseUnnamedGlobal() {
}
/// ParseNamedGlobal:
/// GlobalVar '=' OptionalVisibility ALIAS ...
/// GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ...
/// GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass
/// ... -> global variable
bool LLParser::ParseNamedGlobal() {
@ -530,7 +530,7 @@ bool LLParser::ParseNamedGlobal() {
parseOptionalUnnamedAddr(UnnamedAddr))
return true;
if (Lex.getKind() != lltok::kw_alias)
if (Lex.getKind() != lltok::kw_alias && Lex.getKind() != lltok::kw_ifunc)
return ParseGlobal(Name, NameLoc, Linkage, HasLinkage, Visibility,
DLLStorageClass, TLM, UnnamedAddr);
@ -695,7 +695,7 @@ static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
/// parseIndirectSymbol:
/// ::= GlobalVar '=' OptionalLinkage OptionalVisibility
/// OptionalDLLStorageClass OptionalThreadLocal
/// OptionalUnnamedAddr 'alias' IndirectSymbol
/// OptionalUnnamedAddr 'alias|ifunc' IndirectSymbol
///
/// IndirectSymbol
/// ::= TypeAndValue
@ -710,8 +710,10 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
bool IsAlias;
if (Lex.getKind() == lltok::kw_alias)
IsAlias = true;
else if (Lex.getKind() == lltok::kw_ifunc)
IsAlias = false;
else
llvm_unreachable("Not an alias!");
llvm_unreachable("Not an alias or ifunc!");
Lex.Lex();
GlobalValue::LinkageTypes Linkage = (GlobalValue::LinkageTypes) L;
@ -726,7 +728,7 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
Type *Ty;
LocTy ExplicitTypeLoc = Lex.getLoc();
if (ParseType(Ty) ||
ParseToken(lltok::comma, "expected comma after alias's type"))
ParseToken(lltok::comma, "expected comma after alias or ifunc's type"))
return true;
Constant *Aliasee;
@ -750,7 +752,7 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
Type *AliaseeType = Aliasee->getType();
auto *PTy = dyn_cast<PointerType>(AliaseeType);
if (!PTy)
return Error(AliaseeLoc, "An alias must have pointer type");
return Error(AliaseeLoc, "An alias or ifunc must have pointer type");
unsigned AddrSpace = PTy->getAddressSpace();
if (IsAlias && Ty != PTy->getElementType())
@ -788,7 +790,9 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
(GlobalValue::LinkageTypes)Linkage, Name,
Aliasee, /*Parent*/ nullptr));
else
llvm_unreachable("Not an alias!");
GA.reset(GlobalIFunc::create(Ty, AddrSpace,
(GlobalValue::LinkageTypes)Linkage, Name,
Aliasee, /*Parent*/ nullptr));
GA->setThreadLocalMode(TLM);
GA->setVisibility((GlobalValue::VisibilityTypes)Visibility);
GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass);
@ -814,7 +818,7 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
if (IsAlias)
M->getAliasList().push_back(cast<GlobalAlias>(GA.get()));
else
llvm_unreachable("Not an alias!");
M->getIFuncList().push_back(cast<GlobalIFunc>(GA.get()));
assert(GA->getName() == Name && "Should not be a name conflict!");
// The module owns this now

View File

@ -80,6 +80,7 @@ namespace lltok {
kw_addrspace,
kw_section,
kw_alias,
kw_ifunc,
kw_module,
kw_asm,
kw_sideeffect,

View File

@ -3658,6 +3658,8 @@ std::error_code BitcodeReader::parseModule(uint64_t ResumeBit,
}
// ALIAS: [alias type, addrspace, aliasee val#, linkage]
// ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass]
// IFUNC: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass]
case bitc::MODULE_CODE_IFUNC:
case bitc::MODULE_CODE_ALIAS:
case bitc::MODULE_CODE_ALIAS_OLD: {
bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD;
@ -3684,10 +3686,11 @@ std::error_code BitcodeReader::parseModule(uint64_t ResumeBit,
GlobalIndirectSymbol *NewGA;
if (BitCode == bitc::MODULE_CODE_ALIAS ||
BitCode == bitc::MODULE_CODE_ALIAS_OLD)
NewGA = GlobalAlias::create(
Ty, AddrSpace, getDecodedLinkage(Linkage), "", TheModule);
NewGA = GlobalAlias::create(Ty, AddrSpace, getDecodedLinkage(Linkage),
"", TheModule);
else
llvm_unreachable("Not an alias!");
NewGA = GlobalIFunc::create(Ty, AddrSpace, getDecodedLinkage(Linkage),
"", nullptr, TheModule);
// Old bitcode files didn't have visibility field.
// Local linkage must have default visibility.
if (OpNum != Record.size()) {

View File

@ -809,6 +809,18 @@ static uint64_t WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
Vals.clear();
}
// Emit the ifunc information.
for (const GlobalIFunc &I : M->ifuncs()) {
// IFUNC: [ifunc type, address space, resolver val#, linkage, visibility]
Vals.push_back(VE.getTypeID(I.getValueType()));
Vals.push_back(I.getType()->getAddressSpace());
Vals.push_back(VE.getValueID(I.getResolver()));
Vals.push_back(getEncodedLinkage(I));
Vals.push_back(getEncodedVisibility(I));
Stream.EmitRecord(bitc::MODULE_CODE_IFUNC, Vals);
Vals.clear();
}
// Emit the module's source file name.
{
StringEncoding Bits = getStringEncoding(M->getSourceFileName().data(),

View File

@ -86,6 +86,9 @@ static OrderMap orderModule(const Module &M) {
for (const GlobalAlias &A : M.aliases())
if (!isa<GlobalValue>(A.getAliasee()))
orderValue(A.getAliasee(), OM);
for (const GlobalIFunc &I : M.ifuncs())
if (!isa<GlobalValue>(I.getResolver()))
orderValue(I.getResolver(), OM);
for (const Function &F : M) {
for (const Use &U : F.operands())
if (!isa<GlobalValue>(U.get()))
@ -105,6 +108,8 @@ static OrderMap orderModule(const Module &M) {
orderValue(&F, OM);
for (const GlobalAlias &A : M.aliases())
orderValue(&A, OM);
for (const GlobalIFunc &I : M.ifuncs())
orderValue(&I, OM);
for (const GlobalVariable &G : M.globals())
orderValue(&G, OM);
OM.LastGlobalValueID = OM.size();
@ -261,11 +266,15 @@ static UseListOrderStack predictUseListOrder(const Module &M) {
predictValueUseListOrder(&F, nullptr, OM, Stack);
for (const GlobalAlias &A : M.aliases())
predictValueUseListOrder(&A, nullptr, OM, Stack);
for (const GlobalIFunc &I : M.ifuncs())
predictValueUseListOrder(&I, nullptr, OM, Stack);
for (const GlobalVariable &G : M.globals())
if (G.hasInitializer())
predictValueUseListOrder(G.getInitializer(), nullptr, OM, Stack);
for (const GlobalAlias &A : M.aliases())
predictValueUseListOrder(A.getAliasee(), nullptr, OM, Stack);
for (const GlobalIFunc &I : M.ifuncs())
predictValueUseListOrder(I.getResolver(), nullptr, OM, Stack);
for (const Function &F : M) {
for (const Use &U : F.operands())
predictValueUseListOrder(U.get(), nullptr, OM, Stack);
@ -298,6 +307,10 @@ ValueEnumerator::ValueEnumerator(const Module &M,
for (const GlobalAlias &GA : M.aliases())
EnumerateValue(&GA);
// Enumerate the ifuncs.
for (const GlobalIFunc &GIF : M.ifuncs())
EnumerateValue(&GIF);
// Remember what is the cutoff between globalvalue's and other constants.
unsigned FirstConstant = Values.size();
@ -310,6 +323,10 @@ ValueEnumerator::ValueEnumerator(const Module &M,
for (const GlobalAlias &GA : M.aliases())
EnumerateValue(GA.getAliasee());
// Enumerate the ifunc resolvers.
for (const GlobalIFunc &GIF : M.ifuncs())
EnumerateValue(GIF.getResolver());
// Enumerate any optional Function data.
for (const Function &F : M)
for (const Use &U : F.operands())

View File

@ -1069,12 +1069,15 @@ void AsmPrinter::emitGlobalIndirectSymbol(Module &M,
else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage())
OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference);
else
assert(GIS.hasLocalLinkage() && "Invalid alias linkage");
assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage");
// Set the symbol type to function if the alias has a function type.
// This affects codegen when the aliasee is not a function.
if (GIS.getType()->getPointerElementType()->isFunctionTy())
if (GIS.getType()->getPointerElementType()->isFunctionTy()) {
OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction);
if (isa<GlobalIFunc>(GIS))
OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction);
}
EmitVisibility(Name, GIS.getVisibility());
@ -1209,6 +1212,8 @@ bool AsmPrinter::doFinalization(Module &M) {
emitGlobalIndirectSymbol(M, *AncestorAlias);
AliasStack.clear();
}
for (const auto &IFunc : M.ifuncs())
emitGlobalIndirectSymbol(M, IFunc);
GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
assert(MI && "AsmPrinter didn't require GCModuleInfo?");

View File

@ -102,6 +102,11 @@ static OrderMap orderModule(const Module *M) {
orderValue(A.getAliasee(), OM);
orderValue(&A, OM);
}
for (const GlobalIFunc &I : M->ifuncs()) {
if (!isa<GlobalValue>(I.getResolver()))
orderValue(I.getResolver(), OM);
orderValue(&I, OM);
}
for (const Function &F : *M) {
for (const Use &U : F.operands())
if (!isa<GlobalValue>(U.get()))
@ -249,11 +254,15 @@ static UseListOrderStack predictUseListOrder(const Module *M) {
predictValueUseListOrder(&F, nullptr, OM, Stack);
for (const GlobalAlias &A : M->aliases())
predictValueUseListOrder(&A, nullptr, OM, Stack);
for (const GlobalIFunc &I : M->ifuncs())
predictValueUseListOrder(&I, nullptr, OM, Stack);
for (const GlobalVariable &G : M->globals())
if (G.hasInitializer())
predictValueUseListOrder(G.getInitializer(), nullptr, OM, Stack);
for (const GlobalAlias &A : M->aliases())
predictValueUseListOrder(A.getAliasee(), nullptr, OM, Stack);
for (const GlobalIFunc &I : M->ifuncs())
predictValueUseListOrder(I.getResolver(), nullptr, OM, Stack);
for (const Function &F : *M)
for (const Use &U : F.operands())
predictValueUseListOrder(U.get(), nullptr, OM, Stack);
@ -729,6 +738,9 @@ static SlotTracker *createSlotTracker(const Value *V) {
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(V))
return new SlotTracker(GA->getParent());
if (const GlobalIFunc *GIF = dyn_cast<GlobalIFunc>(V))
return new SlotTracker(GIF->getParent());
if (const Function *Func = dyn_cast<Function>(V))
return new SlotTracker(Func);
@ -782,6 +794,11 @@ void SlotTracker::processModule() {
CreateModuleSlot(&A);
}
for (const GlobalIFunc &I : TheModule->ifuncs()) {
if (!I.hasName())
CreateModuleSlot(&I);
}
// Add metadata used by named metadata.
for (const NamedMDNode &NMD : TheModule->named_metadata()) {
for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i)
@ -945,10 +962,11 @@ void SlotTracker::CreateModuleSlot(const GlobalValue *V) {
ST_DEBUG(" Inserting value [" << V->getType() << "] = " << V << " slot=" <<
DestSlot << " [");
// G = Global, F = Function, A = Alias, o = other
// G = Global, F = Function, A = Alias, I = IFunc, o = other
ST_DEBUG((isa<GlobalVariable>(V) ? 'G' :
(isa<Function>(V) ? 'F' :
(isa<GlobalAlias>(V) ? 'A' : 'o'))) << "]\n");
(isa<GlobalAlias>(V) ? 'A' :
(isa<GlobalIFunc>(V) ? 'I' : 'o')))) << "]\n");
}
/// CreateSlot - Create a new slot for the specified value if it has no name.
@ -2253,6 +2271,11 @@ void AssemblyWriter::printModule(const Module *M) {
for (const GlobalAlias &GA : M->aliases())
printIndirectSymbol(&GA);
// Output all ifuncs.
if (!M->ifunc_empty()) Out << "\n";
for (const GlobalIFunc &GI : M->ifuncs())
printIndirectSymbol(&GI);
// Output global use-lists.
printUseLists(nullptr);
@ -2448,8 +2471,10 @@ void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) {
if (isa<GlobalAlias>(GIS))
Out << "alias ";
else if (isa<GlobalIFunc>(GIS))
Out << "ifunc ";
else
llvm_unreachable("Not an alias!");
llvm_unreachable("Not an alias or ifunc!");
TypePrinter.print(GIS->getValueType(), Out);

View File

@ -145,6 +145,9 @@ Comdat *GlobalValue::getComdat() {
return const_cast<GlobalObject *>(GO)->getComdat();
return nullptr;
}
// ifunc and its resolver are separate things so don't use resolver comdat.
if (isa<GlobalIFunc>(this))
return nullptr;
return cast<GlobalObject>(this)->getComdat();
}
@ -364,3 +367,34 @@ void GlobalAlias::setAliasee(Constant *Aliasee) {
"Alias and aliasee types should match!");
setIndirectSymbol(Aliasee);
}
//===----------------------------------------------------------------------===//
// GlobalIFunc Implementation
//===----------------------------------------------------------------------===//
GlobalIFunc::GlobalIFunc(Type *Ty, unsigned AddressSpace, LinkageTypes Link,
const Twine &Name, Constant *Resolver,
Module *ParentModule)
: GlobalIndirectSymbol(Ty, Value::GlobalIFuncVal, AddressSpace, Link, Name,
Resolver) {
if (ParentModule)
ParentModule->getIFuncList().push_back(this);
}
GlobalIFunc *GlobalIFunc::create(Type *Ty, unsigned AddressSpace,
LinkageTypes Link, const Twine &Name,
Constant *Resolver, Module *ParentModule) {
return new GlobalIFunc(Ty, AddressSpace, Link, Name, Resolver, ParentModule);
}
void GlobalIFunc::setParent(Module *parent) {
Parent = parent;
}
void GlobalIFunc::removeFromParent() {
getParent()->getIFuncList().remove(getIterator());
}
void GlobalIFunc::eraseFromParent() {
getParent()->getIFuncList().erase(getIterator());
}

View File

@ -41,6 +41,7 @@ using namespace llvm;
template class llvm::SymbolTableListTraits<Function>;
template class llvm::SymbolTableListTraits<GlobalVariable>;
template class llvm::SymbolTableListTraits<GlobalAlias>;
template class llvm::SymbolTableListTraits<GlobalIFunc>;
//===----------------------------------------------------------------------===//
// Primitive Module methods.
@ -59,6 +60,7 @@ Module::~Module() {
GlobalList.clear();
FunctionList.clear();
AliasList.clear();
IFuncList.clear();
NamedMDList.clear();
delete ValSymTab;
delete static_cast<StringMap<NamedMDNode *> *>(NamedMDSymTab);
@ -250,6 +252,10 @@ GlobalAlias *Module::getNamedAlias(StringRef Name) const {
return dyn_cast_or_null<GlobalAlias>(getNamedValue(Name));
}
GlobalIFunc *Module::getNamedIFunc(StringRef Name) const {
return dyn_cast_or_null<GlobalIFunc>(getNamedValue(Name));
}
/// getNamedMetadata - Return the first NamedMDNode in the module with the
/// specified name. This method returns null if a NamedMDNode with the
/// specified name is not found.
@ -438,6 +444,9 @@ void Module::dropAllReferences() {
for (GlobalAlias &GA : aliases())
GA.dropAllReferences();
for (GlobalIFunc &GIF : ifuncs())
GIF.dropAllReferences();
}
unsigned Module::getDwarfVersion() const {

View File

@ -0,0 +1,14 @@
; RUN: llvm-as < %s | llvm-dis | FileCheck %s --check-prefix=CHECK-LLVM
; RUN: llvm-as < %s -o - | llc -filetype=asm | FileCheck %s --check-prefix=CHECK-ASM
target triple = "x86_64-unknown-linux-gnu"
@foo = ifunc i32 (i32), i64 ()* @foo_ifunc
; CHECK-LLVM: @foo = ifunc i32 (i32), i64 ()* @foo_ifunc
; CHECK-ASM: .type foo,@gnu_indirect_function
define internal i64 @foo_ifunc() {
entry:
ret i64 0
}
; CHECK-LLVM: define internal i64 @foo_ifunc()

View File

@ -0,0 +1,42 @@
; RUN: verify-uselistorder < %s
; Global referencing ifunc.
@ptr_foo = global void ()* @foo_ifunc
; Alias for ifunc.
@alias_foo = alias void (), void ()* @foo_ifunc
@foo_ifunc = ifunc void (), i8* ()* @foo_resolver
define i8* @foo_resolver() {
entry:
ret i8* null
}
; Function referencing ifunc.
define void @bar() {
entry:
call void @foo_ifunc()
ret void
}
; Global referencing function.
@ptr_bar = global void ()* @bar
; Alias for function.
@alias_bar = alias void (), void ()* @bar
@bar_ifunc = ifunc void (), i8* ()* @bar2_ifunc
@bar2_ifunc = ifunc i8* (), i8* ()* @bar_resolver
define i8* @bar_resolver() {
entry:
ret i8* null
}
; Function referencing bar.
define void @bar2() {
entry:
call void @bar()
ret void
}

View File

@ -249,6 +249,31 @@ declare void @g.f1()
@a.unnamed_addr = unnamed_addr alias i32, i32* @g.unnamed_addr
; CHECK: @a.unnamed_addr = unnamed_addr alias i32, i32* @g.unnamed_addr
;; IFunc
; Format @<Name> = [Linkage] [Visibility] ifunc <IFuncTy>,
; <ResolverTy>* @<Resolver>
; IFunc -- Linkage
@ifunc.external = external ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.external = ifunc void (), i8* ()* @ifunc_resolver
@ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver
@ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver
; IFunc -- Visibility
@ifunc.default = default ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.default = ifunc void (), i8* ()* @ifunc_resolver
@ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver
@ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
define i8* @ifunc_resolver() {
entry:
ret i8* null
}
;; Functions
; Format: define [linkage] [visibility] [DLLStorageClass]
; [cconv] [ret attrs]