Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::getInstructionCost
LoopVectorizationCostModel::shouldConsiderInvariant
Issue title: [clang] Segmentation fault in loop vectorization cost model during optimization pass
Labels: regression
vectorizers
crash
Reported by: cardigan1008

When I compiled this code with -O2 flag, it crashed:

```c
#include <stdint.h>
#define UNDEFINED(x) ((x), 0)
long b;
static int64_t j = 1;
static int64_t *k = &j;
static int64_t **l = &k;
int64_t m;
static uint64_t n;
int16_t ***o;
static int64_t ***p = &l;
uint64_t **q;

uint16_t
safe_mod_func_uint16_t_u_u(uint16_t ui1, uint16_t ui2)
{
  return 
#ifndef UNSAFE
    (ui2 == 0) ? 
    (UNDEFINED(ui1)) : 
#endif
    (ui1 % ui2);
}

int64_t
safe_mod_func_int64_t_s_s(int64_t si1, int64_t si2)
{
  return 
#ifndef UNSAFE
    ((si2 == 0) || ((si1 == INT64_MIN) && (si2 == (-1)))) ? 
    (UNDEFINED(si1)) : 
#endif
    (si1 % si2);
}

int a(int, int, int, int, int) {}
long c(int d, int *e) {
  switch (d) {
  case 9:
    return b;
  case 8:
    return *e;
  }
}
long f(int g, long, int h) {
  long i = c(g, &h);
  return i;
}
int32_t r() { int32_t *s[] = {&k, &m}; }
int32_t t(int32_t *aa) {
  uint64_t ab = 2599693332;
  uint8_t ac = 142;
  for (; n <= 4; n++)
    *aa = (safe_mod_func_uint16_t_u_u(
               safe_mod_func_int64_t_s_s(a(0, 0, 0, 0, **l + 20) + **l, **q),
               ***o |= f(**l, 0, ***p)),
           **l + ac + ab - -1695273821 + *aa);
}
```

The crash is: clang: error: unable to execute command: Segmentation fault (core dumped)
clang: error: clang frontend command failed due to signal (use -v to see invocation)
Compiler returned: 254

Details can be found here: https://godbolt.org/z/3h9j7W6dG

Comments: author: shafik
body: This looks like a clang trunk regression: https://godbolt.org/z/MoKeds3ev

Fix patch:
commit 17bad1a9da228ade0c0b9b020ee99769b188d9b3
Author: Florian Hahn <flo@fhahn.com>
Date:   Fri Nov 1 20:51:25 2024 +0000

    [LV] Bail out on header phis in shouldConsiderInvariant.
    
    This fixes an infinite recursion in rare cases.
    
    Fixes https://github.com/llvm/llvm-project/issues/113794.

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 659b4c30a58a..1c64bd2982d7 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -6389,9 +6389,11 @@ bool LoopVectorizationCostModel::shouldConsiderInvariant(Value *Op) {
     return false;
   // Consider Op invariant, if it or its operands aren't predicated
   // instruction in the loop. In that case, it is not trivially hoistable.
-  return !isa<Instruction>(Op) || !TheLoop->contains(cast<Instruction>(Op)) ||
-         (!isPredicatedInst(cast<Instruction>(Op)) &&
-          all_of(cast<Instruction>(Op)->operands(),
+  auto *OpI = dyn_cast<Instruction>(Op);
+  return !OpI || !TheLoop->contains(OpI) ||
+         (!isPredicatedInst(OpI) &&
+          (!isa<PHINode>(OpI) || OpI->getParent() != TheLoop->getHeader()) &&
+          all_of(OpI->operands(),
                  [this](Value *Op) { return shouldConsiderInvariant(Op); }));
 }
 


Regression tests:
file: llvm/test/Transforms/LoopVectorize/phi-cost.ll
commands: opt < %s -passes='function(loop-vectorize,instcombine)' -force-vector-width=2 -force-vector-interleave=1 -debug-only=loop-vectorize -disable-output -print-after=instcombine 2>&1
tests: test_name: red_phi_0
test_body: target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"

define i32 @red_phi_0(i32 %start, ptr %src) {
entry:
  br label %loop

loop:                                             ; preds = %loop, %entry
  %red = phi i32 [ %start, %entry ], [ %red.next, %loop ]
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %red.next = add i32 0, %red
  %iv.next = add i64 %iv, 1
  %exitcond.not = icmp eq i64 %iv.next, 100
  br i1 %exitcond.not, label %exit, label %loop

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

test_name: phi_three_incoming_values
test_body: target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"

define void @phi_three_incoming_values(ptr noalias %a, ptr noalias %b, i64 %n) {
entry:
  br label %for.body

for.body:                                         ; preds = %if.end, %entry
  %i = phi i64 [ %i.next, %if.end ], [ 0, %entry ]
  %tmp0 = getelementptr inbounds i32, ptr %a, i64 %i
  %tmp1 = load i32, ptr %tmp0, align 4
  %tmp2 = getelementptr inbounds i32, ptr %b, i64 %i
  %tmp3 = load i32, ptr %tmp2, align 4
  %tmp4 = icmp sgt i32 %tmp1, %tmp3
  br i1 %tmp4, label %if.then, label %if.end

if.then:                                          ; preds = %for.body
  %tmp5 = icmp sgt i32 %tmp1, 19
  br i1 %tmp5, label %if.end, label %if.else

if.else:                                          ; preds = %if.then
  %tmp6 = icmp slt i32 %tmp3, 4
  %tmp7 = select i1 %tmp6, i32 4, i32 5
  br label %if.end

if.end:                                           ; preds = %if.else, %if.then, %for.body
  %tmp8 = phi i32 [ 9, %for.body ], [ 3, %if.then ], [ %tmp7, %if.else ]
  store i32 %tmp8, ptr %tmp0, align 4
  %i.next = add i64 %i, 1
  %cond = icmp eq i64 %i, %n
  br i1 %cond, label %for.end, label %for.body

for.end:                                          ; preds = %if.end
  ret void
}

test_name: phi_two_incoming_values
test_body: target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"

define void @phi_two_incoming_values(ptr noalias %a, ptr noalias %b, i64 %n) {
entry:
  br label %for.body

for.body:                                         ; preds = %if.end, %entry
  %i = phi i64 [ %i.next, %if.end ], [ 0, %entry ]
  %tmp0 = getelementptr inbounds i32, ptr %a, i64 %i
  %tmp1 = load i32, ptr %tmp0, align 4
  %tmp2 = getelementptr inbounds i32, ptr %b, i64 %i
  %tmp3 = icmp sgt i32 %tmp1, 0
  br i1 %tmp3, label %if.then, label %if.end

if.then:                                          ; preds = %for.body
  %tmp4 = add i32 %tmp1, 1
  br label %if.end

if.end:                                           ; preds = %if.then, %for.body
  %tmp5 = phi i32 [ %tmp1, %for.body ], [ %tmp4, %if.then ]
  store i32 %tmp5, ptr %tmp2, align 4
  %i.next = add i64 %i, 1
  %cond = icmp eq i64 %i, %n
  br i1 %cond, label %for.end, label %for.body

for.end:                                          ; preds = %if.end
  ret void
}