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. + +Aliases may have an optional :ref:`linkage type ` and an optional +:ref:`visibility style `. + +Syntax:: + + @ = [Linkage] [Visibility] ifunc , * @ + + .. _langref_comdats: Comdats Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -1186,7 +1186,9 @@ macro(ConstantTokenNone) \ macro(ConstantVector) \ macro(GlobalValue) \ - macro(GlobalAlias) \ + macro(GlobalIndirectSymbol) \ + macro(GlobalAlias) \ + macro(GlobalIFunc) \ macro(GlobalObject) \ macro(Function) \ macro(GlobalVariable) \ @@ -1877,6 +1879,18 @@ const char *Name); /** + * @defgroup LLVMCoreValueConstantGlobalIFunc Global IFuncs + * + * This group contains function that operate on global ifunc values. + * + * @see llvm::GlobalIFunc + * + * @{ + */ +LLVMValueRef LLVMAddIFunc(LLVMModuleRef M, LLVMTypeRef Ty, + LLVMValueRef Resolver, const char *Name); + +/** * @} */ Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -105,6 +105,9 @@ // METADATA_VALUES: [numvals] MODULE_CODE_METADATA_VALUES = 15, + + // IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility] + MODULE_CODE_IFUNC = 16 }; /// 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; @@ -551,6 +552,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/GlobalAlias.h =================================================================== --- include/llvm/IR/GlobalAlias.h +++ include/llvm/IR/GlobalAlias.h @@ -17,15 +17,15 @@ #include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/GlobalIndirectSymbol.h" namespace llvm { class Module; template class SymbolTableListTraits; -class GlobalAlias : public GlobalValue, public ilist_node { +class GlobalAlias : public GlobalIndirectSymbol, + public ilist_node { friend class SymbolTableListTraits; void operator=(const GlobalAlias &) = delete; GlobalAlias(const GlobalAlias &) = delete; @@ -36,11 +36,6 @@ const Twine &Name, Constant *Aliasee, Module *Parent); public: - // allocate space for exactly one operand - void *operator new(size_t s) { - return User::operator new(s, 1); - } - /// If a parent module is specified, the alias is automatically inserted into /// the end of the specified module's alias list. static GlobalAlias *create(Type *Ty, unsigned AddressSpace, @@ -64,9 +59,6 @@ // Linkage, Type, Parent and AddressSpace taken from the Aliasee. static GlobalAlias *create(const Twine &Name, GlobalValue *Aliasee); - /// Provide fast operand accessors - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - /// removeFromParent - This method unlinks 'this' from the containing module, /// but does not delete it. /// @@ -77,13 +69,13 @@ /// void eraseFromParent() override; - /// These methods retrive and set alias target. + /// These methods retrieve and set alias target. void setAliasee(Constant *Aliasee); const Constant *getAliasee() const { - return const_cast(this)->getAliasee(); + return getIndirectSymbol(); } Constant *getAliasee() { - return getOperand(0); + return getIndirectSymbol(); } const GlobalObject *getBaseObject() const { @@ -112,13 +104,6 @@ } }; -template <> -struct OperandTraits : - public FixedNumOperandTraits { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Constant) - } // End llvm namespace #endif 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 =================================================================== --- /dev/null +++ include/llvm/IR/GlobalIndirectSymbol.h @@ -0,0 +1,68 @@ +//===- llvm/GlobalIndirectSymbol.h - GlobalIndirectSymbol class -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the GlobalIndirectSymbol class, which +// is a base class for GlobalAlias and GlobalIFunc. It contains all common code +// for aliases and ifuncs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_GLOBALINDIRECTSYMBOL_H +#define LLVM_IR_GLOBALINDIRECTSYMBOL_H + +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/OperandTraits.h" + +namespace llvm { + +class GlobalIndirectSymbol : public GlobalValue { + void operator=(const GlobalIndirectSymbol &) = delete; + GlobalIndirectSymbol(const GlobalIndirectSymbol &) = delete; + +protected: + GlobalIndirectSymbol(Type *Ty, ValueTy VTy, unsigned AddressSpace, + LinkageTypes Linkage, const Twine &Name, Constant *Symbol); + +public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// These methods set and retrieve indirect symbol. + void setIndirectSymbol(Constant *Symbol) { + setOperand(0, Symbol); + } + const Constant *getIndirectSymbol() const { + return const_cast(this)->getIndirectSymbol(); + } + Constant *getIndirectSymbol() { + return getOperand(0); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Value *V) { + return V->getValueID() == Value::GlobalAliasVal || + V->getValueID() == Value::GlobalIFuncVal; + } +}; + +template <> +struct OperandTraits : + public FixedNumOperandTraits { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalIndirectSymbol, Constant) + +} // End llvm namespace + +#endif Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -371,7 +371,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 @@ -375,6 +384,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 /// @{ @@ -488,6 +506,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. @@ -562,6 +587,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,8 @@ class DataLayout; class Function; class GlobalAlias; +class GlobalIFunc; +class GlobalIndirectSymbol; class GlobalObject; class GlobalValue; class GlobalVariable; @@ -661,9 +663,21 @@ } }; +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) || isa(Val); + } +}; + template <> struct isa_impl { static inline bool doit(const Value &Val) { - return isa(Val) || isa(Val); + return isa(Val) || isa(Val); } }; Index: include/llvm/IR/Value.def =================================================================== --- include/llvm/IR/Value.def +++ include/llvm/IR/Value.def @@ -57,6 +57,7 @@ HANDLE_GLOBAL_VALUE(Function) HANDLE_GLOBAL_VALUE(GlobalAlias) +HANDLE_GLOBAL_VALUE(GlobalIFunc) HANDLE_GLOBAL_VALUE(GlobalVariable) HANDLE_CONSTANT(UndefValue) HANDLE_CONSTANT(BlockAddress) 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 @@ -559,6 +559,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 @@ -271,9 +271,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 @@ -428,10 +428,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() { @@ -461,15 +461,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() { @@ -490,12 +491,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() { @@ -652,26 +653,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)) @@ -681,7 +689,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; @@ -705,14 +713,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 @@ -732,9 +745,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); @@ -757,7 +776,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 @@ -79,6 +79,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 @@ -157,7 +157,7 @@ SmallVector InstructionList; std::vector > GlobalInits; - std::vector > AliasInits; + std::vector > IndirectSymbolInits; std::vector > FunctionPrefixes; std::vector > FunctionPrologues; std::vector > FunctionPersonalityFns; @@ -392,7 +392,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 parseMetadataKinds(); std::error_code parseMetadataKindRecord(SmallVectorImpl &Record); @@ -2415,15 +2415,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); @@ -2442,20 +2443,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()) { @@ -3083,8 +3084,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 @@ -3101,7 +3102,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(); } @@ -3251,7 +3253,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: @@ -3583,9 +3585,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; @@ -3606,7 +3610,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. @@ -3625,7 +3634,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 @@ -776,6 +776,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(); + } + // Write a record indicating the number of module-level metadata IDs // This is needed because the ids of metadata are assigned implicitly // based on their ordering in the bitcode, with the function-level Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1089,6 +1089,47 @@ 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 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()); + + // 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 @@ -1177,40 +1218,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()); - - // Emit the directives as assignments aka .set: - OutStreamer->EmitAssignment(Name, lowerConstant(Alias.getAliasee())); - - // 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) { if (F.hasPrefixData()) if (!isa(F.getPrefixData())) @@ -257,11 +262,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) if (F.hasPrefixData()) predictValueUseListOrder(F.getPrefixData(), 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. @@ -2044,7 +2062,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); @@ -2261,7 +2279,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); @@ -2442,36 +2465,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'; } @@ -3326,7 +3354,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/Core.cpp =================================================================== --- lib/IR/Core.cpp +++ lib/IR/Core.cpp @@ -1649,6 +1649,16 @@ unwrap(Aliasee), unwrap(M))); } +/*--.. Operations on ifuncs ......................................--*/ + +LLVMValueRef LLVMAddIFunc(LLVMModuleRef M, LLVMTypeRef Ty, + LLVMValueRef Resolver, const char *Name) { + auto *PTy = cast(unwrap(Ty)); + return wrap(GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(), + GlobalValue::ExternalLinkage, Name, + unwrap(Resolver), unwrap(M))); +} + /*--.. Operations on functions .............................................--*/ LLVMValueRef LLVMAddFunction(LLVMModuleRef M, const char *Name, Index: lib/IR/Globals.cpp =================================================================== --- lib/IR/Globals.cpp +++ lib/IR/Globals.cpp @@ -121,6 +121,8 @@ return const_cast(GO)->getComdat(); return nullptr; } + if (isa(this)) + return nullptr; return cast(this)->getComdat(); } @@ -229,16 +231,26 @@ //===----------------------------------------------------------------------===// +// GlobalIndirectSymbol Implementation +//===----------------------------------------------------------------------===// + +GlobalIndirectSymbol::GlobalIndirectSymbol(Type *Ty, ValueTy VTy, + unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, + Constant *Symbol) + : GlobalValue(Ty, VTy, &Op<0>(), 1, Linkage, Name, AddressSpace) { + Op<0>() = Symbol; +} + + +//===----------------------------------------------------------------------===// // GlobalAlias Implementation //===----------------------------------------------------------------------===// GlobalAlias::GlobalAlias(Type *Ty, unsigned AddressSpace, LinkageTypes Link, const Twine &Name, Constant *Aliasee, Module *ParentModule) - : GlobalValue(Ty, Value::GlobalAliasVal, &Op<0>(), 1, Link, Name, - AddressSpace) { - Op<0>() = Aliasee; - + : GlobalIndirectSymbol(Ty, Value::GlobalAliasVal, AddressSpace, Link, Name, + Aliasee) { if (ParentModule) ParentModule->getAliasList().push_back(this); } @@ -287,5 +299,36 @@ void GlobalAlias::setAliasee(Constant *Aliasee) { assert((!Aliasee || Aliasee->getType() == getType()) && "Alias and aliasee types should match!"); - setOperand(0, Aliasee); + 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. @@ -456,6 +465,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-alias.ll =================================================================== --- /dev/null +++ test/Assembler/ifunc-alias.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()