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