Search code examples
compiler-constructionllvmcompiler-optimizationllvm-c++-api

CloneFunction then replace original function with cloned one in LLVM opt pass


I am writing an LLVM optimization module pass and I want to be able to restore the original function if I do not like the results. So I wrote a ModulePass with the following basic structure:

while(cloneAndTryAgain){

    ValueToValueMapTy vmap;
    Function *F_clone = CloneFunction(F, vmap, true);

    .... trying out things on F

    if(cloneAndTryAgain){ //not happy with changes to F
        //replace F with clone
        replaceCurrentFunction(F, F_clone);
        F_clone = NULL;
    } 
}

However, after running replaceCurrentFunction(..), I try to print F but I get a segfault. There is something wrong with F after trying to replace it with the clone.

replaceCurrentFunction(..) looks like this:

void replaceCurrentFunction(Function *F, Function *F_clone) {

  Module *M = F->getParent();

  // New function will take the name of the current function.
  F_clone->takeName(F);

  // Insert new function right next to current function.
  M->getFunctionList().insert(F, F_clone);

  // Erase current function.
  F->eraseFromParent();

  // The new function is now the current function.
  F = F_clone;

}

Here's the segfault and stack trace:

Program received signal SIGSEGV, Segmentation fault.
(anonymous namespace)::SlotTracker::SlotTracker (this=0x7fffffff94b0, F=0x1b) at AsmWriter.cpp:438
438     mNext(0), fNext(0), mdnNext(0) {

#0  (anonymous namespace)::SlotTracker::SlotTracker (this=0x7fffffff94b0, F=0x1b) at AsmWriter.cpp:438
#1  0x00007ffff63c66dc in llvm::Value::print (this=0x6d4a30, ROS=..., AAW=0x0) at AsmWriter.cpp:2092
#2  0x00007ffff6fb536c in operator<< (V=..., OS=...) at /llvm/include/llvm/Value.h:318
#4 ....

Solution

  • Wow you're using a bunch of unsafe APIs here, and some statements are not even making sense. For instance what do you expect from the last line of void replaceCurrentFunction(Function *F, Function *F_clone) which is F = F_clone;? If you want "F" in the caller to be updated, you should end this function with return F_clone and call it this way F = replaceCurrentFunction(F, F_clone);.

    For the actual LLVM API, the correct sequence is:

    1. Replace all uses of the old function with the clone: F->replaceAllUsesWith(F_clone)
    2. Save the name: std::string Name = F->getName()
    3. Delete F: F->eraseFromParent()
    4. Rename the clone: F_clone->setName(Name)