With ELLCC, you can easily check out the LLVM IR for code like:
That code is:
I was trying to use @foo in a “struct” object, and was getting an error attempting this:
llvm/lib/IR/Constants.cpp:879:llvm::ConstantAggregate::ConstantAggregate( llvm::CompositeType*, llvm::Value::ValueTy, llvm::ArrayRef<llvm::Constant*>): Assertion `V[I]->getType() == T->getTypeAtIndex(I) && "Initializer for composite element doesn't match!"' failed.
After adding:
where it shows the whole function body of foo(), I thought that’s where the error was coming from, and that I needed some other method to obtain just “@foo”, a global variable reference to the function, and not the function body itself.
The actual story is much simpler. Here the LLVM code to generate the IR for a foo() with this interface:
//------------
// void foo(){ }
//
auto vt = m_builder.getVoidTy();
auto voidFuncVoidType = FunctionType::get( vt, false /* varargs */ );
Function *fooFunc = Function::Create(
voidFuncVoidType, Function::InternalLinkage, "foo",
m_module );
BasicBlock *fooBB =
BasicBlock::Create( m_context, "", fooFunc );
m_builder.SetInsertPoint( fooBB );
m_builder.CreateRetVoid();
My clue that the error is something else is that I am able to build a function that returns a foo function pointer:
//------------
// void(*)() bar() { return foo ; }
//
auto fpRetFuncType = FunctionType::get( voidFuncVoidType->getPointerTo(), false /* varargs */ );
Function *barFunc = Function::Create(
fpRetFuncType, Function::ExternalLinkage, "bar",
m_module );
BasicBlock *barBB =
BasicBlock::Create( m_context, "", barFunc );
m_builder.SetInsertPoint( barBB );
m_builder.CreateRet( fooFunc );
The module at this point looks like:
So why can I used fooFunc in a return statement, but don’t appear to be able to use it in a structure object? Here’s the code that created that structure type
//------------
//
// struct { int, void (*)(), char * }
auto i8t = m_builder.getInt8Ty();
auto i32t = m_builder.getInt32Ty();
std::vector<Type *> consStructMembers{
i32t, voidFuncVoidType->getPointerTo(), i8t->getPointerTo()};
auto consStructType =
StructType::create( m_context, consStructMembers, "" );
and my attempt to populate an object of this type:
//
// %struct { int, void (*)(), char * } = { 65535, foo, null };
//
auto consPriority = ConstantInt::get( i32t, 65535 );
auto consDataZero = ConstantInt::get( i8t->getPointerTo(), 0 );
std::vector<Constant *> v{consPriority, fooFunc, consDataZero};
Constant *g = ConstantStruct::get( consStructType, v );
The actual error was in the third struct member initialization, and had nothing to do with the function pointer value. In retrospect, this makes sense since llvm::Function is derived from llvm::Constant, so there shouldn’t logically be a mismatch there.
What actually fixed the error was simply:
It appears that the numeric zero value isn’t the same thing as an LLVM ‘null’. With that corrected, my variable declaration is:
… so I should now be able to proceed with the actual task at hand.