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.