Issue 136120
Summary Custom unroll pass results in "opt: CommandLine Error: Option 'max-deopt-or-unreachable-succ-check-depth' registered more than once!"
Labels new issue
Assignees
Reporter mahmoodn
    I have written the following code, `loop.c`:
```
#include <stdio.h>
int main() {
    volatile int sum = 0;
 
    for (int i = 0; i < 4; i++) {
        ++sum;
    }
 printf("Sum is %d\n", sum);
    return 0;
}
```
with a custom and basic loop unrolling pass, `MyUnroll.cpp`:
```
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Constants.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {
 struct SimpleLoopUnroll : public LoopPass {
    static char ID;
 SimpleLoopUnroll() : LoopPass(ID) {}

    bool runOnLoop(Loop *L, LPPassManager &LPM) override {
      // Ensure loop is in simplified form and has a single basic block
      if (!L->isLoopSimplifyForm() || L->getNumBlocks() != 1)
        return false;

      // Get loop components
      BasicBlock *Header = L->getHeader();
      BasicBlock *Preheader = L->getLoopPreheader();
      BasicBlock *Latch = L->getLoopLatch();
      BasicBlock *Exit = L->getExitBlock();
      if (!Preheader || !Latch || !Exit)
        return false;

      // Check for constant trip count of exactly 4
      if (!hasTripCountFour(L))
 return false;

      // Unroll the loop fully (4 times)
 unrollLoopFully(L, LPM);
      return true;
    }

    // Check if the loop has a trip count of exactly 4
    bool hasTripCountFour(Loop *L) {
 BasicBlock *Header = L->getHeader();
      BasicBlock *Latch = L->getLoopLatch();

      // Find the induction variable and its step
 PHINode *IndVar = nullptr;
      for (PHINode &PN : Header->phis()) {
 IndVar = &PN;
        break; // Assume first PHI is the induction variable
      }
      if (!IndVar)
        return false;

      // Get the step value from the latch
      Value *LatchValue = IndVar->getIncomingValueForBlock(Latch);
      Instruction *StepInst = dyn_cast<Instruction>(LatchValue);
      if (!StepInst || StepInst->getOpcode() != Instruction::Add)
        return false;

 ConstantInt *Step = dyn_cast<ConstantInt>(StepInst->getOperand(1));
      if (!Step || Step->getSExtValue() != 1)
        return false;

      // Get the initial and final values
      Value *InitValue = IndVar->getIncomingValueForBlock(L->getLoopPreheader());
      ConstantInt *Init = dyn_cast<ConstantInt>(InitValue);
      if (!Init)
        return false;

      // Find the comparison in the latch
      BranchInst *LatchBr = dyn_cast<BranchInst>(Latch->getTerminator());
      if (!LatchBr || !LatchBr->isConditional())
        return false;

      ICmpInst *Cmp = dyn_cast<ICmpInst>(LatchBr->getCondition());
      if (!Cmp || Cmp->getPredicate() != ICmpInst::ICMP_SLT)
        return false;

 ConstantInt *Limit = dyn_cast<ConstantInt>(Cmp->getOperand(1));
      if (!Limit)
        return false;

      // Calculate trip count: (Limit - Init) / Step
      int64_t TripCount = Limit->getSExtValue() - Init->getSExtValue();
      return TripCount == 4;
    }

    void unrollLoopFully(Loop *L, LPPassManager &LPM) {
      BasicBlock *Header = L->getHeader();
      BasicBlock *Preheader = L->getLoopPreheader();
 BasicBlock *Latch = L->getLoopLatch();
      BasicBlock *Exit = L->getExitBlock();
      Function *F = Header->getParent();

      // Clone the loop body 4 times
      SmallVector<BasicBlock *, 4> NewBlocks;
 ValueToValueMapTy VMap;
      for (unsigned i = 0; i < 4; ++i) {
 BasicBlock *NewBB = CloneBasicBlock(Header, VMap, ".unroll" + Twine(i), F);
        NewBlocks.push_back(NewBB);
        for (Instruction &I : *NewBB) {
          RemapInstruction(&I, VMap, RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
        }
      }

      // Redirect preheader to the first unrolled block
 Preheader->getTerminator()->replaceSuccessorWith(Header, NewBlocks[0]);

 // Chain the unrolled blocks
      for (unsigned i = 0; i < 3; ++i) {
 NewBlocks[i]->getTerminator()->replaceSuccessorWith(Header, NewBlocks[i + 1]);
      }

      // Redirect the last block to the exit
 NewBlocks[3]->getTerminator()->replaceSuccessorWith(Header, Exit);

 // Remove the original loop
      DeleteDeadBlock(Header);
 DeleteDeadBlock(Latch);

      // Remove the loop from LoopInfo
 LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
 LI->erase(L);
    }

    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.addRequired<LoopInfoWrapperPass>();
    }
 };
}

char SimpleLoopUnroll::ID = 0;
static RegisterPass<SimpleLoopUnroll> X("simple-loop-unroll", "Simple Loop Unrolling Pass for Loops with 4 Iterations", false, false);
```

I then ran these commands to build the pass and deploy it:
```
$ FILE=loop
$ clang -O0 -emit-llvm -S -Xclang -disable-O0-optnone -emit-llvm $FILE.c -o $FILE.ll
$ opt -load ./MyUnroll.so -simple-loop-unroll -S $FILE.ll -o $FILE-MyUnroll.ll
opt: CommandLine Error: Option 'max-deopt-or-unreachable-succ-check-depth' registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: opt -load ./MyUnroll.so -simple-loop-unroll -S loop.ll -o loop-MyUnroll.ll
 #0 0x00000000032b68db llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/mahmood/llvm-project/build/bin/opt+0x32b68db)
 #1 0x00000000032b40ec SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #2 0x0000155555116990 __restore_rt (/lib64/libpthread.so.0+0x12990)
 #3 0x0000155553f1852f raise (/lib64/libc.so.6+0x4e52f)
 #4 0x0000155553eebe65 abort (/lib64/libc.so.6+0x21e65)
 #5 0x0000000000757bf4 llvm::GlobPattern::create(llvm::StringRef, std::optional<unsigned long>) (.cold) GlobPattern.cpp:0:0
 #6 0x00000000031f40b8 (/scratch/mahmood/llvm-project/build/bin/opt+0x31f40b8)
 #7 0x00000000031deb1e (/scratch/mahmood/llvm-project/build/bin/opt+0x31deb1e)
 #8 0x00000000031df02d llvm::cl::Option::addArgument() (/scratch/mahmood/llvm-project/build/bin/opt+0x31df02d)
 #9 0x0000155553486a33 _GLOBAL__sub_I_BasicBlockUtils.cpp BasicBlockUtils.cpp:0:0
#10 0x000015555532d11a call_init.part.0 /usr/src/debug/glibc-2.28-251.el8_10.13.x86_64/elf/dl-init.c:71:19
#11 0x000015555532d21a _dl_init /usr/src/debug/glibc-2.28-251.el8_10.13.x86_64/elf/dl-init.c:118:9
#12 0x000015555404309c _dl_catch_exception (/lib64/libc.so.6+0x17909c)
#13 0x000015555533492e dl_open_worker /usr/src/debug/glibc-2.28-251.el8_10.13.x86_64/elf/dl-open.c:792:6
#14 0x000015555533492e dl_open_worker /usr/src/debug/glibc-2.28-251.el8_10.13.x86_64/elf/dl-open.c:751:1
#15 0x0000155554043044 _dl_catch_exception (/lib64/libc.so.6+0x179044)
#16 0x0000155555334b81 _dl_open /usr/src/debug/glibc-2.28-251.el8_10.13.x86_64/elf/dl-open.c:870:17
#17 0x0000155554cf8f8a dlopen_doit (/lib64/libdl.so.2+0xf8a)
#18 0x0000155554043044 _dl_catch_exception (/lib64/libc.so.6+0x179044)
#19 0x0000155554043103 _dl_catch_error (/lib64/libc.so.6+0x179103)
#20 0x0000155554cf952e _dlerror_run (/lib64/libdl.so.2+0x152e)
#21 0x0000155554cf902a dlopen@@GLIBC_2.2.5 (/lib64/libdl.so.2+0x102a)
#22 0x000000000329f3fc llvm::sys::DynamicLibrary::getPermanentLibrary(char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*) (/scratch/mahmood/llvm-project/build/bin/opt+0x329f3fc)
#23 0x000000000321e124 llvm::PluginLoader::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) (/scratch/mahmood/llvm-project/build/bin/opt+0x321e124)
#24 0x0000000000824e07 llvm::cl::opt<llvm::PluginLoader, false, llvm::cl::parser<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>::handleOccurrence(unsigned int, llvm::StringRef, llvm::StringRef) (/scratch/mahmood/llvm-project/build/bin/opt+0x824e07)
#25 0x00000000031e25d6 llvm::cl::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*, char const*, bool) (/scratch/mahmood/llvm-project/build/bin/opt+0x31e25d6)
#26 0x00000000008284d8 optMain (/scratch/mahmood/llvm-project/build/bin/opt+0x8284d8)
#27 0x0000155553f047e5 __libc_start_main (/lib64/libc.so.6+0x3a7e5)
#28 0x00000000008225fe _start (/scratch/mahmood/llvm-project/build/bin/opt+0x8225fe)
Aborted (core dumped)
```

As you can see using the pass resulted in a crash. I don't know how that option has come to my pass, but according to the crash output and following grep, it is related to basic blocks.
```
$ grep -r "max-deopt-or-unreachable-succ-check-depth" ./llvm
./llvm/lib/Transforms/Utils/BasicBlockUtils.cpp: "max-deopt-or-unreachable-succ-check-depth", cl::init(8), cl::Hidden,

```
I wonder how can I fix this conflict?
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to