commit 09361953116770b646decf5820a9455ada2ba4fc
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed Oct 16 19:13:52 2024 +0800

    [InstCombine] Drop `samesign` in InstCombine (#112480)

    Closes https://github.com/llvm/llvm-project/issues/112476.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7129499e0f8f..18a6fdcec172 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1738,7 +1738,7 @@ Instruction *InstCombinerImpl::foldICmpAndShift(ICmpInst &Cmp,

     // Compute X & (C2 << Y).
     Value *NewAnd = Builder.CreateAnd(Shift->getOperand(0), NewShift);
-    return replaceOperand(Cmp, 0, NewAnd);
+    return new ICmpInst(Cmp.getPredicate(), NewAnd, Cmp.getOperand(1));
   }

   return nullptr;
@@ -1844,7 +1844,7 @@ Instruction *InstCombinerImpl::foldICmpAndConstConst(ICmpInst &Cmp,
                                                /*HasNUW=*/true),
                              One, Or->getName());
         Value *NewAnd = Builder.CreateAnd(A, NewOr, And->getName());
-        return replaceOperand(Cmp, 0, NewAnd);
+        return new ICmpInst(Cmp.getPredicate(), NewAnd, Cmp.getOperand(1));
       }
     }
   }
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 8be2eeed84ad..623694663aa1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1448,6 +1448,7 @@ Instruction *InstCombinerImpl::foldSelectEqualityTest(SelectInst &Sel) {
              m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Specific(X), m_Specific(Y))))
     return nullptr;

+  cast<ICmpInst>(XeqY)->setSameSign(false);
   return replaceInstUsesWith(Sel, XeqY);
 }

define i1 @test_shr_and_1_ne_0(i32 %a, i32 %b) {
  %shr = lshr i32 %a, %b
  %and = and i32 %shr, 1
  %cmp = icmp ne i32 %and, 0
  ret i1 %cmp
}

define i1 @icmp_equality_test_swift_optional_pointers(i64 %X, i64 %Y) {
entry:
  %XeqC = icmp eq i64 %X, 0
  %YeqC = icmp eq i64 %Y, 0
  %either = select i1 %XeqC, i1 true, i1 %YeqC
  %both = select i1 %XeqC, i1 %YeqC, i1 false
  %XeqY = icmp eq i64 %X, %Y
  %equal = select i1 %either, i1 %both, i1 %XeqY
  ret i1 %equal
}

define i1 @icmp_equality_test_wrong_equal(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, %Y
  %not.YeqZ = xor i1 %YeqZ, true
  %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
  %equal = select i1 %XeqZ, i1 %and, i1 %YeqZ
  ret i1 %equal
}

define i1 @icmp_equality_test_commute_icmp1(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %Z, %X
  %YeqZ = icmp eq i64 %Z, %Y
  %XeqY = icmp eq i64 %Y, %X
  %not.YeqZ = xor i1 %YeqZ, true
  %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_wrong_cmp(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, 999
  %not.YeqZ = xor i1 %YeqZ, true
  %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_wrong_constant(i64 %X, i64 %Y) {
entry:
  %XeqC = icmp eq i64 %X, 0
  %YeqC = icmp eq i64 %Y, 999
  %XeqY = icmp eq i64 %X, %Y
  %not.YeqC = xor i1 %YeqC, true
  %and = select i1 %not.YeqC, i1 %XeqY, i1 false
  %equal = select i1 %XeqC, i1 %YeqC, i1 %and
  ret i1 %equal
}

define <2 x i1> @icmp_equality_test_vector(<2 x i64> %X, <2 x i64> %Y) {
entry:
  %XeqC = icmp eq <2 x i64> %X, <i64 123, i64 456>
  %YeqC = icmp eq <2 x i64> %Y, <i64 123, i64 456>
  %XeqY = icmp eq <2 x i64> %X, %Y
  %not.YeqC = xor <2 x i1> %YeqC, splat (i1 true)
  %and = select <2 x i1> %not.YeqC, <2 x i1> %XeqY, <2 x i1> zeroinitializer
  %equal = select <2 x i1> %XeqC, <2 x i1> %YeqC, <2 x i1> %and
  ret <2 x i1> %equal
}

define i1 @icmp_equality_test_commute_select2(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, %Y
  %not.XeqZ = xor i1 %XeqZ, true
  %and = select i1 %YeqZ, i1 false, i1 %XeqY
  %equal = select i1 %not.XeqZ, i1 %and, i1 %YeqZ
  ret i1 %equal
}

define i1 @icmp_equality_test_constant(i42 %X, i42 %Y) {
entry:
  %XeqC = icmp eq i42 %X, -42
  %YeqC = icmp eq i42 %Y, -42
  %XeqY = icmp eq i42 %X, %Y
  %not.YeqC = xor i1 %YeqC, true
  %and = select i1 %not.YeqC, i1 %XeqY, i1 false
  %equal = select i1 %XeqC, i1 %YeqC, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_wrong_and(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, %Y
  %not.YeqZ = xor i1 %YeqZ, true
  %and = select i1 %not.YeqZ, i1 false, i1 %XeqY
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, %Y
  %not.YeqZ = xor i1 %YeqZ, true
  %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_missing_not(i64 %X, i64 %Y, i64 %Z) {
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, %Y
  %and = select i1 %YeqZ, i1 %XeqY, i1 false
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_constant_samesign(i42 %X, i42 %Y) {
entry:
  %XeqC = icmp eq i42 %X, -42
  %YeqC = icmp eq i42 %Y, -42
  %XeqY = icmp samesign eq i42 %X, %Y
  %not.YeqC = xor i1 %YeqC, true
  %and = select i1 %not.YeqC, i1 %XeqY, i1 false
  %equal = select i1 %XeqC, i1 %YeqC, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
  %XeqZ = icmp eq i64 %Z, %X
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %Y, %X
  %not.YeqZ = xor i1 %YeqZ, true
  %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

define i1 @icmp_equality_test_commute_select1(i64 %X, i64 %Y, i64 %Z) {
entry:
  %XeqZ = icmp eq i64 %X, %Z
  %YeqZ = icmp eq i64 %Y, %Z
  %XeqY = icmp eq i64 %X, %Y
  %and = select i1 %YeqZ, i1 false, i1 %XeqY
  %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
  ret i1 %equal
}

[InstCombine] `samesign` flag should be dropped in `InstCombinerImpl::foldICmpAndConstConst`

Reproducer:
```
define i1 @src(i32 %x, i32 %y) {
  %shf = lshr i32 %x, %y
  %or = or i32 %shf, %x
  %and = and i32 %or, 1
  %ret = icmp samesign ne i32 %and, 0
  ret i1 %ret
}

define i1 @tgt(i32 %x, i32 %y) {
  %shf1 = shl nuw i32 1, %y
  %or2 = or i32 %shf1, 1
  %and3 = and i32 %x, %or2
  %ret = icmp samesign ne i32 %and3, 0
  ret i1 %ret
}
```
```
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i32 %x = #x80000000 (2147483648, -2147483648)
i32 %y = #x0000001f (31)

Source:
i32 %shf = #x00000001 (1)
i32 %or = #x80000001 (2147483649, -2147483647)
i32 %and = #x00000001 (1)
i1 %ret = #x1 (1)

Target:
i32 %shf1 = #x80000000 (2147483648, -2147483648)
i32 %or2 = #x80000001 (2147483649, -2147483647)
i32 %and3 = #x80000000 (2147483648, -2147483648)
i1 %ret = poison
Source value: #x1 (1)
Target value: poison
```


commit 2ab910c08c4ed43d6fd9eb2ef9b3ff52e0293cf9
Author: Florian Hahn <flo@fhahn.com>
Date:   Tue Aug 13 09:23:44 2024 +0100

    [LV] Check pointer user are in loop when checking for uniform pointers.

    Widening decisions are not set for users outside the loop. Avoid
    crashing by only calling isVectorizedMemAccessUse for users in the loop.

    Fixes https://github.com/llvm/llvm-project/issues/102934.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 5547116133e8..0d1262fa1872 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -3705,7 +3705,8 @@ void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
     auto *I = cast<Instruction>(V);
     auto UsersAreMemAccesses =
       llvm::all_of(I->users(), [&](User *U) -> bool {
-        return isVectorizedMemAccessUse(cast<Instruction>(U), V);
+        auto *UI = cast<Instruction>(U);
+        return TheLoop->contains(UI) && isVectorizedMemAccessUse(UI, V);
       });
     if (UsersAreMemAccesses)
       addToWorklistIfAllowed(I);

opt -p loop-vectorize -mtriple=x86_64-apple-macosx -mcpu=skylake-avx512 -force-vector-width=4 -force-vector-interleave=1 -S %s

define void @gep_use_outside_loop(ptr noalias %dst, ptr %src) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %gep.dst = getelementptr i16, ptr %dst, i64 %iv
  %gep.src = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep.src, align 2
  %c = icmp eq i16 %l, 10
  br i1 %c, label %loop.latch, label %then

then:                                             ; preds = %loop.header
  store i16 0, ptr %gep.dst, align 2
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop.header
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 99
  br i1 %ec, label %exit, label %loop.header

exit:                                             ; preds = %loop.latch
  store i16 0, ptr %gep.dst, align 2
  ret void
}

define void @gep_use_in_dead_block(ptr noalias %dst, ptr %src) {
entry:
  br label %loop.header

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %gep.src = getelementptr i16, ptr %src, i64 %iv
  %l = load i16, ptr %gep.src, align 2
  %c = icmp eq i16 %l, 10
  br i1 %c, label %loop.latch, label %then

then:                                             ; preds = %loop.header
  %gep.dst = getelementptr i16, ptr %dst, i64 %iv
  store i16 0, ptr %gep.dst, align 2
  br label %loop.latch

dead:                                             ; preds = %dead
  store i16 0, ptr %gep.dst, align 2
  br label %dead

loop.latch:                                       ; preds = %then, %loop.header
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 99
  br i1 %ec, label %exit, label %loop.header

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

[LoopVectorize] Assertion `WideningDecision != CM_Unknown && "Widening decision should be ready at this moment"' failed.

Reduced LLVM IR:
```llvm ir
; ModuleID = 'reduced.bc'
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"

define i32 @main(i64 %indvars.iv.i) #0 {
entry:
  br label %for.body6.i

for.body6.i:                                      ; preds = %for.inc34.i, %entry
  %indvars.iv.i1 = phi i64 [ 0, %entry ], [ %indvars.iv.next.i, %for.inc34.i ]
  br i1 false, label %for.body6.i.for.inc34.i_crit_edge, label %for.cond7.preheader.i

for.body6.i.for.inc34.i_crit_edge:                ; preds = %for.body6.i
  br label %for.inc34.i

for.cond7.preheader.i:                            ; preds = %for.body6.i
  %arrayidx30.i = getelementptr [0 x i16], ptr null, i64 0, i64 %indvars.iv.i
  store i16 0, ptr %arrayidx30.i, align 2
  br label %for.inc34.i

for.body19.1.i:                                   ; preds = %for.body19.1.i
  store i16 0, ptr %arrayidx30.i, align 2
  br label %for.body19.1.i

for.inc34.i:                                      ; preds = %for.cond7.preheader.i, %for.body6.i.for.inc34.i_crit_edge
  %indvars.iv.next.i = add i64 %indvars.iv.i1, 1
  %exitcond.not.i = icmp eq i64 %indvars.iv.next.i, 0
  br i1 %exitcond.not.i, label %q.exit, label %for.body6.i

q.exit:                                           ; preds = %for.inc34.i
  ret i32 0
}

attributes #0 = { "target-features"="+64bit,+a,+c,+d,+f,+m,+relax,+v,+zicsr,+zifencei,+zmmul,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl256b,+zvl32b,+zvl64b,-b,-e,-experimental-smmpm,-experimental-smnpm,-experimental-ssnpm,-experimental-sspm,-experimental-ssqosid,-experimental-supm,-experimental-zacas,-experimental-zalasr,-experimental-zicfilp,-experimental-zicfiss,-h,-shcounterenw,-shgatpa,-shtvala,-shvsatpa,-shvstvala,-shvstvecd,-smaia,-smcdeleg,-smcsrind,-smepmp,-smstateen,-ssaia,-ssccfg,-ssccptr,-sscofpmf,-sscounterenw,-sscsrind,-ssstateen,-ssstrict,-sstc,-sstvala,-sstvecd,-ssu64xl,-svade,-svadu,-svbare,-svinval,-svnapot,-svpbmt,-xcvalu,-xcvbi,-xcvbitmanip,-xcvelw,-xcvmac,-xcvmem,-xcvsimd,-xsfcease,-xsfvcp,-xsfvfnrclipxfqf,-xsfvfwmaccqqq,-xsfvqmaccdod,-xsfvqmaccqoq,-xsifivecdiscarddlone,-xsifivecflushdlone,-xtheadba,-xtheadbb,-xtheadbs,-xtheadcmo,-xtheadcondmov,-xtheadfmemidx,-xtheadmac,-xtheadmemidx,-xtheadmempair,-xtheadsync,-xtheadvdot,-xventanacondops,-xwchc,-za128rs,-za64rs,-zaamo,-zabha,-zalrsc,-zama16b,-zawrs,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zca,-zcb,-zcd,-zce,-zcf,-zcmop,-zcmp,-zcmt,-zdinx,-zfa,-zfbfmin,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zic64b,-zicbom,-zicbop,-zicboz,-ziccamoa,-ziccif,-zicclsm,-ziccrse,-zicntr,-zicond,-zihintntl,-zihintpause,-zihpm,-zimop,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-ztso,-zvbb,-zvbc,-zvfbfmin,-zvfbfwma,-zvfh,-zvfhmin,-zvkb,-zvkg,-zvkn,-zvknc,-zvkned,-zvkng,-zvknha,-zvknhb,-zvks,-zvksc,-zvksed,-zvksg,-zvksh,-zvkt,-zvl1024b,-zvl16384b,-zvl2048b,-zvl32768b,-zvl4096b,-zvl512b,-zvl65536b,-zvl8192b" }
```

Backtrace:
```
> /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes="loop-vectorize" -S reduced.ll
opt: /scratch/tc-testing/tc-compiler-fuzz-trunk/llvm/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:3631: llvm::LoopVectorizationCostModel::collectLoopUniforms(llvm::ElementCount)::<lambda(llvm::Instruction*, llvm::ElementCount)>: Assertion `WideningDecision != CM_Unknown && "Widening decision should be ready at this moment"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt -passes=loop-vectorize -S reduced.ll
1.      Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "reduced.ll"
2.      Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "main"
 #0 0x000059f80448a570 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f4f570)
 #1 0x000059f80448798f llvm::sys::RunSignalHandlers() (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2f4c98f)
 #2 0x000059f804487ae5 SignalHandler(int) Signals.cpp:0:0
 #3 0x0000795355842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007953558969fc __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #5 0x00007953558969fc __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #6 0x00007953558969fc pthread_kill ./nptl/pthread_kill.c:89:10
 #7 0x0000795355842476 gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #8 0x00007953558287f3 abort ./stdlib/abort.c:81:7
 #9 0x000079535582871b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#10 0x0000795355839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#11 0x000059f80347d610 llvm::LoopVectorizationCostModel::collectLoopUniforms(llvm::ElementCount) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f42610)
#12 0x000059f80348fa77 llvm::LoopVectorizationPlanner::plan(llvm::ElementCount, unsigned int) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f54a77)
#13 0x000059f803491b83 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f56b83)
#14 0x000059f803494de1 llvm::LoopVectorizePass::runImpl(llvm::Function&, llvm::ScalarEvolution&, llvm::LoopInfo&, llvm::TargetTransformInfo&, llvm::DominatorTree&, llvm::BlockFrequencyInfo*, llvm::TargetLibraryInfo*, llvm::DemandedBits&, llvm::AssumptionCache&, llvm::LoopAccessInfoManager&, llvm::OptimizationRemarkEmitter&, llvm::ProfileSummaryInfo*) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f59de1)
#15 0x000059f803495497 llvm::LoopVectorizePass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x1f5a497)
#16 0x000059f8022ff336 llvm::detail::PassModel<llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdc4336)
#17 0x000059f8042a17ff llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d667ff)
#18 0x000059f8023024c6 llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdc74c6)
#19 0x000059f8042a057b llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d6557b)
#20 0x000059f8022fe7c6 llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0xdc37c6)
#21 0x000059f80429e5dd llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x2d635dd)
#22 0x000059f801b38c36 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5fdc36)
#23 0x000059f801b2a881 optMain (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5ef881)
#24 0x0000795355829d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#25 0x0000795355829e40 call_init ./csu/../csu/libc-start.c:128:20
#26 0x0000795355829e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
#27 0x000059f801b206c5 _start (/scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt+0x5e56c5)
zsh: IOT instruction (core dumped)  /scratch/tc-testing/tc-compiler-fuzz-trunk/build-gcv/build-llvm-linux/bin/opt
```

Found via fuzzer.


commit fc5c89900f2a4b50e0f3a88ef7c89115d93684f4
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Nov 27 11:47:22 2024 +0100

    [SimpleLoopUnswitch] Fix LCSSA phi node invalidation

    Fixes https://github.com/llvm/llvm-project/issues/117537.

diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index aa3cbc5e4bdd..d8ef450eeb9a 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -1248,8 +1248,9 @@ static BasicBlock *buildClonedLoopBlocks(
       assert(VMap.lookup(&I) == &ClonedI && "Mismatch in the value map!");

       // Forget SCEVs based on exit phis in case SCEV looked through the phi.
-      if (SE && isa<PHINode>(I))
-        SE->forgetValue(&I);
+      if (SE)
+        if (auto *PN = dyn_cast<PHINode>(&I))
+          SE->forgetLcssaPhiWithNewPredecessor(&L, PN);

       BasicBlock::iterator InsertPt = MergeBB->getFirstInsertionPt();

opt -S -passes='print<scalar-evolution>,simple-loop-unswitch<nontrivial>,print<scalar-evolution>' -verify-scev < %s 2>&1

define void @test(ptr %p) {
entry:
  %check = icmp eq ptr %p, null
  br label %bb0

bb0:                                              ; preds = %loop0, %entry
  br i1 %check, label %loop0, label %latch

latch:                                            ; preds = %bb0
  br i1 %check, label %exit0, label %loop0

exit0:                                            ; preds = %latch
  ret void

loop0:                                            ; preds = %latch, %bb0
  %v = load atomic i32, ptr %p unordered, align 8
  %add = add i32 %v, 3
  br i1 true, label %preheader, label %bb0

preheader:                                        ; preds = %loop0
  br label %loop1

loop1:                                            ; preds = %backedge, %preheader
  %iv1 = phi i32 [ %add, %preheader ], [ %iv1.next, %backedge ]
  %iv1.next = add i32 %iv1, -33
  br label %loop2

backedge:                                         ; preds = %loop2
  br i1 true, label %exit1, label %loop1

loop2:                                            ; preds = %loop2, %loop1
  %iv0 = phi i32 [ %iv1, %loop1 ], [ %iv0.next, %loop2 ]
  %iv0.next = add nsw i32 %iv0, 1
  %cmp = icmp sgt i32 %iv0.next, 0
  br i1 %cmp, label %backedge, label %loop2

exit1:                                            ; preds = %backedge
  ret void
}

[SCEV] Assertion `isAvailableAtLoopEntry(Op, L) && "SCEVAddRecExpr operand is not available at loop entry!"' failed.

Faulty IR:
```
; ModuleID = 'test.ll'
source_filename = "/nfs/build-cache/zvm-dev-4598/jdk11/x86_64/fastdebug/lib/server/boilerplate.ll"
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-ni:1-p2:32:8:8:32-ni:2"
target triple = "x86_64-unknown-linux-gnu"

define void @test(ptr addrspace(1) %p) {
entry:
  %check = icmp eq ptr addrspace(1) %p, null
  br label %bb0

bb0:                                              ; preds = %loop0, %entry
  br i1 %check, label %loop0, label %latch

latch:                                            ; preds = %bb0
  br i1 %check, label %exit0, label %loop0

exit0:                                            ; preds = %latch
  ret void

loop0:                                            ; preds = %latch, %bb0
  %0 = load atomic i32, ptr addrspace(1) %p unordered, align 8
  %add = add i32 %0, 3
  br i1 true, label %preheader, label %bb0

preheader:                                        ; preds = %loop0
  br label %loop1

loop1:                                            ; preds = %backedge, %preheader
  %iv1 = phi i32 [ %add, %preheader ], [ %1, %backedge ]
  %1 = add i32 %iv1, -33
  br label %loop2

backedge:                                         ; preds = %loop2
  br i1 true, label %exit1, label %loop1

loop2:                                            ; preds = %loop2, %loop1
  %iv0 = phi i32 [ %iv1, %loop1 ], [ %2, %loop2 ]
  %2 = add nsw i32 %iv0, 1
  %3 = icmp sgt i32 %2, 0
  br i1 %3, label %backedge, label %loop2

exit1:                                            ; preds = %backedge
  ret void
}
```
fails when run with `opt -passes='print<scalar-evolution>,simple-loop-unswitch<nontrivial>,print<scalar-evolution>' `
Demo of failure: https://godbolt.org/z/qhboK5r3j

Here is the IR after simple-loop-unswitch pass:
![res](https://github.com/user-attachments/assets/8a35df98-54f4-45f6-9e96-626fd6814e7f)

At the point of crash, the SCEV for Exit Value of `%iv0`(which I assume, as we crashed while printing it) is `(-4 + (-1 * %1) + %.us-phi)`, which is incorrect. The crash happens because `%1` is in a block that does not properly dominate `%iv0`. Looks like, simple-loop-unswitch is either incorrectly updating the SCEV in the pass, or is incorrectly reporting SCEV to be preserved. As of now, I'm not sure which is the case.

@nikic @dtcxzyw @EugeneZelenko any thoughts? I'm inclined to having a patch that removes SCEV from simple-loop-unswitch 's list of preserved analyses.

> I'm inclined to having a patch that removes SCEV from simple-loop-unswitch 's list of preserved analyses.

Some SCEVs should be invalidated in `unswitchNontrivialInvariants`. Removing SCEV from the list of preserved analyses doesn't fix the issue.


commit 6d6eea92e36c301e34a7ec11b2a40e3080f79f53
Author: Florian Hahn <flo@fhahn.com>
Date:   Wed Oct 2 13:45:48 2024 +0100

    [LV] Use SCEV to simplify wide binop operand to constant.

    The legacy cost model uses SCEV to determine if the second operand of a
    binary op is a constant. Update the VPlan construction logic to mirror
    the current legacy behavior, to fix a difference in the cost models.

    Fixes https://github.com/llvm/llvm-project/issues/109528.
    Fixes https://github.com/llvm/llvm-project/issues/110440.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index e1f9f29ac6d9..de3b981a4fe3 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -8420,21 +8420,28 @@ VPWidenRecipe *VPRecipeBuilder::tryToWiden(Instruction *I,
   case Instruction::Sub:
   case Instruction::Xor:
   case Instruction::Freeze:
-    if (I->getOpcode() == Instruction::Mul) {
-      // Simplify operands of multiplications using SCEV. This is needed at the
-      // moment to match the behavior of the legacy cost-model.
-      // TODO: Generalize to any opcode and move to VPlan transformation.
-      SmallVector<VPValue *> NewOps(Operands);
+    SmallVector<VPValue *> NewOps(Operands);
+    if (Instruction::isBinaryOp(I->getOpcode())) {
+      // The legacy cost model uses SCEV to check if some of the operands are
+      // constants. To match the legacy cost model's behavior, use SCEV to try
+      // to replace operands with constants.
       ScalarEvolution &SE = *PSE.getSE();
-      for (unsigned I = 0; I < Operands.size(); ++I) {
-        Value *V = NewOps[I]->getUnderlyingValue();
-        if (!isa<Constant>(V) && SE.isSCEVable(V->getType()))
-          if (auto *C = dyn_cast<SCEVConstant>(PSE.getSE()->getSCEV(V)))
-            NewOps[I] = Plan.getOrAddLiveIn(C->getValue());
-      }
-      return new VPWidenRecipe(*I, make_range(NewOps.begin(), NewOps.end()));
+      auto GetConstantViaSCEV = [this, &SE](VPValue *Op) {
+        Value *V = Op->getUnderlyingValue();
+        if (isa<Constant>(V) || !SE.isSCEVable(V->getType()))
+          return Op;
+        auto *C = dyn_cast<SCEVConstant>(SE.getSCEV(V));
+        if (!C)
+          return Op;
+        return Plan.getOrAddLiveIn(C->getValue());
+      };
+      // For Mul, the legacy cost model checks both operands.
+      if (I->getOpcode() == Instruction::Mul)
+        NewOps[0] = GetConstantViaSCEV(NewOps[0]);
+      // For other binops, the legacy cost model only checks the second operand.
+      NewOps[1] = GetConstantViaSCEV(NewOps[1]);
     }
-    return new VPWidenRecipe(*I, make_range(Operands.begin(), Operands.end()));
+    return new VPWidenRecipe(*I, make_range(NewOps.begin(), NewOps.end()));
   };
 }

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 i64 @test_foldable_live_in_via_scev() {
entry:
  %conv = zext i16 -6 to i64
  %add = add nsw i64 %conv, -65528
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i32 [ 1, %entry ], [ %iv.next, %loop ]
  %red = phi i64 [ 1, %entry ], [ %mul, %loop ]
  %mul = mul nsw i64 %red, %add
  %iv.next = add nsw i32 %iv, 1
  %ec = icmp eq i32 %iv.next, 100
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  %ret = phi i64 [ %mul, %loop ]
  ret i64 %ret
}

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 i64 @second_lshr_operand_zero_via_scev() {
entry:
  %ext.0 = sext i8 0 to i32
  br label %loops

loops:                                            ; preds = %loops, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loops ]
  %red = phi i64 [ 0, %entry ], [ %red.next, %loops ]
  %c = icmp eq i64 %iv, 0
  %and = and i64 %iv, 0
  %0 = trunc i64 %iv to i32
  %shr = lshr i32 %0, %ext.0
  %conv.1 = zext i32 %shr to i64
  %red.next.v = select i1 %c, i64 %and, i64 %conv.1
  %red.next = or i64 %red.next.v, %red
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, 0
  br i1 %ec, label %exit, label %loops

exit:                                             ; preds = %loops
  %res = phi i64 [ %red.next, %loops ]
  ret i64 %res
}

[clang] Assertion failed in Vectorize

When I compiled this code with O2 flag, it crashed:

```c
#include <stdint.h>
static uint64_t
safe_sub_func_uint64_t_u_u(uint64_t ui1, uint64_t ui2)
{
  return ui1 - ui2;
}
long a;
static int8_t c;
void b(long d, int f) {
  int e = 0;
  for (; e < 64; e++)
    if (e - f)
      a |= e >> f;
    else
      a |= d & e;
}
uint32_t g() {
  b(6, c);
  for (;; c = safe_sub_func_uint64_t_u_u(c, 4))
    ;
}
```

The crash is:
```
clang: /root/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp:7383: llvm::VectorizationFactor llvm::LoopVectorizationPlanner::computeBestVF(): Assertion `(BestFactor.Width == LegacyVF.Width || planContainsAdditionalSimplifications(getPlanFor(BestFactor.Width), CostCtx, OrigLoop)) && " VPlan cost model and legacy cost model disagreed"' failed.
```

Details can be found here: https://godbolt.org/z/7733x1hvP

This looks like a regression in trunk: https://godbolt.org/z/eo7WG1e66

Probably a recent change caused this? cc: @ayalz @fhahn


commit 2e6deb1dd3a4422807633ba08773e8d786e43d4c
Author: Sjoerd Meijer <smeijer@nvidia.com>
Date:   Thu Nov 14 08:40:45 2024 +0000

    [LoopInterchange] Fix overflow in cost calculation (#111807)

    If the iteration count is really large, e.g. UINT_MAX, then the cost
    calculation can overflows and trigger an assert. So saturate the cost to
    INT_MAX if this is the case by using InstructionCost as a type which
    already supports this kind of overflow handling.

    This fixes #104761

diff --git a/llvm/include/llvm/Analysis/LoopCacheAnalysis.h b/llvm/include/llvm/Analysis/LoopCacheAnalysis.h
index 4fd2485e39d6..3e22487e5e34 100644
--- a/llvm/include/llvm/Analysis/LoopCacheAnalysis.h
+++ b/llvm/include/llvm/Analysis/LoopCacheAnalysis.h
@@ -16,6 +16,7 @@

 #include "llvm/Analysis/LoopAnalysisManager.h"
 #include "llvm/IR/PassManager.h"
+#include "llvm/Support/InstructionCost.h"
 #include <optional>

 namespace llvm {
@@ -31,7 +32,7 @@ class ScalarEvolution;
 class SCEV;
 class TargetTransformInfo;

-using CacheCostTy = int64_t;
+using CacheCostTy = InstructionCost;
 using LoopVectorTy = SmallVector<Loop *, 8>;

 /// Represents a memory reference as a base pointer and a set of indexing
@@ -192,8 +193,6 @@ class CacheCost {
   using LoopCacheCostTy = std::pair<const Loop *, CacheCostTy>;

 public:
-  static CacheCostTy constexpr InvalidCost = -1;
-
   /// Construct a CacheCost object for the loop nest described by \p Loops.
   /// The optional parameter \p TRT can be used to specify the max. distance
   /// between array elements accessed in a loop so that the elements are
diff --git a/llvm/lib/Analysis/LoopCacheAnalysis.cpp b/llvm/lib/Analysis/LoopCacheAnalysis.cpp
index 7ca9f15ad5fc..2897b922f61e 100644
--- a/llvm/lib/Analysis/LoopCacheAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopCacheAnalysis.cpp
@@ -328,6 +328,8 @@ CacheCostTy IndexedReference::computeRefCost(const Loop &L,
       const SCEV *TripCount =
           computeTripCount(*AR->getLoop(), *Sizes.back(), SE);
       Type *WiderType = SE.getWiderType(RefCost->getType(), TripCount->getType());
+      // For the multiplication result to fit, request a type twice as wide.
+      WiderType = WiderType->getExtendedType();
       RefCost = SE.getMulExpr(SE.getNoopOrZeroExtend(RefCost, WiderType),
                               SE.getNoopOrZeroExtend(TripCount, WiderType));
     }
@@ -338,14 +340,18 @@ CacheCostTy IndexedReference::computeRefCost(const Loop &L,
   assert(RefCost && "Expecting a valid RefCost");

   // Attempt to fold RefCost into a constant.
+  // CacheCostTy is a signed integer, but the tripcount value can be large
+  // and may not fit, so saturate/limit the value to the maximum signed
+  // integer value.
   if (auto ConstantCost = dyn_cast<SCEVConstant>(RefCost))
-    return ConstantCost->getValue()->getZExtValue();
+    return ConstantCost->getValue()->getLimitedValue(
+        std::numeric_limits<int64_t>::max());

   LLVM_DEBUG(dbgs().indent(4)
              << "RefCost is not a constant! Setting to RefCost=InvalidCost "
                 "(invalid value).\n");

-  return CacheCost::InvalidCost;
+  return CacheCostTy::getInvalid();
 }

 bool IndexedReference::tryDelinearizeFixedSize(
@@ -696,7 +702,7 @@ CacheCostTy
 CacheCost::computeLoopCacheCost(const Loop &L,
                                 const ReferenceGroupsTy &RefGroups) const {
   if (!L.isLoopSimplifyForm())
-    return InvalidCost;
+    return CacheCostTy::getInvalid();

   LLVM_DEBUG(dbgs() << "Considering loop '" << L.getName()
                     << "' as innermost loop.\n");

opt <  %s  -passes='print<loop-cache-cost>' -disable-output 2>&1

@A = external local_unnamed_addr global [11 x [11 x [11 x i32]]], align 16

define void @foo(i32 noundef %b) {
entry:
  %0 = sext i32 %b to i64
  br label %outer.loop

outer.loop:                                       ; preds = %outer.loop.cleanup, %entry
  %indvars.iv = phi i64 [ %indvars.iv.next, %outer.loop.cleanup ], [ 0, %entry ]
  br label %inner.loop

outer.loop.cleanup:                               ; preds = %inner.loop
  %indvars.iv.next = add nsw i64 %indvars.iv, %0
  br label %outer.loop

inner.loop:                                       ; preds = %inner.loop, %outer.loop
  %inner.iv = phi i64 [ 0, %outer.loop ], [ %add, %inner.loop ]
  %arrayidx3 = getelementptr inbounds [11 x [11 x [11 x i32]]], ptr @A, i64 0, i64 %indvars.iv, i64 %inner.iv, i64 %inner.iv
  store i32 0, ptr %arrayidx3, align 4
  %add = add nuw i64 %inner.iv, 2
  %cmp = icmp ult i64 %inner.iv, -5
  br i1 %cmp, label %inner.loop, label %outer.loop.cleanup
}

[LoopInterchange]  Assertion `getActiveBits() <= 64 && "Too many bits for uint64_t"

With options "-O3 --target=aarch64 func.cpp -mllvm -enable-loopinterchange" and this input:
```
unsigned int A[11][11][11] __attribute__((aligned(16)));
void a(int b) {
  for (int c;; c += b)
    for (long d = 0; d < -3ULL; d += 2ULL)
      A[c][d][d] = 0;
}
```

Loop-interchange runs in an assert:

```
llvm-project/llvm/include/llvm/ADT/APInt.h:1501: uint64_t llvm::APInt::getZExtValue() const: Assertion `getActiveBits() <= 64 && "Too many bits for uint64_t"' failed.
```

IR reproducer, compile this with "opt -passes=loop-interchange -S":

```
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "aarch64-unknown-linux-gnu"

@A = local_unnamed_addr global [11 x [11 x [11 x i32]]] zeroinitializer, align 16

define void @_Z1ai(i32 noundef %b) local_unnamed_addr #0 {
entry:
  %0 = sext i32 %b to i64
  br label %for.cond

; Loop:
for.cond:                                         ; preds = %for.cond.cleanup, %entry
  %indvars.iv = phi i64 [ %indvars.iv.next, %for.cond.cleanup ], [ 0, %entry ]
  br label %for.body

for.cond.cleanup:                                 ; preds = %for.body
  %indvars.iv.next = add nsw i64 %indvars.iv, %0
  br label %for.cond

for.body:                                         ; preds = %for.cond, %for.body
  %d.010 = phi i64 [ 0, %for.cond ], [ %add, %for.body ]
  %arrayidx3 = getelementptr inbounds [11 x [11 x [11 x i32]]], ptr @A, i64 0, i64 %indvars.iv, i64 %d.010, i64 %d.010
  store i32 0, ptr %arrayidx3, align 4
  %add = add nuw i64 %d.010, 2
  %cmp = icmp ult i64 %d.010, -5
  br i1 %cmp, label %for.body, label %for.cond.cleanup
}
```

```
opt: /root/llvm-project/llvm/include/llvm/ADT/APInt.h:1501: uint64_t llvm::APInt::getZExtValue() const: Assertion `getActiveBits() <= 64 && "Too many bits for uint64_t"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=loop-interchange -debug <source>
1.	Running pass "function(loop(loop-interchange))" on module "<source>"
2.	Running pass "loop(loop-interchange)" on function "_Z1ai"
 #0 0x0000000004f7f528 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4f7f528)
 #1 0x0000000004f7cc9c SignalHandler(int) Signals.cpp:0:0
 #2 0x00007f497b842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x00007f497b8969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x00007f497b842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x00007f497b8287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x00007f497b82871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x00007f497b839e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x00000000045677cc llvm::IndexedReference::computeRefCost(llvm::Loop const&, unsigned int) const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x45677cc)
 #9 0x000000000456995f llvm::CacheCost::computeLoopCacheCost(llvm::Loop const&, llvm::SmallVector<llvm::SmallVector<std::unique_ptr<llvm::IndexedReference, std::default_delete<llvm::IndexedReference>>, 8u>, 8u> const&) const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x456995f)
#10 0x000000000456c137 llvm::CacheCost::calculateCacheFootprint() (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x456c137)
#11 0x0000000004573d5c llvm::CacheCost::getCacheCost(llvm::Loop&, llvm::LoopStandardAnalysisResults&, llvm::DependenceInfo&, std::optional<unsigned int>) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4573d5c)
#12 0x0000000003c71d66 llvm::LoopInterchangePass::run(llvm::LoopNest&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3c71d66)
#13 0x0000000002eb0a6e llvm::detail::PassModel<llvm::LoopNest, llvm::LoopInterchangePass, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::run(llvm::LoopNest&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2eb0a6e)
#14 0x0000000003c85255 llvm::PassManager<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::runWithLoopNestPasses(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3c85255)
#15 0x0000000003c85ce3 llvm::PassManager<llvm::Loop, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&>::run(llvm::Loop&, llvm::AnalysisManager<llvm::Loop, llvm::LoopStandardAnalysisResults&>&, llvm::LoopStandardAnalysisResults&, llvm::LPMUpdater&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3c85ce3)
#16 0x0000000003c868b8 llvm::FunctionToLoopPassAdaptor::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3c868b8)
#17 0x0000000000df128e llvm::detail::PassModel<llvm::Function, llvm::FunctionToLoopPassAdaptor, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xdf128e)
#18 0x0000000004d7c368 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d7c368)
#19 0x0000000000df14be llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xdf14be)
#20 0x0000000004d7ad5e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d7ad5e)
#21 0x0000000000df0f8e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xdf0f8e)
#22 0x0000000004d78ec0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4d78ec0)
#23 0x00000000008e7582 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8e7582)
#24 0x00000000008da45c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8da45c)
#25 0x00007f497b829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#26 0x00007f497b829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#27 0x00000000008d1eee _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8d1eee)
```
Which seems to be due to the getZExtValue() call inside IndexedReference::computeRefCost
https://github.com/llvm/llvm-project/blob/b05c55472bf7cadcd0e4cb1a669b3474695b0524/llvm/lib/Analysis/LoopCacheAnalysis.cpp#L340:L343

cc: @caojoshua

I have a fix, will put it up for review tomorrow.


commit cd88bfcb5906049e1387b856fc7256e5fae22e5f
Author: Matt Arsenault <Matthew.Arsenault@amd.com>
Date:   Wed Nov 13 07:43:50 2024 -0800

    ConstantFolding: Do not fold fcmp of denormal without known mode (#115407)

    Fixes #114947

diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 88db315ffd0b..1971c28fc4c4 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1266,14 +1266,16 @@ Constant *llvm::ConstantFoldCompareInstOperands(
     return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI);
   }

-  // Flush any denormal constant float input according to denormal handling
-  // mode.
-  Ops0 = FlushFPConstant(Ops0, I, /* IsOutput */ false);
-  if (!Ops0)
-    return nullptr;
-  Ops1 = FlushFPConstant(Ops1, I, /* IsOutput */ false);
-  if (!Ops1)
-    return nullptr;
+  if (CmpInst::isFPPredicate(Predicate)) {
+    // Flush any denormal constant float input according to denormal handling
+    // mode.
+    Ops0 = FlushFPConstant(Ops0, I, /*IsOutput=*/false);
+    if (!Ops0)
+      return nullptr;
+    Ops1 = FlushFPConstant(Ops1, I, /*IsOutput=*/false);
+    if (!Ops1)
+      return nullptr;
+  }

   return ConstantFoldCompareInstruction(Predicate, Ops0, Ops1);
 }
@@ -1298,47 +1300,110 @@ Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
   return ConstantFoldBinaryInstruction(Opcode, LHS, RHS);
 }

-Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I,
-                                bool IsOutput) {
-  if (!I || !I->getParent() || !I->getFunction())
-    return Operand;
+static ConstantFP *flushDenormalConstant(Type *Ty, const APFloat &APF,
+                                         DenormalMode::DenormalModeKind Mode) {
+  switch (Mode) {
+  case DenormalMode::Dynamic:
+    return nullptr;
+  case DenormalMode::IEEE:
+    return ConstantFP::get(Ty->getContext(), APF);
+  case DenormalMode::PreserveSign:
+    return ConstantFP::get(
+        Ty->getContext(),
+        APFloat::getZero(APF.getSemantics(), APF.isNegative()));
+  case DenormalMode::PositiveZero:
+    return ConstantFP::get(Ty->getContext(),
+                           APFloat::getZero(APF.getSemantics(), false));
+  default:
+    break;
+  }

-  ConstantFP *CFP = dyn_cast<ConstantFP>(Operand);
-  if (!CFP)
-    return Operand;
+  llvm_unreachable("unknown denormal mode");
+}
+
+/// Return the denormal mode that can be assumed when executing a floating point
+/// operation at \p CtxI.
+static DenormalMode getInstrDenormalMode(const Instruction *CtxI, Type *Ty) {
+  if (!CtxI || !CtxI->getParent() || !CtxI->getFunction())
+    return DenormalMode::getDynamic();
+  return CtxI->getFunction()->getDenormalMode(Ty->getFltSemantics());
+}

+static ConstantFP *flushDenormalConstantFP(ConstantFP *CFP,
+                                           const Instruction *Inst,
+                                           bool IsOutput) {
   const APFloat &APF = CFP->getValueAPF();
-  // TODO: Should this canonicalize nans?
   if (!APF.isDenormal())
-    return Operand;
+    return CFP;

-  Type *Ty = CFP->getType();
-  DenormalMode DenormMode =
-      I->getFunction()->getDenormalMode(Ty->getFltSemantics());
-  DenormalMode::DenormalModeKind Mode =
-      IsOutput ? DenormMode.Output : DenormMode.Input;
-  switch (Mode) {
-  default:
-    llvm_unreachable("unknown denormal mode");
-  case DenormalMode::Dynamic:
-    return nullptr;
-  case DenormalMode::IEEE:
+  DenormalMode Mode = getInstrDenormalMode(Inst, CFP->getType());
+  return flushDenormalConstant(CFP->getType(), APF,
+                               IsOutput ? Mode.Output : Mode.Input);
+}
+
+Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *Inst,
+                                bool IsOutput) {
+  if (ConstantFP *CFP = dyn_cast<ConstantFP>(Operand))
+    return flushDenormalConstantFP(CFP, Inst, IsOutput);
+
+  if (isa<ConstantAggregateZero, UndefValue, ConstantExpr>(Operand))
     return Operand;
-  case DenormalMode::PreserveSign:
-    if (APF.isDenormal()) {
-      return ConstantFP::get(
-          Ty->getContext(),
-          APFloat::getZero(Ty->getFltSemantics(), APF.isNegative()));
+
+  Type *Ty = Operand->getType();
+  VectorType *VecTy = dyn_cast<VectorType>(Ty);
+  if (VecTy) {
+    if (auto *Splat = dyn_cast_or_null<ConstantFP>(Operand->getSplatValue())) {
+      ConstantFP *Folded = flushDenormalConstantFP(Splat, Inst, IsOutput);
+      if (!Folded)
+        return nullptr;
+      return ConstantVector::getSplat(VecTy->getElementCount(), Folded);
     }
-    return Operand;
-  case DenormalMode::PositiveZero:
-    if (APF.isDenormal()) {
-      return ConstantFP::get(Ty->getContext(),
-                             APFloat::getZero(Ty->getFltSemantics(), false));
+
+    Ty = VecTy->getElementType();
+  }
+
+  if (const auto *CV = dyn_cast<ConstantVector>(Operand)) {
+    SmallVector<Constant *, 16> NewElts;
+    for (unsigned i = 0, e = CV->getNumOperands(); i != e; ++i) {
+      Constant *Element = CV->getAggregateElement(i);
+      if (isa<UndefValue>(Element)) {
+        NewElts.push_back(Element);
+        continue;
+      }
+
+      ConstantFP *CFP = dyn_cast<ConstantFP>(Element);
+      if (!CFP)
+        return nullptr;
+
+      ConstantFP *Folded = flushDenormalConstantFP(CFP, Inst, IsOutput);
+      if (!Folded)
+        return nullptr;
+      NewElts.push_back(Folded);
     }
-    return Operand;
+
+    return ConstantVector::get(NewElts);
+  }
+
+  if (const auto *CDV = dyn_cast<ConstantDataVector>(Operand)) {
+    SmallVector<Constant *, 16> NewElts;
+    for (unsigned I = 0, E = CDV->getNumElements(); I < E; ++I) {
+      const APFloat &Elt = CDV->getElementAsAPFloat(I);
+      if (!Elt.isDenormal()) {
+        NewElts.push_back(ConstantFP::get(Ty, Elt));
+      } else {
+        DenormalMode Mode = getInstrDenormalMode(Inst, Ty);
+        ConstantFP *Folded =
+            flushDenormalConstant(Ty, Elt, IsOutput ? Mode.Output : Mode.Input);
+        if (!Folded)
+          return nullptr;
+        NewElts.push_back(Folded);
+      }
+    }
+
+    return ConstantVector::get(NewElts);
   }
-  return Operand;
+
+  return nullptr;
 }

 Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,

define <2 x i1> @no_fold_fcmp_denormal_double_ieee_dynamic_vector_nonsplat() #0 {
  %cmp = fcmp une <2 x double> <double 0x8000000000000, double 1.000000e+00>, zeroinitializer
  ret <2 x i1> %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define <3 x i1> @fold_fcmp_nondenormal_double_ieee_dynamic_vector_nonsplat_undef() #0 {
  %cmp = fcmp une <3 x double> <double 2.000000e+00, double undef, double 4.000000e+00>, <double 1.000000e+00, double undef, double 4.000000e+00>
  ret <3 x i1> %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define i1 @no_fold_fcmp_denormal_double_ieee_dynamic_denormal_undef() #0 {
  %cmp = fcmp une double 0x8000000000000, undef
  ret i1 %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define <2 x i1> @fold_fcmp_nondenormal_double_ieee_dynamic_vector_nonsplat() #0 {
  %cmp = fcmp une <2 x double> <double 2.000000e+00, double 4.000000e+00>, <double 2.000000e+00, double 8.000000e+00>
  ret <2 x i1> %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define <2 x i1> @fold_fcmp_nondenormal_double_ieee_dynamic_vector_splat() #0 {
  %cmp = fcmp une <2 x double> splat (double 2.000000e+00), zeroinitializer
  ret <2 x i1> %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define i1 @fold_fcmp_nondenormal_double_ieee_dynamic() #0 {
  %cmp = fcmp une double 2.000000e+00, 0.000000e+00
  ret i1 %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define <2 x i1> @fold_fcmp_nondenormal_double_ieee_dynamic_zero() #0 {
  %cmp = fcmp une <2 x double> zeroinitializer, zeroinitializer
  ret <2 x i1> %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define i1 @no_fold_fcmp_denormal_double_ieee_dynamic_denormal_poison() #0 {
  %cmp = fcmp une double 0x8000000000000, poison
  ret i1 %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define <2 x i1> @no_fold_fcmp_denormal_double_ieee_dynamic_vector_splat() #0 {
  %cmp = fcmp une <2 x double> splat (double 0x8000000000000), zeroinitializer
  ret <2 x i1> %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

define i1 @no_fold_fcmp_denormal_double_ieee_dynamic() #0 {
  %cmp = fcmp une double 0x8000000000000, 0.000000e+00
  ret i1 %cmp
}

attributes #0 = { "denormal-fp-math"="ieee,dynamic" }

`fcmp` miscompiled to a constant

Alive2 report: https://alive2.llvm.org/ce/z/324E7x

```llvm
----------------------------------------
define i1 @fcmp_double_dynamic_dynamic.2() denormal-fp-math=dynamic,dynamic {
#0:
  %cmp = fcmp une double 0x0008000000000000, -0.000000
  ret i1 %cmp
}
=>
define i1 @fcmp_double_dynamic_dynamic.2() nofree noundef willreturn denormal-fp-math=dynamic,dynamic memory(none) {
#0:
  ret i1 1
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:

Source:
i1 %cmp = #x0 (0)

Target:
Source value: #x0 (0)
Target value: #x1 (1)

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```

I don't see the issue? Those values are in fact not equal, so this is true. Alive bug?

it's comparing a denormal to 0, and the `denormal-fp-mode` is set to `dynamic`, so `fcmp` may or may not be flushing denormals to 0.

InstCombine doesn't fold this, IPSCCP does

I expect this is because we got through ValueLattice comparison, which does not have access to the denormal mode: https://github.com/llvm/llvm-project/blob/9501af5f92bb31fa9527d12a4b17b88d9fd651c4/llvm/lib/Analysis/ValueLattice.cpp#L28-L29

Really, the constant folding implementation should be defaulting to the conservatively correct behavior if the denormal mode is unknown.


commit 24c2ba07ce65a5bf7d1113e05c517169d950b663
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Sun Jan 5 01:20:54 2025 +0800

    [InstCombine] Drop NSW when converting `shl X, BW - 1` back into mul (#121633)

    `X <<s BW - 1` and `X *s INT_MIN` are not equivalent.
    Alive2: https://alive2.llvm.org/ce/z/MKKFrj
    Closes https://github.com/llvm/llvm-project/issues/121584

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index f85a3c936513..97a765ecfb6b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -2066,14 +2066,18 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
   bool ShiftByX = false;

   // If V is not nullptr, it will be matched using m_Specific.
-  auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C) -> bool {
+  auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C,
+                              bool &PreserveNSW) -> bool {
     const APInt *Tmp = nullptr;
     if ((!V && match(Op, m_Mul(m_Value(V), m_APInt(Tmp)))) ||
         (V && match(Op, m_Mul(m_Specific(V), m_APInt(Tmp)))))
       C = *Tmp;
     else if ((!V && match(Op, m_Shl(m_Value(V), m_APInt(Tmp)))) ||
-             (V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp)))))
+             (V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp))))) {
       C = APInt(Tmp->getBitWidth(), 1) << *Tmp;
+      // We cannot preserve NSW when shifting by BW - 1.
+      PreserveNSW = Tmp->ult(Tmp->getBitWidth() - 1);
+    }
     if (Tmp != nullptr)
       return true;

@@ -2095,7 +2099,9 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
     return false;
   };

-  if (MatchShiftOrMulXC(Op0, X, Y) && MatchShiftOrMulXC(Op1, X, Z)) {
+  bool Op0PreserveNSW = true, Op1PreserveNSW = true;
+  if (MatchShiftOrMulXC(Op0, X, Y, Op0PreserveNSW) &&
+      MatchShiftOrMulXC(Op1, X, Z, Op1PreserveNSW)) {
     // pass
   } else if (MatchShiftCX(Op0, Y, X) && MatchShiftCX(Op1, Z, X)) {
     ShiftByX = true;
@@ -2108,7 +2114,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
   OverflowingBinaryOperator *BO0 = cast<OverflowingBinaryOperator>(Op0);
   // TODO: We may be able to deduce more about nsw/nuw of BO0/BO1 based on Y >=
   // Z or Z >= Y.
-  bool BO0HasNSW = BO0->hasNoSignedWrap();
+  bool BO0HasNSW = Op0PreserveNSW && BO0->hasNoSignedWrap();
   bool BO0HasNUW = BO0->hasNoUnsignedWrap();
   bool BO0NoWrap = IsSRem ? BO0HasNSW : BO0HasNUW;

@@ -2131,7 +2137,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
   };

   OverflowingBinaryOperator *BO1 = cast<OverflowingBinaryOperator>(Op1);
-  bool BO1HasNSW = BO1->hasNoSignedWrap();
+  bool BO1HasNSW = Op1PreserveNSW && BO1->hasNoSignedWrap();
   bool BO1HasNUW = BO1->hasNoUnsignedWrap();
   bool BO1NoWrap = IsSRem ? BO1HasNSW : BO1HasNUW;
   // (rem (mul X, Y), (mul nuw/nsw X, Z))

define <2 x i8> @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out(<2 x i8> %X) {
  %BO0 = mul nsw <2 x i8> %X, splat (i8 10)
  %BO1 = shl nuw nsw <2 x i8> %X, splat (i8 3)
  %r = srem <2 x i8> %BO0, %BO1
  ret <2 x i8> %r
}

define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted(i8 noundef %X) {
  %BO0 = mul nsw i8 %X, 127
  %BO1 = shl nsw i8 %X, 7
  %r = srem i8 %BO0, %BO1
  ret i8 %r
}

define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(i8 noundef %X) {
  %BO0 = mul nsw i8 %X, 127
  %BO1 = shl nsw i8 %X, 7
  %r = srem i8 %BO1, %BO0
  ret i8 %r
}

define i8 @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(i8 %X) {
  %BO0 = mul nuw nsw i8 %X, 10
  %BO1 = mul nuw i8 %X, 6
  %r = srem i8 %BO0, %BO1
  ret i8 %r
}

[InstCombine] Miscompilation in `simplifyIRemMulShl`

Alive2: https://alive2.llvm.org/ce/z/rdeehL
```

----------------------------------------
define i8 @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out1(i8 noundef %X) {
#0:
  %BO0 = mul nsw i8 noundef %X, 127
  %BO1 = shl nsw i8 noundef %X, 7
  %r = srem i8 %BO1, %BO0
  ret i8 %r
}
=>
define i8 @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out1(i8 noundef %X) {
#0:
  %r = sub nsw i8 0, noundef %X
  ret i8 %r
}
Transformation doesn't verify!

ERROR: Value mismatch

Example:
i8 noundef %X = #xff (255, -1)

Source:
i8 %BO0 = #x81 (129, -127)
i8 %BO1 = #x80 (128, -128)
i8 %r = #xff (255, -1)

Target:
i8 %r = #x01 (1)
Source value: #xff (255, -1)
Target value: #x01 (1)

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```


commit 30f3752e54fa7cd595a434a985efbe9a7abe9b65
Author: Florian Hahn <flo@fhahn.com>
Date:   Mon Feb 3 17:01:02 2025 +0000

    [VPlan] Only use SCEV for live-ins in tryToWiden. (#125436)

    Replacing a recipe with a live-in may not be correct in all cases,
    e.g. when replacing recipes involving header-phi recipes, like
    reductions.

    For now, only use SCEV to simplify live-ins.

    More powerful input simplification can be built in top of
    https://github.com/llvm/llvm-project/pull/124432 in the future.

    Fixes https://github.com/llvm/llvm-project/issues/119173.
    Fixes https://github.com/llvm/llvm-project/issues/125374.

    PR: https://github.com/llvm/llvm-project/pull/125436

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index cbb9960959f2..ce66350669d5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6637,8 +6637,10 @@ LoopVectorizationCostModel::getInstructionCost(Instruction *I,
     // fold away.  We can generalize this for all operations using the notion
     // of neutral elements.  (TODO)
     if (I->getOpcode() == Instruction::Mul &&
-        (PSE.getSCEV(I->getOperand(0))->isOne() ||
-         PSE.getSCEV(I->getOperand(1))->isOne()))
+        ((TheLoop->isLoopInvariant(I->getOperand(0)) &&
+          PSE.getSCEV(I->getOperand(0))->isOne()) ||
+         (TheLoop->isLoopInvariant(I->getOperand(1)) &&
+          PSE.getSCEV(I->getOperand(1))->isOne())))
       return 0;

     // Detect reduction patterns
@@ -8588,6 +8590,8 @@ VPWidenRecipe *VPRecipeBuilder::tryToWiden(Instruction *I,
       // to replace operands with constants.
       ScalarEvolution &SE = *PSE.getSE();
       auto GetConstantViaSCEV = [this, &SE](VPValue *Op) {
+        if (!Op->isLiveIn())
+          return Op;
         Value *V = Op->getUnderlyingValue();
         if (isa<Constant>(V) || !SE.isSCEVable(V->getType()))
           return Op;

target triple = "arm64-apple-macosx"

define i64 @mul_select_operand_known_1_via_scev() {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %red = phi i64 [ 12, %entry ], [ %red.next, %loop ]
  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
  %0 = and i32 %iv, 1
  %cmp1.i = icmp eq i32 %0, 0
  %narrow.i = select i1 %cmp1.i, i32 1, i32 %iv
  %mul = zext nneg i32 %narrow.i to i64
  %red.next = mul nsw i64 %red, %mul
  %iv.next = add nuw nsw i32 %iv, 1
  %ec = icmp eq i32 %iv, 1
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  %res = phi i64 [ %red.next, %loop ]
  ret i64 %res
}

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 i32 @main() {
entry:
  br label %for.body.i.i

for.body.i.i:                                     ; preds = %for.body.i.i, %entry
  %indvars.iv.i.i = phi i64 [ 0, %entry ], [ %indvars.iv.next.i.i, %for.body.i.i ]
  %conv678.i.i = phi i8 [ 1, %entry ], [ %add.i.i.i, %for.body.i.i ]
  %add.i.i.i = add i8 0, %conv678.i.i
  %indvars.iv.next.i.i = add i64 %indvars.iv.i.i, 1
  %exitcond.not.i.i = icmp eq i64 %indvars.iv.i.i, 1
  br i1 %exitcond.not.i.i, label %o.exit, label %for.body.i.i

o.exit:                                           ; preds = %for.body.i.i
  %conv6.i.i = zext i8 %add.i.i.i to i32
  ret i32 %conv6.i.i
}

[clang] Miscompilation at -O3

This code prints 15 at -O3, but prints 5 at -O0/1/2:
```c
int printf(const char *, ...);
static int a[] = {4294967295, 5};
int b, c;
int main() {
  a[1] = b = 5;
  unsigned d = -13;
  for (; d >= 8; d = a[0] + d + 6) {
    int *e = &b;
    *e = a[0] - -1 + b;
  }
  a[c];
  printf("%d\n", b);
}
```

Compiler Explorer: https://godbolt.org/z/4xdPqcjPb

Bisected to https://github.com/llvm/llvm-project/commit/6d6eea92e36c301e34a7ec11b2a40e3080f79f53, which was committed by @fhahn

Don't ignore the warning.

```
<source>:2:19: warning: implicit conversion from 'long' to 'int' changes value from 4294967294 to -2 [-Wconstant-conversion]
    2 | static int a[] = {4294967294, 5};
      |                  ~^~~~~~~~~~
```

Please leave the issue opened, as it's implementation-defined behaviour, not undefined behaviour.

Reduced to:
```llvm
target triple = "x86_64-unknown-linux-gnu"

define noundef i32 @src() {
entry:
  br label %for.body

for.body:                                         ; preds = %entry, %for.body
  %d.06 = phi i32 [ -13, %entry ], [ %add2.reass, %for.body ]
  %add45 = phi i32 [ 5, %entry ], [ %add, %for.body ]
  %add = add i32 0, %add45
  %add2.reass = add i32 %d.06, 5
  %cmp = icmp ugt i32 %add2.reass, 7
  br i1 %cmp, label %for.body, label %for.end

for.end:                                          ; preds = %for.body
  ret i32 %add
}
```

@fhahn I think the issue fundamentally here lies in the fact that we are incorrectly widening the constant 5 (retrieved from SCEV) to `<5, 5, 5, 5>`, when in fact it should be `<5, 0, 0, 0>` (VPlan value: `WIDEN-REDUCTION-PHI ir<%add45> = phi ir<5>`). The VPBasicBlock for the miscompiled basic block is the following one:
```
vector.body:
  EMIT vp<%4> = CANONICAL-INDUCTION ir<0>, vp<%7>
  WIDEN-INDUCTION %d.06 = phi -13, %add2.reass, ir<5>, vp<%0>
  WIDEN-REDUCTION-PHI ir<%add45> = phi ir<5>
  EMIT vp<%5> = WIDEN-CANONICAL-INDUCTION vp<%4>
  EMIT vp<%6> = icmp ule vp<%5>, vp<%3>
```
I'm not that familiar with VPlan, though I feel like that either we are not taking into account the active lane, or we should have not emitted a widen instruction in the first place.

(Godbolt: https://llvm.godbolt.org/z/4Wz46ceh1)

@fhahn Would you be willing to have a look at it? Happy to help with any additional triage, if needed.

Yep let me take a look!


commit 3db0f8c895d4e814a18b754f9afbb1e03bd839a5
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Sep 23 10:49:54 2024 -0700

    [SLP]Update TrackedToOrig mappings after reduction vectorization

    Need to update mappings in TrackedToOrig to correctly provide mapping
    between updated reduced value after vectorization and its original
    value, otherwise the compiler might miss this update and it may cause
    compiler crash later, when it tries to find the original instruction
    mapping for the updated value.

    Fixes https://github.com/llvm/llvm-project/issues/109376

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index a88702b81096..04b8fc09a724 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -18668,6 +18668,14 @@ public:
         // Vectorize a tree.
         Value *VectorizedRoot =
             V.vectorizeTree(LocalExternallyUsedValues, InsertPt);
+        // Update TrackedToOrig mapping, since the tracked values might be
+        // updated.
+        for (Value *RdxVal : Candidates) {
+          Value *OrigVal = TrackedToOrig.at(RdxVal);
+          Value *TransformedRdxVal = TrackedVals.at(OrigVal);
+          if (TransformedRdxVal != RdxVal)
+            TrackedToOrig.try_emplace(TransformedRdxVal, OrigVal);
+        }

         Builder.SetInsertPoint(InsertPt);

opt -S -passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s

[SLPVectorizer] Assertion `Iter != this->end() && "DenseMap::at failed due to a missing key"' failed.

Reproducer: https://godbolt.org/z/v5bqhPWqb
```
; bin/opt -passes=slp-vectorizer reduced.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 i16 @test() {
entry:
  %sub.i487.i.reass.i = add i16 0, 0
  %sub.i487.i.reass.40.i = add i16 %sub.i487.i.reass.i, 0
  %sub.i487.i.reass.41.i = add i16 %sub.i487.i.reass.i, 0
  %sub.i487.i.reass.42.i = add i16 %sub.i487.i.reass.i, 0
  %sub.i487.i.reass.43.i = add i16 %sub.i487.i.reass.i, 0
  %sub.i487.i.reass.44.i = add i16 %sub.i487.i.reass.i, 0
  %sub.i487.i.reass.45.i = add i16 %sub.i487.i.reass.i, 0
  %sub.i487.i.reass.46.i = add i16 0, 0
  %sub.i487.i.reass.47.i = add i16 0, 0
  %sub.i487.i.reass.48.i = add i16 0, 0
  %sub.i487.i.reass.49.i = add i16 0, 0
  %or374461.i.40.i = or i16 %sub.i487.i.reass.40.i, %sub.i487.i.reass.41.i
  %or374461.i.41.i = or i16 %or374461.i.40.i, %sub.i487.i.reass.42.i
  %or374461.i.42.i = or i16 %or374461.i.41.i, %sub.i487.i.reass.43.i
  %or374461.i.43.i = or i16 %or374461.i.42.i, %sub.i487.i.reass.44.i
  %or374461.i.44.i = or i16 %or374461.i.43.i, %sub.i487.i.reass.45.i
  %or374461.i.45.i = or i16 %or374461.i.44.i, %sub.i487.i.reass.46.i
  %or374461.i.46.i = or i16 %or374461.i.45.i, %sub.i487.i.reass.47.i
  %or374461.i.47.i = or i16 %or374461.i.46.i, %sub.i487.i.reass.48.i
  %or374461.i.48.i = or i16 %or374461.i.47.i, %sub.i487.i.reass.49.i
  %or374461.i.50.i = or i16 %or374461.i.48.i, %sub.i487.i.reass.i
  %sub.i487.i96.reass.i = add i16 0, 0
  %sub.i487.i96.reass.16.i = add i16 %sub.i487.i96.reass.i, 0
  %sub.i487.i96.reass.17.i = add i16 %sub.i487.i96.reass.i, 0
  %0 = or i16 %sub.i487.i96.reass.16.i, %sub.i487.i96.reass.17.i
  %1 = or i16 %0, %or374461.i.50.i
  ret i16 %1
}
```
```
opt: /root/llvm-project/llvm/include/llvm/ADT/DenseMap.h:204: const ValueT& llvm::DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT>::at(llvm::DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT>::const_arg_type_t<KeyT>) const [with DerivedT = llvm::DenseMap<llvm::Value*, llvm::Value*>; KeyT = llvm::Value*; ValueT = llvm::Value*; KeyInfoT = llvm::DenseMapInfo<llvm::Value*, void>; BucketT = llvm::detail::DenseMapPair<llvm::Value*, llvm::Value*>; llvm::DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT>::const_arg_type_t<KeyT> = const llvm::Value*]: Assertion `Iter != this->end() && "DenseMap::at failed due to a missing key"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=slp-vectorizer <source>
1.	Running pass "function(slp-vectorizer)" on module "<source>"
2.	Running pass "slp-vectorizer" on function "test"
 #0 0x0000000005035d68 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x5035d68)
 #1 0x00000000050334ac SignalHandler(int) Signals.cpp:0:0
 #2 0x0000707bdcc42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #3 0x0000707bdcc969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #4 0x0000707bdcc42476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #5 0x0000707bdcc287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #6 0x0000707bdcc2871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
 #7 0x0000707bdcc39e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
 #8 0x000000000409326e llvm::DenseMapBase<llvm::DenseMap<llvm::Value*, llvm::Value*, llvm::DenseMapInfo<llvm::Value*, void>, llvm::detail::DenseMapPair<llvm::Value*, llvm::Value*>>, llvm::Value*, llvm::Value*, llvm::DenseMapInfo<llvm::Value*, void>, llvm::detail::DenseMapPair<llvm::Value*, llvm::Value*>>::at(llvm::Value const*) const (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x409326e)
 #9 0x000000000413473f (anonymous namespace)::HorizontalReduction::tryToReduce(llvm::slpvectorizer::BoUpSLP&, llvm::DataLayout const&, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo const&) SLPVectorizer.cpp:0:0
#10 0x00000000041370d1 llvm::SLPVectorizerPass::vectorizeHorReduction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::TargetTransformInfo*, llvm::SmallVectorImpl<llvm::WeakTrackingVH>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x41370d1)
#11 0x000000000413b996 llvm::SLPVectorizerPass::vectorizeRootInstruction(llvm::PHINode*, llvm::Instruction*, llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&, llvm::TargetTransformInfo*) (.constprop.0) SLPVectorizer.cpp:0:0
#12 0x000000000413ff36 llvm::SLPVectorizerPass::vectorizeChainsInBlock(llvm::BasicBlock*, llvm::slpvectorizer::BoUpSLP&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x413ff36)
#13 0x0000000004146401 llvm::SLPVectorizerPass::runImpl(llvm::Function&, llvm::ScalarEvolution*, llvm::TargetTransformInfo*, llvm::TargetLibraryInfo*, llvm::AAResults*, llvm::LoopInfo*, llvm::DominatorTree*, llvm::AssumptionCache*, llvm::DemandedBits*, llvm::OptimizationRemarkEmitter*) (.part.0) SLPVectorizer.cpp:0:0
#14 0x000000000414708b llvm::SLPVectorizerPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x414708b)
#15 0x0000000002f1a1ae llvm::detail::PassModel<llvm::Function, llvm::SLPVectorizerPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2f1a1ae)
#16 0x0000000004e38158 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e38158)
#17 0x0000000000e0b02e llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe0b02e)
#18 0x0000000004e36b7e llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e36b7e)
#19 0x0000000000e0a83e llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xe0a83e)
#20 0x0000000004e365b0 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e365b0)
#21 0x00000000008feef2 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8feef2)
#22 0x00000000008f1d7c optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8f1d7c)
#23 0x0000707bdcc29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#24 0x0000707bdcc29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#25 0x00000000008e984e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8e984e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
```
llvm version: e8a739062490ce1bb30974f216ba187cd7b5a2a4


commit 4a0bbbcbcf6ebc87e794e7b86b9f4651bffcd806
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Fri Aug 16 13:24:03 2024 -0700

    [SLP]Fix PR104637: do not create new nodes for fully overlapped non-schedulable nodes

    If the scalars do not require scheduling and were already vectorized,
    but in the different order, compiler still tries to create the new node.
    It may cause the compiler crash for the gathered operands. Instead need
    to consider such nodes as full overlap and just reshuffle vectorized
    node.

    Fixes https://github.com/llvm/llvm-project/issues/104637

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 667d0df781aa..9ecd8160a978 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -7144,6 +7144,21 @@ void BoUpSLP::buildTree_rec(ArrayRef<Value *> VL, unsigned Depth,
                        ReuseShuffleIndices);
         return;
       }
+      SmallPtrSet<const TreeEntry *, 4> Nodes;
+      Nodes.insert(getTreeEntry(S.OpValue));
+      for (const TreeEntry *E : MultiNodeScalars.lookup(S.OpValue))
+        Nodes.insert(E);
+      SmallPtrSet<Value *, 8> Values(VL.begin(), VL.end());
+      if (any_of(Nodes, [&](const TreeEntry *E) {
+            return all_of(E->Scalars,
+                          [&](Value *V) { return Values.contains(V); });
+          })) {
+        LLVM_DEBUG(dbgs() << "SLP: Gathering due to full overlap.\n");
+        if (TryToFindDuplicates(S))
+          newTreeEntry(VL, std::nullopt /*not vectorized*/, S, UserTreeIdx,
+                       ReuseShuffleIndices);
+        return;
+      }
     } else {
       // Record the reuse of the tree node.  FIXME, currently this is only used
       // to properly draw the graph rather than for the actual vectorization.

opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu < %s

define void @test(double %v) {
entry:
  %mul.3 = fmul double 0.000000e+00, %v
  %mul.4 = fmul double 0.000000e+00, 0.000000e+00
  br label %loop

loop:                                             ; preds = %loop, %entry
  %t48.0 = phi double [ 0.000000e+00, %entry ], [ %5, %loop ]
  %t50.02 = phi double [ 0.000000e+00, %entry ], [ %3, %loop ]
  %t52.0 = phi double [ 0.000000e+00, %entry ], [ %7, %loop ]
  %0 = fmul double %t52.0, %mul.3
  %1 = fmul double %t48.0, %mul.4
  %2 = fadd double %1, %0
  %3 = fadd double %2, %v
  %4 = fmul double 0.000000e+00, %mul.3
  %5 = fadd double 0.000000e+00, %4
  %6 = fmul double 0.000000e+00, %mul.4
  %7 = fadd double 0.000000e+00, %6
  br label %loop
}

SLP Vectorizer crash due to commit ca654acc16c43191228eadfec8f7241dca10b0c3

ca654acc16c43191228eadfec8f7241dca10b0c3 change in SLP Vectorizer causes a crash for this test case:

```
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 @a_(double %c__fetch.3) {
alloca_0:
  %mul.3 = fmul double 0.000000e+00, %c__fetch.3
  %mul.4 = fmul double 0.000000e+00, 0.000000e+00
  br label %loop.69

loop.69:                                          ; preds = %loop.69, %alloca_0
  %t48.0 = phi double [ 0.000000e+00, %alloca_0 ], [ %5, %loop.69 ]
  %t50.0 = phi double [ 0.000000e+00, %alloca_0 ], [ %3, %loop.69 ]
  %t52.0 = phi double [ 0.000000e+00, %alloca_0 ], [ %7, %loop.69 ]
  %0 = fmul double %t52.0, %mul.3
  %1 = fmul double %t48.0, %mul.4
  %2 = fadd double %1, %0
  %3 = fadd double %2, 0.000000e+00
  %4 = fmul double 0.000000e+00, %mul.3
  %5 = fadd double 0.000000e+00, %4
  %6 = fmul double 0.000000e+00, %mul.4
  %7 = fadd double 0.000000e+00, %6
  br label %loop.69
}
```

After slp-vectorizer pass IR is being transformed to as incorrect one:
```
define void @a_(double %c__fetch.3) {
alloca_0:
  %0 = shufflevector <2 x double> %2, <2 x double> <double 0.000000e+00, double poison>, <2 x i32> <i32 2, i32 0>
  %1 = fmul <2 x double> zeroinitializer, %0
  %2 = insertelement <2 x double> <double poison, double 0.000000e+00>, double %c__fetch.3, i32 0
  %3 = fmul <2 x double> zeroinitializer, %2
  br label %loop.69

loop.69:                                          ; preds = %loop.69, %alloca_0
  %t50.0 = phi double [ 0.000000e+00, %alloca_0 ], [ %9, %loop.69 ]
  %4 = phi <2 x double> [ zeroinitializer, %alloca_0 ], [ %11, %loop.69 ]
  %5 = fmul <2 x double> %4, %1
  %6 = extractelement <2 x double> %5, i32 0
  %7 = extractelement <2 x double> %5, i32 1
  %8 = fadd double %6, %7
  %9 = fadd double %8, 0.000000e+00
  %10 = fmul <2 x double> zeroinitializer, %3
  %11 = fadd <2 x double> zeroinitializer, %10
  br label %loop.69
}
```

Error message:

```
Instruction does not dominate all uses!
  %2 = insertelement <2 x double> <double poison, double 0.000000e+00>, double %c__fetch.3, i32 0
  %0 = shufflevector <2 x double> %2, <2 x double> <double 0.000000e+00, double poison>, <2 x i32> <i32 2, i32 0>
LLVM ERROR: Broken module found, compilation aborted!
```

Reverting the mentioned commit makes this test pass. @alexey-bataev could you please take a look?

Update: It appears that the mentioned commit merely obscures a more fundamental issue. The following test continues to fail even after the commit has been reverted:

```
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 @a_(double %c__fetch.3) {
alloca_0:
  %mul.3 = fmul double 0.000000e+00, %c__fetch.3
  %mul.4 = fmul double 0.000000e+00, 0.000000e+00
  br label %loop.69

loop.69:                                          ; preds = %loop.69, %alloca_0
  %t48.0 = phi double [ 0.000000e+00, %alloca_0 ], [ %5, %loop.69 ]
  %t50.02 = phi double [ 0.000000e+00, %alloca_0 ], [ %3, %loop.69 ]
  %t52.0 = phi double [ 0.000000e+00, %alloca_0 ], [ %7, %loop.69 ]
  %0 = fmul double %t52.0, %mul.3
  %1 = fmul double %t48.0, %mul.4
  %2 = fadd double %1, %0
  %3 = fadd double %2, %c__fetch.3
  %4 = fmul double 0.000000e+00, %mul.3
  %5 = fadd double 0.000000e+00, %4
  %6 = fmul double 0.000000e+00, %mul.4
  %7 = fadd double 0.000000e+00, %6
  br label %loop.69
}
```

It appears that the actual problematic commit is the following:

```
commit 66775f8ccdcc8264ef349518e1c59d96d4227823
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Mon Oct 16 12:50:29 2023 -0700

    [SLP]Fix PR69196: Instruction does not dominate all uses

    During emission of the postponed gathers, need to insert them before
    user instruction to avoid use before definition crash.
```
For compiler builds prior to this change, the test passes, and the correct code is generated as follows:
```
define void @a_(double %c__fetch.3) {
alloca_0:
  %0 = insertelement <2 x double> <double poison, double 0.000000e+00>, double %c__fetch.3, i32 0
  %1 = fmul <2 x double> zeroinitializer, %0
  %2 = shufflevector <2 x double> %0, <2 x double> <double 0.000000e+00, double poison>, <2 x i32> <i32 2, i32 0>
  %3 = fmul <2 x double> zeroinitializer, %2
  br label %loop.69

loop.69:                                          ; preds = %loop.69, %alloca_0
  %t50.02 = phi double [ 0.000000e+00, %alloca_0 ], [ %9, %loop.69 ]
  %4 = phi <2 x double> [ zeroinitializer, %alloca_0 ], [ %11, %loop.69 ]
  %5 = fmul <2 x double> %4, %3
  %6 = extractelement <2 x double> %5, i32 0
  %7 = extractelement <2 x double> %5, i32 1
  %8 = fadd double %6, %7
  %9 = fadd double %8, %c__fetch.3
  %10 = fmul <2 x double> zeroinitializer, %1
  %11 = fadd <2 x double> zeroinitializer, %10
  br label %loop.69
}
```

Although the commit may seem quite old, there is a test case for which it causes incorrect code generation. Alexey, could you please revisit this change and address the code generation issue for the provided test case?

> It appears that the actual problematic commit is the following:
>
> ```
> commit 66775f8ccdcc8264ef349518e1c59d96d4227823
> Author: Alexey Bataev <a.bataev@outlook.com>
> Date:   Mon Oct 16 12:50:29 2023 -0700
>
>     [SLP]Fix PR69196: Instruction does not dominate all uses
>
>     During emission of the postponed gathers, need to insert them before
>     user instruction to avoid use before definition crash.
> ```
>
> For compiler builds prior to this change, the test passes, and the correct code is generated as follows:
>
> ```
> define void @a_(double %c__fetch.3) {
> alloca_0:
>   %0 = insertelement <2 x double> <double poison, double 0.000000e+00>, double %c__fetch.3, i32 0
>   %1 = fmul <2 x double> zeroinitializer, %0
>   %2 = shufflevector <2 x double> %0, <2 x double> <double 0.000000e+00, double poison>, <2 x i32> <i32 2, i32 0>
>   %3 = fmul <2 x double> zeroinitializer, %2
>   br label %loop.69
>
> loop.69:                                          ; preds = %loop.69, %alloca_0
>   %t50.02 = phi double [ 0.000000e+00, %alloca_0 ], [ %9, %loop.69 ]
>   %4 = phi <2 x double> [ zeroinitializer, %alloca_0 ], [ %11, %loop.69 ]
>   %5 = fmul <2 x double> %4, %3
>   %6 = extractelement <2 x double> %5, i32 0
>   %7 = extractelement <2 x double> %5, i32 1
>   %8 = fadd double %6, %7
>   %9 = fadd double %8, %c__fetch.3
>   %10 = fmul <2 x double> zeroinitializer, %1
>   %11 = fadd <2 x double> zeroinitializer, %10
>   br label %loop.69
> }
> ```
>
> Although the commit may seem quite old, there is a test case for which it causes incorrect code generation. Alexey, could you please revisit this change and address the code generation issue for the provided test case?

The actual problem is not in this commit, the fix is almost ready


commit c546b5317c518987a5f45dd4c4d25321a955c758
Author: DianQK <dianqk@dianqk.net>
Date:   Fri Jan 24 23:02:50 2025 +0800

    [ValueTracking] Pass changed predicate `SignedLPred` to `isImpliedByMatchingCmp` (#124271)

    Fixes #124267.

    Since we are using the new predicate, we should also update the
    parameters of `isImpliedByMatchingCmp`.

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 264fedd6b66b..eba728c7c8c3 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9494,7 +9494,7 @@ isImpliedCondICmps(const ICmpInst *LHS, CmpPredicate RPred, const Value *R0,
        SignedLPred == ICmpInst::ICMP_SGE) &&
       match(R0, m_NSWSub(m_Specific(L0), m_Specific(L1)))) {
     if (match(R1, m_NonPositive()) &&
-        ICmpInst::isImpliedByMatchingCmp(LPred, RPred) == false)
+        ICmpInst::isImpliedByMatchingCmp(SignedLPred, RPred) == false)
       return false;
   }

@@ -9504,7 +9504,7 @@ isImpliedCondICmps(const ICmpInst *LHS, CmpPredicate RPred, const Value *R0,
        SignedLPred == ICmpInst::ICMP_SLE) &&
       match(R0, m_NSWSub(m_Specific(L0), m_Specific(L1)))) {
     if (match(R1, m_NonNegative()) &&
-        ICmpInst::isImpliedByMatchingCmp(LPred, RPred) == true)
+        ICmpInst::isImpliedByMatchingCmp(SignedLPred, RPred) == true)
       return true;
   }

define i1 @gt_sub_nsw_ult(i8 %L0, i8 %L1, i1 %V) {
  %LHS = icmp samesign ugt i8 %L0, %L1
  br i1 %LHS, label %LHS_true, label %LHS_false

LHS_true:                                         ; preds = %0
  %R0 = sub nsw i8 %L0, %L1
  %RHS = icmp ult i8 %R0, -1
  ret i1 %RHS

LHS_false:                                        ; preds = %0
  ret i1 %V
}

define i1 @lt_sub_nsw_ult(i8 %L0, i8 %L1, i1 %V) {
  %LHS = icmp samesign ult i8 %L0, %L1
  br i1 %LHS, label %LHS_true, label %LHS_false

LHS_true:                                         ; preds = %0
  %R0 = sub nsw i8 %L0, %L1
  %RHS = icmp ult i8 %R0, 1
  ret i1 %RHS

LHS_false:                                        ; preds = %0
  ret i1 %V
}

[ValueTracking] miscompile in samesign compare

#122590 and #122700 miscompile the following code:

```llvm
define i1 @src(i8 %L0, i8 %L1, i1 %V) {
  %LHS = icmp samesign ugt i8 %L0, %L1
  %R0 = sub nsw i8 %L0, %L1
  %RHS = icmp ult i8 %R0, -1
  br i1 %LHS, label %LHS_true, label %LHS_false

LHS_true:
  br label %EXIT

LHS_false:
  br label %EXIT

EXIT:
  %RET = phi i1 [ %RHS, %LHS_true ], [ %V, %LHS_false ]
  ret i1 %RET
}
```

`%RHS` should be 1: https://alive2.llvm.org/ce/z/RscAzy.


commit a37dbc1f51c70d92fd209c2e52a9d794eb15e4e7
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon Jan 6 00:04:28 2025 +0800

    [InstCombine] Drop noundef in `foldSelectCttzCtlz` (#121692)

    Close https://github.com/llvm/llvm-project/issues/121428

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index e7a8e947705f..a18b927678ef 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1225,8 +1225,12 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
   // zext/trunc) have one use (ending at the select), the cttz/ctlz result will
   // not be used if the input is zero. Relax to 'zero is poison' for that case.
   if (II->hasOneUse() && SelectArg->hasOneUse() &&
-      !match(II->getArgOperand(1), m_One()))
+      !match(II->getArgOperand(1), m_One())) {
     II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));
+    // noundef attribute on the intrinsic may no longer be valid.
+    II->dropUBImplyingAttrsAndMetadata();
+    IC.addToWorklist(II);
+  }

   return nullptr;
 }

define i32 @test_cttz_not_bw_multiuse(i32 %x) {
  %ct = tail call i32 @llvm.cttz.i32(i32 %x, i1 false)
  %cmp = icmp ne i32 %x, 0
  %sel = select i1 %cmp, i32 %ct, i32 123
  %res = or i32 %sel, %ct
  ret i32 %res
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.cttz.i32(i32, i1 immarg) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

define i32 @test_cttz_not_bw(i32 %x) {
  %ct = tail call i32 @llvm.cttz.i32(i32 %x, i1 false)
  %cmp = icmp ne i32 %x, 0
  %res = select i1 %cmp, i32 %ct, i32 123
  ret i32 %res
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.cttz.i32(i32, i1 immarg) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

define i32 @test_cttz_not_bw_noundef(i32 %x) {
  %ct = tail call noundef i32 @llvm.cttz.i32(i32 %x, i1 false)
  %cmp = icmp ne i32 %x, 0
  %res = select i1 %cmp, i32 %ct, i32 123
  ret i32 %res
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.cttz.i32(i32, i1 immarg) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

[InstCombine] `noundef` attribute should be dropped

Alive2: https://alive2.llvm.org/ce/z/wKsUWK
```
define i32 @src(i32 noundef %x) {
  %ct = call noundef i32 @llvm.cttz.i32(i32 %x, i1 false)
  %cmp = icmp ne i32 %x, 0
  %res = select i1 %cmp, i32 %ct, i32 123
  ret i32 %res
}
define i32 @tgt(i32 noundef %x) {
  %ct = call noundef range(i32 0, 33) i32 @llvm.cttz.i32(i32 %x, i1 true)
  %cmp.not = icmp eq i32 %x, 0
  %res = select i1 %cmp.not, i32 123, i32 %ct
  ret i32 %res
}
```