[llvm] r265667 - [GCC] Attribute ifunc support in llvm

Dmitry Polukhin via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 7 05:32:20 PDT 2016


Author: dpolukhin
Date: Thu Apr  7 07:32:19 2016
New Revision: 265667

URL: http://llvm.org/viewvc/llvm-project?rev=265667&view=rev
Log:
[GCC] Attribute ifunc support in llvm

This patch add support for GCC attribute((ifunc("resolver"))) for
targets that use ELF as object file format. In general ifunc is a
special kind of function alias with type @gnu_indirect_function. Patch
for Clang http://reviews.llvm.org/D15524

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

Added:
    llvm/trunk/include/llvm/IR/GlobalIFunc.h   (with props)
    llvm/trunk/test/Assembler/ifunc-asm.ll
    llvm/trunk/test/Assembler/ifunc-use-list-order.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm-c/Core.h
    llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
    llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h
    llvm/trunk/include/llvm/IR/GlobalValue.h
    llvm/trunk/include/llvm/IR/Module.h
    llvm/trunk/include/llvm/IR/SymbolTableListTraits.h
    llvm/trunk/include/llvm/IR/Value.def
    llvm/trunk/include/llvm/IR/Value.h
    llvm/trunk/include/llvm/IR/ValueSymbolTable.h
    llvm/trunk/lib/AsmParser/LLLexer.cpp
    llvm/trunk/lib/AsmParser/LLParser.cpp
    llvm/trunk/lib/AsmParser/LLToken.h
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/trunk/lib/IR/AsmWriter.cpp
    llvm/trunk/lib/IR/Globals.cpp
    llvm/trunk/lib/IR/Module.cpp
    llvm/trunk/test/Bitcode/compatibility.ll

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Thu Apr  7 07:32:19 2016
@@ -764,6 +764,25 @@ some can only be checked when producing
 * No global value in the expression can be a declaration, since that
   would require a relocation, which is not possible.
 
+.. _langref_ifunc:
+
+IFuncs
+-------
+
+IFuncs, like as aliases, don't create any new data or func. They are just a new
+symbol that dynamic linker resolves at runtime by calling a resolver function.
+
+IFuncs have a name and a resolver that is a function called by dynamic linker
+that returns address of another function associated with the name.
+
+IFunc may have an optional :ref:`linkage type <linkage>` and an optional
+:ref:`visibility style <visibility>`.
+
+Syntax::
+
+    @<Name> = [Linkage] [Visibility] ifunc <IFuncTy>, <ResolverTy>* @<Resolver>
+
+
 .. _langref_comdats:
 
 Comdats

Modified: llvm/trunk/include/llvm-c/Core.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Core.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm-c/Core.h (original)
+++ llvm/trunk/include/llvm-c/Core.h Thu Apr  7 07:32:19 2016
@@ -256,6 +256,7 @@ typedef enum {
 
   LLVMFunctionValueKind,
   LLVMGlobalAliasValueKind,
+  LLVMGlobalIFuncValueKind,
   LLVMGlobalVariableValueKind,
   LLVMBlockAddressValueKind,
   LLVMConstantExprValueKind,

Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
+++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Apr  7 07:32:19 2016
@@ -110,6 +110,9 @@ enum ModuleCodes {
 
   // HASH: [5*i32]
   MODULE_CODE_HASH = 17,
+
+  // IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility]
+  MODULE_CODE_IFUNC = 18,
 };
 
 /// PARAMATTR blocks have code for defining a parameter attribute set.

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

Propchange: llvm/trunk/include/llvm/IR/GlobalIFunc.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: llvm/trunk/include/llvm/IR/GlobalIFunc.h
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Rev URL"

Propchange: llvm/trunk/include/llvm/IR/GlobalIFunc.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h (original)
+++ llvm/trunk/include/llvm/IR/GlobalIndirectSymbol.h Thu Apr  7 07:32:19 2016
@@ -51,7 +51,8 @@ public:
 
   // Methods for support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const Value *V) {
-    return V->getValueID() == Value::GlobalAliasVal;
+    return V->getValueID() == Value::GlobalAliasVal ||
+           V->getValueID() == Value::GlobalIFuncVal;
   }
 };
 

Modified: llvm/trunk/include/llvm/IR/GlobalValue.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/GlobalValue.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/GlobalValue.h (original)
+++ llvm/trunk/include/llvm/IR/GlobalValue.h Thu Apr  7 07:32:19 2016
@@ -388,7 +388,8 @@ public:
   static bool classof(const Value *V) {
     return V->getValueID() == Value::FunctionVal ||
            V->getValueID() == Value::GlobalVariableVal ||
-           V->getValueID() == Value::GlobalAliasVal;
+           V->getValueID() == Value::GlobalAliasVal ||
+           V->getValueID() == Value::GlobalIFuncVal;
   }
 };
 

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

Modified: llvm/trunk/include/llvm/IR/SymbolTableListTraits.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/SymbolTableListTraits.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/SymbolTableListTraits.h (original)
+++ llvm/trunk/include/llvm/IR/SymbolTableListTraits.h Thu Apr  7 07:32:19 2016
@@ -49,6 +49,7 @@ class Function;
 class Instruction;
 class GlobalVariable;
 class GlobalAlias;
+class GlobalIFunc;
 class Module;
 #define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT)                          \
   template <> struct SymbolTableListParentType<NODE> { typedef PARENT type; };
@@ -58,6 +59,7 @@ DEFINE_SYMBOL_TABLE_PARENT_TYPE(Argument
 DEFINE_SYMBOL_TABLE_PARENT_TYPE(Function, Module)
 DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalVariable, Module)
 DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalAlias, Module)
+DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalIFunc, Module)
 #undef DEFINE_SYMBOL_TABLE_PARENT_TYPE
 
 template <typename NodeTy> class SymbolTableList;

Modified: llvm/trunk/include/llvm/IR/Value.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Value.def?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Value.def (original)
+++ llvm/trunk/include/llvm/IR/Value.def Thu Apr  7 07:32:19 2016
@@ -60,6 +60,7 @@ HANDLE_VALUE(MemoryPhi)
 
 HANDLE_GLOBAL_VALUE(Function)
 HANDLE_GLOBAL_VALUE(GlobalAlias)
+HANDLE_GLOBAL_VALUE(GlobalIFunc)
 HANDLE_GLOBAL_VALUE(GlobalVariable)
 HANDLE_CONSTANT(BlockAddress)
 HANDLE_CONSTANT(ConstantExpr)

Modified: llvm/trunk/include/llvm/IR/Value.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Value.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Value.h (original)
+++ llvm/trunk/include/llvm/IR/Value.h Thu Apr  7 07:32:19 2016
@@ -32,6 +32,7 @@ class ConstantAggregate;
 class DataLayout;
 class Function;
 class GlobalAlias;
+class GlobalIFunc;
 class GlobalIndirectSymbol;
 class GlobalObject;
 class GlobalValue;
@@ -751,9 +752,15 @@ template <> struct isa_impl<GlobalAlias,
   }
 };
 
+template <> struct isa_impl<GlobalIFunc, Value> {
+  static inline bool doit(const Value &Val) {
+    return Val.getValueID() == Value::GlobalIFuncVal;
+  }
+};
+
 template <> struct isa_impl<GlobalIndirectSymbol, Value> {
   static inline bool doit(const Value &Val) {
-    return isa<GlobalAlias>(Val);
+    return isa<GlobalAlias>(Val) || isa<GlobalIFunc>(Val);
   }
 };
 

Modified: llvm/trunk/include/llvm/IR/ValueSymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ValueSymbolTable.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/ValueSymbolTable.h (original)
+++ llvm/trunk/include/llvm/IR/ValueSymbolTable.h Thu Apr  7 07:32:19 2016
@@ -39,6 +39,7 @@ class ValueSymbolTable {
   friend class SymbolTableListTraits<Function>;
   friend class SymbolTableListTraits<GlobalVariable>;
   friend class SymbolTableListTraits<GlobalAlias>;
+  friend class SymbolTableListTraits<GlobalIFunc>;
 /// @name Types
 /// @{
 public:

Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Apr  7 07:32:19 2016
@@ -560,6 +560,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(addrspace);
   KEYWORD(section);
   KEYWORD(alias);
+  KEYWORD(ifunc);
   KEYWORD(module);
   KEYWORD(asm);
   KEYWORD(sideeffect);

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

Modified: llvm/trunk/lib/AsmParser/LLToken.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLToken.h (original)
+++ llvm/trunk/lib/AsmParser/LLToken.h Thu Apr  7 07:32:19 2016
@@ -80,6 +80,7 @@ namespace lltok {
     kw_addrspace,
     kw_section,
     kw_alias,
+    kw_ifunc,
     kw_module,
     kw_asm,
     kw_sideeffect,

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Apr  7 07:32:19 2016
@@ -3658,6 +3658,8 @@ std::error_code BitcodeReader::parseModu
     }
     // ALIAS: [alias type, addrspace, aliasee val#, linkage]
     // ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass]
+    // IFUNC: [alias type, addrspace, aliasee val#, linkage, visibility, dllstorageclass]
+    case bitc::MODULE_CODE_IFUNC:
     case bitc::MODULE_CODE_ALIAS:
     case bitc::MODULE_CODE_ALIAS_OLD: {
       bool NewRecord = BitCode != bitc::MODULE_CODE_ALIAS_OLD;
@@ -3684,10 +3686,11 @@ std::error_code BitcodeReader::parseModu
       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()) {

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Apr  7 07:32:19 2016
@@ -809,6 +809,18 @@ static uint64_t WriteModuleInfo(const Mo
     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(),

Modified: llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/ValueEnumerator.cpp Thu Apr  7 07:32:19 2016
@@ -86,6 +86,9 @@ static OrderMap orderModule(const Module
   for (const GlobalAlias &A : M.aliases())
     if (!isa<GlobalValue>(A.getAliasee()))
       orderValue(A.getAliasee(), OM);
+  for (const GlobalIFunc &I : M.ifuncs())
+    if (!isa<GlobalValue>(I.getResolver()))
+      orderValue(I.getResolver(), OM);
   for (const Function &F : M) {
     for (const Use &U : F.operands())
       if (!isa<GlobalValue>(U.get()))
@@ -105,6 +108,8 @@ static OrderMap orderModule(const Module
     orderValue(&F, OM);
   for (const GlobalAlias &A : M.aliases())
     orderValue(&A, OM);
+  for (const GlobalIFunc &I : M.ifuncs())
+    orderValue(&I, OM);
   for (const GlobalVariable &G : M.globals())
     orderValue(&G, OM);
   OM.LastGlobalValueID = OM.size();
@@ -261,11 +266,15 @@ static UseListOrderStack predictUseListO
     predictValueUseListOrder(&F, nullptr, OM, Stack);
   for (const GlobalAlias &A : M.aliases())
     predictValueUseListOrder(&A, nullptr, OM, Stack);
+  for (const GlobalIFunc &I : M.ifuncs())
+    predictValueUseListOrder(&I, nullptr, OM, Stack);
   for (const GlobalVariable &G : M.globals())
     if (G.hasInitializer())
       predictValueUseListOrder(G.getInitializer(), nullptr, OM, Stack);
   for (const GlobalAlias &A : M.aliases())
     predictValueUseListOrder(A.getAliasee(), nullptr, OM, Stack);
+  for (const GlobalIFunc &I : M.ifuncs())
+    predictValueUseListOrder(I.getResolver(), nullptr, OM, Stack);
   for (const Function &F : M) {
     for (const Use &U : F.operands())
       predictValueUseListOrder(U.get(), nullptr, OM, Stack);
@@ -298,6 +307,10 @@ ValueEnumerator::ValueEnumerator(const M
   for (const GlobalAlias &GA : M.aliases())
     EnumerateValue(&GA);
 
+  // Enumerate the ifuncs.
+  for (const GlobalIFunc &GIF : M.ifuncs())
+    EnumerateValue(&GIF);
+
   // Remember what is the cutoff between globalvalue's and other constants.
   unsigned FirstConstant = Values.size();
 
@@ -310,6 +323,10 @@ ValueEnumerator::ValueEnumerator(const M
   for (const GlobalAlias &GA : M.aliases())
     EnumerateValue(GA.getAliasee());
 
+  // Enumerate the ifunc resolvers.
+  for (const GlobalIFunc &GIF : M.ifuncs())
+    EnumerateValue(GIF.getResolver());
+
   // Enumerate any optional Function data.
   for (const Function &F : M)
     for (const Use &U : F.operands())

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Thu Apr  7 07:32:19 2016
@@ -1069,12 +1069,15 @@ void AsmPrinter::emitGlobalIndirectSymbo
   else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage())
     OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference);
   else
-    assert(GIS.hasLocalLinkage() && "Invalid alias linkage");
+    assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage");
 
   // Set the symbol type to function if the alias has a function type.
   // This affects codegen when the aliasee is not a function.
-  if (GIS.getType()->getPointerElementType()->isFunctionTy())
+  if (GIS.getType()->getPointerElementType()->isFunctionTy()) {
     OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction);
+    if (isa<GlobalIFunc>(GIS))
+      OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction);
+  }
 
   EmitVisibility(Name, GIS.getVisibility());
 
@@ -1209,6 +1212,8 @@ bool AsmPrinter::doFinalization(Module &
       emitGlobalIndirectSymbol(M, *AncestorAlias);
     AliasStack.clear();
   }
+  for (const auto &IFunc : M.ifuncs())
+    emitGlobalIndirectSymbol(M, IFunc);
 
   GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
   assert(MI && "AsmPrinter didn't require GCModuleInfo?");

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

Modified: llvm/trunk/lib/IR/Globals.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Globals.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Globals.cpp (original)
+++ llvm/trunk/lib/IR/Globals.cpp Thu Apr  7 07:32:19 2016
@@ -145,6 +145,9 @@ Comdat *GlobalValue::getComdat() {
       return const_cast<GlobalObject *>(GO)->getComdat();
     return nullptr;
   }
+  // ifunc and its resolver are separate things so don't use resolver comdat.
+  if (isa<GlobalIFunc>(this))
+    return nullptr;
   return cast<GlobalObject>(this)->getComdat();
 }
 
@@ -364,3 +367,34 @@ void GlobalAlias::setAliasee(Constant *A
          "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());
+}

Modified: llvm/trunk/lib/IR/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Module.cpp?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Module.cpp (original)
+++ llvm/trunk/lib/IR/Module.cpp Thu Apr  7 07:32:19 2016
@@ -41,6 +41,7 @@ using namespace llvm;
 template class llvm::SymbolTableListTraits<Function>;
 template class llvm::SymbolTableListTraits<GlobalVariable>;
 template class llvm::SymbolTableListTraits<GlobalAlias>;
+template class llvm::SymbolTableListTraits<GlobalIFunc>;
 
 //===----------------------------------------------------------------------===//
 // Primitive Module methods.
@@ -59,6 +60,7 @@ Module::~Module() {
   GlobalList.clear();
   FunctionList.clear();
   AliasList.clear();
+  IFuncList.clear();
   NamedMDList.clear();
   delete ValSymTab;
   delete static_cast<StringMap<NamedMDNode *> *>(NamedMDSymTab);
@@ -250,6 +252,10 @@ GlobalAlias *Module::getNamedAlias(Strin
   return dyn_cast_or_null<GlobalAlias>(getNamedValue(Name));
 }
 
+GlobalIFunc *Module::getNamedIFunc(StringRef Name) const {
+  return dyn_cast_or_null<GlobalIFunc>(getNamedValue(Name));
+}
+
 /// getNamedMetadata - Return the first NamedMDNode in the module with the
 /// specified name. This method returns null if a NamedMDNode with the
 /// specified name is not found.
@@ -438,6 +444,9 @@ void Module::dropAllReferences() {
 
   for (GlobalAlias &GA : aliases())
     GA.dropAllReferences();
+
+  for (GlobalIFunc &GIF : ifuncs())
+    GIF.dropAllReferences();
 }
 
 unsigned Module::getDwarfVersion() const {

Added: llvm/trunk/test/Assembler/ifunc-asm.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/ifunc-asm.ll?rev=265667&view=auto
==============================================================================
--- llvm/trunk/test/Assembler/ifunc-asm.ll (added)
+++ llvm/trunk/test/Assembler/ifunc-asm.ll Thu Apr  7 07:32:19 2016
@@ -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"
+
+ at foo = ifunc i32 (i32), i64 ()* @foo_ifunc
+; CHECK-LLVM: @foo = ifunc i32 (i32), i64 ()* @foo_ifunc
+; CHECK-ASM: .type   foo, at gnu_indirect_function
+
+define internal i64 @foo_ifunc() {
+entry:
+  ret i64 0
+}
+; CHECK-LLVM: define internal i64 @foo_ifunc()

Added: llvm/trunk/test/Assembler/ifunc-use-list-order.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/ifunc-use-list-order.ll?rev=265667&view=auto
==============================================================================
--- llvm/trunk/test/Assembler/ifunc-use-list-order.ll (added)
+++ llvm/trunk/test/Assembler/ifunc-use-list-order.ll Thu Apr  7 07:32:19 2016
@@ -0,0 +1,42 @@
+; RUN: verify-uselistorder < %s
+
+; Global referencing ifunc.
+ at ptr_foo = global void ()* @foo_ifunc
+
+; Alias for ifunc.
+ at alias_foo = alias void (), void ()* @foo_ifunc
+
+ at 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.
+ at ptr_bar = global void ()* @bar
+
+; Alias for function.
+ at alias_bar = alias void (), void ()* @bar
+
+ at bar_ifunc = ifunc void (), i8* ()* @bar2_ifunc
+ at 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
+}

Modified: llvm/trunk/test/Bitcode/compatibility.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility.ll?rev=265667&r1=265666&r2=265667&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/compatibility.ll (original)
+++ llvm/trunk/test/Bitcode/compatibility.ll Thu Apr  7 07:32:19 2016
@@ -249,6 +249,31 @@ declare void @g.f1()
 @a.unnamed_addr = unnamed_addr alias i32, i32* @g.unnamed_addr
 ; CHECK: @a.unnamed_addr = unnamed_addr alias i32, i32* @g.unnamed_addr
 
+;; IFunc
+; Format @<Name> = [Linkage] [Visibility] ifunc <IFuncTy>,
+;                  <ResolverTy>* @<Resolver>
+
+; IFunc -- Linkage
+ at ifunc.external = external ifunc void (), i8* ()* @ifunc_resolver
+; CHECK: @ifunc.external = ifunc void (), i8* ()* @ifunc_resolver
+ at ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver
+; CHECK: @ifunc.private = private ifunc void (), i8* ()* @ifunc_resolver
+ at ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver
+; CHECK: @ifunc.internal = internal ifunc void (), i8* ()* @ifunc_resolver
+
+; IFunc -- Visibility
+ at ifunc.default = default ifunc void (), i8* ()* @ifunc_resolver
+; CHECK: @ifunc.default = ifunc void (), i8* ()* @ifunc_resolver
+ at ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver
+; CHECK: @ifunc.hidden = hidden ifunc void (), i8* ()* @ifunc_resolver
+ at 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]




More information about the llvm-commits mailing list