05_llvm IR测试创建ifelse语句及多个block
一个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 } */
使用phi指令实现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; /* 使用phi指令获取分支block的返回值,格式如下: %value = phi i32 [5, %branch1], [6, %branch2], [7, %branch3] 解释:待赋值value,名称,返回值类型i32,如果执行的是branch1,则返回5,则value=5,如果执行的是branch2,则value=6,以此类推。 创建API: PHINode * llvm::IRBuilderBase::CreatePHI(Type * Ty, unsigned NumReservedValues, const Twine & Name = "") void llvm::PHINode::addIncoming(Value * V, BasicBlock * BB) // 添加branch及对应的返回值 具体结合代码体会 */ int main() { LLVMContext c; Module *m = new Module("test module", c); IRBuilder<> builder(c); 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执行 /***前边代码和上一个一样,以下开始和上一个if else有所不同***/ // 3 if.then代码块:无需再store 6给b,改成创建出目标value=6,后设置给phi指令 builder.SetInsertPoint(bIf); // 设置当前Builder的操作对象为if.then ConstantInt *vConst6 = builder.getInt32(6); // 只创建出一个6常量,设置给phi指令即可 builder.CreateBr(bIfEnd); // 无条件跳转指令,无条件跳转到return代码块 // 4 if.else代码块:同样也去除store指令,将目标值设给phi指令 builder.SetInsertPoint(bElse); // 设置当前Builder的操作对象为if.then ConstantInt *vConst4 = builder.getInt32(4); builder.CreateBr(bIfEnd); // 也无条件跳转到return代码块 // 5 最后构造返回代码块,return b builder.SetInsertPoint(bIfEnd); // 函数接口:llvm::PHINode * CreatePHI(llvm::Type *Ty, unsigned int NumReservedValues, const llvm::Twine &Name = "") PHINode *phi = builder.CreatePHI(builder.getInt32Ty(), 2); phi->addIncoming(vConst6, bIf); phi->addIncoming(vConst4, bElse); builder.CreateStore(phi, bPtr); // 这里再把phi获得的值设置给b // 创建返回值,从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_phi_bin `llvm-config --cxxflags --ldflags --system-libs --libs core` ./09_test_phi_stm.cpp // 运行结果,运行test_phi_bin /* ; 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 br label %if.end if.else: ; preds = %entry_block br label %if.end if.end: ; preds = %if.else, %if.then %0 = phi i32 [ 6, %if.then ], [ 4, %if.else ] store i32 %0, i32* %b.addr %ret.val = load i32, i32* %b.addr ret i32 %ret.val } */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!