Object used to incrementally build up our IR. The equivalent of a file-pointer when reading/writing a file.
Inserting Instructions at End of a block
SetInsertPoint(BasicBlock *TheBB)
Getting Current Basic Block
GetInsertBlock()
Creating Instructions
Using the Create*()
methods of the IRBuilder object
Takes an optional Twine
argument that gives the register a custom name like iftmp
. which is the twine for this instruction: %iftmp = phi i32 [ 1, %then ], [ %mult, %else]
Refer to the https://llvm.org/doxygen/classllvm_1_1IRBuilderBase.html docs for help building instructions.
CreateLoad
Creates a LLVM load instruction
CreateSub
Creates a LLVM sub instruction
CreateFSub
Creates a LLVM fsub instruction
CreateAlloca
CreateStore
Getting Types
Using the get*()
methods of the IRBuilder object
Example:
Value *IRCodegenVisitor::codegen(const ExprIntegerIR &expr) {
return ConstantInt::getSigned((Type::getInt32Ty(*context)),
expr.val);
};
Getting Function Types
Using the FunctionType::get
Requires parameters for:
- returntype
- paramater types
- whether the function is Variadic
FunctionType::get(returnType, paramTypes, false /* doesn't have variadic args */);
Creating Struct Types
StructType *treeType = StructType::create(*context, StringRef("Tree"));
Creating Multiple Structs
The best way to do this is to define all the structs initially like Preprocessor Directives and then define their bodies later.
void IRCodegenVisitor::codegenClasses(
const std::vector<std::unique_ptr<ClassIR>> &classes) {
// create (opaque) struct types for each of the classes
for (auto &currClass : classes) {
StructType::create(*context, StringRef(currClass->className));
}
// fill in struct bodies
for (auto &currClass : classes) {
std::vector<Type *> bodyTypes;
for (auto &field : currClass->fields) {
// add field type
bodyTypes.push_back(field->codegen(*this));
}
// get opaque class struct type from module symbol table
StructType *classType =
module->getTypeByName(StringRef(currClass->className));
classType->setBody(ArrayRef<Type *>(bodyTypes));
}
Creating Globals
module->getOrInsertGlobal(globalVarName, globalVarType);
...
GlobalVariable *globalVar = module->getNamedGlobal(globalVarName);
globalVar->setInitializer(initValue);
Or, use the LLVM Namespace GlobalVariable
Creating LLVM GEP
Value *ptr = builder->CreateGEP(baseType, basePtr, arrayofIndices);