Hello! I am implementing a compiler in LLVM using Python, and I have got to the point where I am generating LLVM code for function calls. I have managed to successfully generate LLVM IR for functions which take no arguments, but I am struggling to generate code for functions which take one or more arguments.
I am looking at the Kaleidoscope tutorial on the LLVM documentation website, but I am struggling to work out how they are achieving the goal of passing function arguments and data around so that the argument passed to the function is able to be used inside the body of the function.
I have allocated the variables passed to the function into my symbol table, but when I run the code that I have at the moment, it tells me that I cannotdo that because the argument is not a pointer.
Any help with either this issue or understanding how the authors achieve this in the Kaleidoscope tutorial is greatly appreciated.
Hi,
there are 3 parts involved for parameter passing:
- You already create a function prototype via
FunctionType::get()
. The 2nd argument is a list of the parameter types.
- When generating the function body, the arguments are available at the function as instances of
Argument
. When you refer to an argument, e.g. for loading the value, you have to use the Argument
instance.
- When calling the function you have to provide the list of values for the parameters.
You find all this in the source of chapter 3 of the Kaleidoscope tutorial.
The prototype and the function are created in PrototypeAST::codegen()
, e.g.
std::vector<Type *> Doubles(Args.size(), Type::getDoubleTy(*TheContext));
FunctionType *FT =
FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false);
Function *F =
Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get());
In function FunctionAST::codegen()
, the arguments are copied into stack memory:
for (auto &Arg : TheFunction->args()) {
AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName());
Builder->CreateStore(&Arg, Alloca);
// ...
}
And last, to when calling the function the parameter values are passed. E.g. in CallExprAST::codegen()
:
std::vector<Value *> ArgsV;
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
ArgsV.push_back(Args[i]->codegen());
if (!ArgsV.back())
return nullptr;
}
return Builder->CreateCall(CalleeF, ArgsV, "calltmp");
Please note that much more needs to be done if you want to create ABI-conforming calls.
I hope this helps.
Regards,
Kai
1 Like