6

Let's say I want manually turn code below to IR code:

#include <stdio.h>
int main()
{
  int (*p)(const char *__s);  // how to implement this?
  p = puts;                   // and this?
  p("Hello World!\n");
}

I found that the IR representation of the function pointer is this:

%p = alloca i32 (i8*)*, align 8
store i32 (i8*)* @puts, i32 (i8*)** %p, align 8 

but I don't know which api I should use to generate this.

here's part of my implementation:

#include "llvm/Support/raw_ostream.h"

int main() {
  llvm::LLVMContext context;
  llvm::IRBuilder<> builder(context);
  llvm::Module *module = new llvm::Module("top", context);

  llvm::FunctionType *functionType = llvm::FunctionType::get(builder.getInt32Ty(), false);
  llvm::Function *mainFunction = llvm::Function::Create(functionType, llvm::Function::ExternalLinkage, "main", module);

  llvm::BasicBlock *entry = llvm::BasicBlock::Create(context, "entrypoint", mainFunction);
  builder.SetInsertPoint(entry);

  llvm::Value *helloWorld = builder.CreateGlobalStringPtr("hello world\n");

  std::vector<llvm::Type *> putArgs;
  putArgs.push_back(builder.getInt8Ty()->getPointerTo());
  llvm::ArrayRef<llvm::Type *> argsRef(putArgs);
  llvm::FunctionType *putsType = llvm::FunctionType::get(builder.getInt32Ty(), argsRef, false);
  llvm::Constant *putFunction = module->getOrInsertFunction("puts", putsType);

  // code to implement function pointer
  // code to assign puts() to function pointer

  builder.CreateCall(putFunction, helloWorld);  // call the function pointer instead of the function it self
  builder.CreateRet(llvm::ConstantInt::get(builder.getInt32Ty(), 0));

  module->print(llvm::errs(), nullptr);
}

I found that llvm::Function is a subclass of llvm::Value, so I guess the llvm::Constant *putFunction itself is the function pointer I'm looking for, but how to make this value represented in IR code? More specific, how to use the builder to generate the IR code?

  • `@puts` is already a function pointer. The `alloca` code just copies that pointer onto the stack. Depending on what you're trying to do, you won't need that (for example, if you're trying to create a vtable, like in your other question, you can just use `@puts` directly in the global array - and by "directly" I mean "with a bitcast attached to it" because generally not every function in a vtable has the same type). – sepp2k Feb 27 '19 at 15:48
  • @sepp2k nice to see you again. The original purpose for this question is I don’t know how to generate C style function pointer into ir code. I think you are right I must go the wrong way. It just difficult for me to see a pice of code in the assembly language view, do you have any suggestions? I just want to invent a oop toy language,as simple as possible, but it seems harder than I thought. –  Feb 27 '19 at 16:10

1 Answers1

6

I worked it out.

the missing puzzle is blow:

llvm::Value *p = builder.CreateAlloca(putFunction->getType(), nullptr, "p");
builder.CreateStore(putFunction, p, false);
llvm::Value *temp = builder.CreateLoad(p);
builder.CreateCall(temp, helloWorld);

the key concept is that putFunction->getType() and llvm::FunctionType::get() are different type, I take the llvm::FunctionType::get() as a function pointer by mistake.