LLVM uses the store
instruction to write into a memory location. There are two arguments to the store
instruction: a value to store and an address at which to store it. The store
instruction has no return value. Let's say that we want to write a data to the second element of the vector of two integers. The store
instruction looks like store i32 3, i32* %a1
. To emit the store
instruction, we can use the following API provided by LLVM:
void getStore(IRBuilder<> &Builder, Value *Address, Value *V) { Builder.CreateStore(V, Address); }
For example, we will multiply the second element of the <2 x i32>
vector by 16
and store it back at the same location.
Consider the following code:
#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 *createArith(IRBuilder<> &Builder, Value *L, Value *R) { return Builder.CreateMul(L, R, "multmp"); } 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"); } void getStore(IRBuilder<> &Builder, Value *Address, Value *V) { Builder.CreateStore(V, Address); } 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); Value *constant = Builder.getInt32(16); Value *val = createArith(Builder, load, constant); getStore(Builder, gep, val); Builder.CreateRet(val); verifyFunction(*fooFunc); ModuleOb->dump(); return 0; }
$ clang++ toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -fno-rtti -o toy $ ./toy
The resulting output will be as follows:
; 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 %multmp = mul i32 %load, 16 store i32 %multmp, i32* %a1 ret i32 %multmp }
3.138.69.163