Reading from the memory

Now, since we have the address, we are ready to read the data from that address and assign the read value to a variable.

In LLVM the load instruction is used to read from a memory location. This simple instruction or combination of similar instructions may then be mapped to some of the sophisticated memory read instructions in low-level assembly.

A load instruction takes an argument, which is the memory address from which the data should be read. We obtained the address in the previous section by the getelementptr instruction in a1.

The load instruction looks like the following:

%val = load i32, i32* a1

This means that the load will take the data pointed by a1 and save in %val.

To emit this we can use the API provided by LLVM in a function, as shown in the following code:

Value *getLoad(IRBuilder<> &Builder, Value *Address) {
  return Builder.CreateLoad(Address, "load");
}

Let's also return the loaded value:

   builder.CreateRet(val);

The whole 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;

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) {
  Type *u32Ty = Type::getInt32Ty(Context);
  Type *vecTy = VectorType::get(u32Ty, 2);
  Type *ptrTy = vecTy->getPointerTo(0);
  FunctionType *funcType =
      FunctionType::get(Builder.getInt32Ty(), ptrTy, false);
  Function *fooFunc =
      Function::Create(funcType, 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);
}

Value *getGEP(IRBuilder<> &Builder, Value *Base, Value *Offset) {
  return Builder.CreateGEP(Builder.getInt32Ty(), Base, Offset, "a1");
}

Value *getLoad(IRBuilder<> &Builder, Value *Address) {
  return Builder.CreateLoad(Address, "load");
}

int main(int argc, char *argv[]) {
  FunArgs.push_back("a");
  static IRBuilder<> Builder(Context);
  Function *fooFunc = createFunc(Builder, "foo");
  setFuncArgs(fooFunc, FunArgs);
  Value *Base = fooFunc->arg_begin();
  BasicBlock *entry = createBB(fooFunc, "entry");
  Builder.SetInsertPoint(entry);
  Value *gep = getGEP(Builder, Base, Builder.getInt32(1));
  Value *load = getLoad(Builder, gep);
  Builder.CreateRet(load);
  verifyFunction(*fooFunc);
  ModuleOb->dump();
  return 0;
}

Compile the following code:

$ clang++ toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -fno-rtti -o toy
$ ./toy

The following is the output:

; ModuleID = 'my compiler'

define i32 @foo(<2 x i32>* %a) {
entry:
  %a1 = getelementptr i32, <2 x i32>* %a, i32 1
  %load = load i32, i32* %a1
  ret i32 %load
}
..................Content has been hidden....................

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