Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -764,6 +764,25 @@ * 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 ` and an optional +:ref:`visibility style `. + +Syntax:: + + @ = [Linkage] [Visibility] ifunc , * @ + + .. _langref_comdats: Comdats Index: llvm/trunk/include/llvm-c/Core.h =================================================================== --- llvm/trunk/include/llvm-c/Core.h +++ llvm/trunk/include/llvm-c/Core.h @@ -256,6 +256,7 @@ LLVMFunctionValueKind, LLVMGlobalAliasValueKind, + LLVMGlobalIFuncValueKind, LLVMGlobalVariableValueKind, LLVMBlockAddressValueKind, LLVMConstantExprValueKind, Index: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h @@ -110,6 +110,9 @@ // 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. Index: llvm/trunk/include/llvm/IR/GlobalIFunc.h =================================================================== --- llvm/trunk/include/llvm/IR/GlobalIFunc.h +++ llvm/trunk/include/llvm/IR/GlobalIFunc.h @@ -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 class SymbolTableListTraits; + +class GlobalIFunc final : public GlobalIndirectSymbol, + public ilist_node { + friend class SymbolTableListTraits; + 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 Index: llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h =================================================================== --- llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h +++ llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h @@ -51,7 +51,8 @@ // 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; } }; Index: llvm/trunk/include/llvm/IR/GlobalValue.h =================================================================== --- llvm/trunk/include/llvm/IR/GlobalValue.h +++ llvm/trunk/include/llvm/IR/GlobalValue.h @@ -388,7 +388,8 @@ 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; } }; Index: llvm/trunk/include/llvm/IR/Module.h =================================================================== --- llvm/trunk/include/llvm/IR/Module.h +++ llvm/trunk/include/llvm/IR/Module.h @@ -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 @@ typedef SymbolTableList FunctionListType; /// The type for the list of aliases. typedef SymbolTableList AliasListType; + /// The type for the list of ifuncs. + typedef SymbolTableList IFuncListType; /// The type for the list of named metadata. typedef ilist NamedMDListType; /// The type of the comdat "symbol" table. @@ -100,6 +103,11 @@ /// 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 @@ 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 @@ -384,6 +393,15 @@ 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 @@ 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. @@ -560,6 +585,24 @@ } /// @} +/// @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 ifuncs() { + return make_range(ifunc_begin(), ifunc_end()); + } + iterator_range ifuncs() const { + return make_range(ifunc_begin(), ifunc_end()); + } + +/// @} /// @name Named Metadata Iteration /// @{ Index: llvm/trunk/include/llvm/IR/SymbolTableListTraits.h =================================================================== --- llvm/trunk/include/llvm/IR/SymbolTableListTraits.h +++ llvm/trunk/include/llvm/IR/SymbolTableListTraits.h @@ -49,6 +49,7 @@ class Instruction; class GlobalVariable; class GlobalAlias; +class GlobalIFunc; class Module; #define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \ template <> struct SymbolTableListParentType { typedef PARENT type; }; @@ -58,6 +59,7 @@ 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 class SymbolTableList; Index: llvm/trunk/include/llvm/IR/Value.h =================================================================== --- llvm/trunk/include/llvm/IR/Value.h +++ llvm/trunk/include/llvm/IR/Value.h @@ -32,6 +32,7 @@ class DataLayout; class Function; class GlobalAlias; +class GlobalIFunc; class GlobalIndirectSymbol; class GlobalObject; class GlobalValue; @@ -751,9 +752,15 @@ } }; +template <> struct isa_impl { + static inline bool doit(const Value &Val) { + return Val.getValueID() == Value::GlobalIFuncVal; + } +}; + template <> struct isa_impl { static inline bool doit(const Value &Val) { - return isa(Val); + return isa(Val) || isa(Val); } }; Index: llvm/trunk/include/llvm/IR/Value.def =================================================================== --- llvm/trunk/include/llvm/IR/Value.def +++ llvm/trunk/include/llvm/IR/Value.def @@ -60,6 +60,7 @@ HANDLE_GLOBAL_VALUE(Function) HANDLE_GLOBAL_VALUE(GlobalAlias) +HANDLE_GLOBAL_VALUE(GlobalIFunc) HANDLE_GLOBAL_VALUE(GlobalVariable) HANDLE_CONSTANT(BlockAddress) HANDLE_CONSTANT(ConstantExpr) Index: llvm/trunk/include/llvm/IR/ValueSymbolTable.h =================================================================== --- llvm/trunk/include/llvm/IR/ValueSymbolTable.h +++ llvm/trunk/include/llvm/IR/ValueSymbolTable.h @@ -39,6 +39,7 @@ friend class SymbolTableListTraits; friend class SymbolTableListTraits; friend class SymbolTableListTraits; + friend class SymbolTableListTraits; /// @name Types /// @{ public: Index: llvm/trunk/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLLexer.cpp +++ llvm/trunk/lib/AsmParser/LLLexer.cpp @@ -560,6 +560,7 @@ KEYWORD(addrspace); KEYWORD(section); KEYWORD(alias); + KEYWORD(ifunc); KEYWORD(module); KEYWORD(asm); KEYWORD(sideeffect); Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -467,10 +467,10 @@ } /// 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 @@ 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 @@ } /// ParseNamedGlobal: -/// GlobalVar '=' OptionalVisibility ALIAS ... +/// GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ... /// GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass /// ... -> global variable bool LLParser::ParseNamedGlobal() { @@ -530,7 +530,7 @@ 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 @@ /// parseIndirectSymbol: /// ::= GlobalVar '=' OptionalLinkage OptionalVisibility /// OptionalDLLStorageClass OptionalThreadLocal -/// OptionalUnnamedAddr 'alias' IndirectSymbol +/// OptionalUnnamedAddr 'alias|ifunc' IndirectSymbol /// /// IndirectSymbol /// ::= TypeAndValue @@ -710,8 +710,10 @@ 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 @@ 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 @@ Type *AliaseeType = Aliasee->getType(); auto *PTy = dyn_cast(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 @@ (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 @@ if (IsAlias) M->getAliasList().push_back(cast(GA.get())); else - llvm_unreachable("Not an alias!"); + M->getIFuncList().push_back(cast(GA.get())); assert(GA->getName() == Name && "Should not be a name conflict!"); // The module owns this now Index: llvm/trunk/lib/AsmParser/LLToken.h =================================================================== --- llvm/trunk/lib/AsmParser/LLToken.h +++ llvm/trunk/lib/AsmParser/LLToken.h @@ -80,6 +80,7 @@ kw_addrspace, kw_section, kw_alias, + kw_ifunc, kw_module, kw_asm, kw_sideeffect, Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3658,6 +3658,8 @@ } // 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 @@ 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()) { Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -809,6 +809,18 @@ 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(), Index: llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp +++ llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -86,6 +86,9 @@ for (const GlobalAlias &A : M.aliases()) if (!isa(A.getAliasee())) orderValue(A.getAliasee(), OM); + for (const GlobalIFunc &I : M.ifuncs()) + if (!isa(I.getResolver())) + orderValue(I.getResolver(), OM); for (const Function &F : M) { for (const Use &U : F.operands()) if (!isa(U.get())) @@ -105,6 +108,8 @@ 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 @@ 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 @@ 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 @@ 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()) Index: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1069,12 +1069,15 @@ 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(GIS)) + OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); + } EmitVisibility(Name, GIS.getVisibility()); @@ -1209,6 +1212,8 @@ emitGlobalIndirectSymbol(M, *AncestorAlias); AliasStack.clear(); } + for (const auto &IFunc : M.ifuncs()) + emitGlobalIndirectSymbol(M, IFunc); GCModuleInfo *MI = getAnalysisIfAvailable(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); Index: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/lib/IR/AsmWriter.cpp @@ -102,6 +102,11 @@ orderValue(A.getAliasee(), OM); orderValue(&A, OM); } + for (const GlobalIFunc &I : M->ifuncs()) { + if (!isa(I.getResolver())) + orderValue(I.getResolver(), OM); + orderValue(&I, OM); + } for (const Function &F : *M) { for (const Use &U : F.operands()) if (!isa(U.get())) @@ -249,11 +254,15 @@ 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 @@ if (const GlobalAlias *GA = dyn_cast(V)) return new SlotTracker(GA->getParent()); + if (const GlobalIFunc *GIF = dyn_cast(V)) + return new SlotTracker(GIF->getParent()); + if (const Function *Func = dyn_cast(V)) return new SlotTracker(Func); @@ -782,6 +794,11 @@ 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 @@ 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(V) ? 'G' : (isa(V) ? 'F' : - (isa(V) ? 'A' : 'o'))) << "]\n"); + (isa(V) ? 'A' : + (isa(V) ? 'I' : 'o')))) << "]\n"); } /// CreateSlot - Create a new slot for the specified value if it has no name. @@ -2253,6 +2271,11 @@ 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 @@ if (isa(GIS)) Out << "alias "; + else if (isa(GIS)) + Out << "ifunc "; else - llvm_unreachable("Not an alias!"); + llvm_unreachable("Not an alias or ifunc!"); TypePrinter.print(GIS->getValueType(), Out); Index: llvm/trunk/lib/IR/Globals.cpp =================================================================== --- llvm/trunk/lib/IR/Globals.cpp +++ llvm/trunk/lib/IR/Globals.cpp @@ -145,6 +145,9 @@ return const_cast(GO)->getComdat(); return nullptr; } + // ifunc and its resolver are separate things so don't use resolver comdat. + if (isa(this)) + return nullptr; return cast(this)->getComdat(); } @@ -364,3 +367,34 @@ "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()); +} Index: llvm/trunk/lib/IR/Module.cpp =================================================================== --- llvm/trunk/lib/IR/Module.cpp +++ llvm/trunk/lib/IR/Module.cpp @@ -41,6 +41,7 @@ template class llvm::SymbolTableListTraits; template class llvm::SymbolTableListTraits; template class llvm::SymbolTableListTraits; +template class llvm::SymbolTableListTraits; //===----------------------------------------------------------------------===// // Primitive Module methods. @@ -59,6 +60,7 @@ GlobalList.clear(); FunctionList.clear(); AliasList.clear(); + IFuncList.clear(); NamedMDList.clear(); delete ValSymTab; delete static_cast *>(NamedMDSymTab); @@ -250,6 +252,10 @@ return dyn_cast_or_null(getNamedValue(Name)); } +GlobalIFunc *Module::getNamedIFunc(StringRef Name) const { + return dyn_cast_or_null(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 @@ for (GlobalAlias &GA : aliases()) GA.dropAllReferences(); + + for (GlobalIFunc &GIF : ifuncs()) + GIF.dropAllReferences(); } unsigned Module::getDwarfVersion() const { Index: llvm/trunk/test/Assembler/ifunc-asm.ll =================================================================== --- llvm/trunk/test/Assembler/ifunc-asm.ll +++ llvm/trunk/test/Assembler/ifunc-asm.ll @@ -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() Index: llvm/trunk/test/Assembler/ifunc-use-list-order.ll =================================================================== --- llvm/trunk/test/Assembler/ifunc-use-list-order.ll +++ llvm/trunk/test/Assembler/ifunc-use-list-order.ll @@ -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 +} Index: llvm/trunk/test/Bitcode/compatibility.ll =================================================================== --- llvm/trunk/test/Bitcode/compatibility.ll +++ llvm/trunk/test/Bitcode/compatibility.ll @@ -249,6 +249,31 @@ @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 @ = [Linkage] [Visibility] ifunc , +; * @ + +; 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]