Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: getCost
Issue title: Unhandled  Floating point exception with loop-vectorize 
Labels: vectorizers
crash-on-valid
Reported by: TatyanaDoubts

Run opt with -passes=loop-vectorize 

https://godbolt.org/z/s3PWY3vhE

Test.ll
```
; ModuleID = './reduced.ll'
source_filename = "./reduced.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 ptr addrspace(1) @wombat(i64 %arg, ptr addrspace(1) %arg1) gc "statepoint-example" {
bb:
  br label %bb2

bb2:                                              ; preds = %bb4, %bb
  br label %bb3

bb3:                                              ; preds = %bb3, %bb2
  %phi = phi i64 [ 0, %bb2 ], [ %add, %bb3 ]
  %add = add i64 %phi, 1
  %load = load i8, ptr addrspace(1) %arg1, align 1
  %shl = shl i64 0, 0
  store i16 0, ptr addrspace(1) null, align 2
  %icmp = icmp ult i64 %phi, %arg
  br i1 %icmp, label %bb3, label %bb4

bb4:                                              ; preds = %bb3
  br i1 false, label %bb5, label %bb2, !prof !0

bb5:                                              ; preds = %bb4
  ret ptr addrspace(1) null
}

!0 = !{!"branch_weights", i32 1, i32 -1}
```

Comments: author: DaniilSuchkov
body: It started failing after 962fbafecf4730ba84a3b9fd7a662a5c30bb2c7c
```
Author: David Sherwood <57997763+david-arm@users.noreply.github.com>
Date:   Fri Jan 26 14:43:48 2024 +0000

    [LoopVectorize] Refine runtime memory check costs when there is an outer loop (#76034)

    When we generate runtime memory checks for an inner loop it's
    possible that these checks are invariant in the outer loop and
    so will get hoisted out. In such cases, the effective cost of
    the checks should reduce to reflect the outer loop trip count.

    This fixes a 25% performance regression introduced by commit

    49b0e6dcc296792b577ae8f0f674e61a0929b99d

    when building the SPEC2017 x264 benchmark with PGO, where we
    decided the inner loop trip count wasn't high enough to warrant
    the (incorrect) high cost of the runtime checks. Also, when
    runtime memory checks consist entirely of diff checks these are
    likely to be outer loop invariant.
```
We have a division by 0 here https://github.com/llvm/llvm-project/commit/962fbafecf4730ba84a3b9fd7a662a5c30bb2c7c#diff-da321d454a7246f8ae276bf1db2782bf26b5210b8133cb59e4d7fd45d0905decR2114 because `getLoopEstimatedTripCount(OuterLoop)` just above that line returns 0.
author: david-arm
body: OK thanks for raising this issue - I'll take a look this morning!
author: david-arm
body: I have a fix in review - https://github.com/llvm/llvm-project/pull/81721

Fix patch:
commit 1c10821022f1799452065fb57474e894e2562b7f
Author: David Sherwood <57997763+david-arm@users.noreply.github.com>
Date:   Wed Feb 14 16:07:51 2024 +0000

    [LoopVectorize] Fix divide-by-zero bug (#80836) (#81721)
    
    When attempting to use the estimated trip count to refine the costs of
    the runtime memory checks we should also check for sane trip counts to
    prevent divide-by-zero faults on some platforms.
    
    Fixes #80836

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index b39bf21cacdb..98b177cf5d2d 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -2010,16 +2010,18 @@ public:
               BestTripCount = *EstimatedTC;
           }
 
+          BestTripCount = std::max(BestTripCount, 1U);
           InstructionCost NewMemCheckCost = MemCheckCost / BestTripCount;
 
           // Let's ensure the cost is always at least 1.
           NewMemCheckCost = std::max(*NewMemCheckCost.getValue(),
                                      (InstructionCost::CostType)1);
 
-          LLVM_DEBUG(dbgs()
-                     << "We expect runtime memory checks to be hoisted "
-                     << "out of the outer loop. Cost reduced from "
-                     << MemCheckCost << " to " << NewMemCheckCost << '\n');
+          if (BestTripCount > 1)
+            LLVM_DEBUG(dbgs()
+                       << "We expect runtime memory checks to be hoisted "
+                       << "out of the outer loop. Cost reduced from "
+                       << MemCheckCost << " to " << NewMemCheckCost << '\n');
 
           MemCheckCost = NewMemCheckCost;
         }


Regression tests:
file: llvm/test/Transforms/LoopVectorize/AArch64/low_trip_memcheck_cost.ll
commands: opt -p loop-vectorize -debug-only=loop-vectorize -S -disable-output < %s 2>&1
tests: test_name: outer_known_tc3_full_range_checks
test_body: target triple = "aarch64-unknown-linux-gnu"

define void @outer_known_tc3_full_range_checks(ptr nocapture noundef %dst, ptr nocapture noundef readonly %src, i64 noundef %n) {
entry:
  br label %outer.loop

outer.loop:                                       ; preds = %inner.exit, %entry
  %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %inner.exit ]
  %0 = mul nsw i64 %outer.iv, %n
  br label %inner.loop

inner.loop:                                       ; preds = %inner.loop, %outer.loop
  %iv.inner = phi i64 [ 0, %outer.loop ], [ %iv.inner.next, %inner.loop ]
  %1 = add nuw nsw i64 %iv.inner, %0
  %arrayidx.us = getelementptr inbounds i32, ptr %src, i64 %1
  %2 = load i32, ptr %arrayidx.us, align 4
  %arrayidx8.us = getelementptr inbounds i32, ptr %dst, i64 %1
  %3 = load i32, ptr %arrayidx8.us, align 4
  %add9.us = add nsw i32 %3, %2
  store i32 %add9.us, ptr %arrayidx8.us, align 4
  %iv.inner.next = add nuw nsw i64 %iv.inner, 1
  %inner.exit.cond = icmp eq i64 %iv.inner.next, %n
  br i1 %inner.exit.cond, label %inner.exit, label %inner.loop

inner.exit:                                       ; preds = %inner.loop
  %outer.iv.next = add nuw nsw i64 %outer.iv, 1
  %outer.exit.cond = icmp eq i64 %outer.iv.next, 3
  br i1 %outer.exit.cond, label %outer.exit, label %outer.loop

outer.exit:                                       ; preds = %inner.exit
  ret void
}

test_name: outer_pgo_minus1
test_body: target triple = "aarch64-unknown-linux-gnu"

define void @outer_pgo_minus1(ptr nocapture noundef %a, ptr nocapture noundef readonly %b, i64 noundef %m, i64 noundef %n) {
entry:
  br label %outer.loop

outer.loop:                                       ; preds = %inner.exit, %entry
  %outer.iv = phi i64 [ %outer.iv.next, %inner.exit ], [ 0, %entry ]
  %mul.us = mul nsw i64 %outer.iv, %n
  br label %inner.loop

inner.loop:                                       ; preds = %inner.loop, %outer.loop
  %inner.iv = phi i64 [ 0, %outer.loop ], [ %inner.iv.next, %inner.loop ]
  %add.us = add nuw nsw i64 %inner.iv, %mul.us
  %arrayidx.us = getelementptr inbounds i8, ptr %b, i64 %add.us
  %0 = load i8, ptr %arrayidx.us, align 1
  %arrayidx7.us = getelementptr inbounds i8, ptr %a, i64 %add.us
  %1 = load i8, ptr %arrayidx7.us, align 1
  %add9.us = add i8 %1, %0
  store i8 %add9.us, ptr %arrayidx7.us, align 1
  %inner.iv.next = add nuw nsw i64 %inner.iv, 1
  %exitcond.not = icmp eq i64 %inner.iv.next, %n
  br i1 %exitcond.not, label %inner.exit, label %inner.loop

inner.exit:                                       ; preds = %inner.loop
  %outer.iv.next = add nuw nsw i64 %outer.iv, 1
  %exitcond26.not = icmp eq i64 %outer.iv.next, %m
  br i1 %exitcond26.not, label %outer.exit, label %outer.loop, !prof !0

outer.exit:                                       ; preds = %inner.exit
  ret void
}

!0 = !{!"branch_weights", i32 1, i32 -1}