Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp: InstCombinerImpl::foldICmpTruncWithTruncOrExt
Issue title: [InstCombine] Miscompilation which converts `icmp eq (trunc nsw i64 X), (trunc nsw i32 Y)` into `icmp eq (zext i32 Y), X`
Labels: miscompilation
llvm:instcombine
Reported by: dtcxzyw

Reduced test case: https://alive2.llvm.org/ce/z/MLgA5x
```
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 @src() {
entry:
  br label %for.cond

for.cond:                                         ; preds = %if.end, %entry
  %storemerge = phi i32 [ 3, %entry ], [ %dec, %if.end ]
  %h = phi i32 [ 1, %entry ], [ %hres, %if.end ]
  %e = phi i32 [ 0, %entry ], [ -1, %if.end ]
  %tobool.not = icmp eq i32 %storemerge, 0
  br i1 %tobool.not, label %for.end9, label %for.body

for.body:                                         ; preds = %for.cond
  %cmp = icmp eq i32 %h, 5
  %conv1 = zext i1 %cmp to i64
  %conv2 = sext i32 %e to i64
  %cond.i = call i64 @llvm.umax.i64(i64 %conv1, i64 %conv2)
  %conv3 = trunc nsw i64 %cond.i to i16
  %conv4 = trunc nsw i32 %e to i16
  %sub.i = sub i16 %conv3, %conv4
  %tobool6.not = icmp eq i16 %sub.i, 0
  br i1 %tobool6.not, label %if.end, label %if.then

if.then:                                          ; preds = %for.body
  br label %if.end

if.end:                                           ; preds = %if.then, %for.body
  %hres = phi i32 [ 0, %if.then ], [ %h, %for.body ]
  %dec = add nsw i32 %storemerge, -1
  br label %for.cond

for.end9:                                         ; preds = %for.cond
  ret i32 %h
}

define i32 @tgt() {
entry:
  br label %for.cond

for.cond:                                         ; preds = %if.end, %entry
  %storemerge = phi i32 [ 3, %entry ], [ %dec, %if.end ]
  %h = phi i32 [ 1, %entry ], [ %hres, %if.end ]
  %e = phi i32 [ 0, %entry ], [ -1, %if.end ]
  %tobool.not = icmp eq i32 %storemerge, 0
  br i1 %tobool.not, label %for.end9, label %for.body

for.body:                                         ; preds = %for.cond
  %cmp = icmp eq i32 %h, 5
  %conv1 = zext i1 %cmp to i64
  %conv2 = sext i32 %e to i64
  %cond.i = call i64 @llvm.umax.i64(i64 %conv1, i64 %conv2)
  %0 = zext i32 %e to i64
  %tobool6.not = icmp eq i64 %cond.i, %0
  br i1 %tobool6.not, label %if.end, label %if.then

if.then:                                          ; preds = %for.body
  br label %if.end

if.end:                                           ; preds = %if.then, %for.body
  %hres = phi i32 [ 0, %if.then ], [ %h, %for.body ]
  %dec = add nsw i32 %storemerge, -1
  br label %for.cond

for.end9:                                         ; preds = %for.cond
  ret i32 %h
}
```

llvm version: de9b386f84b58ad0ffc12e221bc6d9161ca5b62d

Comments: author: dtcxzyw
body: Reduced test case: https://alive2.llvm.org/ce/z/ndR8PQ
```
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 i1 @src(i64 %x, i32 %y) {
  %conv1 = trunc nsw i64 %x to i16
  %conv2 = trunc nsw i32 %y to i16
  %cond = icmp eq i16 %conv1, %conv2
  ret i1 %cond
}

define i1 @tgt(i64 %x, i32 %y) {
  %1 = zext i32 %y to i64
  %cond = icmp eq i64 %1, %x
  ret i1 %cond
}
```

It should be caused by https://github.com/llvm/llvm-project/pull/90436.

I will post a fix later. cc @nikic

author: dtcxzyw
body: POC without DataLayout:
```
define i1 @test_eq(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp eq i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_ult(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp ult i8 %conv1, %conv2
  ret i1 %cond
}

define i1 @test_slt(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp slt i8 %conv1, %conv2
  ret i1 %cond
}
```

Fix patch:
commit d3dad7a74be50d90754bf5c072e1a2330e92712c
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon May 6 16:30:07 2024 +0800

    [InstCombine] Fix miscompilation caused by #90436 (#91133)
    
    Proof: https://alive2.llvm.org/ce/z/iRnJ4i
    
    Fixes https://github.com/llvm/llvm-project/issues/91127.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c60a290ce72e..7092fb5e509b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1510,6 +1510,7 @@ InstCombinerImpl::foldICmpTruncWithTruncOrExt(ICmpInst &Cmp,
       std::swap(X, Y);
       Pred = Cmp.getSwappedPredicate(Pred);
     }
+    YIsSExt = !(NoWrapFlags & TruncInst::NoUnsignedWrap);
   }
   // Try to match icmp (trunc nuw X), (zext Y)
   else if (!Cmp.isSigned() &&


Regression tests:
file: llvm/test/Transforms/InstCombine/icmp-of-trunc-ext.ll
commands: opt -S -passes=instcombine < %s
tests: test_name: trunc_equality_both_sext
test_body: define i1 @trunc_equality_both_sext(i32 %x, i8 %y) {
  %xt = trunc nuw nsw i32 %x to i16
  %ye = sext i8 %y to i16
  %c = icmp ne i16 %xt, %ye
  ret i1 %c
}

test_name: test_slt_nuw
test_body: define i1 @test_slt_nuw(i32 %x, i16 %y) {
  %conv1 = trunc nuw nsw i32 %x to i8
  %conv2 = trunc nuw nsw i16 %y to i8
  %cond = icmp slt i8 %conv1, %conv2
  ret i1 %cond
}

test_name: test_slt
test_body: define i1 @test_slt(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp slt i8 %conv1, %conv2
  ret i1 %cond
}

test_name: test_ult_nuw
test_body: define i1 @test_ult_nuw(i32 %x, i16 %y) {
  %conv1 = trunc nuw nsw i32 %x to i8
  %conv2 = trunc nuw nsw i16 %y to i8
  %cond = icmp ult i8 %conv1, %conv2
  ret i1 %cond
}

test_name: test_ult
test_body: define i1 @test_ult(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp ult i8 %conv1, %conv2
  ret i1 %cond
}

test_name: test_eq1
test_body: define i1 @test_eq1(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp eq i8 %conv1, %conv2
  ret i1 %cond
}

test_name: test_eq2
test_body: define i1 @test_eq2(i32 %x, i16 %y) {
  %conv1 = trunc nsw i32 %x to i8
  %conv2 = trunc nsw i16 %y to i8
  %cond = icmp eq i8 %conv2, %conv1
  ret i1 %cond
}