为什么我的 llvm 函数 jit-evaluate 为 0?

发布于 2025-01-11 08:32:36 字数 4004 浏览 0 评论 0原文

我正在使用 llvm (和 antlr),大致按照万花筒教程的思路进行工作。我成功地从顶层和函数定义的基本算术表达式创建了 LLVM-IR 代码,这对应于教程的最多 3 章

。现在我想从顶层算术表达式开始逐步添加 JIT 支持。这是我的问题:

  • 基本比较使我看起来好像遵循与教程相同的函数调用顺序,只是代码组织更简单
  • 生成的 IR 代码看起来不错
  • 函数定义显然已找到,因为否则代码将退出(我通过故意查找拼写错误的函数名称来验证这一点)
  • 然而,JIT 评估创建的函数指针的调用始终返回零。

这些片段(摘录)作为 antlr 访问者的一部分执行主/入口节点我的语法:

  //Top node main -- top level expression
  antlrcpp::Any visitMain(ExprParser::MainContext *ctx)  
  {
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();
    TheJIT = ExitOnErr( llvm::orc::KaleidoscopeJIT::Create() );

    InitializeModuleAndPassManager();
    
    // ... Code which visits the child nodes  ...

  }

InitializeModuleAndPassManager() 与教程中的相同:

static void InitializeModuleAndPassManager() 
{
  // Open a new context and module.
  TheContext = std::make_unique<llvm::LLVMContext>();
  TheModule = std::make_unique<llvm::Module>("commandline", *TheContext);
  TheModule->setDataLayout(TheJIT->getDataLayout());
  // Create a new builder for the module.
  Builder = std::make_unique<llvm::IRBuilder<>>(*TheContext);
  // Create a new pass manager attached to it.
  TheFPM = std::make_unique<llvm::legacy::FunctionPassManager>(TheModule.get());
  // Do simple "peephole" optimizations and bit-twiddling optzns.
  TheFPM->add(llvm::createInstructionCombiningPass());
  // Reassociate expressions.
  TheFPM->add(llvm::createReassociatePass());
  // Eliminate Common SubExpressions.
  TheFPM->add(llvm::createGVNPass());
  // Simplify the control flow graph (deleting unreachable blocks, etc).
  TheFPM->add(llvm::createCFGSimplificationPass());
  TheFPM->doInitialization();
}

这是处理顶级表达式的函数,并且也应该执行 JIT 评估:

//Bare expression without function definition -- create anonymous function
  antlrcpp::Any visitBareExpr(ExprParser::BareExprContext *ctx)
  {
    string fName = "__anon_expr";
    llvm::FunctionType  *FT = llvm::FunctionType::get(llvm::Type::getDoubleTy(*TheContext), false);
    llvm::Function      *F  = llvm::Function::Create(FT, llvm::Function::ExternalLinkage, fName, TheModule.get());
    llvm::BasicBlock    *BB = llvm::BasicBlock::Create(*TheContext, "entry", F);
    Builder->SetInsertPoint(BB);
    llvm::Value* Expression=visit(ctx->expr()).as<llvm::Value* >();
    Builder->CreateRet(Expression);
    llvm::verifyFunction(*F);   
    //TheFPM->run(*F);//outcommented this because i wanted to try JIT before optimization- 
    //it causes a compile error right now because i probably lack some related code.
    //However i do not assume that a missing optimization run will cause the problem that i have
    F->print(llvm::errs());
    // Create a ResourceTracker to track JIT'd memory allocated to our
    // anonymous expression -- that way we can free it after executing.
    auto RT = TheJIT->getMainJITDylib().createResourceTracker();
    auto TSM = llvm::orc::ThreadSafeModule(move(TheModule), move(TheContext));
    ExitOnErr(TheJIT->addModule(move(TSM), RT));
    InitializeModuleAndPassManager();
    // Search the JIT for the __anon_expr symbol.
    auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
    // Get the symbol's address and cast it to the right type (takes no
    // arguments, returns a double) so we can call it as a native function.
    double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
    double ret = FP();
    fprintf(stderr, "Evaluated to %f\n", ret);
    // Delete the anonymous expression module from the JIT.
    ExitOnErr(RT->remove());
    return F;
  }

现在这就是作为示例发生的情况:

[robert@robert-ux330uak test4_expr_llvm_2]$ ./testmain '3*4'
define double @__anon_expr() {
entry:
  ret float 1.200000e+01
}
Evaluated to 0.000000

如果有任何关于我可能做错的事情的想法,我将不胜感激。

I am playing with llvm (and antlr), working vaguely along the lines of the Kaleidoscope tutorial. I successfully created LLVM-IR code from basic arithmetic expressions both on top-level and as function definitions, which corresponds to the tutorial chapters up to 3.

Now I would like to incrementally add JIT support, starting with the top-level arithmetic expressions. Here is my problem:

  • Basic comparison makes it seem as if I follow the same sequence of function calls as the tutorial, only with a simpler code organization
  • The generated IR code looks good
  • The function definition is apparently found, since otherwise the code would exit (i verified this by intentionally looking for a wrongly spelled function name)
  • However the call of the function pointer created by JIT evaluation always returns zero.

These snippets (excerpt) are executed as part of the antlr visitor of the main/entry-node of my grammar:

  //Top node main -- top level expression
  antlrcpp::Any visitMain(ExprParser::MainContext *ctx)  
  {
    llvm::InitializeNativeTarget();
    llvm::InitializeNativeTargetAsmPrinter();
    llvm::InitializeNativeTargetAsmParser();
    TheJIT = ExitOnErr( llvm::orc::KaleidoscopeJIT::Create() );

    InitializeModuleAndPassManager();
    
    // ... Code which visits the child nodes  ...

  }

InitializeModuleAndPassManager() is the same as in the tutorial:

static void InitializeModuleAndPassManager() 
{
  // Open a new context and module.
  TheContext = std::make_unique<llvm::LLVMContext>();
  TheModule = std::make_unique<llvm::Module>("commandline", *TheContext);
  TheModule->setDataLayout(TheJIT->getDataLayout());
  // Create a new builder for the module.
  Builder = std::make_unique<llvm::IRBuilder<>>(*TheContext);
  // Create a new pass manager attached to it.
  TheFPM = std::make_unique<llvm::legacy::FunctionPassManager>(TheModule.get());
  // Do simple "peephole" optimizations and bit-twiddling optzns.
  TheFPM->add(llvm::createInstructionCombiningPass());
  // Reassociate expressions.
  TheFPM->add(llvm::createReassociatePass());
  // Eliminate Common SubExpressions.
  TheFPM->add(llvm::createGVNPass());
  // Simplify the control flow graph (deleting unreachable blocks, etc).
  TheFPM->add(llvm::createCFGSimplificationPass());
  TheFPM->doInitialization();
}

This is the function which handles the top-level expression and which is also supposed to do JIT evaluation:

//Bare expression without function definition -- create anonymous function
  antlrcpp::Any visitBareExpr(ExprParser::BareExprContext *ctx)
  {
    string fName = "__anon_expr";
    llvm::FunctionType  *FT = llvm::FunctionType::get(llvm::Type::getDoubleTy(*TheContext), false);
    llvm::Function      *F  = llvm::Function::Create(FT, llvm::Function::ExternalLinkage, fName, TheModule.get());
    llvm::BasicBlock    *BB = llvm::BasicBlock::Create(*TheContext, "entry", F);
    Builder->SetInsertPoint(BB);
    llvm::Value* Expression=visit(ctx->expr()).as<llvm::Value* >();
    Builder->CreateRet(Expression);
    llvm::verifyFunction(*F);   
    //TheFPM->run(*F);//outcommented this because i wanted to try JIT before optimization- 
    //it causes a compile error right now because i probably lack some related code.
    //However i do not assume that a missing optimization run will cause the problem that i have
    F->print(llvm::errs());
    // Create a ResourceTracker to track JIT'd memory allocated to our
    // anonymous expression -- that way we can free it after executing.
    auto RT = TheJIT->getMainJITDylib().createResourceTracker();
    auto TSM = llvm::orc::ThreadSafeModule(move(TheModule), move(TheContext));
    ExitOnErr(TheJIT->addModule(move(TSM), RT));
    InitializeModuleAndPassManager();
    // Search the JIT for the __anon_expr symbol.
    auto ExprSymbol = ExitOnErr(TheJIT->lookup("__anon_expr"));
    // Get the symbol's address and cast it to the right type (takes no
    // arguments, returns a double) so we can call it as a native function.
    double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
    double ret = FP();
    fprintf(stderr, "Evaluated to %f\n", ret);
    // Delete the anonymous expression module from the JIT.
    ExitOnErr(RT->remove());
    return F;
  }

Now this is what happens as an example:

[robert@robert-ux330uak test4_expr_llvm_2]$ ./testmain '3*4'
define double @__anon_expr() {
entry:
  ret float 1.200000e+01
}
Evaluated to 0.000000

I would be thankful for any ideas about what I might be doing wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文