LLVM系列第十章:控制流语句if-else-phi

系列文章目录

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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值