05_llvm IR测试创建ifelse语句及多个block

发布时间 2023-08-02 21:10:59作者: UFOFCZ

一个ifelse源码编译

先看如下代码:

int func(int a) {
  int b;
  if (a > 5) b = 6;
  else b = 5;
  return b;
}

编译命令 ../output/bin/clang++ -emit-llvm llvm_if_else.c -S -o ir.ll

编译后的IR如下:

; ModuleID = 'llvm_if_else.c'
source_filename = "llvm_if_else.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: mustprogress noinline nounwind optnone uwtable
define dso_local noundef i32 @_Z4funci(i32 noundef %a) #0 {
entry:
  %a.addr = alloca i32, align 4 ;解释:使用alloca指令在栈上分配一个i32的局部变量,4字节对齐,获得内存地址指针变量a.addr
  %b = alloca i32, align 4 ;解释:同样在栈上分配一个变量,获得指针变量b
  store i32 %a, ptr %a.addr, align 4 ;解释:取出参数a的值,store给a.addr指针指向的内存
  %0 = load i32, ptr %a.addr, align 4 ;从a.addr指针指向的内存中取出值load给临时变量0%
  %cmp = icmp sgt i32 %0, 5
  br i1 %cmp, label %if.then, label %if.else

if.then:                                          ; preds = %entry 这是if block
  store i32 6, ptr %b, align 4
  br label %if.end

if.else:                                          ; preds = %entry
  store i32 5, ptr %b, align 4
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  %1 = load i32, ptr %b, align 4
  ret i32 %1
}

attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"clang version 16.0.5"}

使用接口创建if-else代码块

解释及代码如下:

#include <vector>
#include "llvm/IR/Module.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/GlobalVariable.h"
// #include "llvm/Support/Alignment.h"
#include "llvm/IR/Constants.h"

using namespace llvm;
using namespace std;

/*
根据上边IR,使用相应接口创建出IR。
*/
int main() {
  LLVMContext c;
  Module *m = new Module("test module", c);
  IRBuilder<> builder(c);

  // Type *voidTy = Type::getVoidTy(c);// 原来创建void 参数类型
  vector<Type *> paramTys(2, builder.getInt32Ty());
  /*get函数在 include/llvm/IR/DerivedTypes.h:102:class FunctionType : public Type {
  /// This static method is the primary way of constructing a FunctionType.
  static FunctionType *get(Type *Result, ArrayRef<Type*> Params, bool isVarArg);
  */
  FunctionType *funcTy = FunctionType::get(builder.getInt32Ty(), paramTys, false);
  Function *func = Function::Create(funcTy, GlobalValue::ExternalLinkage, "test_function", m);
  // 低版本无getArg()函数
  Value *arg0 = func->getArg(0);
  arg0->setName("a");
  func->getArg(1)->setName("c");

  // 1 给函数创建主block
  BasicBlock *bEntry = BasicBlock::Create(c, "entry_block", func);
  // 创建出if else需要的block
  BasicBlock *bIf = BasicBlock::Create(c, "if.then", func);
  BasicBlock *bElse = BasicBlock::Create(c, "if.else", func);
  BasicBlock *bIfEnd = BasicBlock::Create(c, "if.end", func);

  // 2 给主block填充分配b和获取a值、比较等指令
  builder.SetInsertPoint(bEntry); // 设置当前Builder的操作对象
  // b局部变量:alloca指令创建局部变量b,接口为AllocaInst * llvm::IRBuilderBase::CreateAlloca(Type * Ty, Value * ArraySize = nullptr, const Twine & Name = "")
  Value *bPtr = builder.CreateAlloca(builder.getInt32Ty(), nullptr, "b.addr");
  // 再创建出对参数a的判断入口
  ConstantInt *vConst5 = builder.getInt32(5);
  Value *vCondition = builder.CreateICmpSGT(arg0, vConst5, "compare.ret"); // if a>5
  builder.CreateCondBr(vCondition, bIf, bElse); // 条件跳转指令,vCondition为真 跳转到if.then代码块内执行,否则到if.else执行

  // 3 接下来给if.then代码块填充指令
  builder.SetInsertPoint(bIf); // 设置当前Builder的操作对象为if.then
  ConstantInt *vConst6 = builder.getInt32(6);
  builder.CreateStore(vConst6, bPtr); // b=6语句
  builder.CreateBr(bIfEnd); // 无条件跳转指令,无条件跳转到return代码块

  // 4 接下来填充if.else代码块
  builder.SetInsertPoint(bElse); // 设置当前Builder的操作对象为if.then
  ConstantInt *vConst4 = builder.getInt32(4);
  builder.CreateStore(vConst4, bPtr);
  builder.CreateStore(vConst5, bPtr);
  builder.CreateBr(bIfEnd); // 也无条件跳转到return代码块

  // 5 最后构造返回代码块
  builder.SetInsertPoint(bIfEnd);
  // 创建返回值,从b的地址中load出数据后返回
  Value *bVal = builder.CreateLoad(bPtr, "ret.val");
  builder.CreateRet(bVal);

  verifyFunction(*func);
  m->print(outs(), nullptr);
  return 0;
}

// 编译命令 ../clang-16/bin/clang++ -w -o test_ifelse_bin `llvm-config --cxxflags --ldflags --system-libs --libs core` ./08_test_ifelse_stm.cpp
// 运行结果
/*
; ModuleID = 'test module'
source_filename = "test module"

define i32 @test_function(i32 %a, i32 %c) {
entry_block:
  %b.addr = alloca i32
  %compare.ret = icmp sgt i32 %a, 5
  br i1 %compare.ret, label %if.then, label %if.else

if.then:                                          ; preds = %entry_block
  store i32 6, i32* %b.addr
  br label %if.end

if.else:                                          ; preds = %entry_block
  store i32 4, i32* %b.addr
  store i32 5, i32* %b.addr
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then
  %ret.val = load i32, i32* %b.addr
  ret i32 %ret.val
}

*/