Search code examples
c++llvmllvm-clangllvm-ir

LLVM replace operand with function


Using a LLVM pass, I wish to iterate through all conditional branches of the form if(a==b) and change these statements to if(func(a)==func(b)) thereby replacing the original operands a and b with the result of function calls func(a) and func(b). This should occur wherever an if statement of the form if(a==b) is found.

Here a is the operand. I can access this operand in my LLVM pass but I can't change it to be the result of a function. What approach should I use to achieve this.

It can be assumed that a and b are always of the same type and func takes in parameters of any type and returns the same type of the parameter. For simplicity it can also be assumed that a and b are integers and func returns an integer as well.


Solution

  • Elaborating on my comment (although there are aspects that are still unclear)

    Adopting the following simplifications:

    • that we are operating on integers
    • the function to be called is defined already

    we could do something like this in a llvm::Function pass:

    bool runOnFunction(llvm::Function &CurFunc) override {
        bool hasChanged = false;
    
        // the llvm::Function to be called could be specified here
        auto *toCallFunc = [...];
    
        for (auto &bb : CurFunc) {
          auto *ti = bb.getTerminator();
          auto *bri = llvm::dyn_cast<llvm::BranchInst>(ti);
          if (!bri)
            continue;
          if (!bri->isConditional())
            continue;
    
          auto *cond = bri->getCondition();
    
          // please note that this cast is for integer comparisons
          // adjust according to your needs
          auto cmpi = llvm::dyn_cast<llvm::ICmpInst>(cond);
          if (!cmpi)
            continue;
    
          auto *opA = cmpi->getOperand(0);
          auto *opB = cmpi->getOperand(1);
    
          auto argsA = llvm::ArrayRef<llvm::Value *>(&opA, 1);
          auto argsB = llvm::ArrayRef<llvm::Value *>(&opB, 1);
    
          // note the insertion before the comparison operation
          auto *ciA = llvm::CallInst(toCallFunc, argsA, "funcA", cmpi);
          auto *ciB = llvm::CallInst(toCallFunc, argsB, "funcB", cmpi);
    
          cmpi->setOperand(1, opA);
          cmpi->setOperand(1, opB);
          hasChanged |= true;
        }
    
        return hasChanged;
      }
    

    From then on, you can expand and deal with other argument types, depending on the required handling.