9

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?

2
  • @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). Commented Feb 27, 2019 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. Commented Feb 27, 2019 at 16:10

1 Answer 1

7

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.