I am trying to create a pass that will add conditional statements like
if(v1<v2){
printf(“a\n”);
}else{
printf(“b”);
}
For test purposes, wrote the following minimal code
void ThisWillBeRunOnFunctions(Function &F) {
LLVMContext &ctx = F.getContext();
IRBuilder<> builder(ctx);
If this is the only code you put into main then you need to make sure that continueBlock has a terminator like ret i32 0. You already set the IRBuilder to the right block at the end so you should just be able to call CreateRet.
You probably already know this and it’s just to get something working, but you’re also inserting your code right at the beginning of the function. If the function is not empty then that will almost certainly break things in the future.
For more complicated cases you’ll probably have to find where you want to insert the code and split the basic block there. Fortunately it’s a common enough situation that there’s llvm::SplitBlock to help.
I modified the above code by adding
builder.SetInsertPoint(continueBlock);
Type *intType = Type::getInt32Ty(ctx);
Value *constantInt = ConstantInt::get(intType, 0);
builder.CreateRet(constantInt);
at the end. This gives “Terminator found in the middle of a basic block!” It seems, am adding return statement to the newly inserted block, which is not expected. How to fix this?
As you said, I need to use SplitBlock in order to insert an if statement. As a test, I decided to insert the above if statement after each call to malloc. Below is the code that I wrote.
void runOnFunctions(Function &F) {
LLVMContext &ctx = F.getContext();
Function *printfFunc = F.getParent()->getFunction(“printf”);
if (!printfFunc) {
Type *printfTypes = {PointerType::get(IntegerType::get(ctx, 8), 0)};
FunctionType *printfType = FunctionType::get(IntegerType::get(ctx, 32), printfTypes, true);
printfFunc = Function::Create(printfType, GlobalValue::ExternalLinkage, “printf”, F.getParent());
}
for (auto &BB : F) {
for (auto &Inst : BB) {
if (auto *Call = dyn_cast(&Inst)) {
Function *Callee = Call->getCalledFunction();
errs()<<“Callee”<<*Callee<<“\n”;
Could you run F.dump() after all the code is generated and show us the output? It sounds like there actually is other code going into the function and that affects how best to fix it.
It looks like you’re modifying the blocks while iterating through them. This can be done in LLVM you need to really think about which block you want to look at next after your modification.
Usually you have to manually manage iterators (old-school!) rather than use the simpler for (auto &BB : F) style loop.
I tried F.dump(). It gives opt: symbol lookup error: /path/to/lib.so: undefined symbol: _ZNK4llvm5Value4dumpEv
I would like to check every call to malloc. I see only one way to check all mallocs: iterate over blocks and then over instructions. How would you do that?