llvm if expr

想要什么:

int fun(int p1)
{
 if(p1 < 5) return 1;
 else return 2;
}

IR:

define i32 @fun(i32 %p1) {
entry:
  %cmp = icmp slt i32 %p1, 5
  br i1 %cmp, label %then, label %else

then:                                             ; preds = %entry
  ret i32 1

else:                                             ; preds = %entry
  ret i32 2
}
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace llvm::orc;

ExitOnError ExitOnErr;

ThreadSafeModule createTSM() {
  // context 拥有许多核心的 LLVM 数据结构,例如类型和常量值表
  auto Context = std::make_unique<LLVMContext>();

  // module 包含函数和全局变量的LLVM构造,它是 LLVM IR 用来包含代码的顶级结构。它将拥有我们生成的所有 IR 的内存
  auto M = std::make_unique<Module>("test", *Context);

  // 创建一个构建器,可以轻松生成 LLVM 指令
  IRBuilder<> builder(*Context);

  // 声明一个函数 int fun(int) 添加到module中
  auto funcType = FunctionType::get(Type::getInt32Ty(*Context), { Type::getInt32Ty(*Context) }, false);
  Function* Add1F = Function::Create(funcType, Function::ExternalLinkage, "fun", M.get());

  // 创建一个block添加到Add1F
  BasicBlock* BB = BasicBlock::Create(*Context, "entry", Add1F);

  // 构建器接下来的指令将插入到BB
  builder.SetInsertPoint(BB);

  Argument* p1 = Add1F->getArg(0); // 获取参数
  p1->setName("p1"); // 设置arg name
  
  // p1 < 5, 返回 1 or 0
  auto _cmp = builder.CreateICmpSLT(p1, builder.getInt32(5), "cmp");
  
  BasicBlock* ThenBB = BasicBlock::Create(*Context, "then", Add1F);
  BasicBlock* ElseBB = BasicBlock::Create(*Context, "else", Add1F);

  // 条件跳转
  builder.CreateCondBr(_cmp, ThenBB, ElseBB);

  // 填充then block
  builder.SetInsertPoint(ThenBB);
  builder.CreateRet(builder.getInt32(1));

  // 填充else block
  builder.SetInsertPoint(ElseBB);
  builder.CreateRet(builder.getInt32(2));

  // 打印出所有生成的代码
  M->print(errs(), nullptr);

  // 返回线程模块
  return ThreadSafeModule(std::move(M), std::move(Context));
}

int main() {
  InitializeNativeTarget();
  InitializeNativeTargetAsmPrinter();

  // Create an LLJIT instance.
  auto _jit = ExitOnErr(LLJITBuilder().create());
  auto M = createTSM();

  ExitOnErr(_jit->addIRModule(std::move(M)));

  // 查找 JIT 函数,将其转换为函数指针,然后调用它.
  auto Add1Sym = ExitOnErr(_jit->lookup("fun"));
  int (*_fun)(int) = (int (*)(int))Add1Sym.getAddress();
  outs() << "fun(-1) = " << _fun(-1) << "\n"; // 1
  outs() << "fun(5) = " << _fun(5) << "\n"; // 2

  return 0;
}

或者:

define i32 @fun(i32 %p1) {
entry:
  %cmp = icmp slt i32 %p1, 5
  br i1 %cmp, label %then, label %else

then:                                             ; preds = %entry
  br label %return

else:                                             ; preds = %entry
  br label %return

return:                                           ; preds = %else, %then
  %0 = phi i32 [ 1, %then ], [ 2, %else ]
  ret i32 %0
}
ThreadSafeModule createTSM() {
 ...
  
  BasicBlock* ThenBB = BasicBlock::Create(*Context, "then", Add1F);
  BasicBlock* ElseBB = BasicBlock::Create(*Context, "else", Add1F);
  BasicBlock* ReturnBB = BasicBlock::Create(*Context, "return", Add1F);

  // 条件跳转
  builder.CreateCondBr(_cmp, ThenBB, ElseBB);

  // 填充then block
  builder.SetInsertPoint(ThenBB);
  auto ThenVal = builder.getInt32(1);
  // 无条件跳转
  builder.CreateBr(ReturnBB);

  // 填充else block
  builder.SetInsertPoint(ElseBB);
  auto ElseVal = builder.getInt32(2);
  // 无条件跳转
  builder.CreateBr(ReturnBB);

  builder.SetInsertPoint(ReturnBB);
  PHINode* PN = builder.CreatePHI(Type::getInt32Ty(*Context), 2);
  PN->addIncoming(ThenVal, ThenBB);
  PN->addIncoming(ElseVal, ElseBB);
  
  builder.CreateRet(PN);

  // 打印出所有生成的代码
  M->print(errs(), nullptr);

  // 返回线程模块
  return ThreadSafeModule(std::move(M), std::move(Context));
}
posted @ 2021-06-01 22:08  Ajanuw  阅读(131)  评论(0编辑  收藏  举报