Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp: InstCombinerImpl::foldPHIArgGEPIntoPHI
Issue title: [clang] Miscompile with -O3 and -O0/1/2 since 18.1.0
Labels: miscompilation
llvm:instcombine
Reported by: cardigan1008

When I compiled this code with -O0/1/2, its output is 0. However, with -O3, it returned 143:

```c
int printf(const char *, ...);
char a, b;
int c;
char *e = &b;
int f(char *g, int *k) {
  char *d = g + *k;
  for (; *d && *d <= ' '; d++)
    ;
  if (*d)
    return 0;
  return 1;
}
int l(int g) {
  char h[] = {a, a, a};
  int i[] = {g};
  int j = f(h, i);
  return j;
}
long m() {
  *e = 255;
  for (; l(b + 1);)
    return 0;
  for (;;)
    ;
}
int main() {
  m();
  printf("%d\n", c);
}
```

Details can be found here: https://godbolt.org/z/dnvvTPror

Comments: author: antoniofrighetto
body: This looks like a nasty one. Getting the optimized IR via -O3 and setting noinline/optnone to main, we get: https://llvm.godbolt.org/z/vaPvs6d16. 

This is the initial assembly output with -O1 (which leads to the infinite loop):

```asm
main:                                   # @main
        push    rax
        mov     rax, qword ptr [e]
        mov     byte ptr [rax], -1
        movsx   rax, byte ptr [b]
        mov     cl, byte ptr [a]
        mov     byte ptr [rsp + 6], cl
        mov     byte ptr [rsp + 7], cl
        lea     rdx, [rsp + 5]
        add     rdx, rax
        mov     rax, rdx
.LBB0_1:                                # %for.cond.i.i.i
        add     rax, 1
        mov     cl, byte ptr [rdx + 1]
        ...
```
Whereas this is with -O0 (returns 0):
```asm
main:                                   # @main
        sub     rsp, 24
        mov     rax, qword ptr [e]
        mov     byte ptr [rax], -1
        movsx   rcx, byte ptr [b]
        mov     al, byte ptr [a]
        mov     byte ptr [rsp + 22], al
        mov     byte ptr [rsp + 23], al
        lea     rax, [rsp + 21]
        add     rax, rcx
        mov     qword ptr [rsp + 8], rax        # 8-byte Spill
.LBB0_1:                                # %for.cond.i.i.i
        mov     rcx, qword ptr [rsp + 8]        # 8-byte Reload
        mov     rax, rcx
        add     rax, 1
        mov     dl, byte ptr [rcx + 1]
```
In the optimized one, $rdx is set to point to $rsp+0x5, part of the stack slot containing $rax (undef), later dereferenced to set the condition leading to the loop. Initially I thought some bug in regalloc, but to me it seems more something in prologepiloginserter. Function prologue / epilogue seems set up correctly with triple arm64-apple-macosx.
author: antoniofrighetto
body: Looking at the IR better, it seems like InstCombine performs a wrong optimization immediately after inlining `l` into `m`, probably related with default argument conversion done by operator + (which should include integer promotion on types smaller than integer). Alive2 seems to confirm it: https://alive2.llvm.org/ce/z/XAzrip.
author: antoniofrighetto
body: Reduced to:
```llvm
@a = global i8 0, align 1

define i64 @src(i8 noundef %arg) {
entry:
  %h.i = alloca [3 x i8], align 1
  %conv = sext i8 %arg to i32
  %add = add nsw i32 %conv, 1
  %2 = load i8, ptr @a, align 1
  store i8 %2, ptr %h.i, align 1
  %idx.ext.i.i = sext i32 %add to i64
  %add.ptr.i.i = getelementptr inbounds i8, ptr %h.i, i64 %idx.ext.i.i
  br label %for.cond.i.i

for.cond.i.i:                                     ; preds = %for.cond.i.i, %entry
  %d.0.i.i = phi ptr [ %add.ptr.i.i, %entry ], [ %incdec.ptr.i.i, %for.cond.i.i ]
  %3 = load i8, ptr %d.0.i.i, align 1
  %tobool.not.i.i = icmp ne i8 %3, 0
  %incdec.ptr.i.i = getelementptr inbounds nuw i8, ptr %d.0.i.i, i64 1
  br i1 %tobool.not.i.i, label %for.cond.i.i, label %l.exit

l.exit:                                           ; preds = %for.cond.i.i
  ret i64 0
}
```
Wrong sext of add of sext simplified to sext leads to wrong gep offset: https://alive2.llvm.org/ce/z/JaR4j9.
author: AZero13
body: Can we backport this to 19.x?
author: antoniofrighetto
body: Should be fixed in 929cbe7f596733f85cd274485acc19442dd34a80, thanks for reporting!
author: AZero13
body: @antoniofrighetto can we please backport this 

Fix patch:
commit 929cbe7f596733f85cd274485acc19442dd34a80
Author: Antonio Frighetto <me@antoniofrighetto.com>
Date:   Tue Nov 12 19:02:04 2024 +0100

    [InstCombine] Intersect nowrap flags between geps while folding into phi
    
    A miscompilation issue has been addressed with refined checking.
    
    Fixes: https://github.com/llvm/llvm-project/issues/115149.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index cb5c44730512..1fcf1c570add 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -545,7 +545,8 @@ Instruction *InstCombinerImpl::foldPHIArgGEPIntoPHI(PHINode &PN) {
   // especially bad when the PHIs are in the header of a loop.
   bool NeededPhi = false;
 
-  GEPNoWrapFlags NW = GEPNoWrapFlags::all();
+  // Remember flags of the first phi-operand getelementptr.
+  GEPNoWrapFlags NW = FirstInst->getNoWrapFlags();
 
   // Scan to see if all operands are the same opcode, and all have one user.
   for (Value *V : drop_begin(PN.incoming_values())) {


Regression tests:
file: llvm/test/Transforms/InstCombine/opaque-ptr.ll
commands: opt -S -passes=instcombine < %s
tests: test_name: phi_of_gep_flags_1
test_body: define ptr @phi_of_gep_flags_1(i1 %c, ptr %p) {
  br i1 %c, label %if, label %else

if:                                               ; preds = %0
  %gep1 = getelementptr inbounds i32, ptr %p, i64 1
  br label %join

else:                                             ; preds = %0
  %gep2 = getelementptr nusw nuw i32, ptr %p, i64 1
  br label %join

join:                                             ; preds = %else, %if
  %phi = phi ptr [ %gep1, %if ], [ %gep2, %else ]
  ret ptr %phi
}

file: llvm/test/Transforms/InstCombine/phi.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: wrong_gep_arg_into_phi
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"

define i64 @wrong_gep_arg_into_phi(ptr noundef %ptr) {
entry:
  %add.ptr = getelementptr i8, ptr %ptr, i64 1
  br label %for.cond

for.cond:                                         ; preds = %for.cond, %entry
  %.pn = phi ptr [ %add.ptr, %entry ], [ %incdec.ptr, %for.cond ]
  %val = load i8, ptr %.pn, align 1
  %cond = icmp ne i8 %val, 0
  %incdec.ptr = getelementptr inbounds nuw i8, ptr %.pn, i64 1
  br i1 %cond, label %for.cond, label %exit

exit:                                             ; preds = %for.cond
  ret i64 0
}