Bug type: miscompilation
Component: ScalarEvolution
Bug location: llvm/lib/Analysis/ScalarEvolution.cpp: ScalarEvolution::computeConstantDifference
Issue title: [SCEV] WRONG code 
Labels: miscompilation
llvm:SCEV
Reported by: JonPsson1

```
int printf(const char *, ...);
__int128 a = 3, c;
char b;
int main() {
  c = 3;
  for (; c >= 0; c--) {
    b = 0;
    for (; b <= 3; b++) {
      if (c)
        break;
      a = 0;
    }
  }
  printf("%d\n", (int)a);
}

```

clang -march=z15 -O1 wrong0.i -o a.out

This program should print '0' as 'a' is set to zero inside the loop. It now prints '3' instead. A bisect leads to a recent commit: 79af689 " [SCEV] Handle more adds in computeConstantDifference() (#101339)".

Seems like IndVarSimplify has gone wrong with an i128:
GOOD <> BROKEN
```
; *** IR Dump After IndVarSimplifyPass on loo   ; *** IR Dump After IndVarSimplifyPass on loo

; Preheader:                                    ; Preheader:
entry:                                          entry:
  br label %for.cond1.preheader                   br label %for.cond1.preheader

; Loop:                                         ; Loop:
for.cond1.preheader:                            for.cond1.preheader:                         
  %storemerge11 = phi i128 [ 3, %entry ], [ %     %storemerge11 = phi i128 [ 3, %entry ], [ %
  %tobool = icmp ne i128 %storemerge11, 0     |   br i1 true, label %for.inc5, label %if.end.
  br i1 %tobool, label %for.inc5, label %if.e <

if.end.lr.ph:                                   if.end.lr.ph:                                
  store i128 0, ptr @a, align 8, !tbaa !4         store i128 0, ptr @a, align 8, !tbaa !4
  br label %if.end                                br label %if.end

if.end:                                         if.end:                                      
  %storemerge89 = phi i8 [ 0, %if.end.lr.ph ]     %storemerge89 = phi i8 [ 0, %if.end.lr.ph ]
  %inc = add nuw nsw i8 %storemerge89, 1          %inc = add nuw nsw i8 %storemerge89, 1
  %cmp2 = icmp ugt i8 %storemerge89, 2            %cmp2 = icmp ugt i8 %storemerge89, 2
  %or.cond = or i1 %tobool, %cmp2             |   %or.cond = or i1 true, %cmp2
  br i1 %or.cond, label %for.inc5.loopexit, l     br i1 %or.cond, label %for.inc5.loopexit, l

for.inc5:                                       for.inc5:                                    
  %storemerge8.lcssa = phi i8 [ 0, %for.cond1     %storemerge8.lcssa = phi i8 [ 0, %for.cond1
  %dec = add nsw i128 %storemerge11, -1           %dec = add nsw i128 %storemerge11, -1
  %cmp = icmp ugt i128 %storemerge11, 0           %cmp = icmp ugt i128 %storemerge11, 0
  br i1 %cmp, label %for.cond1.preheader, lab     br i1 %cmp, label %for.cond1.preheader, lab

for.inc5.loopexit:                              for.inc5.loopexit:                           
  %inc.lcssa = phi i8 [ %inc, %if.end ]           %inc.lcssa = phi i8 [ %inc, %if.end ]
  br label %for.inc5                              br label %for.inc5

; Exit blocks                                   ; Exit blocks
for.end6:                                       for.end6:                                    
  %storemerge8.lcssa.lcssa = phi i8 [ %storem     %storemerge8.lcssa.lcssa = phi i8 [ %storem
  store i128 -1, ptr @c, align 8, !tbaa !4        store i128 -1, ptr @c, align 8, !tbaa !4
  store i8 %storemerge8.lcssa.lcssa, ptr @b,      store i8 %storemerge8.lcssa.lcssa, ptr @b, 
  %0 = load i128, ptr @a, align 8, !tbaa !4       %0 = load i128, ptr @a, align 8, !tbaa !4
  %conv7 = trunc i128 %0 to i32                   %conv7 = trunc i128 %0 to i32
  %call = call signext i32 (ptr, ...) @printf     %call = call signext i32 (ptr, ...) @printf
  ret i32 0                                       ret i32 0

```

Comments: author: nikic
body: Classic mistake: https://github.com/llvm/llvm-project/blob/2f8f58dd17a11934e8c8ec212b6474f76fb18e61/llvm/lib/Analysis/ScalarEvolution.cpp#L11967 This `* Mul` doesn't do what I wanted it to do :)

I should really pick up https://github.com/llvm/llvm-project/pull/80309 again to prevent this kind of mistake in the first place.
author: JonPsson1
body: Is this commit self-contained in the sense that I could revert it on my testing machines? Or will you revert / fix soon?

Fix patch:
commit 3512bcc2e9ab06b0ae2cab78744550b515e54184
Author: Nikita Popov <npopov@redhat.com>
Date:   Mon Aug 12 15:18:32 2024 +0200

    [SCEV] Fix incorrect extension in computeConstantDifference()
    
    The Mul factor was zero-extended here, resulting in incorrect
    results for integers larger than 64-bit.
    
    As we currently only multiply by 1 or -1, just split this into
    two cases -- there's no need for a full multiplication here.
    
    Fixes https://github.com/llvm/llvm-project/issues/102597.

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 9ecdcbe2c5de..318a9d773dc2 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11961,9 +11961,14 @@ ScalarEvolution::computeConstantDifference(const SCEV *More, const SCEV *Less) {
   SmallDenseMap<const SCEV *, int, 8> Multiplicity;
   APInt Diff(BW, 0);
   auto Add = [&](const SCEV *S, int Mul) {
-    if (auto *C = dyn_cast<SCEVConstant>(S))
-      Diff += C->getAPInt() * Mul;
-    else
+    if (auto *C = dyn_cast<SCEVConstant>(S)) {
+      if (Mul == 1) {
+        Diff += C->getAPInt();
+      } else {
+        assert(Mul == -1);
+        Diff -= C->getAPInt();
+      }
+    } else
       Multiplicity[S] += Mul;
   };
   auto Decompose = [&](const SCEV *S, int Mul) {


Regression tests:
file: llvm/test/Transforms/IndVarSimplify/pr102597.ll
commands: opt -S -passes=indvars < %s
tests: test_name: test
test_body: define void @test() {
entry:
  br label %loop

loop:                                             ; preds = %loop.latch, %entry
  %iv = phi i128 [ 3, %entry ], [ %iv.dec, %loop.latch ]
  %tobool = icmp ne i128 %iv, 0
  br i1 %tobool, label %loop.latch, label %if

if:                                               ; preds = %loop
  call void @foo()
  br label %loop.latch

loop.latch:                                       ; preds = %if, %loop
  %iv.dec = add nsw i128 %iv, -1
  %cmp = icmp sgt i128 %iv, 0
  br i1 %cmp, label %loop, label %exit

exit:                                             ; preds = %loop.latch
  ret void
}

declare void @foo()

additional_args: -src-unroll=4 -tgt-unroll=4