An if-else statement has a condition expression and two code paths to execute, depending on the condition evaluating to true or false. The condition expression is generally a comparison statement. Let's emit a condition statement at the start of the block. For example, let the condition be like a<100
.
Value *val2 = Builder.getInt32(100); Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp");
On compilation, we get following output:
; ModuleID = 'my compiler' @x = common global i32, align 4 define i32 @foo(i32 %a, i32 %b) { entry: %multmp = mul i32 %a, 16 %cmptmp = icmp ult i32 %multmp, 100 ret i32 %multmp }
The next step is to define the then and else block expressions, which will be executed depending on the result of condition expression "booltmp
". Here, an important concept of
PHI instruction comes into picture. A phi instruction takes various values coming from different basic blocks and decides which value to assign depending on the condition expression.
Two separate basic blocks "ThenBB
" and "ElseBB
" will be created. Let's say that the then expression is 'add 1 to a' and else expression is 'add 2 to a'.
A third block will represent the merge block, which contains the instructions to be executed at the merging of the then and else blocks. These blocks need to be pushed into the function foo()
.
For reusability, we create BasicBlock
and Value
containers as follows:
typedef SmallVector<BasicBlock *, 16> BBList; typedef SmallVector<Value *, 16> ValList;
We also push some of the values in a Value*
list to process them in the if-else block, as follows:
Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond"); ValList VL; VL.push_back(Condtn); VL.push_back(Arg1);
We create three basic blocks and push them in container, as follows:
BasicBlock *ThenBB = createBB(fooFunc, "then"); BasicBlock *ElseBB = createBB(fooFunc, "else"); BasicBlock *MergeBB = createBB(fooFunc, "ifcont"); BBList List; List.push_back(ThenBB); List.push_back(ElseBB); List.push_back(MergeBB);
We finally create a function to emit the if-else block:
Value *createIfElse(IRBuilder<> &Builder, BBList List, ValList VL) { Value *Condtn = VL[0]; Value *Arg1 = VL[1]; BasicBlock *ThenBB = List[0]; BasicBlock *ElseBB = List[1]; BasicBlock *MergeBB = List[2]; Builder.CreateCondBr(Condtn, ThenBB, ElseBB); Builder.SetInsertPoint(ThenBB); Value *ThenVal = Builder.CreateAdd(Arg1, Builder.getInt32(1), "thenaddtmp"); Builder.CreateBr(MergeBB); Builder.SetInsertPoint(ElseBB); Value *ElseVal = Builder.CreateAdd(Arg1, Builder.getInt32(2), "elseaddtmp"); Builder.CreateBr(MergeBB); unsigned PhiBBSize = List.size() - 1; Builder.SetInsertPoint(MergeBB); PHINode *Phi = Builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), PhiBBSize, "iftmp"); Phi->addIncoming(ThenVal, ThenBB); Phi->addIncoming(ElseVal, ElseBB); return Phi; }
#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; static LLVMContext &Context = getGlobalContext(); static Module *ModuleOb = new Module("my compiler", Context); static std::vector<std::string> FunArgs; typedef SmallVector<BasicBlock *, 16> BBList; typedef SmallVector<Value *, 16> ValList; Function *createFunc(IRBuilder<> &Builder, std::string Name) { std::vector<Type *> Integers(FunArgs.size(), Type::getInt32Ty(Context)); FunctionType *funcType = llvm::FunctionType::get(Builder.getInt32Ty(), Integers, false); Function *fooFunc = llvm::Function::Create( funcType, llvm::Function::ExternalLinkage, Name, ModuleOb); return fooFunc; } void setFuncArgs(Function *fooFunc, std::vector<std::string> FunArgs) { unsigned Idx = 0; Function::arg_iterator AI, AE; for (AI = fooFunc->arg_begin(), AE = fooFunc->arg_end(); AI != AE; ++AI, ++Idx) AI->setName(FunArgs[Idx]); } BasicBlock *createBB(Function *fooFunc, std::string Name) { return BasicBlock::Create(Context, Name, fooFunc); } GlobalVariable *createGlob(IRBuilder<> &Builder, std::string Name) { ModuleOb->getOrInsertGlobal(Name, Builder.getInt32Ty()); GlobalVariable *gVar = ModuleOb->getNamedGlobal(Name); gVar->setLinkage(GlobalValue::CommonLinkage); gVar->setAlignment(4); return gVar; } Value *createArith(IRBuilder<> &Builder, Value *L, Value *R) { return Builder.CreateMul(L, R, "multmp"); } Value *createIfElse(IRBuilder<> &Builder, BBList List, ValList VL) { Value *Condtn = VL[0]; Value *Arg1 = VL[1]; BasicBlock *ThenBB = List[0]; BasicBlock *ElseBB = List[1]; BasicBlock *MergeBB = List[2]; Builder.CreateCondBr(Condtn, ThenBB, ElseBB); Builder.SetInsertPoint(ThenBB); Value *ThenVal = Builder.CreateAdd(Arg1, Builder.getInt32(1), "thenaddtmp"); Builder.CreateBr(MergeBB); Builder.SetInsertPoint(ElseBB); Value *ElseVal = Builder.CreateAdd(Arg1, Builder.getInt32(2), "elseaddtmp"); Builder.CreateBr(MergeBB); unsigned PhiBBSize = List.size() - 1; Builder.SetInsertPoint(MergeBB); PHINode *Phi = Builder.CreatePHI(Type::getInt32Ty(getGlobalContext()), PhiBBSize, "iftmp"); PhiBBSize, "iftmp"); Phi->addIncoming(ThenVal, ThenBB); Phi->addIncoming(ElseVal, ElseBB); return Phi; } int main(int argc, char *argv[]) { FunArgs.push_back("a"); FunArgs.push_back("b"); static IRBuilder<> Builder(Context); GlobalVariable *gVar = createGlob(Builder, "x"); Function *fooFunc = createFunc(Builder, "foo"); setFuncArgs(fooFunc, FunArgs); BasicBlock *entry = createBB(fooFunc, "entry"); Builder.SetInsertPoint(entry); Value *Arg1 = fooFunc->arg_begin(); Value *constant = Builder.getInt32(16); Value *val = createArith(Builder, Arg1, constant); Value *val2 = Builder.getInt32(100); Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp"); Value *Condtn = Builder.CreateICmpNE(Compare, Builder.getInt32(0), "ifcond"); ValList VL; VL.push_back(Condtn); VL.push_back(Arg1); BasicBlock *ThenBB = createBB(fooFunc, "then"); BasicBlock *ElseBB = createBB(fooFunc, "else"); BasicBlock *MergeBB = createBB(fooFunc, "ifcont"); BBList List; List.push_back(ThenBB); List.push_back(ElseBB); List.push_back(MergeBB); Value *v = createIfElse(Builder, List, VL); Builder.CreateRet(v); verifyFunction(*fooFunc); ModuleOb->dump(); return 0; }
After compiling, the output looks like the following:
; ModuleID = 'my compiler' @x = common global i32, align 4 define i32 @foo(i32 %a, i32 %b) { entry: %multmp = mul i32 %a, 16 %cmptmp = icmp ult i32 %multmp, 100 %ifcond = icmp ne i1 %cmptmp, i32 0 br i1 %ifcond, label %then, label %else then: ; preds = %entry %thenaddtmp = add i32 %a, 1 br label %ifcont else: ; preds = %entry %elseaddtmp = add i32 %a, 2 br label %ifcont ifcont: ; preds = %else, %then %iftmp = phi i32 [ %thenaddtmp, %then ], [ %elseaddtmp, %else ] ret i32 %iftmp }
3.133.156.251