Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opt -indvars with -verify-scev-strict causes Trip Count Changed! error #128

Open
jayfoad opened this issue Feb 12, 2020 · 10 comments
Open
Labels
crash Prefer [crash-on-valid] or [crash-on-invalid] llvm:SCEV Scalar Evolution miscompilation

Comments

@jayfoad
Copy link
Contributor

jayfoad commented Feb 12, 2020

With the attached r.ll (in r.zip) and a debug build of opt, I get:

$ opt -o /dev/null -indvars -verify-indvars -verify-scev -verify-scev-strict r.ll
Trip Count for Loop at depth 2 containing: %bb4<header>,%bb6<latch><exiting>
 Changed!
Old: 1
New: ({-1,+,-2}<%bb1> + ({1,+,2}<%bb1> umax {2,+,2}<%bb1>))
Delta: ((-1 * ({1,+,2}<%bb1> umax {2,+,2}<%bb1>))<nsw> + {2,+,2}<%bb1>)
Stack dump:
0.	Program arguments: /home/jayfoad2/llvm-debug/bin/opt -o /dev/null -indvars -verify-indvars -verify-scev -verify-scev-strict r.ll 
1.	Running pass 'Function Pass Manager' on module 'r.ll'.
2.	Running pass 'Loop Pass Manager' on function '@f'
 #0 0x0000000006491669 llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/jayfoad2/git/llvm-project/llvm/lib/Support/Unix/Signals.inc:564:11
 #1 0x0000000006491819 PrintStackTraceSignalHandler(void*) /home/jayfoad2/git/llvm-project/llvm/lib/Support/Unix/Signals.inc:625:1
 #2 0x000000000648ff06 llvm::sys::RunSignalHandlers() /home/jayfoad2/git/llvm-project/llvm/lib/Support/Signals.cpp:67:5
 #3 0x0000000006491fbb SignalHandler(int) /home/jayfoad2/git/llvm-project/llvm/lib/Support/Unix/Signals.inc:406:1
 #4 0x00007f30f87a2890 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12890)
 #5 0x00007f30f724be97 raise /build/glibc-OTsEL5/glibc-2.27/signal/../sysdeps/unix/sysv/linux/raise.c:51:0
 #6 0x00007f30f724d801 abort /build/glibc-OTsEL5/glibc-2.27/stdlib/abort.c:81:0
 #7 0x00000000050baa7d llvm::ScalarEvolution::verify() const /home/jayfoad2/git/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp:12005:3
 #8 0x00000000050bb1be llvm::ScalarEvolutionWrapperPass::verifyAnalysis() const /home/jayfoad2/git/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp:12122:1
 #9 0x000000000592c1ed llvm::PMDataManager::verifyPreservedAnalysis(llvm::Pass*) /home/jayfoad2/git/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:911:11
#10 0x0000000004f7a197 llvm::LPPassManager::runOnFunction(llvm::Function&) /home/jayfoad2/git/llvm-project/llvm/lib/Analysis/LoopPass.cpp:241:9
#11 0x000000000592ecdc llvm::FPPassManager::runOnFunction(llvm::Function&) /home/jayfoad2/git/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1482:23
#12 0x000000000592f0f5 llvm::FPPassManager::runOnModule(llvm::Module&) /home/jayfoad2/git/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1518:16
#13 0x000000000592f874 (anonymous namespace)::MPPassManager::runOnModule(llvm::Module&) /home/jayfoad2/git/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1583:23
#14 0x000000000592f388 llvm::legacy::PassManagerImpl::run(llvm::Module&) /home/jayfoad2/git/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1695:16
#15 0x000000000592fe01 llvm::legacy::PassManager::run(llvm::Module&) /home/jayfoad2/git/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1726:3
#16 0x00000000034350a7 main /home/jayfoad2/git/llvm-project/llvm/tools/opt/opt.cpp:941:3
#17 0x00007f30f722eb97 __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:344:0
#18 0x00000000033ff02a _start (/home/jayfoad2/llvm-debug/bin/opt+0x33ff02a)
Aborted (core dumped)
mmitche pushed a commit to mmitche/llvm-project that referenced this issue Aug 3, 2022
…812.1 (llvm#128)

[release/11.x] Update dependencies from dotnet/arcade
@nikic
Copy link
Contributor

nikic commented Mar 9, 2023

Doesn't reproduce anymore, so I'll assume it is fixed.

@nikic nikic closed this as completed Mar 9, 2023
@jayfoad
Copy link
Contributor Author

jayfoad commented Mar 9, 2023

Here's an updated repro for the same kind of failure:

target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7"
define void @f(i32 %arg) {
bb:
  %i = and i32 %arg, 31
  %i1 = icmp ugt i32 %i, 0
  br i1 %i1, label %bb2, label %bb8
bb2:
  %i3 = phi i32 [ %i6, %bb2 ], [ 0, %bb ]
  %i4 = shl i32 %i3, 1
  %i5 = call i32 @g(i32 %i4)
  %i6 = add i32 %i3, 1
  %i7 = icmp eq i32 %i6, %i
  br i1 %i7, label %bb8, label %bb2
bb8:
  ret void
}
declare i32 @g(i32)

opt -passes=loop-reduce -verify-scev -verify-scev-strict -o /dev/null r.ll:

Trip Count for Loop at depth 1 containing: %bb2<header><latch><exiting>
 Changed!
Old: (-1 + (zext i5 (trunc i32 %arg to i5) to i32))<nsw>
New: ((-2 + (2 * (zext i5 (trunc i32 %arg to i5) to i32))<nuw><nsw>)<nsw> /u 2)
Delta: (-1 + (zext i5 (trunc i32 %arg to i5) to i32) + (-1 * ((-2 + (2 * (zext i5 (trunc i32 %arg to i5) to i32))<nuw><nsw>)<nsw> /u 2))<nsw>)
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /home/jayfoad2/llvm-debug/bin/opt -passes=loop-reduce -verify-scev -verify-scev-strict -o /dev/null r.ll
 #0 0x0000555eca02318a llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/jayfoad2/git/llvm-project/llvm/lib/Support/Unix/Signals.inc:602:11
 #1 0x0000555eca02333b PrintStackTraceSignalHandler(void*) /home/jayfoad2/git/llvm-project/llvm/lib/Support/Unix/Signals.inc:676:1
 #2 0x0000555eca0218a6 llvm::sys::RunSignalHandlers() /home/jayfoad2/git/llvm-project/llvm/lib/Support/Signals.cpp:104:5
 #3 0x0000555eca023b55 SignalHandler(int) /home/jayfoad2/git/llvm-project/llvm/lib/Support/Unix/Signals.inc:413:1
 #4 0x00007f0bf5e5e520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #5 0x00007f0bf5eb2a7c __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #6 0x00007f0bf5eb2a7c __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #7 0x00007f0bf5eb2a7c pthread_kill ./nptl/pthread_kill.c:89:10
 #8 0x00007f0bf5e5e476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #9 0x00007f0bf5e447f3 abort ./stdlib/abort.c:81:7
#10 0x0000555ec88ae958 llvm::ScalarEvolution::verify() const /home/jayfoad2/git/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp:14062:3
#11 0x0000555eca6b6807 llvm::FunctionToLoopPassAdaptor::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/jayfoad2/git/llvm-project/llvm/lib/Transforms/Scalar/LoopPassManager.cpp:325:9
#12 0x0000555eca554ad7 llvm::detail::PassModel<llvm::Function, llvm::FunctionToLoopPassAdaptor, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/jayfoad2/git/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:89:17
#13 0x0000555ec958de3a llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/jayfoad2/git/llvm-project/llvm/include/llvm/IR/PassManager.h:521:33
#14 0x0000555ec6b9b767 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) /home/jayfoad2/git/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:89:17
#15 0x0000555ec958cb85 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/jayfoad2/git/llvm-project/llvm/lib/IR/PassManager.cpp:124:38
#16 0x0000555ec6b9b337 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/jayfoad2/git/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h:89:17
#17 0x0000555ec958d0ba llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) /home/jayfoad2/git/llvm-project/llvm/include/llvm/IR/PassManager.h:521:33
#18 0x0000555ec62d8ca7 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool) /home/jayfoad2/git/llvm-project/llvm/tools/opt/NewPMDriver.cpp:522:3
#19 0x0000555ec630aa3a main /home/jayfoad2/git/llvm-project/llvm/tools/opt/opt.cpp:719:12
#20 0x00007f0bf5e45d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#21 0x00007f0bf5e45e40 call_init ./csu/../csu/libc-start.c:128:20
#22 0x00007f0bf5e45e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#23 0x0000555ec62d13a5 _start (/home/jayfoad2/llvm-debug/bin/opt+0x578f3a5)
Aborted (core dumped)

@jayfoad jayfoad reopened this Mar 9, 2023
@EugeneZelenko EugeneZelenko added llvm:SCEV Scalar Evolution crash Prefer [crash-on-valid] or [crash-on-invalid] labels Mar 9, 2023
@jayfoad
Copy link
Contributor Author

jayfoad commented Mar 14, 2023

@max-quazan FYI

@xortator
Copy link
Contributor

Do we know the patch when it started?

@jayfoad
Copy link
Contributor Author

jayfoad commented Mar 14, 2023

Do we know the patch when it started?

I don't know, sorry, but I think it was probably a long time ago.

@nikic
Copy link
Contributor

nikic commented Mar 14, 2023

FWIW, a verify-scev-strict failure like this isn't a bug, just a potential optimization opportunity. The trip counts are equivalent, but SCEV isn't able to detect that the new one can be simplified to the old one.

@jayfoad
Copy link
Contributor Author

jayfoad commented Mar 14, 2023

FWIW, a verify-scev-strict failure like this isn't a bug, just a potential optimization opportunity. The trip counts are equivalent, but SCEV isn't able to detect that the new one can be simplified to the old one.

That's a strange use of "verify". Should it be an Optimization Remark instead?

@nikic
Copy link
Contributor

nikic commented Mar 14, 2023

FWIW, a verify-scev-strict failure like this isn't a bug, just a potential optimization opportunity. The trip counts are equivalent, but SCEV isn't able to detect that the new one can be simplified to the old one.

That's a strange use of "verify". Should it be an Optimization Remark instead?

verify-scev-strict can fail either because of a bug, or because SCEV cannot determine equivalence of expressions. This is why by default it is not enabled, and instead only the cases that are "definitely wrong" are detected.

It's intended as a verification option, but it has too many false positives to be practical for most purposes.

As to why this particular issue occurs, this is the usual problem with add -> sub canonicalization. The sub 2 here is nuw and it would be safe to fold the division into the operands, but add -2 is not nuw.

This looks like a pretty basic case though, so maybe it would be worthwhile to special case it.

@nikic
Copy link
Contributor

nikic commented Mar 14, 2023

I tried to add support for this like this:

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 424ff1c26c68..07307980e287 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -3536,6 +3536,23 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS,
           if (Operands.size() == A->getNumOperands())
             return getAddExpr(Operands);
         }
+
+        // (Op+NegC)/RHSC == (Op-C)/RHSC == (Op/RHSC) - (C/RHSC) if
+        // the subtract is nuw and the divisions are exact. This is handled
+        // separately because SCEV can't represent sub nuw.
+        const auto *NegC = dyn_cast<SCEVConstant>(A->getOperand(0));
+        if (A->getNumOperands() == 2 && NegC && NegC->getAPInt().isNegative()) {
+          const SCEV *Op = A->getOperand(1);
+          APInt C = -NegC->getAPInt();
+          APInt NewC = C.udiv(RHSC->getAPInt());
+          if (C == NewC * RHSC->getAPInt() &&
+              getUnsignedRange(Op).unsignedSubMayOverflow(C) ==
+                  ConstantRange::OverflowResult::NeverOverflows) {
+            const SCEV *NewOp = getUDivExpr(Op, RHS);
+            if (!isa<SCEVUDivExpr>(NewOp) && getMulExpr(NewOp, RHS) != Op)
+              return getMinusSCEV(NewOp, getConstant(NewC));
+          }
+        }
       }
 
       // Fold if both operands are constant.

But this doesn't work because we don't know that (zext i5 (trunc i32 %arg to i5) to i32) is not zero. Or rather, we only know that after loop guard application, but loop guards aren't used for the BECount itself.

@xortator
Copy link
Contributor

xortator commented Mar 14, 2023

Looking at this SCEV:

New: ({-1,+,-2}<%bb1> + ({1,+,2}<%bb1> umax {2,+,2}<%bb1>))

why didn't we combine AR1 + umax(AR2, AR3) into umax(AR1 + AR2, AR1 + AR3)? Because their steps are opposite, it should be OK to just simplify it into a constant. I guess the only precondition here is that start(AR1) + umax(start(AR2), start(AR3)) == umax(start(AR1) + start(AR2), start(AR1) + start (AR3)) which I believe is true.

trevor-m pushed a commit to trevor-m/llvm-project that referenced this issue Apr 20, 2023
Summary:
feature coverage is a useful signal that is available during the merge
process, but was not printed previously.

Output example:

```
$ ./fuzzer -use_value_profile=1 -merge=1 new_corpus/ seed_corpus/
INFO: Seed: 1676551929
INFO: Loaded 1 modules   (2380 inline 8-bit counters): 2380 [0x90d180, 0x90dacc), 
INFO: Loaded 1 PC tables (2380 PCs): 2380 [0x684018,0x68d4d8), 
MERGE-OUTER: 180 files, 78 in the initial corpus
MERGE-OUTER: attempt 1
INFO: Seed: 1676574577
INFO: Loaded 1 modules   (2380 inline 8-bit counters): 2380 [0x90d180, 0x90dacc), 
INFO: Loaded 1 PC tables (2380 PCs): 2380 [0x684018,0x68d4d8), 
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 1048576 bytes
MERGE-INNER: using the control file '/tmp/libFuzzerTemp.111754.txt'
MERGE-INNER: 180 total files; 0 processed earlier; will process 180 files now
llvm#1	pulse  cov: 134 ft: 330 exec/s: 0 rss: 37Mb
llvm#2	pulse  cov: 142 ft: 462 exec/s: 0 rss: 38Mb
llvm#4	pulse  cov: 152 ft: 651 exec/s: 0 rss: 38Mb
llvm#8	pulse  cov: 152 ft: 943 exec/s: 0 rss: 38Mb
llvm#16	pulse  cov: 520 ft: 2783 exec/s: 0 rss: 39Mb
llvm#32	pulse  cov: 552 ft: 3280 exec/s: 0 rss: 41Mb
llvm#64	pulse  cov: 576 ft: 3641 exec/s: 0 rss: 50Mb
llvm#78	LOADED cov: 602 ft: 3936 exec/s: 0 rss: 88Mb
llvm#128	pulse  cov: 611 ft: 3996 exec/s: 0 rss: 93Mb
llvm#180	DONE   cov: 611 ft: 4016 exec/s: 0 rss: 155Mb
MERGE-OUTER: succesfull in 1 attempt(s)
MERGE-OUTER: the control file has 39741 bytes
MERGE-OUTER: consumed 0Mb (37Mb rss) to parse the control file
MERGE-OUTER: 9 new files with 80 new features added; 9 new coverage edges
```

Reviewers: hctim, morehouse

Reviewed By: morehouse

Subscribers: delcypher, #sanitizers, llvm-commits, kcc

Tags: #llvm, #sanitizers

Differential Revision: https://reviews.llvm.org/D66030

llvm-svn: 368617
searlmc1 pushed a commit to ROCm/llvm-project that referenced this issue Nov 27, 2023
…ine/2023.08.02

Promote develop branch (as of a118509) to mainline
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crash Prefer [crash-on-valid] or [crash-on-invalid] llvm:SCEV Scalar Evolution miscompilation
Projects
None yet
Development

No branches or pull requests

5 participants