当前位置:网站首页>LLVM系列第十章:控制流语句if-else-phi
LLVM系列第十章:控制流语句if-else-phi
2022-08-02 14:07:00 【飞翼剑仆】
系列文章目录
LLVM系列第一章:编译LLVM源码
LLVM系列第二章:模块Module
LLVM系列第三章:函数Function
LLVM系列第四章:逻辑代码块Block
LLVM系列第五章:全局变量Global Variable
LLVM系列第六章:函数返回值Return
LLVM系列第七章:函数参数Function Arguments
LLVM系列第八章:算术运算语句Arithmetic Statement
LLVM系列第九章:控制流语句if-else
LLVM系列第十章:控制流语句if-else-phi
LLVM系列第十一章:写一个Hello World
LLVM系列第十二章:写一个简单的词法分析器Lexer
LLVM系列第十三章:写一个简单的语法分析器Parser
LLVM系列第十四章:写一个简单的语义分析器Semantic Analyzer
LLVM系列第十五章:写一个简单的中间代码生成器IR Generator
LLVM系列第十六章:写一个简单的编译器
LLVM系列第十七章:for循环
LLVM系列第十八章:写一个简单的IR处理流程Pass
LLVM系列第十九章:写一个简单的Module Pass
LLVM系列第二十章:写一个简单的Function Pass
LLVM系列第二十一章:写一个简单的Loop Pass
LLVM系列第二十二章:写一个简单的编译时函数调用统计器(Pass)
LLVM系列第二十三章:写一个简单的运行时函数调用统计器(Pass)
LLVM系列第二十四章:用Xcode编译调试LLVM源码
LLVM系列第二十五章:简单统计一下LLVM源码行数
前言
在此记录下用LLVM创建if-else-phi控制流语句的过程,以备查阅。
开发环境的配置请参考第一章 《LLVM系列第一章:编译LLVM源码》。
这一章仍然是在处理if-else语句。不过,这一次我们用一个特殊的指令来生成IR代码,即phi指令。
我们知道,一个if-else语句包含了一个条件判断以及两个逻辑分支。最终会运行哪个分支的代码,取决于条件判断的结果为真还是假。而“条件”则一般是一个比较表达式。
在很多情况下,控制流只是为了给某一个变量赋值,而phi 指令,则可以根据控制流来选择合适的值。它的用法如下(示例):
%value = phi i32 [66, %branch1], [77, %branch2], [88, %branch3]
可以看到phi指令可以接收多个输入参数,参数的个数也不是固定的。第一个参数表示的是phi指令的返回值类型,如在以上示例中为i32。接下来的每一个参数都是一个数组,代表了每一个分支及其对应的返回值。例如,如果前一步执行的是branch1分支,则返回值为66;当执行的是branch2,则返回值为77;以此类推…
LLVM也提供了相应的C++ API用于创建phi指令:
PHINode * llvm::IRBuilderBase::CreatePHI(Type * Ty, unsigned NumReservedValues, const Twine & Name = "")
以及向phi指令中添加条件返回值:
void llvm::PHINode::addIncoming(Value * V, BasicBlock * BB)
本章,我们就利用phi指令来处理简单的if-else控制流语句。
一、Hello if-else-phi
为简单起见,我就来为一个简单的C函数生成IR代码。C函数跟上一章用到的是一样的,只不过我们这次在IR代码中用到了phi指令而已。C函数如下(示例):
// Test.c
int Test(int a)
{
int b;
if (a > 33)
{
b = 66;
}
else
{
b = 77;
}
return b;
}
以下就是我们调用LLVM C++ API来生成IR的代码(示例):
// HelloIfElsePhi.cpp
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include <vector>
using namespace llvm;
int main(int argc, char* argv[])
{
LLVMContext context;
IRBuilder<> builder(context);
// Create a module
Module* module = new Module("Test.c", context);
// Add a function
std::vector<Type*> parameters(1, builder.getInt32Ty());
FunctionType* functionType = FunctionType::get(builder.getInt32Ty(), parameters, false);
Function* function = Function::Create(functionType, GlobalValue::ExternalLinkage, "Test", module);
// Add an argument to the function
Value* arg = function->getArg(0);
arg->setName("a");
// Add some basic blocks to the function
BasicBlock* entryBlock = BasicBlock::Create(context, "entry", function);
BasicBlock* thenBlock = BasicBlock::Create(context, "if.then", function);
BasicBlock* elseBlock = BasicBlock::Create(context, "if.else", function);
BasicBlock* returnBlock = BasicBlock::Create(context, "if.end", function);
// Fill the "entry" block (1):
// int b;
builder.SetInsertPoint(entryBlock);
Value* b = builder.CreateAlloca(builder.getInt32Ty(), nullptr, "b.address");
// Fill the "entry" block (2):
// if (a > 33)
ConstantInt* value33 = builder.getInt32(33);
Value* condition = builder.CreateICmpSGT(arg, value33, "compare.result");
builder.CreateCondBr(condition, thenBlock, elseBlock);
// Fill the "if.then" block:
// b = 66;
builder.SetInsertPoint(thenBlock);
ConstantInt* value66 = builder.getInt32(66);
builder.CreateBr(returnBlock);
// Fill the "if.else" block:
// b = 77;
builder.SetInsertPoint(elseBlock);
ConstantInt* value77 = builder.getInt32(77);
builder.CreateBr(returnBlock);
// Fill the "if.end" block with phi instruction:
// return b;
builder.SetInsertPoint(returnBlock);
PHINode* phi = builder.CreatePHI(builder.getInt32Ty(), 2);
phi->addIncoming(value66, thenBlock);
phi->addIncoming(value77, elseBlock);
builder.CreateStore(phi, b);
Value* returnValue = builder.CreateLoad(b, "return.value");
builder.CreateRet(returnValue);
// Print the IR
verifyFunction(*function);
module->print(outs(), nullptr);
return 0;
}
二、编译
用clang++进行编译(示例):
# Set up C++ standard library and header path
export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
# Compile
clang++ -w -o HelloIfElsePhi `llvm-config --cxxflags --ldflags --system-libs --libs core` HelloIfElsePhi.cpp
以上命令会生成一个名为HelloIfElsePhi的可执行程序。
三、运行
运行HelloIfElsePhi(示例):
./HelloIfElsePhi
输出结果如下(示例):
; ModuleID = 'Test.c'
source_filename = "Test.c"
define i32 @Test(i32 %a) {
entry:
%b.address = alloca i32, align 4
%compare.result = icmp sgt i32 %a, 33
br i1 %compare.result, label %if.then, label %if.else
if.then: ; preds = %entry
br label %if.end
if.else: ; preds = %entry
br label %if.end
if.end: ; preds = %if.else, %if.then
%0 = phi i32 [ 66, %if.then ], [ 77, %if.else ]
store i32 %0, i32* %b.address, align 4
%return.value = load i32, i32* %b.address, align 4
ret i32 %return.value
}
四、总结
我们用LLVM提供的C++ API,创建了简单的if-else控制流语句,并打印出了其带有phi指令的IR代码。完整源码示例请参看:
https://github.com/wuzhanglin/llvm-IR-examples
边栏推荐
猜你喜欢
随机推荐
7.如何给RecyclerView添加Click和LongClick事件
MySQL知识总结 (十一) MySql 日志,数据备份,数据恢复
Using the cloud GPU + pycharm training model to realize automatic background run programs, save training results, the server automatically power off
数据的表示方法和转换(二进制、八进制、十进制、十六进制)
vscode编译keil工程,烧录程序
ThinkPHP5.0内置分页函数Paginate无法获取POST页数问题的解决办法
liunx下mysql遇到的简单问题
Scala连接Mysql数据库
YOLOv7 uses cloud GPU to train its own dataset
Win10不能启动WampServer图标呈橘黄色的解决方法
uni-app页面、组件视图数据无法刷新问题的解决办法
AAPT: error: duplicate value for resource ‘attr/xxx‘ with config ‘‘, file failed to compile.
十分钟带你入门Nodejs
2022最新交规记忆重点
Flink前期代码结构
无人驾驶综述:国外国内发展历程
C语言日记 4 变量
spark(standalone,yarn)
1.RecyclerView是什么
checkPermissions Missing write access to /usr/local/lib









