LCOV - code coverage report
Current view: top level - lib/ExecutionEngine/Orc - IndirectionUtils.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 98 129 76.0 %
Date: 2018-06-17 00:07:59 Functions: 19 24 79.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===---- IndirectionUtils.cpp - Utilities for call indirection in Orc ----===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
      11             : #include "llvm/ADT/STLExtras.h"
      12             : #include "llvm/ADT/Triple.h"
      13             : #include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
      14             : #include "llvm/IR/CallSite.h"
      15             : #include "llvm/IR/IRBuilder.h"
      16             : #include "llvm/Support/Format.h"
      17             : #include "llvm/Transforms/Utils/Cloning.h"
      18             : #include <sstream>
      19             : 
      20             : using namespace llvm;
      21             : using namespace llvm::orc;
      22             : 
      23             : namespace {
      24             : 
      25          54 : class CompileCallbackMaterializationUnit : public orc::MaterializationUnit {
      26             : public:
      27             :   using CompileFunction = JITCompileCallbackManager::CompileFunction;
      28             : 
      29          18 :   CompileCallbackMaterializationUnit(SymbolStringPtr Name,
      30             :                                      CompileFunction Compile)
      31          72 :       : MaterializationUnit(SymbolFlagsMap({{Name, JITSymbolFlags::Exported}})),
      32          36 :         Name(std::move(Name)), Compile(std::move(Compile)) {}
      33             : 
      34             : private:
      35          17 :   void materialize(MaterializationResponsibility R) {
      36             :     SymbolMap Result;
      37          17 :     Result[Name] = JITEvaluatedSymbol(Compile(), JITSymbolFlags::Exported);
      38          17 :     R.resolve(Result);
      39          17 :     R.finalize();
      40          17 :   }
      41             : 
      42           0 :   void discard(const VSO &V, SymbolStringPtr Name) {
      43           0 :     llvm_unreachable("Discard should never occur on a LMU?");
      44             :   }
      45             : 
      46             :   SymbolStringPtr Name;
      47             :   CompileFunction Compile;
      48             : };
      49             : 
      50             : } // namespace
      51             : 
      52             : namespace llvm {
      53             : namespace orc {
      54             : 
      55           0 : void JITCompileCallbackManager::anchor() {}
      56           0 : void IndirectStubsManager::anchor() {}
      57             : 
      58             : Expected<JITTargetAddress>
      59          18 : JITCompileCallbackManager::getCompileCallback(CompileFunction Compile) {
      60          36 :   if (auto TrampolineAddr = getAvailableTrampolineAddr()) {
      61          18 :     auto CallbackName = ES.getSymbolStringPool().intern(
      62         108 :         std::string("cc") + std::to_string(++NextCallbackId));
      63             : 
      64          18 :     std::lock_guard<std::mutex> Lock(CCMgrMutex);
      65          18 :     AddrToSymbol[*TrampolineAddr] = CallbackName;
      66          54 :     cantFail(CallbacksVSO.define(
      67          36 :         llvm::make_unique<CompileCallbackMaterializationUnit>(
      68             :             std::move(CallbackName), std::move(Compile))));
      69             :     return *TrampolineAddr;
      70             :   } else
      71             :     return TrampolineAddr.takeError();
      72             : }
      73             : 
      74          17 : JITTargetAddress JITCompileCallbackManager::executeCompileCallback(
      75             :     JITTargetAddress TrampolineAddr) {
      76          17 :   SymbolStringPtr Name;
      77             : 
      78             :   {
      79          17 :     std::unique_lock<std::mutex> Lock(CCMgrMutex);
      80             :     auto I = AddrToSymbol.find(TrampolineAddr);
      81             : 
      82             :     // If this address is not associated with a compile callback then report an
      83             :     // error to the execution session and return ErrorHandlerAddress to the
      84             :     // callee.
      85          17 :     if (I == AddrToSymbol.end()) {
      86           0 :       Lock.unlock();
      87             :       std::string ErrMsg;
      88             :       {
      89           0 :         raw_string_ostream ErrMsgStream(ErrMsg);
      90           0 :         ErrMsgStream << "No compile callback for trampoline at "
      91           0 :                      << format("0x%016x", TrampolineAddr);
      92             :       }
      93           0 :       ES.reportError(
      94           0 :           make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode()));
      95           0 :       return ErrorHandlerAddress;
      96             :     } else
      97          17 :       Name = I->second;
      98             :   }
      99             : 
     100          85 :   if (auto Sym = lookup({&CallbacksVSO}, Name))
     101          17 :     return Sym->getAddress();
     102             :   else {
     103             :     // If anything goes wrong materializing Sym then report it to the session
     104             :     // and return the ErrorHandlerAddress;
     105           0 :     ES.reportError(Sym.takeError());
     106           0 :     return ErrorHandlerAddress;
     107             :   }
     108             : }
     109             : 
     110             : std::unique_ptr<JITCompileCallbackManager>
     111          18 : createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES,
     112             :                                   JITTargetAddress ErrorHandlerAddress) {
     113          18 :   switch (T.getArch()) {
     114             :     default: return nullptr;
     115             : 
     116           0 :     case Triple::aarch64: {
     117             :       typedef orc::LocalJITCompileCallbackManager<orc::OrcAArch64> CCMgrT;
     118             :       return llvm::make_unique<CCMgrT>(ES, ErrorHandlerAddress);
     119             :     }
     120             : 
     121           0 :     case Triple::x86: {
     122             :       typedef orc::LocalJITCompileCallbackManager<orc::OrcI386> CCMgrT;
     123             :       return llvm::make_unique<CCMgrT>(ES, ErrorHandlerAddress);
     124             :     }
     125             : 
     126          18 :     case Triple::x86_64: {
     127          18 :       if ( T.getOS() == Triple::OSType::Win32 ) {
     128             :         typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64_Win32> CCMgrT;
     129             :         return llvm::make_unique<CCMgrT>(ES, ErrorHandlerAddress);
     130             :       } else {
     131             :         typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64_SysV> CCMgrT;
     132             :         return llvm::make_unique<CCMgrT>(ES, ErrorHandlerAddress);
     133             :       }
     134             :     }
     135             : 
     136             :   }
     137             : }
     138             : 
     139             : std::function<std::unique_ptr<IndirectStubsManager>()>
     140          11 : createLocalIndirectStubsManagerBuilder(const Triple &T) {
     141          11 :   switch (T.getArch()) {
     142             :     default:
     143             :       return [](){
     144             :         return llvm::make_unique<
     145             :                        orc::LocalIndirectStubsManager<orc::OrcGenericABI>>();
     146           0 :       };
     147             : 
     148             :     case Triple::aarch64:
     149             :       return [](){
     150             :         return llvm::make_unique<
     151             :                        orc::LocalIndirectStubsManager<orc::OrcAArch64>>();
     152           0 :       };
     153             : 
     154             :     case Triple::x86:
     155             :       return [](){
     156             :         return llvm::make_unique<
     157             :                        orc::LocalIndirectStubsManager<orc::OrcI386>>();
     158           0 :       };
     159             : 
     160          11 :     case Triple::x86_64:
     161          11 :       if (T.getOS() == Triple::OSType::Win32) {
     162             :         return [](){
     163             :           return llvm::make_unique<
     164             :                      orc::LocalIndirectStubsManager<orc::OrcX86_64_Win32>>();
     165           0 :         };
     166             :       } else {
     167             :         return [](){
     168             :           return llvm::make_unique<
     169             :                      orc::LocalIndirectStubsManager<orc::OrcX86_64_SysV>>();
     170          12 :         };
     171             :       }
     172             : 
     173             :   }
     174             : }
     175             : 
     176           0 : Constant* createIRTypedAddress(FunctionType &FT, JITTargetAddress Addr) {
     177             :   Constant *AddrIntVal =
     178           0 :     ConstantInt::get(Type::getInt64Ty(FT.getContext()), Addr);
     179             :   Constant *AddrPtrVal =
     180             :     ConstantExpr::getCast(Instruction::IntToPtr, AddrIntVal,
     181           0 :                           PointerType::get(&FT, 0));
     182           0 :   return AddrPtrVal;
     183             : }
     184             : 
     185           7 : GlobalVariable* createImplPointer(PointerType &PT, Module &M,
     186             :                                   const Twine &Name, Constant *Initializer) {
     187             :   auto IP = new GlobalVariable(M, &PT, false, GlobalValue::ExternalLinkage,
     188             :                                Initializer, Name, nullptr,
     189           7 :                                GlobalValue::NotThreadLocal, 0, true);
     190             :   IP->setVisibility(GlobalValue::HiddenVisibility);
     191           7 :   return IP;
     192             : }
     193             : 
     194           7 : void makeStub(Function &F, Value &ImplPointer) {
     195             :   assert(F.isDeclaration() && "Can't turn a definition into a stub.");
     196             :   assert(F.getParent() && "Function isn't in a module.");
     197           7 :   Module &M = *F.getParent();
     198          14 :   BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry", &F);
     199             :   IRBuilder<> Builder(EntryBlock);
     200           7 :   LoadInst *ImplAddr = Builder.CreateLoad(&ImplPointer);
     201             :   std::vector<Value*> CallArgs;
     202          10 :   for (auto &A : F.args())
     203           6 :     CallArgs.push_back(&A);
     204           7 :   CallInst *Call = Builder.CreateCall(ImplAddr, CallArgs);
     205             :   Call->setTailCall();
     206             :   Call->setAttributes(F.getAttributes());
     207           7 :   if (F.getReturnType()->isVoidTy())
     208           5 :     Builder.CreateRetVoid();
     209             :   else
     210           2 :     Builder.CreateRet(Call);
     211           7 : }
     212             : 
     213             : // Utility class for renaming global values and functions during partitioning.
     214             : class GlobalRenamer {
     215             : public:
     216             : 
     217           6 :   static bool needsRenaming(const Value &New) {
     218          12 :     return !New.hasName() || New.getName().startswith("\01L");
     219             :   }
     220             : 
     221           0 :   const std::string& getRename(const Value &Orig) {
     222             :     // See if we have a name for this global.
     223             :     {
     224           0 :       auto I = Names.find(&Orig);
     225           0 :       if (I != Names.end())
     226           0 :         return I->second;
     227             :     }
     228             : 
     229             :     // Nope. Create a new one.
     230             :     // FIXME: Use a more robust uniquing scheme. (This may blow up if the user
     231             :     //        writes a "__orc_anon[[:digit:]]* method).
     232             :     unsigned ID = Names.size();
     233           0 :     std::ostringstream NameStream;
     234             :     NameStream << "__orc_anon" << ID++;
     235           0 :     auto I = Names.insert(std::make_pair(&Orig, NameStream.str()));
     236           0 :     return I.first->second;
     237             :   }
     238             : private:
     239             :   DenseMap<const Value*, std::string> Names;
     240             : };
     241             : 
     242          33 : static void raiseVisibilityOnValue(GlobalValue &V, GlobalRenamer &R) {
     243             :   if (V.hasLocalLinkage()) {
     244           6 :     if (R.needsRenaming(V))
     245           0 :       V.setName(R.getRename(V));
     246             :     V.setLinkage(GlobalValue::ExternalLinkage);
     247             :     V.setVisibility(GlobalValue::HiddenVisibility);
     248             :   }
     249             :   V.setUnnamedAddr(GlobalValue::UnnamedAddr::None);
     250             :   assert(!R.needsRenaming(V) && "Invalid global name.");
     251          33 : }
     252             : 
     253           9 : void makeAllSymbolsExternallyAccessible(Module &M) {
     254             :   GlobalRenamer Renamer;
     255             : 
     256          32 :   for (auto &F : M)
     257          23 :     raiseVisibilityOnValue(F, Renamer);
     258             : 
     259          17 :   for (auto &GV : M.globals())
     260           8 :     raiseVisibilityOnValue(GV, Renamer);
     261             : 
     262          11 :   for (auto &A : M.aliases())
     263           2 :     raiseVisibilityOnValue(A, Renamer);
     264           9 : }
     265             : 
     266          29 : Function* cloneFunctionDecl(Module &Dst, const Function &F,
     267             :                             ValueToValueMapTy *VMap) {
     268             :   assert(F.getParent() != &Dst && "Can't copy decl over existing function.");
     269             :   Function *NewF =
     270          58 :     Function::Create(cast<FunctionType>(F.getValueType()),
     271          58 :                      F.getLinkage(), F.getName(), &Dst);
     272          29 :   NewF->copyAttributesFrom(&F);
     273             : 
     274          29 :   if (VMap) {
     275          16 :     (*VMap)[&F] = NewF;
     276             :     auto NewArgI = NewF->arg_begin();
     277          42 :     for (auto ArgI = F.arg_begin(), ArgE = F.arg_end(); ArgI != ArgE;
     278             :          ++ArgI, ++NewArgI)
     279          13 :       (*VMap)[&*ArgI] = &*NewArgI;
     280             :   }
     281             : 
     282          29 :   return NewF;
     283             : }
     284             : 
     285          16 : void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap,
     286             :                       ValueMaterializer *Materializer,
     287             :                       Function *NewF) {
     288             :   assert(!OrigF.isDeclaration() && "Nothing to move");
     289          16 :   if (!NewF)
     290          16 :     NewF = cast<Function>(VMap[&OrigF]);
     291             :   else
     292             :     assert(VMap[&OrigF] == NewF && "Incorrect function mapping in VMap.");
     293             :   assert(NewF && "Function mapping missing from VMap.");
     294             :   assert(NewF->getParent() != OrigF.getParent() &&
     295             :          "moveFunctionBody should only be used to move bodies between "
     296             :          "modules.");
     297             : 
     298             :   SmallVector<ReturnInst *, 8> Returns; // Ignore returns cloned.
     299          16 :   CloneFunctionInto(NewF, &OrigF, VMap, /*ModuleLevelChanges=*/true, Returns,
     300             :                     "", nullptr, nullptr, Materializer);
     301             :   OrigF.deleteBody();
     302          16 : }
     303             : 
     304          13 : GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV,
     305             :                                         ValueToValueMapTy *VMap) {
     306             :   assert(GV.getParent() != &Dst && "Can't copy decl over existing global var.");
     307             :   GlobalVariable *NewGV = new GlobalVariable(
     308          26 :       Dst, GV.getValueType(), GV.isConstant(),
     309          26 :       GV.getLinkage(), nullptr, GV.getName(), nullptr,
     310          13 :       GV.getThreadLocalMode(), GV.getType()->getAddressSpace());
     311          13 :   NewGV->copyAttributesFrom(&GV);
     312          13 :   if (VMap)
     313           7 :     (*VMap)[&GV] = NewGV;
     314          13 :   return NewGV;
     315             : }
     316             : 
     317           7 : void moveGlobalVariableInitializer(GlobalVariable &OrigGV,
     318             :                                    ValueToValueMapTy &VMap,
     319             :                                    ValueMaterializer *Materializer,
     320             :                                    GlobalVariable *NewGV) {
     321             :   assert(OrigGV.hasInitializer() && "Nothing to move");
     322           7 :   if (!NewGV)
     323           7 :     NewGV = cast<GlobalVariable>(VMap[&OrigGV]);
     324             :   else
     325             :     assert(VMap[&OrigGV] == NewGV &&
     326             :            "Incorrect global variable mapping in VMap.");
     327             :   assert(NewGV->getParent() != OrigGV.getParent() &&
     328             :          "moveGlobalVariable should only be used to move initializers between "
     329             :          "modules");
     330             : 
     331           7 :   NewGV->setInitializer(MapValue(OrigGV.getInitializer(), VMap, RF_None,
     332             :                                  nullptr, Materializer));
     333           7 : }
     334             : 
     335           2 : GlobalAlias* cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA,
     336             :                                   ValueToValueMapTy &VMap) {
     337             :   assert(OrigA.getAliasee() && "Original alias doesn't have an aliasee?");
     338           6 :   auto *NewA = GlobalAlias::create(OrigA.getValueType(),
     339             :                                    OrigA.getType()->getPointerAddressSpace(),
     340           6 :                                    OrigA.getLinkage(), OrigA.getName(), &Dst);
     341           2 :   NewA->copyAttributesFrom(&OrigA);
     342           2 :   VMap[&OrigA] = NewA;
     343           2 :   return NewA;
     344             : }
     345             : 
     346           4 : void cloneModuleFlagsMetadata(Module &Dst, const Module &Src,
     347             :                               ValueToValueMapTy &VMap) {
     348           4 :   auto *MFs = Src.getModuleFlagsMetadata();
     349           4 :   if (!MFs)
     350             :     return;
     351           2 :   for (auto *MF : MFs->operands())
     352           1 :     Dst.addModuleFlag(MapMetadata(MF, VMap));
     353             : }
     354             : 
     355             : } // End namespace orc.
     356             : } // End namespace llvm.

Generated by: LCOV version 1.13