A basic block consists of a list of instructions. For example, an instruction can be a simple statement performing tasks based on some simple arithmetic instruction. We will see how the LLVM API can be used to emit arithmetic instructions.
For example, if we want to multiply first argument a with integer value 16
, we will create a constant integer value 16
with the following API:
Value *constant = Builder.getInt32(16);
We already have a from the function argument list:
Value *Arg1 = fooFunc->arg_begin();
LLVM provides a rich list of API's to create binary operations. You can go through the include/llvm/IR/IRBuild.h
file for more details on the APIs.
Value *createArith(IRBuilder<> &Builder, Value *L, Value *R) { return Builder.CreateMul(L, R, "multmp"); }
The whole code now looks 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) { 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"); } 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); Builder.CreateRet(val); verifyFunction(*fooFunc); ModuleOb->dump(); return 0; }
Compile the following program:
$ clang++ -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -o toy
The output will be as follows:
; ModuleID = 'my compiler' @x = common global i32, align 4 define i32 @foo(i32 %a, i32 %b) { entry: %multmp = mul i32 %a, 16 ret i32 %multmp }
Did you notice the return value? We returned the multiplication instead of constant 0.
18.226.172.200