[llvm] r229461 - [Orc] Update the Orc indirection utils and refactor the CompileOnDemand layer.

Yaron Keren yaron.keren at gmail.com
Tue Feb 17 01:44:58 PST 2015


Hi Lang,

I get the following errors on Visual C++ 2013, 32 bit after this revision:

  C:\llvm\lib\ExecutionEngine\Orc\OrcTargetSupport.cpp(58): error C2440:
'reinterpret_cast' : cannot convert from 'uint64_t (__cdecl
*)(llvm::JITCompileCallbackManagerBase<TargetT> *,llvm::TargetAddress)' to
'uintptr_t'

  C:\llvm\lib\ExecutionEngine\Orc\IndirectionUtils.cpp(107): error C2280:
'std::unique_ptr<llvm::Module,std::default_delete< _Ty>>::unique_ptr(const
std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference
a deleted function

Yaron


2015-02-17 3:18 GMT+02:00 Lang Hames <lhames at gmail.com>:

> Author: lhames
> Date: Mon Feb 16 19:18:38 2015
> New Revision: 229461
>
> URL: http://llvm.org/viewvc/llvm-project?rev=229461&view=rev
> Log:
> [Orc] Update the Orc indirection utils and refactor the CompileOnDemand
> layer.
>
> This patch replaces most of the Orc indirection utils API with a new class:
> JITCompileCallbackManager, which creates and manages JIT callbacks.
> Exposing this functionality directly allows the user to create callbacks
> that
> are associated with user supplied compilation actions. For example, you can
> create a callback to lazyily IR-gen something from an AST. (A kaleidoscope
> example demonstrating this will be committed shortly).
>
> This patch also refactors the CompileOnDemand layer to use the
> JITCompileCallbackManager API.
>
>
> Modified:
>     llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h
>     llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
>     llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
>     llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h
>     llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp
>     llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
>     llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp
>
> Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h Mon Feb
> 16 19:18:38 2015
> @@ -15,6 +15,7 @@
>  #ifndef LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H
>  #define LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H
>
> +#include "llvm/ADT/DenseSet.h"
>  #include "llvm/Transforms/Utils/ValueMapper.h"
>  #include <functional>
>
> @@ -36,9 +37,9 @@ void copyGVInitializer(GlobalVariable &N
>  void copyFunctionBody(Function &New, const Function &Orig,
>                        ValueToValueMapTy &VMap);
>
> -std::unique_ptr<Module>
> -CloneSubModule(const Module &M, HandleGlobalVariableFtor
> HandleGlobalVariable,
> -               HandleFunctionFtor HandleFunction, bool KeepInlineAsm);
> +void CloneSubModule(Module &Dst, const Module &Src,
> +                    HandleGlobalVariableFtor HandleGlobalVariable,
> +                    HandleFunctionFtor HandleFunction, bool
> KeepInlineAsm);
>  }
>
>  #endif // LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H
>
> Modified:
> llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
> (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h Mon
> Feb 16 19:18:38 2015
> @@ -33,7 +33,8 @@ namespace llvm {
>  /// It is expected that this layer will frequently be used on top of a
>  /// LazyEmittingLayer. The combination of the two ensures that each
> function is
>  /// compiled only when it is first called.
> -template <typename BaseLayerT> class CompileOnDemandLayer {
> +template <typename BaseLayerT, typename CompileCallbackMgrT>
> +class CompileOnDemandLayer {
>  public:
>    /// @brief Lookup helper that provides compatibility with the classic
>    ///        static-compilation symbol resolution process.
> @@ -114,13 +115,6 @@ private:
>      // Logical module handles.
>      std::vector<typename CODScopedLookup::LMHandle> LMHandles;
>
> -    // Persistent manglers - one per TU.
> -    std::vector<PersistentMangler> PersistentManglers;
> -
> -    // Symbol resolution callback handlers - one per TU.
> -    std::vector<std::unique_ptr<JITResolveCallbackHandler>>
> -        JITResolveCallbackHandlers;
> -
>      // List of vectors of module set handles:
>      // One vector per logical module - each vector holds the handles for
> the
>      // exploded modules for that logical module in the base layer.
> @@ -143,91 +137,37 @@ public:
>    /// @brief Handle to a set of loaded modules.
>    typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;
>
> -  /// @brief Convenience typedef for callback inserter.
> -  typedef std::function<void(Module&, JITResolveCallbackHandler&)>
> -    InsertCallbackAsmFtor;
> +  // @brief Fallback lookup functor.
> +  typedef std::function<uint64_t(const std::string &)> LookupFtor;
>
>    /// @brief Construct a compile-on-demand layer instance.
> -  CompileOnDemandLayer(BaseLayerT &BaseLayer,
> -                       InsertCallbackAsmFtor InsertCallbackAsm)
> -    : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}
> +  CompileOnDemandLayer(BaseLayerT &BaseLayer, LLVMContext &Context)
> +    : BaseLayer(BaseLayer),
> +      CompileCallbackMgr(BaseLayer, Context, 0, 64) {}
>
>    /// @brief Add a module to the compile-on-demand layer.
>    template <typename ModuleSetT>
>    ModuleSetHandleT addModuleSet(ModuleSetT Ms,
> -                                std::unique_ptr<RTDyldMemoryManager> MM) {
> +                                LookupFtor FallbackLookup = nullptr) {
>
> -    const char *JITAddrSuffix = "$orc_addr";
> -    const char *JITImplSuffix = "$orc_impl";
> -
> -    // Create a symbol lookup context and ModuleSetInfo for this module
> set.
> +    // If the user didn't supply a fallback lookup then just use
> +    // getSymbolAddress.
> +    if (!FallbackLookup)
> +      FallbackLookup = [=](const std::string &Name) {
> +                         return findSymbol(Name, true).getAddress();
> +                       };
> +
> +    // Create a lookup context and ModuleSetInfo for this module set.
> +    // For the purposes of symbol resolution the set Ms will be treated
> as if
> +    // the modules it contained had been linked together as a dylib.
>      auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);
>      ModuleSetHandleT H =
>          ModuleSetInfos.insert(ModuleSetInfos.end(),
> ModuleSetInfo(DylibLookup));
>      ModuleSetInfo &MSI = ModuleSetInfos.back();
>
> -    // Process each of the modules in this module set. All modules share
> the
> -    // same lookup context, but each will get its own TU lookup context.
> -    for (auto &M : Ms) {
> -
> -      // Create a TU lookup context for this module.
> -      auto LMH = DylibLookup->createLogicalModule();
> -      MSI.LMHandles.push_back(LMH);
> -
> -      // Create a persistent mangler for this module.
> -      MSI.PersistentManglers.emplace_back(*M->getDataLayout());
> -
> -      // Make all calls to functions defined in this module indirect.
> -      JITIndirections Indirections =
> -          makeCallsDoubleIndirect(*M, [](const Function &) { return true;
> },
> -                                  JITImplSuffix, JITAddrSuffix);
> -
> -      // Then carve up the module into a bunch of single-function modules.
> -      std::vector<std::unique_ptr<Module>> ExplodedModules =
> -          explode(*M, Indirections);
> -
> -      // Add a resolve-callback handler for this module to look up symbol
> -      // addresses when requested via a callback.
> -      MSI.JITResolveCallbackHandlers.push_back(
> -          createCallbackHandlerFromJITIndirections(
> -              Indirections, MSI.PersistentManglers.back(),
> -              [=](StringRef S) {
> -                return DylibLookup->findSymbol(LMH, S).getAddress();
> -              }));
> -
> -      // Insert callback asm code into the first module.
> -      InsertCallbackAsm(*ExplodedModules[0],
> -                        *MSI.JITResolveCallbackHandlers.back());
> -
> -      // Now we need to take each of the extracted Modules and add them to
> -      // base layer. Each Module will be added individually to make sure
> they
> -      // can be compiled separately, and each will get its own lookaside
> -      // memory manager with lookup functors that resolve symbols in
> sibling
> -      // modules first.OA
> -      for (auto &M : ExplodedModules) {
> -        std::vector<std::unique_ptr<Module>> MSet;
> -        MSet.push_back(std::move(M));
> -
> -        BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(
> -            std::move(MSet),
> -            createLookasideRTDyldMM<SectionMemoryManager>(
> -                [=](const std::string &Name) {
> -                  if (auto Symbol = DylibLookup->findSymbol(LMH, Name))
> -                    return Symbol.getAddress();
> -                  return findSymbol(Name, true).getAddress();
> -                },
> -                [=](const std::string &Name) {
> -                  return DylibLookup->findSymbol(LMH, Name).getAddress();
> -                }));
> -        DylibLookup->addToLogicalModule(LMH, H);
> -        MSI.BaseLayerModuleSetHandles.push_back(H);
> -      }
> -
> -      initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(),
> Indirections,
> -                          MSI.PersistentManglers.back(), [=](StringRef S)
> {
> -                            return DylibLookup->findSymbol(LMH,
> S).getAddress();
> -                          });
> -    }
> +    // Process each of the modules in this module set.
> +    for (auto &M : Ms)
> +      partitionAndAdd(*M, MSI, FallbackLookup);
>
>      return H;
>    }
> @@ -262,8 +202,149 @@ public:
>    }
>
>  private:
> +
> +  void partitionAndAdd(Module &M, ModuleSetInfo &MSI,
> +                       LookupFtor FallbackLookup) {
> +    const char *AddrSuffix = "$orc_addr";
> +    const char *BodySuffix = "$orc_body";
> +
> +    // We're going to break M up into a bunch of sub-modules, but we want
> +    // internal linkage symbols to still resolve sensibly. CODScopedLookup
> +    // provides the "logical module" concept to make this work, so create
> a
> +    // new logical module for M.
> +    auto DylibLookup = MSI.Lookup;
> +    auto LogicalModule = DylibLookup->createLogicalModule();
> +    MSI.LMHandles.push_back(LogicalModule);
> +
> +    // Partition M into a "globals and stubs" module, a "common symbols"
> module,
> +    // and a list of single-function modules.
> +    auto PartitionedModule = fullyPartition(M);
> +    auto StubsModule = std::move(PartitionedModule.GlobalVars);
> +    auto CommonsModule = std::move(PartitionedModule.Commons);
> +    auto FunctionModules = std::move(PartitionedModule.Functions);
> +
> +    // Emit the commons stright away.
> +    auto CommonHandle = addModule(std::move(CommonsModule), MSI,
> LogicalModule,
> +                                  FallbackLookup);
> +    BaseLayer.emitAndFinalize(CommonHandle);
> +
> +    // Map of definition names to callback-info data structures. We'll use
> +    // this to build the compile actions for the stubs below.
> +    typedef std::map<std::string,
> +                     typename CompileCallbackMgrT::CompileCallbackInfo>
> +      StubInfoMap;
> +    StubInfoMap StubInfos;
> +
> +    // Now we need to take each of the extracted Modules and add them to
> +    // base layer. Each Module will be added individually to make sure
> they
> +    // can be compiled separately, and each will get its own lookaside
> +    // memory manager that will resolve within this logical module first.
> +    for (auto &SubM : FunctionModules) {
> +
> +      // Keep track of the stubs we create for this module so that we can
> set
> +      // their compile actions.
> +      std::vector<typename StubInfoMap::iterator> NewStubInfos;
> +
> +      // Search for function definitions and insert stubs into the stubs
> +      // module.
> +      for (auto &F : *SubM) {
> +        if (F.isDeclaration())
> +          continue;
> +
> +        std::string Name = F.getName();
> +        Function *Proto = StubsModule->getFunction(Name);
> +        assert(Proto && "Failed to clone function decl into stubs
> module.");
> +        auto CallbackInfo =
> +
> CompileCallbackMgr.getCompileCallback(*Proto->getFunctionType());
> +        GlobalVariable *FunctionBodyPointer =
> +          createImplPointer(*Proto, Name + AddrSuffix,
> +                            CallbackInfo.getAddress());
> +        makeStub(*Proto, *FunctionBodyPointer);
> +
> +        F.setName(Name + BodySuffix);
> +        F.setVisibility(GlobalValue::HiddenVisibility);
> +
> +        auto KV = std::make_pair(std::move(Name),
> std::move(CallbackInfo));
> +        NewStubInfos.push_back(StubInfos.insert(StubInfos.begin(), KV));
> +      }
> +
> +      auto H = addModule(std::move(SubM), MSI, LogicalModule,
> FallbackLookup);
> +
> +      // Set the compile actions for this module:
> +      for (auto &KVPair : NewStubInfos) {
> +        std::string BodyName = Mangle(KVPair->first + BodySuffix,
> +                                      *M.getDataLayout());
> +        auto &CCInfo = KVPair->second;
> +        CCInfo.setCompileAction(
> +          [=](){
> +            return BaseLayer.findSymbolIn(H, BodyName,
> false).getAddress();
> +          });
> +      }
> +
> +    }
> +
> +    // Ok - we've processed all the partitioned modules. Now add the
> +    // stubs/globals module and set the update actions.
> +    auto StubsH =
> +      addModule(std::move(StubsModule), MSI, LogicalModule,
> FallbackLookup);
> +
> +    for (auto &KVPair : StubInfos) {
> +      std::string AddrName = Mangle(KVPair.first + AddrSuffix,
> +                                    *M.getDataLayout());
> +      auto &CCInfo = KVPair.second;
> +      CCInfo.setUpdateAction(
> +        CompileCallbackMgr.getLocalFPUpdater(StubsH, AddrName));
> +    }
> +  }
> +
> +  // Add the given Module to the base layer using a memory manager that
> will
> +  // perform the appropriate scoped lookup (i.e. will look first with in
> the
> +  // module from which it was extracted, then into the set to which that
> module
> +  // belonged, and finally externally).
> +  BaseLayerModuleSetHandleT addModule(
> +                               std::unique_ptr<Module> M,
> +                               ModuleSetInfo &MSI,
> +                               typename CODScopedLookup::LMHandle
> LogicalModule,
> +                               LookupFtor FallbackLookup) {
> +
> +    // Add this module to the JIT with a memory manager that uses the
> +    // DylibLookup to resolve symbols.
> +    std::vector<std::unique_ptr<Module>> MSet;
> +    MSet.push_back(std::move(M));
> +
> +    auto DylibLookup = MSI.Lookup;
> +    auto MM =
> +      createLookasideRTDyldMM<SectionMemoryManager>(
> +        [=](const std::string &Name) {
> +          if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name))
> +            return Symbol.getAddress();
> +          return FallbackLookup(Name);
> +        },
> +        [=](const std::string &Name) {
> +          return DylibLookup->findSymbol(LogicalModule,
> Name).getAddress();
> +        });
> +
> +    BaseLayerModuleSetHandleT H =
> +      BaseLayer.addModuleSet(std::move(MSet), std::move(MM));
> +    // Add this module to the logical module lookup.
> +    DylibLookup->addToLogicalModule(LogicalModule, H);
> +    MSI.BaseLayerModuleSetHandles.push_back(H);
> +
> +    return H;
> +  }
> +
> +  static std::string Mangle(StringRef Name, const DataLayout &DL) {
> +    Mangler M(&DL);
> +    std::string MangledName;
> +    {
> +      raw_string_ostream MangledNameStream(MangledName);
> +      M.getNameWithPrefix(MangledNameStream, Name);
> +    }
> +    return MangledName;
> +  }
> +
>    BaseLayerT &BaseLayer;
> -  InsertCallbackAsmFtor InsertCallbackAsm;
> +  CompileCallbackMgrT CompileCallbackMgr;
>    ModuleSetInfoListT ModuleSetInfos;
>  };
>  }
>
> Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
> (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h Mon Feb
> 16 19:18:38 2015
> @@ -15,271 +15,224 @@
>  #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
>
>  #include "JITSymbol.h"
> +#include "llvm/ADT/DenseSet.h"
> +#include "llvm/IR/IRBuilder.h"
>  #include "llvm/IR/Mangler.h"
>  #include "llvm/IR/Module.h"
>  #include <sstream>
>
>  namespace llvm {
>
> -/// @brief Persistent name mangling.
> -///
> -///   This class provides name mangling that can outlive a Module (and its
> -/// DataLayout).
> -class PersistentMangler {
> +/// @brief Base class for JITLayer independent aspects of
> +///        JITCompileCallbackManager.
> +template <typename TargetT>
> +class JITCompileCallbackManagerBase {
>  public:
> -  PersistentMangler(DataLayout DL) : DL(std::move(DL)), M(&this->DL) {}
>
> -  std::string getMangledName(StringRef Name) const {
> -    std::string MangledName;
> -    {
> -      raw_string_ostream MangledNameStream(MangledName);
> -      M.getNameWithPrefix(MangledNameStream, Name);
> +  /// @brief Construct a JITCompileCallbackManagerBase.
> +  /// @param ErrorHandlerAddress The address of an error handler in the
> target
> +  ///                            process to be used if a compile callback
> fails.
> +  /// @param NumTrampolinesPerBlock Number of trampolines to emit if
> there is no
> +  ///                             available trampoline when
> getCompileCallback is
> +  ///                             called.
> +  JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress,
> +                                unsigned NumTrampolinesPerBlock)
> +    : ErrorHandlerAddress(ErrorHandlerAddress),
> +      NumTrampolinesPerBlock(NumTrampolinesPerBlock) {}
> +
> +  /// @brief Execute the callback for the given trampoline id. Called by
> the JIT
> +  ///        to compile functions on demand.
> +  TargetAddress executeCompileCallback(TargetAddress TrampolineID) {
> +    typename TrampolineMapT::iterator I =
> ActiveTrampolines.find(TrampolineID);
> +    // FIXME: Also raise an error in the Orc error-handler when we
> finally have
> +    //        one.
> +    if (I == ActiveTrampolines.end())
> +      return ErrorHandlerAddress;
> +
> +    // Found a callback handler. Yank this trampoline out of the active
> list and
> +    // put it back in the available trampolines list, then try to run the
> +    // handler's compile and update actions.
> +    // Moving the trampoline ID back to the available list first means
> there's at
> +    // least one available trampoline if the compile action triggers a
> request for
> +    // a new one.
> +    AvailableTrampolines.push_back(I->first);
> +    auto CallbackHandler = std::move(I->second);
> +    ActiveTrampolines.erase(I);
> +
> +    if (auto Addr = CallbackHandler.Compile()) {
> +      CallbackHandler.Update(Addr);
> +      return Addr;
>      }
> -    return MangledName;
> +    return ErrorHandlerAddress;
>    }
>
> -private:
> -  DataLayout DL;
> -  Mangler M;
> -};
> +protected:
>
> -/// @brief Handle callbacks from the JIT process requesting the
> definitions of
> -///        symbols.
> -///
> -///   This utility is intended to be used to support compile-on-demand for
> -/// functions.
> -class JITResolveCallbackHandler {
> -private:
> -  typedef std::vector<std::string> FuncNameList;
> +  typedef std::function<TargetAddress()> CompileFtorT;
> +  typedef std::function<void(TargetAddress)> UpdateFtorT;
>
> -public:
> -  typedef FuncNameList::size_type StubIndex;
> +  struct CallbackHandler {
> +    CompileFtorT Compile;
> +    UpdateFtorT Update;
> +  };
> +
> +  TargetAddress ErrorHandlerAddress;
> +  unsigned NumTrampolinesPerBlock;
> +
> +  typedef std::map<TargetAddress, CallbackHandler> TrampolineMapT;
> +  TrampolineMapT ActiveTrampolines;
> +  std::vector<TargetAddress> AvailableTrampolines;
> +};
>
> +/// @brief Manage compile callbacks.
> +template <typename JITLayerT, typename TargetT>
> +class JITCompileCallbackManager :
> +    public JITCompileCallbackManagerBase<TargetT> {
>  public:
> -  /// @brief Create a JITResolveCallbackHandler with the given functors
> for
> -  ///        looking up symbols and updating their use-sites.
> -  ///
> -  /// @return A JITResolveCallbackHandler instance that will invoke the
> -  ///         Lookup and Update functors as needed to resolve missing
> symbol
> -  ///         definitions.
> -  template <typename LookupFtor, typename UpdateFtor>
> -  static std::unique_ptr<JITResolveCallbackHandler> create(LookupFtor
> Lookup,
> -                                                           UpdateFtor
> Update);
> -
> -  /// @brief Destroy instance. Does not modify existing emitted symbols.
> -  ///
> -  ///   Not-yet-emitted symbols will need to be resolved some other way
> after
> -  /// this class is destroyed.
> -  virtual ~JITResolveCallbackHandler() {}
> -
> -  /// @brief Add a function to be resolved on demand.
> -  void addFuncName(std::string Name) {
> FuncNames.push_back(std::move(Name)); }
> -
> -  /// @brief Get the name associated with the given index.
> -  const std::string &getFuncName(StubIndex Idx) const { return
> FuncNames[Idx]; }
> -
> -  /// @brief Returns the number of symbols being managed by this instance.
> -  StubIndex getNumFuncs() const { return FuncNames.size(); }
> -
> -  /// @brief Get the address for the symbol associated with the given
> index.
> -  ///
> -  ///   This is expected to be called by code in the JIT process itself,
> in
> -  /// order to resolve a function.
> -  virtual TargetAddress resolve(StubIndex StubIdx) = 0;
>
> -private:
> -  FuncNameList FuncNames;
> -};
> +  typedef typename JITCompileCallbackManagerBase<TargetT>::CompileFtorT
> +    CompileFtorT;
> +  typedef typename JITCompileCallbackManagerBase<TargetT>::UpdateFtorT
> +    UpdateFtorT;
> +
> +  /// @brief Construct a JITCompileCallbackManager.
> +  /// @param JIT JIT layer to emit callback trampolines, etc. into.
> +  /// @param Context LLVMContext to use for trampoline & resolve block
> modules.
> +  /// @param ErrorHandlerAddress The address of an error handler in the
> target
> +  ///                            process to be used if a compile callback
> fails.
> +  /// @param NumTrampolinesPerBlock Number of trampolines to allocate
> whenever
> +  ///                               there is no existing callback
> trampoline.
> +  ///                               (Trampolines are allocated in blocks
> for
> +  ///                               efficiency.)
> +  JITCompileCallbackManager(JITLayerT &JIT, LLVMContext &Context,
> +                            TargetAddress ErrorHandlerAddress,
> +                            unsigned NumTrampolinesPerBlock)
> +    : JITCompileCallbackManagerBase<TargetT>(ErrorHandlerAddress,
> +                                             NumTrampolinesPerBlock),
> +      JIT(JIT) {
> +    emitResolverBlock(Context);
> +  }
>
> -// Implementation class for JITResolveCallbackHandler.
> -template <typename LookupFtor, typename UpdateFtor>
> -class JITResolveCallbackHandlerImpl : public JITResolveCallbackHandler {
> -public:
> -  JITResolveCallbackHandlerImpl(LookupFtor Lookup, UpdateFtor Update)
> -      : Lookup(std::move(Lookup)), Update(std::move(Update)) {}
> +  /// @brief Handle to a newly created compile callback. Can be used to
> get an
> +  ///        IR constant representing the address of the trampoline, and
> to set
> +  ///        the compile and update actions for the callback.
> +  class CompileCallbackInfo {
> +  public:
> +    CompileCallbackInfo(Constant *Addr, CompileFtorT &Compile,
> +                        UpdateFtorT &Update)
> +      : Addr(Addr), Compile(Compile), Update(Update) {}
> +
> +    Constant* getAddress() const { return Addr; }
> +    void setCompileAction(CompileFtorT Compile) {
> +      this->Compile = std::move(Compile);
> +    }
> +    void setUpdateAction(UpdateFtorT Update) {
> +      this->Update = std::move(Update);
> +    }
> +  private:
> +    Constant *Addr;
> +    CompileFtorT &Compile;
> +    UpdateFtorT &Update;
> +  };
> +
> +  /// @brief Get/create a compile callback with the given signature.
> +  CompileCallbackInfo getCompileCallback(FunctionType &FT) {
> +    TargetAddress TrampolineAddr =
> getAvailableTrampolineAddr(FT.getContext());
> +    auto &CallbackHandler =
> +      this->ActiveTrampolines[TrampolineAddr + TargetT::CallSize];
> +    Constant *AddrIntVal =
> +      ConstantInt::get(Type::getInt64Ty(FT.getContext()), TrampolineAddr);
> +    Constant *AddrPtrVal =
> +      ConstantExpr::getCast(Instruction::IntToPtr, AddrIntVal,
> +                            PointerType::get(&FT, 0));
>
> -  TargetAddress resolve(StubIndex StubIdx) override {
> -    const std::string &FuncName = getFuncName(StubIdx);
> -    TargetAddress Addr = Lookup(FuncName);
> -    Update(FuncName, Addr);
> -    return Addr;
> +    return CompileCallbackInfo(AddrPtrVal, CallbackHandler.Compile,
> +                               CallbackHandler.Update);
> +  }
> +
> +  /// @brief Get a functor for updating the value of a named function
> pointer.
> +  UpdateFtorT getLocalFPUpdater(typename JITLayerT::ModuleSetHandleT H,
> +                                std::string Name) {
> +    // FIXME: Move-capture Name once we can use C++14.
> +    return [=](TargetAddress Addr) {
> +      auto FPSym = JIT.findSymbolIn(H, Name, true);
> +      assert(FPSym && "Cannot find function pointer to update.");
> +      void *FPAddr = reinterpret_cast<void*>(
> +                       static_cast<uintptr_t>(FPSym.getAddress()));
> +      memcpy(FPAddr, &Addr, sizeof(uintptr_t));
> +    };
>    }
>
>  private:
> -  LookupFtor Lookup;
> -  UpdateFtor Update;
> -};
>
> -template <typename LookupFtor, typename UpdateFtor>
> -std::unique_ptr<JITResolveCallbackHandler>
> -JITResolveCallbackHandler::create(LookupFtor Lookup, UpdateFtor Update) {
> -  typedef JITResolveCallbackHandlerImpl<LookupFtor, UpdateFtor> Impl;
> -  return make_unique<Impl>(std::move(Lookup), std::move(Update));
> -}
> +  std::vector<std::unique_ptr<Module>>
> +  SingletonSet(std::unique_ptr<Module> M) {
> +    std::vector<std::unique_ptr<Module>> Ms;
> +    Ms.push_back(std::move(M));
> +    return Ms;
> +  }
>
> -/// @brief Holds a list of the function names that were indirected, plus
> -///        mappings from each of these names to (a) the name of function
> -///        providing the implementation for that name (GetImplNames), and
> -///        (b) the name of the global variable holding the address of the
> -///        implementation.
> -///
> -///   This data structure can be used with a JITCallbackHandler to look
> up and
> -/// update function implementations when lazily compiling.
> -class JITIndirections {
> -public:
> -  JITIndirections(std::vector<std::string> IndirectedNames,
> -                  std::function<std::string(StringRef)> GetImplName,
> -                  std::function<std::string(StringRef)> GetAddrName)
> -      : IndirectedNames(std::move(IndirectedNames)),
> -        GetImplName(std::move(GetImplName)),
> -        GetAddrName(std::move(GetAddrName)) {}
> -
> -  std::vector<std::string> IndirectedNames;
> -  std::function<std::string(StringRef Name)> GetImplName;
> -  std::function<std::string(StringRef Name)> GetAddrName;
> +  void emitResolverBlock(LLVMContext &Context) {
> +    std::unique_ptr<Module> M(new Module("resolver_block_module",
> +                                         Context));
> +    TargetT::insertResolverBlock(*M, *this);
> +    auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr);
> +    JIT.emitAndFinalize(H);
> +    auto ResolverBlockSymbol =
> +      JIT.findSymbolIn(H, TargetT::ResolverBlockName, false);
> +    assert(ResolverBlockSymbol && "Failed to insert resolver block");
> +    ResolverBlockAddr = ResolverBlockSymbol.getAddress();
> +  }
> +
> +  TargetAddress getAvailableTrampolineAddr(LLVMContext &Context) {
> +    if (this->AvailableTrampolines.empty())
> +      grow(Context);
> +    assert(!this->AvailableTrampolines.empty() &&
> +           "Failed to grow available trampolines.");
> +    TargetAddress TrampolineAddr = this->AvailableTrampolines.back();
> +    this->AvailableTrampolines.pop_back();
> +    return TrampolineAddr;
> +  }
> +
> +  void grow(LLVMContext &Context) {
> +    assert(this->AvailableTrampolines.empty() && "Growing prematurely?");
> +    std::unique_ptr<Module> M(new Module("trampoline_block", Context));
> +    auto GetLabelName =
> +      TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr,
> +
> this->NumTrampolinesPerBlock,
> +
> this->ActiveTrampolines.size());
> +    auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr);
> +    JIT.emitAndFinalize(H);
> +    for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) {
> +      std::string Name = GetLabelName(I);
> +      auto TrampolineSymbol = JIT.findSymbolIn(H, Name, false);
> +      assert(TrampolineSymbol && "Failed to emit trampoline.");
> +      this->AvailableTrampolines.push_back(TrampolineSymbol.getAddress());
> +    }
> +  }
> +
> +  JITLayerT &JIT;
> +  TargetAddress ResolverBlockAddr;
>  };
>
> -/// @brief Indirect all calls to functions matching the predicate
> -///        ShouldIndirect through a global variable containing the address
> -///        of the implementation.
> -///
> -/// @return An indirection structure containing the functions that had
> their
> -///         call-sites re-written.
> -///
> -///   For each function 'F' that meets the ShouldIndirect predicate, and
> that
> -/// is called in this Module, add a common-linkage global variable to the
> -/// module that will hold the address of the implementation of that
> function.
> -/// Rewrite all call-sites of 'F' to be indirect calls (via the global).
> -/// This allows clients, either directly or via a JITCallbackHandler, to
> -/// change the address of the implementation of 'F' at runtime.
> -///
> -/// Important notes:
> -///
> -///   Single indirection does not preserve pointer equality for 'F'. If
> the
> -/// program was already calling 'F' indirectly through function pointers,
> or
> -/// if it was taking the address of 'F' for the purpose of pointer
> comparisons
> -/// or arithmetic double indirection should be used instead.
> -///
> -///   This method does *not* initialize the function implementation
> addresses.
> -/// The client must do this prior to running any call-sites that have been
> -/// indirected.
> -JITIndirections makeCallsSingleIndirect(
> -    llvm::Module &M,
> -    const std::function<bool(const Function &)> &ShouldIndirect,
> -    const char *JITImplSuffix, const char *JITAddrSuffix);
> -
> -/// @brief Replace the body of functions matching the predicate
> ShouldIndirect
> -///        with indirect calls to the implementation.
> -///
> -/// @return An indirections structure containing the functions that had
> their
> -///         implementations re-written.
> -///
> -///   For each function 'F' that meets the ShouldIndirect predicate, add a
> -/// common-linkage global variable to the module that will hold the
> address of
> -/// the implementation of that function and rewrite the implementation of
> 'F'
> -/// to call through to the implementation indirectly (via the global).
> -/// This allows clients, either directly or via a JITCallbackHandler, to
> -/// change the address of the implementation of 'F' at runtime.
> -///
> -/// Important notes:
> -///
> -///   Double indirection is slower than single indirection, but preserves
> -/// function pointer relation tests and correct behavior for function
> pointers
> -/// (all calls to 'F', direct or indirect) go the address stored in the
> global
> -/// variable at the time of the call.
> -///
> -///   This method does *not* initialize the function implementation
> addresses.
> -/// The client must do this prior to running any call-sites that have been
> -/// indirected.
> -JITIndirections makeCallsDoubleIndirect(
> -    llvm::Module &M,
> -    const std::function<bool(const Function &)> &ShouldIndirect,
> -    const char *JITImplSuffix, const char *JITAddrSuffix);
> -
> -/// @brief Given a set of indirections and a symbol lookup functor,
> create a
> -///        JITResolveCallbackHandler instance that will resolve the
> -///        implementations for the indirected symbols on demand.
> -template <typename SymbolLookupFtor>
> -std::unique_ptr<JITResolveCallbackHandler>
> -createCallbackHandlerFromJITIndirections(const JITIndirections &Indirs,
> -                                         const PersistentMangler &NM,
> -                                         SymbolLookupFtor Lookup) {
> -  auto GetImplName = Indirs.GetImplName;
> -  auto GetAddrName = Indirs.GetAddrName;
> -
> -  std::unique_ptr<JITResolveCallbackHandler> J =
> -      JITResolveCallbackHandler::create(
> -          [=](const std::string &S) {
> -            return Lookup(NM.getMangledName(GetImplName(S)));
> -          },
> -          [=](const std::string &S, TargetAddress Addr) {
> -            void *ImplPtr = reinterpret_cast<void *>(
> -                Lookup(NM.getMangledName(GetAddrName(S))));
> -            memcpy(ImplPtr, &Addr, sizeof(TargetAddress));
> -          });
> +GlobalVariable* createImplPointer(Function &F, const Twine &Name,
> +                                  Constant *Initializer);
>
> -  for (const auto &FuncName : Indirs.IndirectedNames)
> -    J->addFuncName(FuncName);
> +void makeStub(Function &F, GlobalVariable &ImplPointer);
>
> -  return J;
> -}
> +typedef std::map<Module*, DenseSet<const GlobalValue*>>
> ModulePartitionMap;
>
> -/// @brief Insert callback asm into module M for the symbols managed by
> -///        JITResolveCallbackHandler J.
> -void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J);
> -
> -/// @brief Initialize global indirects to point into the callback asm.
> -template <typename LookupFtor>
> -void initializeFuncAddrs(JITResolveCallbackHandler &J,
> -                         const JITIndirections &Indirs,
> -                         const PersistentMangler &NM, LookupFtor Lookup) {
> -  // Forward declare so that we can access this, even though it's an
> -  // implementation detail.
> -  std::string getJITResolveCallbackIndexLabel(unsigned I);
> -
> -  if (J.getNumFuncs() == 0)
> -    return;
> -
> -  //   Force a look up one of the global addresses for a function that
> has been
> -  // indirected. We need to do this to trigger the emission of the module
> -  // holding the callback asm. We can't rely on that emission happening
> -  // automatically when we look up the callback asm symbols, since
> lazy-emitting
> -  // layers can't see those.
> -  Lookup(NM.getMangledName(Indirs.GetAddrName(J.getFuncName(0))));
> -
> -  // Now update indirects to point to the JIT resolve callback asm.
> -  for (JITResolveCallbackHandler::StubIndex I = 0; I < J.getNumFuncs();
> ++I) {
> -    TargetAddress ResolveCallbackIdxAddr =
> -        Lookup(getJITResolveCallbackIndexLabel(I));
> -    void *AddrPtr = reinterpret_cast<void *>(
> -        Lookup(NM.getMangledName(Indirs.GetAddrName(J.getFuncName(I)))));
> -    assert(AddrPtr && "Can't find stub addr global to initialize.");
> -    memcpy(AddrPtr, &ResolveCallbackIdxAddr, sizeof(TargetAddress));
> -  }
> -}
> +void partition(Module &M, const ModulePartitionMap &PMap);
> +
> +/// @brief Struct for trivial "complete" partitioning of a module.
> +struct FullyPartitionedModule {
> +  std::unique_ptr<Module> GlobalVars;
> +  std::unique_ptr<Module> Commons;
> +  std::vector<std::unique_ptr<Module>> Functions;
> +};
> +
> +FullyPartitionedModule fullyPartition(Module &M);
>
> -/// @brief Extract all functions matching the predicate ShouldExtract in
> to
> -///        their own modules. (Does not modify the original module.)
> -///
> -/// @return A set of modules, the first containing all symbols (including
> -///         globals and aliases) that did not pass ShouldExtract, and each
> -///         subsequent module containing one of the functions that did
> meet
> -///         ShouldExtract.
> -///
> -///   By adding the resulting modules separately (not as a set) to a
> -/// LazyEmittingLayer instance, compilation can be deferred until symbols
> are
> -/// actually needed.
> -std::vector<std::unique_ptr<llvm::Module>>
> -explode(const llvm::Module &OrigMod,
> -        const std::function<bool(const Function &)> &ShouldExtract);
> -
> -/// @brief Given a module that has been indirectified, break each function
> -///        that has been indirected out into its own module. (Does not
> modify
> -///        the original module).
> -///
> -/// @returns A set of modules covering the symbols provided by OrigMod.
> -std::vector<std::unique_ptr<llvm::Module>>
> -explode(const llvm::Module &OrigMod, const JITIndirections &Indirections);
>  }
>
>  #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
>
> Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h
> (original)
> +++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h Mon Feb
> 16 19:18:38 2015
> @@ -18,9 +18,37 @@
>
>  namespace llvm {
>
> -/// @brief Insert callback asm into module M for the symbols managed by
> -///        JITResolveCallbackHandler J.
> -void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J);
> +class OrcX86_64 {
> +public:
> +  static const char *ResolverBlockName;
> +
> +  /// @brief Insert module-level inline callback asm into module M for the
> +  /// symbols managed by JITResolveCallbackHandler J.
> +  static void insertResolverBlock(
> +                                 Module &M,
> +                                 JITCompileCallbackManagerBase<OrcX86_64>
> &JCBM);
> +
> +  /// @brief Get a label name from the given index.
> +  typedef std::function<std::string(unsigned)> LabelNameFtor;
> +
> +  static const unsigned CallSize = 6;
> +
> +  /// @brief Insert the requested number of trampolines into the given
> module.
> +  /// @param M Module to insert the call block into.
> +  /// @param NumCalls Number of calls to create in the call block.
> +  /// @param StartIndex Optional argument specifying the index suffix to
> start
> +  ///                   with.
> +  /// @return A functor that provides the symbol name for each entry in
> the call
> +  ///         block.
> +  ///
> +  static LabelNameFtor insertCompileCallbackTrampolines(
> +                                                    Module &M,
> +                                                    TargetAddress
> TrampolineAddr,
> +                                                    unsigned NumCalls,
> +                                                    unsigned StartIndex =
> 0);
> +
> +};
> +
>  }
>
>  #endif // LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
>
> Modified: llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp (original)
> +++ llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp Mon Feb 16
> 19:18:38 2015
> @@ -27,27 +27,20 @@ void llvm::copyFunctionBody(Function &Ne
>    }
>  }
>
> -std::unique_ptr<Module>
> -llvm::CloneSubModule(const Module &M,
> +void llvm::CloneSubModule(llvm::Module &Dst, const Module &Src,
>                       HandleGlobalVariableFtor HandleGlobalVariable,
> -                     HandleFunctionFtor HandleFunction, bool
> KeepInlineAsm) {
> +                     HandleFunctionFtor HandleFunction, bool
> CloneInlineAsm) {
>
>    ValueToValueMapTy VMap;
>
> -  // First off, we need to create the new module.
> -  std::unique_ptr<Module> New =
> -      llvm::make_unique<Module>(M.getModuleIdentifier(), M.getContext());
> -
> -  New->setDataLayout(M.getDataLayout());
> -  New->setTargetTriple(M.getTargetTriple());
> -  if (KeepInlineAsm)
> -    New->setModuleInlineAsm(M.getModuleInlineAsm());
> +  if (CloneInlineAsm)
> +    Dst.appendModuleInlineAsm(Src.getModuleInlineAsm());
>
>    // Copy global variables (but not initializers, yet).
> -  for (Module::const_global_iterator I = M.global_begin(), E =
> M.global_end();
> +  for (Module::const_global_iterator I = Src.global_begin(), E =
> Src.global_end();
>         I != E; ++I) {
>      GlobalVariable *GV = new GlobalVariable(
> -        *New, I->getType()->getElementType(), I->isConstant(),
> I->getLinkage(),
> +        Dst, I->getType()->getElementType(), I->isConstant(),
> I->getLinkage(),
>          (Constant *)nullptr, I->getName(), (GlobalVariable *)nullptr,
>          I->getThreadLocalMode(), I->getType()->getAddressSpace());
>      GV->copyAttributesFrom(I);
> @@ -55,21 +48,21 @@ llvm::CloneSubModule(const Module &M,
>    }
>
>    // Loop over the functions in the module, making external functions as
> before
> -  for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) {
> +  for (Module::const_iterator I = Src.begin(), E = Src.end(); I != E;
> ++I) {
>      Function *NF =
>
>  Function::Create(cast<FunctionType>(I->getType()->getElementType()),
> -                         I->getLinkage(), I->getName(), &*New);
> +                         I->getLinkage(), I->getName(), &Dst);
>      NF->copyAttributesFrom(I);
>      VMap[I] = NF;
>    }
>
>    // Loop over the aliases in the module
> -  for (Module::const_alias_iterator I = M.alias_begin(), E =
> M.alias_end();
> +  for (Module::const_alias_iterator I = Src.alias_begin(), E =
> Src.alias_end();
>         I != E; ++I) {
>      auto *PTy = cast<PointerType>(I->getType());
>      auto *GA =
>          GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(),
> -                            I->getLinkage(), I->getName(), &*New);
> +                            I->getLinkage(), I->getName(), &Dst);
>      GA->copyAttributesFrom(I);
>      VMap[I] = GA;
>    }
> @@ -77,7 +70,7 @@ llvm::CloneSubModule(const Module &M,
>    // Now that all of the things that global variable initializer can
> refer to
>    // have been created, loop through and copy the global variable
> referrers
>    // over...  We also set the attributes on the global now.
> -  for (Module::const_global_iterator I = M.global_begin(), E =
> M.global_end();
> +  for (Module::const_global_iterator I = Src.global_begin(), E =
> Src.global_end();
>         I != E; ++I) {
>      GlobalVariable &GV = *cast<GlobalVariable>(VMap[I]);
>      HandleGlobalVariable(GV, *I, VMap);
> @@ -85,13 +78,13 @@ llvm::CloneSubModule(const Module &M,
>
>    // Similarly, copy over function bodies now...
>    //
> -  for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) {
> +  for (Module::const_iterator I = Src.begin(), E = Src.end(); I != E;
> ++I) {
>      Function &F = *cast<Function>(VMap[I]);
>      HandleFunction(F, *I, VMap);
>    }
>
>    // And aliases
> -  for (Module::const_alias_iterator I = M.alias_begin(), E =
> M.alias_end();
> +  for (Module::const_alias_iterator I = Src.alias_begin(), E =
> Src.alias_end();
>         I != E; ++I) {
>      GlobalAlias *GA = cast<GlobalAlias>(VMap[I]);
>      if (const Constant *C = I->getAliasee())
> @@ -99,14 +92,13 @@ llvm::CloneSubModule(const Module &M,
>    }
>
>    // And named metadata....
> -  for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),
> -                                             E = M.named_metadata_end();
> +  for (Module::const_named_metadata_iterator I =
> Src.named_metadata_begin(),
> +                                             E = Src.named_metadata_end();
>         I != E; ++I) {
>      const NamedMDNode &NMD = *I;
> -    NamedMDNode *NewNMD = New->getOrInsertNamedMetadata(NMD.getName());
> +    NamedMDNode *NewNMD = Dst.getOrInsertNamedMetadata(NMD.getName());
>      for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i)
>        NewNMD->addOperand(MapMetadata(NMD.getOperand(i), VMap));
>    }
>
> -  return New;
>  }
>
> Modified: llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp (original)
> +++ llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp Mon Feb 16
> 19:18:38 2015
> @@ -9,149 +9,101 @@ using namespace llvm;
>
>  namespace llvm {
>
> -JITIndirections makeCallsSingleIndirect(
> -    Module &M, const std::function<bool(const Function &)>
> &ShouldIndirect,
> -    const char *JITImplSuffix, const char *JITAddrSuffix) {
> -  std::vector<Function *> Worklist;
> -  std::vector<std::string> FuncNames;
> -
> -  for (auto &F : M)
> -    if (ShouldIndirect(F) && (F.user_begin() != F.user_end())) {
> -      Worklist.push_back(&F);
> -      FuncNames.push_back(F.getName());
> -    }
> -
> -  for (auto *F : Worklist) {
> -    GlobalVariable *FImplAddr = new GlobalVariable(
> -        M, F->getType(), false, GlobalValue::ExternalLinkage,
> -        Constant::getNullValue(F->getType()), F->getName() +
> JITAddrSuffix,
> -        nullptr, GlobalValue::NotThreadLocal, 0, true);
> -    FImplAddr->setVisibility(GlobalValue::HiddenVisibility);
> -
> -    for (auto *U : F->users()) {
> -      assert(isa<Instruction>(U) && "Cannot indirect non-instruction
> use");
> -      IRBuilder<> Builder(cast<Instruction>(U));
> -      U->replaceUsesOfWith(F, Builder.CreateLoad(FImplAddr));
> -    }
> -  }
> +GlobalVariable* createImplPointer(Function &F, const Twine &Name,
> +                                  Constant *Initializer) {
> +  assert(F.getParent() && "Function isn't in a module.");
> +  if (!Initializer)
> +    Initializer = Constant::getNullValue(F.getType());
> +  Module &M = *F.getParent();
> +  return new GlobalVariable(M, F.getType(), false,
> GlobalValue::ExternalLinkage,
> +                            Initializer, Name, nullptr,
> +                            GlobalValue::NotThreadLocal, 0, true);
> +}
>
> -  return JITIndirections(
> -      FuncNames, [=](StringRef S) -> std::string { return std::string(S);
> },
> -      [=](StringRef S)
> -          -> std::string { return std::string(S) + JITAddrSuffix; });
> +void makeStub(Function &F, GlobalVariable &ImplPointer) {
> +  assert(F.isDeclaration() && "Can't turn a definition into a stub.");
> +  assert(F.getParent() && "Function isn't in a module.");
> +  Module &M = *F.getParent();
> +  BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry",
> &F);
> +  IRBuilder<> Builder(EntryBlock);
> +  LoadInst *ImplAddr = Builder.CreateLoad(&ImplPointer);
> +  std::vector<Value*> CallArgs;
> +  for (auto &A : F.args())
> +    CallArgs.push_back(&A);
> +  CallInst *Call = Builder.CreateCall(ImplAddr, CallArgs);
> +  Call->setTailCall();
> +  Builder.CreateRet(Call);
>  }
>
> -JITIndirections makeCallsDoubleIndirect(
> -    Module &M, const std::function<bool(const Function &)>
> &ShouldIndirect,
> -    const char *JITImplSuffix, const char *JITAddrSuffix) {
> -
> -  std::vector<Function *> Worklist;
> -  std::vector<std::string> FuncNames;
> -
> -  for (auto &F : M)
> -    if (!F.isDeclaration() && !F.hasAvailableExternallyLinkage() &&
> -        ShouldIndirect(F))
> -      Worklist.push_back(&F);
> -
> -  for (auto *F : Worklist) {
> -    std::string OrigName = F->getName();
> -    F->setName(OrigName + JITImplSuffix);
> -    FuncNames.push_back(OrigName);
> -
> -    GlobalVariable *FImplAddr = new GlobalVariable(
> -        M, F->getType(), false, GlobalValue::ExternalLinkage,
> -        Constant::getNullValue(F->getType()), OrigName + JITAddrSuffix,
> nullptr,
> -        GlobalValue::NotThreadLocal, 0, true);
> -    FImplAddr->setVisibility(GlobalValue::HiddenVisibility);
> -
> -    Function *FRedirect =
> -        Function::Create(F->getFunctionType(), F->getLinkage(), OrigName,
> &M);
> -
> -    F->replaceAllUsesWith(FRedirect);
> -
> -    BasicBlock *EntryBlock =
> -        BasicBlock::Create(M.getContext(), "entry", FRedirect);
> -
> -    IRBuilder<> Builder(EntryBlock);
> -    LoadInst *FImplLoadedAddr = Builder.CreateLoad(FImplAddr);
> -
> -    std::vector<Value *> CallArgs;
> -    for (Value &Arg : FRedirect->args())
> -      CallArgs.push_back(&Arg);
> -    CallInst *Call = Builder.CreateCall(FImplLoadedAddr, CallArgs);
> -    Call->setTailCall();
> -    Builder.CreateRet(Call);
> -  }
> +void partition(Module &M, const ModulePartitionMap &PMap) {
>
> -  return JITIndirections(
> -      FuncNames, [=](StringRef S)
> -                     -> std::string { return std::string(S) +
> JITImplSuffix; },
> -      [=](StringRef S)
> -          -> std::string { return std::string(S) + JITAddrSuffix; });
> -}
> +  for (auto &KVPair : PMap) {
>
> -std::vector<std::unique_ptr<Module>>
> -explode(const Module &OrigMod,
> -        const std::function<bool(const Function &)> &ShouldExtract) {
> -
> -  std::vector<std::unique_ptr<Module>> NewModules;
> -
> -  // Split all the globals, non-indirected functions, etc. into a single
> module.
> -  auto ExtractGlobalVars = [&](GlobalVariable &New, const GlobalVariable
> &Orig,
> -                               ValueToValueMapTy &VMap) {
> -    copyGVInitializer(New, Orig, VMap);
> -    if (New.getLinkage() == GlobalValue::PrivateLinkage) {
> -      New.setLinkage(GlobalValue::ExternalLinkage);
> -      New.setVisibility(GlobalValue::HiddenVisibility);
> -    }
> -  };
> +    auto ExtractGlobalVars =
> +      [&](GlobalVariable &New, const GlobalVariable &Orig,
> +          ValueToValueMapTy &VMap) {
> +        if (KVPair.second.count(&Orig)) {
> +          copyGVInitializer(New, Orig, VMap);
> +        }
> +        if (New.getLinkage() == GlobalValue::PrivateLinkage) {
> +          New.setLinkage(GlobalValue::ExternalLinkage);
> +          New.setVisibility(GlobalValue::HiddenVisibility);
> +        }
> +      };
>
> -  auto ExtractNonImplFunctions =
> +    auto ExtractFunctions =
>        [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) {
> -        if (!ShouldExtract(New))
> +        if (KVPair.second.count(&Orig))
>            copyFunctionBody(New, Orig, VMap);
> +        if (New.getLinkage() == GlobalValue::InternalLinkage) {
> +          New.setLinkage(GlobalValue::ExternalLinkage);
> +          New.setVisibility(GlobalValue::HiddenVisibility);
> +        }
>        };
>
> -  NewModules.push_back(CloneSubModule(OrigMod, ExtractGlobalVars,
> -                                      ExtractNonImplFunctions, true));
> +    CloneSubModule(*KVPair.first, M, ExtractGlobalVars, ExtractFunctions,
> +                   false);
> +  }
> +}
> +
> +FullyPartitionedModule fullyPartition(Module &M) {
> +  FullyPartitionedModule MP;
>
> -  // Preserve initializers for Common linkage vars, and make private
> linkage
> -  // globals external: they are now provided by the globals module
> extracted
> -  // above.
> -  auto DropGlobalVars = [&](GlobalVariable &New, const GlobalVariable
> &Orig,
> -                            ValueToValueMapTy &VMap) {
> -    if (New.getLinkage() == GlobalValue::CommonLinkage)
> -      copyGVInitializer(New, Orig, VMap);
> -    else if (New.getLinkage() == GlobalValue::PrivateLinkage)
> -      New.setLinkage(GlobalValue::ExternalLinkage);
> -  };
> -
> -  // Split each 'impl' function out in to its own module.
> -  for (const auto &Func : OrigMod) {
> -    if (Func.isDeclaration() || !ShouldExtract(Func))
> -      continue;
> +  ModulePartitionMap PMap;
>
> -    auto ExtractNamedFunction =
> -        [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap)
> {
> -          if (New.getName() == Func.getName())
> -            copyFunctionBody(New, Orig, VMap);
> -        };
> +  for (auto &F : M) {
>
> -    NewModules.push_back(
> -        CloneSubModule(OrigMod, DropGlobalVars, ExtractNamedFunction,
> false));
> -  }
> +    if (F.isDeclaration())
> +      continue;
>
> -  return NewModules;
> -}
> +    std::string NewModuleName = (M.getName() + "." + F.getName()).str();
> +    MP.Functions.push_back(
> +      llvm::make_unique<Module>(NewModuleName, M.getContext()));
> +    MP.Functions.back()->setDataLayout(M.getDataLayout());
> +    PMap[MP.Functions.back().get()].insert(&F);
> +  }
>
> -std::vector<std::unique_ptr<Module>>
> -explode(const Module &OrigMod, const JITIndirections &Indirections) {
> -  std::set<std::string> ImplNames;
> +  MP.GlobalVars =
> +    llvm::make_unique<Module>((M.getName() + ".globals_and_stubs").str(),
> +                              M.getContext());
> +  MP.GlobalVars->setDataLayout(M.getDataLayout());
> +
> +  MP.Commons =
> +    llvm::make_unique<Module>((M.getName() + ".commons").str(),
> M.getContext());
> +  MP.Commons->setDataLayout(M.getDataLayout());
> +
> +  // Make sure there's at least an empty set for the stubs map or we'll
> fail
> +  // to clone anything for it (including the decls).
> +  PMap[MP.GlobalVars.get()] = ModulePartitionMap::mapped_type();
> +  for (auto &GV : M.globals())
> +    if (GV.getLinkage() == GlobalValue::CommonLinkage)
> +      PMap[MP.Commons.get()].insert(&GV);
> +    else
> +      PMap[MP.GlobalVars.get()].insert(&GV);
>
> -  for (const auto &FuncName : Indirections.IndirectedNames)
> -    ImplNames.insert(Indirections.GetImplName(FuncName));
> +  partition(M, PMap);
>
> -  return explode(
> -      OrigMod, [&](const Function &F) { return
> ImplNames.count(F.getName()); });
> +  return MP;
>  }
> +
>  }
>
> Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp?rev=229461&r1=229460&r2=229461&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp (original)
> +++ llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp Mon Feb 16
> 19:18:38 2015
> @@ -1,14 +1,11 @@
>  #include "llvm/ADT/Triple.h"
> -#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
> +#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
>  #include <array>
>
>  using namespace llvm;
>
>  namespace {
>
> -const char *JITCallbackFuncName = "call_jit_for_lazy_compile";
> -const char *JITCallbackIndexLabelPrefix = "jit_resolve_";
> -
>  std::array<const char *, 12> X86GPRsToSave = {{
>      "rbp", "rbx", "r12", "r13", "r14", "r15", // Callee saved.
>      "rdi", "rsi", "rdx", "rcx", "r8", "r9",   // Int args.
> @@ -41,61 +38,90 @@ template <typename OStream> void restore
>      OS << "  popq    %" << X86GPRsToSave[X86GPRsToSave.size() - i - 1] <<
> "\n";
>  }
>
> -uint64_t call_jit_for_fn(JITResolveCallbackHandler *J, uint64_t FuncIdx) {
> -  return J->resolve(FuncIdx);
> +template <typename TargetT>
> +uint64_t executeCompileCallback(JITCompileCallbackManagerBase<TargetT>
> *JCBM,
> +                                TargetAddress CallbackID) {
> +  return JCBM->executeCompileCallback(CallbackID);
>  }
> +
>  }
>
>  namespace llvm {
>
> -std::string getJITResolveCallbackIndexLabel(unsigned I) {
> -  std::ostringstream LabelStream;
> -  LabelStream << JITCallbackIndexLabelPrefix << I;
> -  return LabelStream.str();
> -}
> +const char* OrcX86_64::ResolverBlockName = "orc_resolver_block";
>
> -void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J) {
> +void OrcX86_64::insertResolverBlock(
> +                               Module &M,
> +                               JITCompileCallbackManagerBase<OrcX86_64>
> &JCBM) {
>    uint64_t CallbackAddr =
> -      static_cast<uint64_t>(reinterpret_cast<uintptr_t>(call_jit_for_fn));
> +      static_cast<uint64_t>(
> +        reinterpret_cast<uintptr_t>(executeCompileCallback<OrcX86_64>));
>
> -  std::ostringstream JITCallbackAsm;
> +  std::ostringstream AsmStream;
>    Triple TT(M.getTargetTriple());
>
>    if (TT.getOS() == Triple::Darwin)
> -    JITCallbackAsm << ".section __TEXT,__text,regular,pure_instructions\n"
> -                   << ".align 4, 0x90\n";
> +    AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
> +              << ".align 4, 0x90\n";
>    else
> -    JITCallbackAsm << ".text\n"
> -                   << ".align 16, 0x90\n";
> +    AsmStream << ".text\n"
> +              << ".align 16, 0x90\n";
>
> -  JITCallbackAsm << "jit_object_addr:\n"
> -                 << "  .quad " << &J << "\n" << JITCallbackFuncName <<
> ":\n";
> +  AsmStream << "jit_callback_manager_addr:\n"
> +            << "  .quad " << &JCBM << "\n"
> +            << ResolverBlockName << ":\n";
>
> -  uint64_t ReturnAddrOffset = saveX86Regs(JITCallbackAsm);
> +  uint64_t ReturnAddrOffset = saveX86Regs(AsmStream);
>
>    // Compute index, load object address, and call JIT.
> -  JITCallbackAsm << "  movq    " << ReturnAddrOffset << "(%rsp), %rax\n"
> -                 << "  leaq    (jit_indices_start+5)(%rip), %rbx\n"
> -                 << "  subq    %rbx, %rax\n"
> -                 << "  xorq    %rdx, %rdx\n"
> -                 << "  movq    $5, %rbx\n"
> -                 << "  divq    %rbx\n"
> -                 << "  movq    %rax, %rsi\n"
> -                 << "  leaq    jit_object_addr(%rip), %rdi\n"
> -                 << "  movq    (%rdi), %rdi\n"
> -                 << "  movabsq $" << CallbackAddr << ", %rax\n"
> -                 << "  callq   *%rax\n"
> -                 << "  movq    %rax, " << ReturnAddrOffset << "(%rsp)\n";
> -
> -  restoreX86Regs(JITCallbackAsm);
> -
> -  JITCallbackAsm << "  retq\n"
> -                 << "jit_indices_start:\n";
> -
> -  for (JITResolveCallbackHandler::StubIndex I = 0; I < J.getNumFuncs();
> ++I)
> -    JITCallbackAsm << getJITResolveCallbackIndexLabel(I) << ":\n"
> -                   << "  callq " << JITCallbackFuncName << "\n";
> +  AsmStream << "  leaq    jit_callback_manager_addr(%rip), %rdi\n"
> +            << "  movq    (%rdi), %rdi\n"
> +            << "  movq    " << ReturnAddrOffset << "(%rsp), %rsi\n"
> +            << "  movabsq $" << CallbackAddr << ", %rax\n"
> +            << "  callq   *%rax\n"
> +            << "  movq    %rax, " << ReturnAddrOffset << "(%rsp)\n";
> +
> +  restoreX86Regs(AsmStream);
> +
> +  AsmStream << "  retq\n";
>
> -  M.appendModuleInlineAsm(JITCallbackAsm.str());
> +  M.appendModuleInlineAsm(AsmStream.str());
>  }
> +
> +OrcX86_64::LabelNameFtor
> +OrcX86_64::insertCompileCallbackTrampolines(Module &M,
> +                                            TargetAddress
> ResolverBlockAddr,
> +                                            unsigned NumCalls,
> +                                            unsigned StartIndex) {
> +  const char *ResolverBlockPtrName = "Lorc_resolve_block_addr";
> +
> +  std::ostringstream AsmStream;
> +  Triple TT(M.getTargetTriple());
> +
> +  if (TT.getOS() == Triple::Darwin)
> +    AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
> +              << ".align 4, 0x90\n";
> +  else
> +    AsmStream << ".text\n"
> +              << ".align 16, 0x90\n";
> +
> +  AsmStream << ResolverBlockPtrName << ":\n"
> +            << "  .quad " << ResolverBlockAddr << "\n";
> +
> +  auto GetLabelName =
> +    [=](unsigned I) {
> +      std::ostringstream LabelStream;
> +      LabelStream << "orc_jcc_" << (StartIndex + I);
> +      return LabelStream.str();
> +  };
> +
> +  for (unsigned I = 0; I < NumCalls; ++I)
> +    AsmStream << GetLabelName(I) << ":\n"
> +              << "  callq *" << ResolverBlockPtrName << "(%rip)\n";
> +
> +  M.appendModuleInlineAsm(AsmStream.str());
> +
> +  return GetLabelName;
> +}
> +
>  }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150217/4712736c/attachment.html>


More information about the llvm-commits mailing list