Home | History | Annotate | Line # | Download | only in Orc
      1 //===- IndirectionUtils.h - Utilities for adding indirections ---*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // Contains utilities for adding indirections and breaking up modules.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
     14 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
     15 
     16 #include "llvm/ADT/StringMap.h"
     17 #include "llvm/ADT/StringRef.h"
     18 #include "llvm/ExecutionEngine/JITSymbol.h"
     19 #include "llvm/ExecutionEngine/Orc/Core.h"
     20 #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
     21 #include "llvm/Support/Error.h"
     22 #include "llvm/Support/Memory.h"
     23 #include "llvm/Support/Process.h"
     24 #include "llvm/Transforms/Utils/ValueMapper.h"
     25 #include <algorithm>
     26 #include <cassert>
     27 #include <cstdint>
     28 #include <functional>
     29 #include <future>
     30 #include <map>
     31 #include <memory>
     32 #include <system_error>
     33 #include <utility>
     34 #include <vector>
     35 
     36 namespace llvm {
     37 
     38 class Constant;
     39 class Function;
     40 class FunctionType;
     41 class GlobalAlias;
     42 class GlobalVariable;
     43 class Module;
     44 class PointerType;
     45 class Triple;
     46 class Twine;
     47 class Value;
     48 
     49 namespace orc {
     50 
     51 /// Base class for pools of compiler re-entry trampolines.
     52 /// These trampolines are callable addresses that save all register state
     53 /// before calling a supplied function to return the trampoline landing
     54 /// address, then restore all state before jumping to that address. They
     55 /// are used by various ORC APIs to support lazy compilation
     56 class TrampolinePool {
     57 public:
     58   using NotifyLandingResolvedFunction =
     59       unique_function<void(JITTargetAddress) const>;
     60 
     61   using ResolveLandingFunction = unique_function<void(
     62       JITTargetAddress TrampolineAddr,
     63       NotifyLandingResolvedFunction OnLandingResolved) const>;
     64 
     65   virtual ~TrampolinePool();
     66 
     67   /// Get an available trampoline address.
     68   /// Returns an error if no trampoline can be created.
     69   Expected<JITTargetAddress> getTrampoline() {
     70     std::lock_guard<std::mutex> Lock(TPMutex);
     71     if (AvailableTrampolines.empty()) {
     72       if (auto Err = grow())
     73         return std::move(Err);
     74     }
     75     assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool");
     76     auto TrampolineAddr = AvailableTrampolines.back();
     77     AvailableTrampolines.pop_back();
     78     return TrampolineAddr;
     79   }
     80 
     81   /// Returns the given trampoline to the pool for re-use.
     82   void releaseTrampoline(JITTargetAddress TrampolineAddr) {
     83     std::lock_guard<std::mutex> Lock(TPMutex);
     84     AvailableTrampolines.push_back(TrampolineAddr);
     85   }
     86 
     87 protected:
     88   virtual Error grow() = 0;
     89 
     90   std::mutex TPMutex;
     91   std::vector<JITTargetAddress> AvailableTrampolines;
     92 };
     93 
     94 /// A trampoline pool for trampolines within the current process.
     95 template <typename ORCABI> class LocalTrampolinePool : public TrampolinePool {
     96 public:
     97   /// Creates a LocalTrampolinePool with the given RunCallback function.
     98   /// Returns an error if this function is unable to correctly allocate, write
     99   /// and protect the resolver code block.
    100   static Expected<std::unique_ptr<LocalTrampolinePool>>
    101   Create(ResolveLandingFunction ResolveLanding) {
    102     Error Err = Error::success();
    103 
    104     auto LTP = std::unique_ptr<LocalTrampolinePool>(
    105         new LocalTrampolinePool(std::move(ResolveLanding), Err));
    106 
    107     if (Err)
    108       return std::move(Err);
    109     return std::move(LTP);
    110   }
    111 
    112 private:
    113   static JITTargetAddress reenter(void *TrampolinePoolPtr, void *TrampolineId) {
    114     LocalTrampolinePool<ORCABI> *TrampolinePool =
    115         static_cast<LocalTrampolinePool *>(TrampolinePoolPtr);
    116 
    117     std::promise<JITTargetAddress> LandingAddressP;
    118     auto LandingAddressF = LandingAddressP.get_future();
    119 
    120     TrampolinePool->ResolveLanding(pointerToJITTargetAddress(TrampolineId),
    121                                    [&](JITTargetAddress LandingAddress) {
    122                                      LandingAddressP.set_value(LandingAddress);
    123                                    });
    124     return LandingAddressF.get();
    125   }
    126 
    127   LocalTrampolinePool(ResolveLandingFunction ResolveLanding, Error &Err)
    128       : ResolveLanding(std::move(ResolveLanding)) {
    129 
    130     ErrorAsOutParameter _(&Err);
    131 
    132     /// Try to set up the resolver block.
    133     std::error_code EC;
    134     ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    135         ORCABI::ResolverCodeSize, nullptr,
    136         sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    137     if (EC) {
    138       Err = errorCodeToError(EC);
    139       return;
    140     }
    141 
    142     ORCABI::writeResolverCode(static_cast<char *>(ResolverBlock.base()),
    143                               pointerToJITTargetAddress(ResolverBlock.base()),
    144                               pointerToJITTargetAddress(&reenter),
    145                               pointerToJITTargetAddress(this));
    146 
    147     EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
    148                                           sys::Memory::MF_READ |
    149                                               sys::Memory::MF_EXEC);
    150     if (EC) {
    151       Err = errorCodeToError(EC);
    152       return;
    153     }
    154   }
    155 
    156   Error grow() override {
    157     assert(AvailableTrampolines.empty() && "Growing prematurely?");
    158 
    159     std::error_code EC;
    160     auto TrampolineBlock =
    161         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    162             sys::Process::getPageSizeEstimate(), nullptr,
    163             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    164     if (EC)
    165       return errorCodeToError(EC);
    166 
    167     unsigned NumTrampolines =
    168         (sys::Process::getPageSizeEstimate() - ORCABI::PointerSize) /
    169         ORCABI::TrampolineSize;
    170 
    171     char *TrampolineMem = static_cast<char *>(TrampolineBlock.base());
    172     ORCABI::writeTrampolines(
    173         TrampolineMem, pointerToJITTargetAddress(TrampolineMem),
    174         pointerToJITTargetAddress(ResolverBlock.base()), NumTrampolines);
    175 
    176     for (unsigned I = 0; I < NumTrampolines; ++I)
    177       AvailableTrampolines.push_back(pointerToJITTargetAddress(
    178           TrampolineMem + (I * ORCABI::TrampolineSize)));
    179 
    180     if (auto EC = sys::Memory::protectMappedMemory(
    181                     TrampolineBlock.getMemoryBlock(),
    182                     sys::Memory::MF_READ | sys::Memory::MF_EXEC))
    183       return errorCodeToError(EC);
    184 
    185     TrampolineBlocks.push_back(std::move(TrampolineBlock));
    186     return Error::success();
    187   }
    188 
    189   ResolveLandingFunction ResolveLanding;
    190 
    191   sys::OwningMemoryBlock ResolverBlock;
    192   std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
    193 };
    194 
    195 /// Target-independent base class for compile callback management.
    196 class JITCompileCallbackManager {
    197 public:
    198   using CompileFunction = std::function<JITTargetAddress()>;
    199 
    200   virtual ~JITCompileCallbackManager() = default;
    201 
    202   /// Reserve a compile callback.
    203   Expected<JITTargetAddress> getCompileCallback(CompileFunction Compile);
    204 
    205   /// Execute the callback for the given trampoline id. Called by the JIT
    206   ///        to compile functions on demand.
    207   JITTargetAddress executeCompileCallback(JITTargetAddress TrampolineAddr);
    208 
    209 protected:
    210   /// Construct a JITCompileCallbackManager.
    211   JITCompileCallbackManager(std::unique_ptr<TrampolinePool> TP,
    212                             ExecutionSession &ES,
    213                             JITTargetAddress ErrorHandlerAddress)
    214       : TP(std::move(TP)), ES(ES),
    215         CallbacksJD(ES.createBareJITDylib("<Callbacks>")),
    216         ErrorHandlerAddress(ErrorHandlerAddress) {}
    217 
    218   void setTrampolinePool(std::unique_ptr<TrampolinePool> TP) {
    219     this->TP = std::move(TP);
    220   }
    221 
    222 private:
    223   std::mutex CCMgrMutex;
    224   std::unique_ptr<TrampolinePool> TP;
    225   ExecutionSession &ES;
    226   JITDylib &CallbacksJD;
    227   JITTargetAddress ErrorHandlerAddress;
    228   std::map<JITTargetAddress, SymbolStringPtr> AddrToSymbol;
    229   size_t NextCallbackId = 0;
    230 };
    231 
    232 /// Manage compile callbacks for in-process JITs.
    233 template <typename ORCABI>
    234 class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
    235 public:
    236   /// Create a new LocalJITCompileCallbackManager.
    237   static Expected<std::unique_ptr<LocalJITCompileCallbackManager>>
    238   Create(ExecutionSession &ES, JITTargetAddress ErrorHandlerAddress) {
    239     Error Err = Error::success();
    240     auto CCMgr = std::unique_ptr<LocalJITCompileCallbackManager>(
    241         new LocalJITCompileCallbackManager(ES, ErrorHandlerAddress, Err));
    242     if (Err)
    243       return std::move(Err);
    244     return std::move(CCMgr);
    245   }
    246 
    247 private:
    248   /// Construct a InProcessJITCompileCallbackManager.
    249   /// @param ErrorHandlerAddress The address of an error handler in the target
    250   ///                            process to be used if a compile callback fails.
    251   LocalJITCompileCallbackManager(ExecutionSession &ES,
    252                                  JITTargetAddress ErrorHandlerAddress,
    253                                  Error &Err)
    254       : JITCompileCallbackManager(nullptr, ES, ErrorHandlerAddress) {
    255     using NotifyLandingResolvedFunction =
    256         TrampolinePool::NotifyLandingResolvedFunction;
    257 
    258     ErrorAsOutParameter _(&Err);
    259     auto TP = LocalTrampolinePool<ORCABI>::Create(
    260         [this](JITTargetAddress TrampolineAddr,
    261                NotifyLandingResolvedFunction NotifyLandingResolved) {
    262           NotifyLandingResolved(executeCompileCallback(TrampolineAddr));
    263         });
    264 
    265     if (!TP) {
    266       Err = TP.takeError();
    267       return;
    268     }
    269 
    270     setTrampolinePool(std::move(*TP));
    271   }
    272 };
    273 
    274 /// Base class for managing collections of named indirect stubs.
    275 class IndirectStubsManager {
    276 public:
    277   /// Map type for initializing the manager. See init.
    278   using StubInitsMap = StringMap<std::pair<JITTargetAddress, JITSymbolFlags>>;
    279 
    280   virtual ~IndirectStubsManager() = default;
    281 
    282   /// Create a single stub with the given name, target address and flags.
    283   virtual Error createStub(StringRef StubName, JITTargetAddress StubAddr,
    284                            JITSymbolFlags StubFlags) = 0;
    285 
    286   /// Create StubInits.size() stubs with the given names, target
    287   ///        addresses, and flags.
    288   virtual Error createStubs(const StubInitsMap &StubInits) = 0;
    289 
    290   /// Find the stub with the given name. If ExportedStubsOnly is true,
    291   ///        this will only return a result if the stub's flags indicate that it
    292   ///        is exported.
    293   virtual JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0;
    294 
    295   /// Find the implementation-pointer for the stub.
    296   virtual JITEvaluatedSymbol findPointer(StringRef Name) = 0;
    297 
    298   /// Change the value of the implementation pointer for the stub.
    299   virtual Error updatePointer(StringRef Name, JITTargetAddress NewAddr) = 0;
    300 
    301 private:
    302   virtual void anchor();
    303 };
    304 
    305 template <typename ORCABI> class LocalIndirectStubsInfo {
    306 public:
    307   LocalIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem)
    308       : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {}
    309 
    310   static Expected<LocalIndirectStubsInfo> create(unsigned MinStubs,
    311                                                  unsigned PageSize) {
    312     auto ISAS = getIndirectStubsBlockSizes<ORCABI>(MinStubs, PageSize);
    313 
    314     assert((ISAS.StubBytes % PageSize == 0) &&
    315            "StubBytes is not a page size multiple");
    316     uint64_t PointerAlloc = alignTo(ISAS.PointerBytes, PageSize);
    317 
    318     // Allocate memory for stubs and pointers in one call.
    319     std::error_code EC;
    320     auto StubsAndPtrsMem =
    321         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    322             ISAS.StubBytes + PointerAlloc, nullptr,
    323             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    324     if (EC)
    325       return errorCodeToError(EC);
    326 
    327     sys::MemoryBlock StubsBlock(StubsAndPtrsMem.base(), ISAS.StubBytes);
    328     auto StubsBlockMem = static_cast<char *>(StubsAndPtrsMem.base());
    329     auto PtrBlockAddress =
    330         pointerToJITTargetAddress(StubsBlockMem) + ISAS.StubBytes;
    331 
    332     ORCABI::writeIndirectStubsBlock(StubsBlockMem,
    333                                     pointerToJITTargetAddress(StubsBlockMem),
    334                                     PtrBlockAddress, ISAS.NumStubs);
    335 
    336     if (auto EC = sys::Memory::protectMappedMemory(
    337             StubsBlock, sys::Memory::MF_READ | sys::Memory::MF_EXEC))
    338       return errorCodeToError(EC);
    339 
    340     return LocalIndirectStubsInfo(ISAS.NumStubs, std::move(StubsAndPtrsMem));
    341   }
    342 
    343   unsigned getNumStubs() const { return NumStubs; }
    344 
    345   void *getStub(unsigned Idx) const {
    346     return static_cast<char *>(StubsMem.base()) + Idx * ORCABI::StubSize;
    347   }
    348 
    349   void **getPtr(unsigned Idx) const {
    350     char *PtrsBase =
    351         static_cast<char *>(StubsMem.base()) + NumStubs * ORCABI::StubSize;
    352     return reinterpret_cast<void **>(PtrsBase) + Idx;
    353   }
    354 
    355 private:
    356   unsigned NumStubs = 0;
    357   sys::OwningMemoryBlock StubsMem;
    358 };
    359 
    360 /// IndirectStubsManager implementation for the host architecture, e.g.
    361 ///        OrcX86_64. (See OrcArchitectureSupport.h).
    362 template <typename TargetT>
    363 class LocalIndirectStubsManager : public IndirectStubsManager {
    364 public:
    365   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
    366                    JITSymbolFlags StubFlags) override {
    367     std::lock_guard<std::mutex> Lock(StubsMutex);
    368     if (auto Err = reserveStubs(1))
    369       return Err;
    370 
    371     createStubInternal(StubName, StubAddr, StubFlags);
    372 
    373     return Error::success();
    374   }
    375 
    376   Error createStubs(const StubInitsMap &StubInits) override {
    377     std::lock_guard<std::mutex> Lock(StubsMutex);
    378     if (auto Err = reserveStubs(StubInits.size()))
    379       return Err;
    380 
    381     for (auto &Entry : StubInits)
    382       createStubInternal(Entry.first(), Entry.second.first,
    383                          Entry.second.second);
    384 
    385     return Error::success();
    386   }
    387 
    388   JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
    389     std::lock_guard<std::mutex> Lock(StubsMutex);
    390     auto I = StubIndexes.find(Name);
    391     if (I == StubIndexes.end())
    392       return nullptr;
    393     auto Key = I->second.first;
    394     void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second);
    395     assert(StubAddr && "Missing stub address");
    396     auto StubTargetAddr =
    397         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(StubAddr));
    398     auto StubSymbol = JITEvaluatedSymbol(StubTargetAddr, I->second.second);
    399     if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
    400       return nullptr;
    401     return StubSymbol;
    402   }
    403 
    404   JITEvaluatedSymbol findPointer(StringRef Name) override {
    405     std::lock_guard<std::mutex> Lock(StubsMutex);
    406     auto I = StubIndexes.find(Name);
    407     if (I == StubIndexes.end())
    408       return nullptr;
    409     auto Key = I->second.first;
    410     void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second);
    411     assert(PtrAddr && "Missing pointer address");
    412     auto PtrTargetAddr =
    413         static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr));
    414     return JITEvaluatedSymbol(PtrTargetAddr, I->second.second);
    415   }
    416 
    417   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
    418     using AtomicIntPtr = std::atomic<uintptr_t>;
    419 
    420     std::lock_guard<std::mutex> Lock(StubsMutex);
    421     auto I = StubIndexes.find(Name);
    422     assert(I != StubIndexes.end() && "No stub pointer for symbol");
    423     auto Key = I->second.first;
    424     AtomicIntPtr *AtomicStubPtr = reinterpret_cast<AtomicIntPtr *>(
    425         IndirectStubsInfos[Key.first].getPtr(Key.second));
    426     *AtomicStubPtr = static_cast<uintptr_t>(NewAddr);
    427     return Error::success();
    428   }
    429 
    430 private:
    431   Error reserveStubs(unsigned NumStubs) {
    432     if (NumStubs <= FreeStubs.size())
    433       return Error::success();
    434 
    435     unsigned NewStubsRequired = NumStubs - FreeStubs.size();
    436     unsigned NewBlockId = IndirectStubsInfos.size();
    437     auto ISI =
    438         LocalIndirectStubsInfo<TargetT>::create(NewStubsRequired, PageSize);
    439     if (!ISI)
    440       return ISI.takeError();
    441     for (unsigned I = 0; I < ISI->getNumStubs(); ++I)
    442       FreeStubs.push_back(std::make_pair(NewBlockId, I));
    443     IndirectStubsInfos.push_back(std::move(*ISI));
    444     return Error::success();
    445   }
    446 
    447   void createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
    448                           JITSymbolFlags StubFlags) {
    449     auto Key = FreeStubs.back();
    450     FreeStubs.pop_back();
    451     *IndirectStubsInfos[Key.first].getPtr(Key.second) =
    452         jitTargetAddressToPointer<void *>(InitAddr);
    453     StubIndexes[StubName] = std::make_pair(Key, StubFlags);
    454   }
    455 
    456   unsigned PageSize = sys::Process::getPageSizeEstimate();
    457   std::mutex StubsMutex;
    458   std::vector<LocalIndirectStubsInfo<TargetT>> IndirectStubsInfos;
    459   using StubKey = std::pair<uint16_t, uint16_t>;
    460   std::vector<StubKey> FreeStubs;
    461   StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
    462 };
    463 
    464 /// Create a local compile callback manager.
    465 ///
    466 /// The given target triple will determine the ABI, and the given
    467 /// ErrorHandlerAddress will be used by the resulting compile callback
    468 /// manager if a compile callback fails.
    469 Expected<std::unique_ptr<JITCompileCallbackManager>>
    470 createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
    471                                   JITTargetAddress ErrorHandlerAddress);
    472 
    473 /// Create a local indriect stubs manager builder.
    474 ///
    475 /// The given target triple will determine the ABI.
    476 std::function<std::unique_ptr<IndirectStubsManager>()>
    477 createLocalIndirectStubsManagerBuilder(const Triple &T);
    478 
    479 /// Build a function pointer of FunctionType with the given constant
    480 ///        address.
    481 ///
    482 ///   Usage example: Turn a trampoline address into a function pointer constant
    483 /// for use in a stub.
    484 Constant *createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr);
    485 
    486 /// Create a function pointer with the given type, name, and initializer
    487 ///        in the given Module.
    488 GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name,
    489                                   Constant *Initializer);
    490 
    491 /// Turn a function declaration into a stub function that makes an
    492 ///        indirect call using the given function pointer.
    493 void makeStub(Function &F, Value &ImplPointer);
    494 
    495 /// Promotes private symbols to global hidden, and renames to prevent clashes
    496 /// with other promoted symbols. The same SymbolPromoter instance should be
    497 /// used for all symbols to be added to a single JITDylib.
    498 class SymbolLinkagePromoter {
    499 public:
    500   /// Promote symbols in the given module. Returns the set of global values
    501   /// that have been renamed/promoted.
    502   std::vector<GlobalValue *> operator()(Module &M);
    503 
    504 private:
    505   unsigned NextId = 0;
    506 };
    507 
    508 /// Clone a function declaration into a new module.
    509 ///
    510 ///   This function can be used as the first step towards creating a callback
    511 /// stub (see makeStub), or moving a function body (see moveFunctionBody).
    512 ///
    513 ///   If the VMap argument is non-null, a mapping will be added between F and
    514 /// the new declaration, and between each of F's arguments and the new
    515 /// declaration's arguments. This map can then be passed in to moveFunction to
    516 /// move the function body if required. Note: When moving functions between
    517 /// modules with these utilities, all decls should be cloned (and added to a
    518 /// single VMap) before any bodies are moved. This will ensure that references
    519 /// between functions all refer to the versions in the new module.
    520 Function *cloneFunctionDecl(Module &Dst, const Function &F,
    521                             ValueToValueMapTy *VMap = nullptr);
    522 
    523 /// Move the body of function 'F' to a cloned function declaration in a
    524 ///        different module (See related cloneFunctionDecl).
    525 ///
    526 ///   If the target function declaration is not supplied via the NewF parameter
    527 /// then it will be looked up via the VMap.
    528 ///
    529 ///   This will delete the body of function 'F' from its original parent module,
    530 /// but leave its declaration.
    531 void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
    532                       ValueMaterializer *Materializer = nullptr,
    533                       Function *NewF = nullptr);
    534 
    535 /// Clone a global variable declaration into a new module.
    536 GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
    537                                         ValueToValueMapTy *VMap = nullptr);
    538 
    539 /// Move global variable GV from its parent module to cloned global
    540 ///        declaration in a different module.
    541 ///
    542 ///   If the target global declaration is not supplied via the NewGV parameter
    543 /// then it will be looked up via the VMap.
    544 ///
    545 ///   This will delete the initializer of GV from its original parent module,
    546 /// but leave its declaration.
    547 void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
    548                                    ValueToValueMapTy &VMap,
    549                                    ValueMaterializer *Materializer = nullptr,
    550                                    GlobalVariable *NewGV = nullptr);
    551 
    552 /// Clone a global alias declaration into a new module.
    553 GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
    554                                   ValueToValueMapTy &VMap);
    555 
    556 /// Clone module flags metadata into the destination module.
    557 void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
    558                               ValueToValueMapTy &VMap);
    559 
    560 } // end namespace orc
    561 
    562 } // end namespace llvm
    563 
    564 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H
    565