mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-23 11:49:50 +00:00
[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:
parent
719a4bd1ab
commit
ba4922356c
@ -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
|
||||
|
@ -256,6 +256,7 @@ typedef enum {
|
||||
|
||||
LLVMFunctionValueKind,
|
||||
LLVMGlobalAliasValueKind,
|
||||
LLVMGlobalIFuncValueKind,
|
||||
LLVMGlobalVariableValueKind,
|
||||
LLVMBlockAddressValueKind,
|
||||
LLVMConstantExprValueKind,
|
||||
|
@ -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.
|
||||
|
76
include/llvm/IR/GlobalIFunc.h
Normal file
76
include/llvm/IR/GlobalIFunc.h
Normal 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
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
/// @{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -560,6 +560,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||
KEYWORD(addrspace);
|
||||
KEYWORD(section);
|
||||
KEYWORD(alias);
|
||||
KEYWORD(ifunc);
|
||||
KEYWORD(module);
|
||||
KEYWORD(asm);
|
||||
KEYWORD(sideeffect);
|
||||
|
@ -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
|
||||
|
@ -80,6 +80,7 @@ namespace lltok {
|
||||
kw_addrspace,
|
||||
kw_section,
|
||||
kw_alias,
|
||||
kw_ifunc,
|
||||
kw_module,
|
||||
kw_asm,
|
||||
kw_sideeffect,
|
||||
|
@ -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()) {
|
||||
|
@ -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(),
|
||||
|
@ -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())
|
||||
|
@ -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?");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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 {
|
||||
|
14
test/Assembler/ifunc-asm.ll
Normal file
14
test/Assembler/ifunc-asm.ll
Normal 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()
|
42
test/Assembler/ifunc-use-list-order.ll
Normal file
42
test/Assembler/ifunc-use-list-order.ll
Normal 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
|
||||
}
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user