Emitting LLVM IR for loop

Similar to the if-else statement, loops can also be emitted using LLVM API's, with slight modification of the code. For example, we want to have LLVM IR for the following Loops:

for(i=1; i< b; i++)  {body}

The loop has induction variable i, which has some initial value that updates after each iteration. The induction variable is updated after each iteration by a step value that is 1 in the preceding example. Then there is a loop ending condition. In the preceding example, 'i=1' is the initial value, 'i<b' is the end condition of the loop, and 'i++' is the step value by which the induction variable 'i' is incremented after every iteration of the loop.

Before writing a function to create a loop, some Value and BasicBlock need to be pushed into a list, as follows:

Function::arg_iterator AI = fooFunc->arg_begin();
  Value *Arg1 = AI++;
  Value *Arg2 = AI;
  Value *constant = Builder.getInt32(16);
  Value *val = createArith(Builder, Arg1, constant);
  ValList VL;
  VL.push_back(Arg1);

  BBList List;
  BasicBlock *LoopBB = createBB(fooFunc, "loop");
  BasicBlock *AfterBB = createBB(fooFunc, "afterloop");
  List.push_back(LoopBB);
  List.push_back(AfterBB);

  Value *StartVal = Builder.getInt32(1);

Let's create a function for the emitting loop:

PHINode *createLoop(IRBuilder<> &Builder, BBList List, ValList VL,
                    Value *StartVal, Value *EndVal) {
  BasicBlock *PreheaderBB = Builder.GetInsertBlock();
  Value *val = VL[0];
  BasicBlock *LoopBB = List[0];
  Builder.CreateBr(LoopBB);
  Builder.SetInsertPoint(LoopBB);
  PHINode *IndVar = Builder.CreatePHI(Type::getInt32Ty(Context), 2, "i");
  IndVar->addIncoming(StartVal, PreheaderBB);
  Builder.CreateAdd(val, Builder.getInt32(5), "addtmp");
  Value *StepVal = Builder.getInt32(1);
  Value *NextVal = Builder.CreateAdd(IndVar, StepVal, "nextval");
  Value *EndCond = Builder.CreateICmpULT(IndVar, EndVal, "endcond");
  EndCond = Builder.CreateICmpNE(EndCond, Builder.getInt32(0), "loopcond");
  BasicBlock *LoopEndBB = Builder.GetInsertBlock();
  BasicBlock *AfterBB = List[1];
  Builder.CreateCondBr(EndCond, LoopBB, AfterBB);
  Builder.SetInsertPoint(AfterBB);
  IndVar->addIncoming(NextVal, LoopEndBB);
  return IndVar;
}

Consider the following lines of code:

IndVar->addIncoming(StartVal, PreheaderBB);…
IndVar->addIncoming(NextVal, LoopEndBB);

IndVar is a PHI node, which has two incoming values from two blocks—startval from the Preheader block (i=1), and Nextval from the LoopEnd block.

The overall code is as follows:

#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;

typedef SmallVector<BasicBlock *, 16> BBList;
typedef SmallVector<Value *, 16> ValList;

static LLVMContext &Context = getGlobalContext();
static Module *ModuleOb = new Module("my compiler", Context);
static std::vector<std::string> FunArgs;

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 *createLoop(IRBuilder<> &Builder, BBList List, ValList VL,
                    Value *StartVal, Value *EndVal) {
  BasicBlock *PreheaderBB = Builder.GetInsertBlock();
  Value *val = VL[0];
  BasicBlock *LoopBB = List[0];
  Builder.CreateBr(LoopBB);
  Builder.SetInsertPoint(LoopBB);
  PHINode *IndVar = Builder.CreatePHI(Type::getInt32Ty(Context), 2, "i");
  IndVar->addIncoming(StartVal, PreheaderBB);
  Value *Add = Builder.CreateAdd(val, Builder.getInt32(5), "addtmp");
  Value *StepVal = Builder.getInt32(1);
  Value *NextVal = Builder.CreateAdd(IndVar, StepVal, "nextval");
  Value *EndCond = Builder.CreateICmpULT(IndVar, EndVal, "endcond");
  EndCond = Builder.CreateICmpNE(EndCond, Builder.getInt32(0), "loopcond");
  BasicBlock *LoopEndBB = Builder.GetInsertBlock();
  BasicBlock *AfterBB = List[1];
  Builder.CreateCondBr(EndCond, LoopBB, AfterBB);
  Builder.SetInsertPoint(AfterBB);
  IndVar->addIncoming(NextVal, LoopEndBB);
  return Add;
}

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);
  Function::arg_iterator AI = fooFunc->arg_begin();
  Value *Arg1 = AI++;
  Value *Arg2 = AI;
  Value *constant = Builder.getInt32(16);
  Value *val = createArith(Builder, Arg1, constant);
  ValList VL;
  VL.push_back(Arg1);

  BBList List;
  BasicBlock *LoopBB = createBB(fooFunc, "loop");
  BasicBlock *AfterBB = createBB(fooFunc, "afterloop");
  List.push_back(LoopBB);
  List.push_back(AfterBB);

  Value *StartVal = Builder.getInt32(1);
  Value *Res = createLoop(Builder, List, VL, StartVal, Arg2);

  Builder.CreateRet(Res);
  verifyFunction(*fooFunc);
  ModuleOb->dump();
  return 0;
}

After compiling the program, we get the following output:

; ModuleID = 'my compiler'

@x = common global i32, align 4

define i32 @foo(i32 %a, i32 %b) {
entry:
  %multmp = mul i32 %a, 16
  br label %loop

loop:                                             ; preds = %loop, %entry
  %i = phi i32 [ 1, %entry ], [ %nextval, %loop ]
  %addtmp = add i32 %a, 5
  %nextval = add i32 %i, 1
  %endcond = icmp ult i32 %i, %b
  %loopcond = icmp ne i1 %endcond, i32 0
  br i1 %loopcond, label %loop, label %afterloop

afterloop:                                        ; preds = %loop
  ret i32 %addtmp
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.32