My usual approach with these things is see what Clang generates - both the LLVM IR and the C++ API calls (C++ backend). You can use the online instance for simplicity. So, compiling this C code:
float foo(int a, float b) {
return a + b;
}
Gives me this LLVM IR:
define float @foo(i32 %a, float %b) #0 {
entry:
%conv = sitofp i32 %a to float
%add = fadd float %conv, %b
ret float %add
}
And this is the C++ API calls required to recreate that:
// Function: foo (func_foo)
{
Function::arg_iterator args = func_foo->arg_begin();
Value* int32_a = args++;
int32_a->setName("a");
Value* float_b = args++;
float_b->setName("b");
BasicBlock* label_entry = BasicBlock::Create(mod->getContext(), "entry",func_foo,0);
// Block entry (label_entry)
CastInst* float_conv = new SIToFPInst(int32_a, Type::getFloatTy(mod->getContext()), "conv", label_entry);
BinaryOperator* float_add = BinaryOperator::Create(Instruction::FAdd, float_conv, float_b, "add", label_entry);
ReturnInst::Create(mod->getContext(), float_add, label_entry);
}
You're free to tweak the input C code (i.e. replacing vars with constants, etc) and seeing what Clang/LLVM emit. This is the best/quickest way to find your way around the IR and API when you're not too familiar with it.