首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有数学库的LLVM 8和更高版本的ORC JIT问题

带有数学库的LLVM 8和更高版本的ORC JIT问题
EN

Stack Overflow用户
提问于 2019-05-01 16:16:26
回答 1查看 492关注 0票数 1

由于LLVM 8(包括当前的LLVM主干,也称为LLVM 9),我在使用包含对标准数学库调用的函数的ORC JIT ExecutionEngine时遇到了问题。

JIT编译器能够找到函数的符号,但如果函数调用数学库,则无法获得该函数的地址。

我附加了一个简单的漏洞,显示了这个问题。程序test.cc读取一个IR文件,该文件在LLVM的中间表示中包含一个函数:该函数接受一个参数、一个浮点数,并在

  • "func_works.ll“的论点本身,并在情况下
  • "func_cos_fails.ll“是论点的余弦。

我没有在运行时实现两个文件之间的选择,所以当切换到另一个情况时,需要重新构建程序。

该程序使用LLVM附带的标准KaleidoscopeJIT.h (除了我必须公开Datalayout之外)。

如果您使用"func_works.ll“构建程序并运行它,则该程序将在以下情况下成功:

代码语言:javascript
复制
symbol found!
address found!

如果使用"func_cos_fails.ll“构建程序并运行它,则程序将失败:

代码语言:javascript
复制
symbol found!
Failure value returned from cantFail wrapped call
UNREACHABLE executed at install/llvm-8.0-x86-debug/include/llvm/Support/Error.h:732!

这发生在LLVM 8发行版和当前的LLVM主干中。

有人看到发生了什么事吗?

此测试是在x86 Linux Ubuntu系统上运行的,该系统配置了

代码语言:javascript
复制
cmake -G "Unix Makefiles" \
      -DBUILD_SHARED_LIBS="ON" \
      -DLLVM_ENABLE_RTTI="ON" \
      -DLLVM_ENABLE_ZLIB="OFF" \
      -DLLVM_ENABLE_TERMINFO="OFF" \
      -DCMAKE_BUILD_TYPE="Debug" \
      -DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX \
      -DLLVM_TARGETS_TO_BUILD="X86" \
      $SRC

test.cc:

代码语言:javascript
复制
#include "KaleidoscopeJIT.h"

#include "llvm/Analysis/Passes.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/InitLLVM.h"

#include <iostream>

using namespace llvm;
using namespace llvm::orc;




int main(int argc, char **argv) {
  InitLLVM X(argc, argv);
  EnableDebugBuffering = true;
  LLVMContext Context;

  InitializeNativeTarget();
  InitializeNativeTargetAsmPrinter();
  InitializeNativeTargetAsmParser();

  cl::ParseCommandLineOptions(argc, argv, "Kaleidoscope example program\n");
  SMDiagnostic Err;

  std::unique_ptr<llvm::Module> M = parseIRFile( "func_cos_fails.ll" , Err, Context, false);
  //std::unique_ptr<llvm::Module> M = parseIRFile( "func_works.ll" , Err, Context, false);
  if (!M) {
    Err.print("IR parsing failed: ", errs());
    return 0;
  }

  std::unique_ptr<KaleidoscopeJIT> TheJIT;

  TheJIT = llvm::make_unique<KaleidoscopeJIT>();

  auto H = TheJIT->addModule(std::move(M));

  std::string MangledName;
  llvm::raw_string_ostream MangledNameStream(MangledName);
  llvm::Mangler::getNameWithPrefix(MangledNameStream, "func_ir" , TheJIT->getDL() );

  if (auto Sym = TheJIT->findSymbol(MangledNameStream.str()))
    {
      std::cout << "symbol found!\n";
      void* fptr = (void *)cantFail(Sym.getAddress());

      std::cout << "address found!\n";
    }
  else
    {
      std::cout << "symbol not found!\n";
    }

  return 0;
}

func_cos_fails.ll:

代码语言:javascript
复制
source_filename = "module"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

declare float @cosf(float)

define float @func_ir(float %arg0) {
entrypoint:
  %0 = call float @cosf(float %arg0)
  ret float %0
}

func_works.ll:

代码语言:javascript
复制
source_filename = "module"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"


define float @func_ir(float %arg0) {
entrypoint:
  ret float %arg0
}

H.h:

代码语言:javascript
复制
#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <vector>

namespace llvm {
namespace orc {

class KaleidoscopeJIT {
public:
  using ObjLayerT = LegacyRTDyldObjectLinkingLayer;
  using CompileLayerT = LegacyIRCompileLayer<ObjLayerT, SimpleCompiler>;

  KaleidoscopeJIT()
      : Resolver(createLegacyLookupResolver(
            ES,
            [this](const std::string &Name) {
              return ObjectLayer.findSymbol(Name, true);
            },
            [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })),
        TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
        ObjectLayer(ES,
                    [this](VModuleKey) {
                      return ObjLayerT::Resources{
                          std::make_shared<SectionMemoryManager>(), Resolver};
                    }),
        CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
    llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
  }

  TargetMachine &getTargetMachine() { return *TM; }

  VModuleKey addModule(std::unique_ptr<Module> M) {
    auto K = ES.allocateVModule();
    cantFail(CompileLayer.addModule(K, std::move(M)));
    ModuleKeys.push_back(K);
    return K;
  }

  void removeModule(VModuleKey K) {
    ModuleKeys.erase(find(ModuleKeys, K));
    cantFail(CompileLayer.removeModule(K));
  }

  JITSymbol findSymbol(const std::string Name) {
    return findMangledSymbol(mangle(Name));
  }

  const DataLayout& getDL() const {
    return DL;
  }

private:
  std::string mangle(const std::string &Name) {
    std::string MangledName;
    {
      raw_string_ostream MangledNameStream(MangledName);
      Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
    }
    return MangledName;
  }

  JITSymbol findMangledSymbol(const std::string &Name) {
#ifdef _WIN32
    // The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported
    // flag to decide whether a symbol will be visible or not, when we call
    // IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true.
    //
    // But for Windows COFF objects, this flag is currently never set.
    // For a potential solution see: https://reviews.llvm.org/rL258665
    // For now, we allow non-exported symbols on Windows as a workaround.
    const bool ExportedSymbolsOnly = false;
#else
    const bool ExportedSymbolsOnly = true;
#endif

    // Search modules in reverse order: from last added to first added.
    // This is the opposite of the usual search order for dlsym, but makes more
    // sense in a REPL where we want to bind to the newest available definition.
    for (auto H : make_range(ModuleKeys.rbegin(), ModuleKeys.rend()))
      if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly))
        return Sym;

    // If we can't find the symbol in the JIT, try looking in the host process.
    if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
      return JITSymbol(SymAddr, JITSymbolFlags::Exported);

#ifdef _WIN32
    // For Windows retry without "_" at beginning, as RTDyldMemoryManager uses
    // GetProcAddress and standard libraries like msvcrt.dll use names
    // with and without "_" (for example "_itoa" but "sin").
    if (Name.length() > 2 && Name[0] == '_')
      if (auto SymAddr =
              RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1)))
        return JITSymbol(SymAddr, JITSymbolFlags::Exported);
#endif

    return nullptr;
  }

  ExecutionSession ES;
  std::shared_ptr<SymbolResolver> Resolver;
  std::unique_ptr<TargetMachine> TM;
  const DataLayout DL;
  ObjLayerT ObjectLayer;
  CompileLayerT CompileLayer;
  std::vector<VModuleKey> ModuleKeys;
};

} // end namespace orc
} // end namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H

为了方便起见,我提供了一个Makefile:

代码语言:javascript
复制
LLVM_CONFIG = ${LLVM_INSTALL_PATH}

LLVM_CXXFLAGS = $(shell $(LLVM_CONFIG) --cxxflags)
LLVM_LDFLAGS  = $(shell $(LLVM_CONFIG) --ldflags)
LLVM_LIBS     = $(shell $(LLVM_CONFIG) --libs)

all: test

test.o: test.cc KaleidoscopeJIT.h
    g++ -c -o $@ $< $(LLVM_CXXFLAGS)

test: test.o
    g++ -o $@ $< $(LLVM_LDFLAGS) $(LLVM_LIBS)

clean:
    rm -f *.o
    rm -f test
EN

回答 1

Stack Overflow用户

发布于 2019-08-06 13:13:14

我相信这个问题的解决方案(至少是针对llvm 7和8)是在这里找到的:https://stackoverflow.com/a/56862433/2310373

即取代:

代码语言:javascript
复制
[this](const std::string &Name) {
    return ObjectLayer.findSymbol(Name, true);
},

就像

代码语言:javascript
复制
[this](const std::string &Name) {
    auto FoundSymbol = ObjectLayer.findSymbol(Name, true);
    if (!FoundSymbol) {
        if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
            return JITSymbol(SymAddr, JITSymbolFlags::Exported);
    }
    return FoundSymbol;
},
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55939276

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档