Search code examples
llvmllvm-irllvm-c++-api

Optimize add zero with llvm pass


int func(int i){                                                                     
     int j;
     j = i + 0;
     return j;                                                                                                                       
 } 

I want to practise and learn LLVM transformation pass. For the above simple c function, I want to implement algebraic identification optimization X+0 -> X

I expect the optimized program to be

int func(int i){                                                                     
     int j;                                                                       
     j = i // remove the add instruction                                                                     
     return j;                                                                        
 } 

I read about the IRBuilder, I can create Add/Sub/Mul.... a lot of instructions. But for handling the above case, I can not find any matches.

what should I do to handle the above case?

I also think if I can just remove the instruction.

And the program would be

int func(int i){                                                                                                                                       
     return i;                                                                        
 } 

I am not sure if llvm will do this automatically, once I remove the useless add instruction.


Solution

  • Running clang -O0 -S -emit-llvm -o - test.c on your code produces following IR:

    define i32 @func(i32 %i) #0 {
    entry:
      %i.addr = alloca i32, align 4
      %j = alloca i32, align 4
      store i32 %i, i32* %i.addr, align 4
      %0 = load i32, i32* %i.addr, align 4
      %add = add nsw i32 %0, 0
      store i32 %add, i32* %j, align 4
      %1 = load i32, i32* %j, align 4
      ret i32 %1
    }
    

    As you can see, there is add nsw i32 %0, 0 instruction. This means that clang doesn't optimize it right away (at least on -O0) and this is instruction we are going to process by our pass.

    I'll omit boilerplate code that is required to add your own pass, as it is thoroughly described in the LLVM documentation.

    The pass should do something like (pseudo-code)

    runOnFunction(Function& F)
    {
      for(each instruction in F)
        if(isa<BinaryOperator>(instruction))
          if(instruction.getOpcode() == BinaryInstruction::Add)
             if(isa<ConstantInt>(instruction.getOperand(1))
                if(extract value from constant operand and check if it is 0)
                  instruction.eraseFromParent()
    }