[llvm] [CodeGenPrepare] Folding `urem` with loop invariant value as remainder (PR #96625)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 25 07:43:11 PDT 2024
================
@@ -1974,6 +1975,157 @@ static bool foldFCmpToFPClassTest(CmpInst *Cmp, const TargetLowering &TLI,
return true;
}
+static bool isRemOfLoopIncrementWithLIV(Value *Rem, const LoopInfo *LI,
+ Value *&RemAmtOut,
+ std::optional<bool> &AddOrSubOut,
+ Value *&AddOrSubOffsetOut,
+ PHINode *&LoopIncrPNOut) {
+ Value *Incr, *RemAmt;
+ if (!isa<Instruction>(Rem))
+ return false;
+ // NB: If RemAmt is a power of 2 it *should* have been transformed by now.
+ if (!match(Rem, m_URem(m_Value(Incr), m_Value(RemAmt))))
+ return false;
+
+ // Only trivially analyzable loops.
+ Loop *L = LI->getLoopFor(cast<Instruction>(Rem)->getParent());
+ if (L == nullptr || L->getLoopPreheader() == nullptr ||
+ L->getLoopLatch() == nullptr)
+ return false;
+
+ std::optional<bool> AddOrSub;
+ Value *AddOrSubOffset;
+ // Find out loop increment PHI.
+ PHINode *PN = dyn_cast<PHINode>(Incr);
+ if (PN != nullptr) {
+ AddOrSub = std::nullopt;
+ AddOrSubOffset = nullptr;
+ } else {
+ // Search through a NUW add/sub.
+ Value *V0, *V1;
+ if (match(Incr, m_NUWAddLike(m_Value(V0), m_Value(V1))))
+ AddOrSub = true;
+ else if (match(Incr, m_NUWSub(m_Value(V0), m_Value(V1))))
+ AddOrSub = false;
+ else
+ return false;
+
+ PN = dyn_cast<PHINode>(V0);
+ if (PN != nullptr) {
+ AddOrSubOffset = V1;
+ } else if (*AddOrSub) {
+ PN = dyn_cast<PHINode>(V1);
+ AddOrSubOffset = V0;
+ }
+ }
+
+ if (PN == nullptr)
+ return false;
+
+ // This isn't strictly necessary, what we really need is one increment and any
+ // amount of initial values all being the same.
+ if (PN->getNumIncomingValues() != 2)
+ return false;
+
+ // Only works if the remainder amount is a loop invaraint
+ if (!L->isLoopInvariant(RemAmt))
+ return false;
+
+ // Is the PHI a loop increment?
+ auto LoopIncrInfo = getIVIncrement(PN, LI);
+ if (!LoopIncrInfo.has_value())
+ return false;
+
+ // We need remainder_amount % increment_amount to be zero. Increment of one
+ // satisfies that without any special logic and is overwhelmingly the common
+ // case.
+ if (!match(LoopIncrInfo->second, m_One()))
+ return false;
+
+ // Need the increment to not overflow.
+ if (!match(LoopIncrInfo->first, m_NUWAdd(m_Value(), m_Value())))
+ return false;
+
+ // Set output variables.
+ RemAmtOut = RemAmt;
+ LoopIncrPNOut = PN;
+ AddOrSubOut = AddOrSub;
+ AddOrSubOffsetOut = AddOrSubOffset;
+
+ return true;
+}
+
+// Try to transform:
+//
+// for(i = Start; i < End; ++i)
+// Rem = (i nuw+ IncrLoopInvariant) u% RemAmtLoopInvariant;
+//
+// ->
+//
+// Rem = (Start nuw+ IncrLoopInvariant) % RemAmtLoopInvariant;
+// for(i = Start; i < End; ++i, ++rem)
+// Rem = rem == RemAmtLoopInvariant ? 0 : Rem;
+//
+// Currently only implemented for `Start` and `IncrLoopInvariant` being zero.
+static bool foldURemOfLoopIncrement(Instruction *Rem, const LoopInfo *LI,
+ SmallSet<BasicBlock *, 32> &FreshBBs,
+ bool IsHuge) {
+ std::optional<bool> AddOrSub;
+ Value *AddOrSubOffset, *RemAmt;
+ PHINode *LoopIncrPN;
+ if (!isRemOfLoopIncrementWithLIV(Rem, LI, RemAmt, AddOrSub, AddOrSubOffset,
+ LoopIncrPN))
+ return false;
+
+ // Only non-constant remainder as the extra IV is is probably not profitable
+ // in that case. Further, since remainder amount is non-constant, only handle
+ // case where `IncrLoopInvariant` and `Start` are 0 to entirely eliminate the
+ // rem (as opposed to just hoisting it outside of the loop).
+ //
+ // Potential TODO: Should we have a check for how "nested" this remainder
+ // operation is? The new code runs every iteration so if the remainder is
+ // guarded behind unlikely conditions this might not be worth it.
+ if (AddOrSub.has_value() || match(RemAmt, m_ImmConstant()))
+ return false;
+ Loop *L = LI->getLoopFor(Rem->getParent());
+ if (!match(LoopIncrPN->getIncomingValueForBlock(L->getLoopPreheader()),
----------------
dtcxzyw wrote:
There is an assertion failure when processing `assimp/optimized/clipper.cpp.ll`:
Reproducer:
```
; opt -codegenprepare test.ll -S
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @_ZN10ClipperLib9MinkowskiERKSt6vectorINS_8IntPointESaIS1_EES5_RS0_IS3_SaIS3_EEbb(i64 %sub.ptr.div.i56) personality ptr null {
entry:
br label %for.cond65.preheader.us
for.cond65.preheader.us: ; preds = %_ZNSt12_Vector_baseIN10ClipperLib8IntPointESaIS1_EE11_M_allocateEm.exit.i283.us, %entry
%i57.0540.us = phi i64 [ 0, %entry ], [ %add74.us, %_ZNSt12_Vector_baseIN10ClipperLib8IntPointESaIS1_EE11_M_allocateEm.exit.i283.us ]
%add74.us = add nuw i64 %i57.0540.us, 1
br label %_ZNSt12_Vector_baseIN10ClipperLib8IntPointESaIS1_EE11_M_allocateEm.exit.i283.us
_ZNSt12_Vector_baseIN10ClipperLib8IntPointESaIS1_EE11_M_allocateEm.exit.i283.us: ; preds = %_ZNSt12_Vector_baseIN10ClipperLib8IntPointESaIS1_EE11_M_allocateEm.exit.i283.us, %for.cond65.preheader.us
%rem.us = urem i64 %i57.0540.us, %sub.ptr.div.i56
br i1 false, label %for.cond65.preheader.us, label %_ZNSt12_Vector_baseIN10ClipperLib8IntPointESaIS1_EE11_M_allocateEm.exit.i283.us
}
```
```
opt: /home/dtcxzyw/WorkSpace/Projects/compilers/llvm-project/llvm/include/llvm/IR/Instructions.h:2667: llvm::Value* llvm::PHINode::getIncomingValueForBlock(const llvm::BasicBlock*) const: Assertion `Idx >= 0 && "Invalid basic block argument!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0. Program arguments: bin/opt -codegenprepare reduced.ll
1. Running pass 'Function Pass Manager' on module 'reduced.ll'.
2. Running pass 'CodeGen Prepare' on function '@_ZN10ClipperLib9MinkowskiERKSt6vectorINS_8IntPointESaIS1_EES5_RS0_IS3_SaIS3_EEbb'
#0 0x00007d2dd7014550 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0x214550)
#1 0x00007d2dd701155f llvm::sys::RunSignalHandlers() (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMSupport.so.19.0git+0x21155f)
#2 0x00007d2dd70116b5 SignalHandler(int) Signals.cpp:0:0
#3 0x00007d2dd6a42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
#4 0x00007d2dd6a969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
#5 0x00007d2dd6a969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
#6 0x00007d2dd6a969fc pthread_kill ./nptl/pthread_kill.c:89:10
#7 0x00007d2dd6a42476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
#8 0x00007d2dd6a287f3 abort ./stdlib/abort.c:81:7
#9 0x00007d2dd6a2871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x00007d2dd6a39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x00007d2dd31e7f42 llvm::PHINode::getIncomingValueForBlock(llvm::BasicBlock const*) const (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCodeGen.so.19.0git+0x1e7f42)
#12 0x00007d2dd31f7ca4 foldURemOfLoopIncrement(llvm::Instruction*, llvm::LoopInfo const*, llvm::SmallSet<llvm::BasicBlock*, 32u, std::less<llvm::BasicBlock*>>&, bool) CodeGenPrepare.cpp:0:0
#13 0x00007d2dd321e14c (anonymous namespace)::CodeGenPrepare::optimizeInst(llvm::Instruction*, (anonymous namespace)::ModifyDT&) CodeGenPrepare.cpp:0:0
#14 0x00007d2dd3221e18 (anonymous namespace)::CodeGenPrepare::_run(llvm::Function&) CodeGenPrepare.cpp:0:0
#15 0x00007d2dd32247dd (anonymous namespace)::CodeGenPrepareLegacyPass::runOnFunction(llvm::Function&) CodeGenPrepare.cpp:0:0
#16 0x00007d2dd0cedc2d llvm::FPPassManager::runOnFunction(llvm::Function&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.19.0git+0x2edc2d)
#17 0x00007d2dd0cede79 llvm::FPPassManager::runOnModule(llvm::Module&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.19.0git+0x2ede79)
#18 0x00007d2dd0cee732 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/../lib/libLLVMCore.so.19.0git+0x2ee732)
#19 0x00007d2dd73d9ce8 optMain (/home/dtcxzyw/WorkSpace/Projects/compilers/LLVM/llvm-build/bin/../lib/libLLVMOptDriver.so.19.0git+0x3ace8)
#20 0x00007d2dd6a29d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#21 0x00007d2dd6a29e40 call_init ./csu/../csu/libc-start.c:128:20
#22 0x00007d2dd6a29e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#23 0x00005aeb1b087095 _start (bin/opt+0x1095)
Aborted (core dumped)
```
```
https://github.com/llvm/llvm-project/pull/96625
More information about the llvm-commits
mailing list