Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -760,6 +760,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: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -107,6 +107,9 @@ // SOURCE_FILENAME: [namechar x N] MODULE_CODE_SOURCE_FILENAME = 16, + + // IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility] + MODULE_CODE_IFUNC = 17 }; /// PARAMATTR blocks have code for defining a parameter attribute set. Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -34,6 +34,7 @@ class DIE; class DIEAbbrev; class GCMetadataPrinter; +class GlobalIndirectSymbol; class GlobalValue; class GlobalVariable; class MachineBasicBlock; @@ -546,6 +547,9 @@ void EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor); GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &C); + /// Emit GlobalAlias or GlobalIFunc. + void emitGlobalIndirectSymbol(Module &M, + const GlobalIndirectSymbol& GIS); }; } Index: include/llvm/IR/GlobalIFunc.h =================================================================== --- /dev/null +++ include/llvm/IR/GlobalIFunc.h @@ -0,0 +1,74 @@ +//===-------- 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; +template class SymbolTableListTraits; + +class GlobalIFunc : 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() override; + + /// This method unlinks 'this' from the containing module and deletes it. + void eraseFromParent() override; + + /// 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: include/llvm/IR/GlobalIndirectSymbol.h =================================================================== --- include/llvm/IR/GlobalIndirectSymbol.h +++ 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: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -383,7 +383,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: include/llvm/IR/Module.h =================================================================== --- include/llvm/IR/Module.h +++ 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 alias 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: include/llvm/IR/SymbolTableListTraits.h =================================================================== --- include/llvm/IR/SymbolTableListTraits.h +++ 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: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -31,6 +31,7 @@ class DataLayout; class Function; class GlobalAlias; +class GlobalIFunc; class GlobalIndirectSymbol; class GlobalObject; class GlobalValue; @@ -743,9 +744,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: include/llvm/IR/Value.def =================================================================== --- include/llvm/IR/Value.def +++ 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: include/llvm/IR/ValueSymbolTable.h =================================================================== --- include/llvm/IR/ValueSymbolTable.h +++ 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: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -560,6 +560,7 @@ KEYWORD(addrspace); KEYWORD(section); KEYWORD(alias); + KEYWORD(ifunc); KEYWORD(module); KEYWORD(asm); KEYWORD(sideeffect); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -275,9 +275,11 @@ bool HasLinkage, unsigned Visibility, unsigned DLLStorageClass, GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr); - bool ParseAlias(const std::string &Name, LocTy Loc, unsigned Linkage, - unsigned Visibility, unsigned DLLStorageClass, - GlobalVariable::ThreadLocalMode TLM, bool UnnamedAddr); + bool parseIndirectSymbol(const std::string &Name, LocTy Loc, + unsigned Linkage, unsigned Visibility, + unsigned DLLStorageClass, + GlobalVariable::ThreadLocalMode TLM, + bool UnnamedAddr); bool parseComdat(); bool ParseStandaloneMetadata(); bool ParseNamedMetadata(); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ 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,15 +500,16 @@ 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); - return ParseAlias(Name, NameLoc, Linkage, Visibility, DLLStorageClass, TLM, - UnnamedAddr); + + return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility, + DLLStorageClass, TLM, UnnamedAddr); } /// ParseNamedGlobal: -/// GlobalVar '=' OptionalVisibility ALIAS ... +/// GlobalVar '=' OptionalVisibility (ALIAS | IFUNC) ... /// GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass /// ... -> global variable bool LLParser::ParseNamedGlobal() { @@ -529,12 +530,12 @@ 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); - return ParseAlias(Name, NameLoc, Linkage, Visibility, DLLStorageClass, TLM, - UnnamedAddr); + return parseIndirectSymbol(Name, NameLoc, Linkage, Visibility, + DLLStorageClass, TLM, UnnamedAddr); } bool LLParser::parseComdat() { @@ -690,26 +691,33 @@ (GlobalValue::VisibilityTypes)V == GlobalValue::DefaultVisibility; } -/// ParseAlias: +/// parseIndirectSymbol: /// ::= GlobalVar '=' OptionalLinkage OptionalVisibility /// OptionalDLLStorageClass OptionalThreadLocal -/// OptionalUnnamedAddr 'alias' Aliasee +/// OptionalUnnamedAddr 'alias|ifunc' IndirectSymbol /// -/// Aliasee +/// IndirectSymbol /// ::= TypeAndValue /// /// Everything through OptionalUnnamedAddr has already been parsed. /// -bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, unsigned L, - unsigned Visibility, unsigned DLLStorageClass, - GlobalVariable::ThreadLocalMode TLM, - bool UnnamedAddr) { - assert(Lex.getKind() == lltok::kw_alias); +bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc, + unsigned L, unsigned Visibility, + unsigned DLLStorageClass, + GlobalVariable::ThreadLocalMode TLM, + bool UnnamedAddr) { + 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 or ifunc!"); Lex.Lex(); GlobalValue::LinkageTypes Linkage = (GlobalValue::LinkageTypes) L; - if(!GlobalAlias::isValidLinkage(Linkage)) + if(IsAlias && !GlobalAlias::isValidLinkage(Linkage)) return Error(NameLoc, "invalid linkage type for alias"); if (!isValidVisibilityForLinkage(Visibility, L)) @@ -719,7 +727,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; @@ -743,14 +751,19 @@ 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 (Ty != PTy->getElementType()) + if (IsAlias && Ty != PTy->getElementType()) return Error( ExplicitTypeLoc, "explicit pointee type doesn't match operand's pointee type"); + if (!IsAlias && !PTy->getElementType()->isFunctionTy()) + return Error( + ExplicitTypeLoc, + "explicit pointee type should be a function type"); + GlobalValue *GVal = nullptr; // See if the alias was forward referenced, if so, prepare to replace the @@ -770,9 +783,15 @@ } // Okay, create the alias but do not insert it into the module yet. - std::unique_ptr GA( - GlobalAlias::create(Ty, AddrSpace, (GlobalValue::LinkageTypes)Linkage, - Name, Aliasee, /*Parent*/ nullptr)); + std::unique_ptr GA; + if (IsAlias) + GA.reset(GlobalAlias::create(Ty, AddrSpace, + (GlobalValue::LinkageTypes)Linkage, Name, + Aliasee, /*Parent*/ nullptr)); + else + 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); @@ -795,7 +814,10 @@ } // Insert into the module, we know its name won't collide now. - M->getAliasList().push_back(GA.get()); + if (IsAlias) + M->getAliasList().push_back(cast(GA.get())); + else + M->getIFuncList().push_back(cast(GA.get())); assert(GA->getName() == Name && "Should not be a name conflict!"); // The module owns this now Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -80,6 +80,7 @@ kw_addrspace, kw_section, kw_alias, + kw_ifunc, kw_module, kw_asm, kw_sideeffect, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -154,7 +154,7 @@ SmallVector InstructionList; std::vector > GlobalInits; - std::vector > AliasInits; + std::vector > IndirectSymbolInits; std::vector > FunctionPrefixes; std::vector > FunctionPrologues; std::vector > FunctionPersonalityFns; @@ -386,7 +386,7 @@ std::error_code rememberAndSkipMetadata(); std::error_code parseFunctionBody(Function *F); std::error_code globalCleanup(); - std::error_code resolveGlobalAndAliasInits(); + std::error_code resolveGlobalAndIndirectSymbolInits(); std::error_code parseMetadata(bool ModuleLevel = false); std::error_code parseMetadataStrings(ArrayRef Record, StringRef Blob, @@ -2478,15 +2478,16 @@ } /// Resolve all of the initializers for global values and aliases that we can. -std::error_code BitcodeReader::resolveGlobalAndAliasInits() { +std::error_code BitcodeReader::resolveGlobalAndIndirectSymbolInits() { std::vector > GlobalInitWorklist; - std::vector > AliasInitWorklist; + std::vector > + IndirectSymbolInitWorklist; std::vector > FunctionPrefixWorklist; std::vector > FunctionPrologueWorklist; std::vector > FunctionPersonalityFnWorklist; GlobalInitWorklist.swap(GlobalInits); - AliasInitWorklist.swap(AliasInits); + IndirectSymbolInitWorklist.swap(IndirectSymbolInits); FunctionPrefixWorklist.swap(FunctionPrefixes); FunctionPrologueWorklist.swap(FunctionPrologues); FunctionPersonalityFnWorklist.swap(FunctionPersonalityFns); @@ -2505,20 +2506,20 @@ GlobalInitWorklist.pop_back(); } - while (!AliasInitWorklist.empty()) { - unsigned ValID = AliasInitWorklist.back().second; + while (!IndirectSymbolInitWorklist.empty()) { + unsigned ValID = IndirectSymbolInitWorklist.back().second; if (ValID >= ValueList.size()) { - AliasInits.push_back(AliasInitWorklist.back()); + IndirectSymbolInits.push_back(IndirectSymbolInitWorklist.back()); } else { Constant *C = dyn_cast_or_null(ValueList[ValID]); if (!C) return error("Expected a constant"); - GlobalAlias *Alias = AliasInitWorklist.back().first; - if (C->getType() != Alias->getType()) + GlobalIndirectSymbol *GIS = IndirectSymbolInitWorklist.back().first; + if (isa(GIS) && C->getType() != GIS->getType()) return error("Alias and aliasee types don't match"); - Alias->setAliasee(C); + GIS->setIndirectSymbol(C); } - AliasInitWorklist.pop_back(); + IndirectSymbolInitWorklist.pop_back(); } while (!FunctionPrefixWorklist.empty()) { @@ -3143,8 +3144,8 @@ std::error_code BitcodeReader::globalCleanup() { // Patch the initializers for globals and aliases up. - resolveGlobalAndAliasInits(); - if (!GlobalInits.empty() || !AliasInits.empty()) + resolveGlobalAndIndirectSymbolInits(); + if (!GlobalInits.empty() || !IndirectSymbolInits.empty()) return error("Malformed global initializer set"); // Look for intrinsic functions which need to be upgraded at some point @@ -3161,7 +3162,8 @@ // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector >().swap(GlobalInits); - std::vector >().swap(AliasInits); + std::vector >().swap( + IndirectSymbolInits); return std::error_code(); } @@ -3311,7 +3313,7 @@ case bitc::CONSTANTS_BLOCK_ID: if (std::error_code EC = parseConstants()) return EC; - if (std::error_code EC = resolveGlobalAndAliasInits()) + if (std::error_code EC = resolveGlobalAndIndirectSymbolInits()) return EC; break; case bitc::METADATA_BLOCK_ID: @@ -3642,9 +3644,11 @@ } // 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; + bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD; if (Record.size() < (3 + (unsigned)NewRecord)) return error("Invalid record"); unsigned OpNum = 0; @@ -3665,7 +3669,12 @@ auto Val = Record[OpNum++]; auto Linkage = Record[OpNum++]; - auto *NewGA = GlobalAlias::create( + GlobalIndirectSymbol *NewGA; + if (BitCode == bitc::MODULE_CODE_IFUNC) + NewGA = GlobalIFunc::create( + Ty, AddrSpace, getDecodedLinkage(Linkage), "", nullptr, TheModule); + else + NewGA = GlobalAlias::create( Ty, AddrSpace, getDecodedLinkage(Linkage), "", TheModule); // Old bitcode files didn't have visibility field. // Local linkage must have default visibility. @@ -3684,7 +3693,7 @@ if (OpNum != Record.size()) NewGA->setUnnamedAddr(Record[OpNum++]); ValueList.push_back(NewGA); - AliasInits.push_back(std::make_pair(NewGA, Val)); + IndirectSymbolInits.push_back(std::make_pair(NewGA, Val)); break; } /// MODULE_CODE_PURGEVALS: [numvals] Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -805,6 +805,19 @@ 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)); + unsigned AbbrevToUse = 0; + Stream.EmitRecord(bitc::MODULE_CODE_IFUNC, Vals, AbbrevToUse); + Vals.clear(); + } + // Emit the module's source file name. { StringEncoding Bits = getStringEncoding(M->getSourceFileName().data(), Index: lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- lib/Bitcode/Writer/ValueEnumerator.cpp +++ 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: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1060,6 +1060,53 @@ EmitGlobalVariable(GV); } +void AsmPrinter::emitGlobalIndirectSymbol(Module &M, + const GlobalIndirectSymbol& GIS) { + MCSymbol *Name = getSymbol(&GIS); + + if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective()) + OutStreamer->EmitSymbolAttribute(Name, MCSA_Global); + else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage()) + OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference); + else + 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()) { + OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); + if (isa(GIS)) + OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); + } + + EmitVisibility(Name, GIS.getVisibility()); + + if (auto *GA = dyn_cast(&GIS)) { + const MCExpr *Expr = lowerConstant(GA->getAliasee()); + if (MAI->hasAltEntry() && isa(Expr)) + OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry); + } + + // Emit the directives as assignments aka .set: + OutStreamer->EmitAssignment(Name, lowerConstant(GIS.getIndirectSymbol())); + + if (auto *GA = dyn_cast(&GIS)) { + // If the aliasee does not correspond to a symbol in the output, i.e. the + // alias is not of an object or the aliased object is private, then set the + // size of the alias symbol from the type of the alias. We don't do this in + // other situations as the alias and aliasee having differing types but same + // size may be intentional. + const GlobalObject *BaseObject = GA->getBaseObject(); + if (MAI->hasDotTypeDotSizeDirective() && GA->getValueType()->isSized() && + (!BaseObject || BaseObject->hasPrivateLinkage())) { + const DataLayout &DL = M.getDataLayout(); + uint64_t Size = DL.getTypeAllocSize(GA->getValueType()); + OutStreamer->emitELFSize(cast(Name), + MCConstantExpr::create(Size, OutContext)); + } + } +} + bool AsmPrinter::doFinalization(Module &M) { // Set the MachineFunction to nullptr so that we can catch attempted // accesses to MF specific features at the module level and so that @@ -1148,45 +1195,10 @@ } OutStreamer->AddBlankLine(); - for (const auto &Alias : M.aliases()) { - MCSymbol *Name = getSymbol(&Alias); - - if (Alias.hasExternalLinkage() || !MAI->getWeakRefDirective()) - OutStreamer->EmitSymbolAttribute(Name, MCSA_Global); - else if (Alias.hasWeakLinkage() || Alias.hasLinkOnceLinkage()) - OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference); - else - assert(Alias.hasLocalLinkage() && "Invalid alias 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 (Alias.getType()->getPointerElementType()->isFunctionTy()) - OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); - - EmitVisibility(Name, Alias.getVisibility()); - - const MCExpr *Expr = lowerConstant(Alias.getAliasee()); - - if (MAI->hasAltEntry() && isa(Expr)) - OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry); - - // Emit the directives as assignments aka .set: - OutStreamer->EmitAssignment(Name, Expr); - - // If the aliasee does not correspond to a symbol in the output, i.e. the - // alias is not of an object or the aliased object is private, then set the - // size of the alias symbol from the type of the alias. We don't do this in - // other situations as the alias and aliasee having differing types but same - // size may be intentional. - const GlobalObject *BaseObject = Alias.getBaseObject(); - if (MAI->hasDotTypeDotSizeDirective() && Alias.getValueType()->isSized() && - (!BaseObject || BaseObject->hasPrivateLinkage())) { - const DataLayout &DL = M.getDataLayout(); - uint64_t Size = DL.getTypeAllocSize(Alias.getValueType()); - OutStreamer->emitELFSize(cast(Name), - MCConstantExpr::create(Size, OutContext)); - } - } + for (const auto &Alias : M.aliases()) + emitGlobalIndirectSymbol(M, Alias); + for (const auto &IFunc : M.ifuncs()) + emitGlobalIndirectSymbol(M, IFunc); GCModuleInfo *MI = getAnalysisIfAvailable(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ 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); @@ -724,6 +733,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); @@ -777,6 +789,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) @@ -940,10 +957,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. @@ -2041,7 +2059,7 @@ void printTypeIdentities(); void printGlobal(const GlobalVariable *GV); - void printAlias(const GlobalAlias *GV); + void printIndirectSymbol(const GlobalIndirectSymbol *GIF); void printComdat(const Comdat *C); void printFunction(const Function *F); void printArgument(const Argument *FA, AttributeSet Attrs, unsigned Idx); @@ -2264,7 +2282,12 @@ // Output all aliases. if (!M->alias_empty()) Out << "\n"; for (const GlobalAlias &GA : M->aliases()) - printAlias(&GA); + 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); @@ -2445,36 +2468,41 @@ printInfoComment(*GV); } -void AssemblyWriter::printAlias(const GlobalAlias *GA) { - if (GA->isMaterializable()) +void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) { + if (GIS->isMaterializable()) Out << "; Materializable\n"; - WriteAsOperandInternal(Out, GA, &TypePrinter, &Machine, GA->getParent()); + WriteAsOperandInternal(Out, GIS, &TypePrinter, &Machine, GIS->getParent()); Out << " = "; - PrintLinkage(GA->getLinkage(), Out); - PrintVisibility(GA->getVisibility(), Out); - PrintDLLStorageClass(GA->getDLLStorageClass(), Out); - PrintThreadLocalModel(GA->getThreadLocalMode(), Out); - if (GA->hasUnnamedAddr()) + PrintLinkage(GIS->getLinkage(), Out); + PrintVisibility(GIS->getVisibility(), Out); + PrintDLLStorageClass(GIS->getDLLStorageClass(), Out); + PrintThreadLocalModel(GIS->getThreadLocalMode(), Out); + if (GIS->hasUnnamedAddr()) Out << "unnamed_addr "; - Out << "alias "; + if (isa(GIS)) + Out << "alias "; + else if (isa(GIS)) + Out << "ifunc "; + else + llvm_unreachable("Not an alias or ifunc!"); - TypePrinter.print(GA->getValueType(), Out); + TypePrinter.print(GIS->getValueType(), Out); Out << ", "; - const Constant *Aliasee = GA->getAliasee(); + const Constant *IS = GIS->getIndirectSymbol(); - if (!Aliasee) { - TypePrinter.print(GA->getType(), Out); + if (!IS) { + TypePrinter.print(GIS->getType(), Out); Out << " <>"; } else { - writeOperand(Aliasee, !isa(Aliasee)); + writeOperand(IS, !isa(IS)); } - printInfoComment(*GA); + printInfoComment(*GIS); Out << '\n'; } @@ -3340,7 +3368,7 @@ else if (const Function *F = dyn_cast(GV)) W.printFunction(F); else - W.printAlias(cast(GV)); + W.printIndirectSymbol(cast(GV)); } else if (const MetadataAsValue *V = dyn_cast(this)) { V->getMetadata()->print(ROS, MST, getModuleFromVal(V)); } else if (const Constant *C = dyn_cast(this)) { Index: lib/IR/Globals.cpp =================================================================== --- lib/IR/Globals.cpp +++ lib/IR/Globals.cpp @@ -145,6 +145,8 @@ return const_cast(GO)->getComdat(); return nullptr; } + if (isa(this)) + return nullptr; return cast(this)->getComdat(); } @@ -159,8 +161,8 @@ if (const Function *F = dyn_cast(this)) return F->empty() && !F->isMaterializable(); - // Aliases are always definitions. - assert(isa(this)); + // Aliases and ifuncs are always definitions. + assert(isa(this)); return false; } @@ -364,3 +366,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: lib/IR/Module.cpp =================================================================== --- lib/IR/Module.cpp +++ 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,13 @@ return dyn_cast_or_null(getNamedValue(Name)); } +// getNamedIFunc - Look up the specified global in the module symbol table. +// If it does not exist, return null. +// +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 +447,9 @@ for (GlobalAlias &GA : aliases()) GA.dropAllReferences(); + + for (GlobalIFunc &GIF : ifuncs()) + GIF.dropAllReferences(); } unsigned Module::getDwarfVersion() const { Index: lib/Transforms/IPO/GlobalDCE.cpp =================================================================== --- lib/Transforms/IPO/GlobalDCE.cpp +++ lib/Transforms/IPO/GlobalDCE.cpp @@ -205,9 +205,9 @@ // referenced by the initializer to the alive set. if (GV->hasInitializer()) MarkUsedGlobalsAsNeeded(GV->getInitializer()); - } else if (GlobalAlias *GA = dyn_cast(G)) { - // The target of a global alias is needed. - MarkUsedGlobalsAsNeeded(GA->getAliasee()); + } else if (GlobalIndirectSymbol *GIS = dyn_cast(G)) { + // The target of a global alias or ifunc is needed. + MarkUsedGlobalsAsNeeded(GIS->getIndirectSymbol()); } else { // Otherwise this must be a function object. We have to scan the body of // the function looking for constants and global values which are used as Index: test/Assembler/ifunc-asm.ll =================================================================== --- /dev/null +++ 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: test/Assembler/ifunc-use-list-order.ll =================================================================== --- /dev/null +++ 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: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ 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]