[llvm] [InstCombine] Preserve no wrap kinds for trunc in EvaluateInDifferentType (PR #202233)
Andreas Jonson via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 09:15:41 PDT 2026
https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/202233
>From d05a40df015148b3de1cc38dd66d889a2bc30af8 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 7 Jun 2026 21:32:53 +0200
Subject: [PATCH 1/3] [InstCombine] Precommit test (NFC)
---
llvm/test/Transforms/InstCombine/trunc.ll | 47 +++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index 54f1dac770f85..8984f4a292d20 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1273,3 +1273,50 @@ define i1 @neg_trunc_i1_usub_sat_one_multi_use(i8 %x) {
call void @use.i8(i8 %call)
ret i1 %trunc
}
+
+define i32 @zext_i32_trunc_nuw_i8(i16 %x, i32 %y) {
+; CHECK-LABEL: @zext_i32_trunc_nuw_i8(
+; CHECK-NEXT: [[TRUNC1:%.*]] = zext i16 [[X:%.*]] to i32
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[TRUNC1]]
+; CHECK-NEXT: [[E:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT: ret i32 [[E]]
+;
+ %trunc1 = trunc nuw i16 %x to i8
+ %trunc2 = trunc i32 %y to i8
+ %or = or i8 %trunc1, %trunc2
+ %e = zext i8 %or to i32
+ ret i32 %e
+}
+
+define i16 @zext_i16_trunc_nuw_nsw_i8(i32 %x) {
+; CHECK-LABEL: @zext_i16_trunc_nuw_nsw_i8(
+; CHECK-NEXT: [[C:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[E:%.*]] = and i16 [[C]], 255
+; CHECK-NEXT: ret i16 [[E]]
+;
+ %c = trunc nuw nsw i32 %x to i8
+ %e = zext i8 %c to i16
+ ret i16 %e
+}
+
+define i16 @zext_i16_trunc_nsw_i8(i32 %x) {
+; CHECK-LABEL: @zext_i16_trunc_nsw_i8(
+; CHECK-NEXT: [[C:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[E:%.*]] = and i16 [[C]], 255
+; CHECK-NEXT: ret i16 [[E]]
+;
+ %c = trunc nsw i32 %x to i8
+ %e = zext i8 %c to i16
+ ret i16 %e
+}
+
+define i16 @zext_i16_trunc_nuw_i8(i32 %x) {
+; CHECK-LABEL: @zext_i16_trunc_nuw_i8(
+; CHECK-NEXT: [[C:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[E:%.*]] = and i16 [[C]], 255
+; CHECK-NEXT: ret i16 [[E]]
+;
+ %c = trunc nuw i32 %x to i8
+ %e = zext i8 %c to i16
+ ret i16 %e
+}
>From f3db7834d5465cdda705e98f856e01ebaa25fb70 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 7 Jun 2026 21:35:38 +0200
Subject: [PATCH 2/3] [InstCombine] Preserve no wrap kinds for trunc
---
.../Transforms/InstCombine/InstCombineCasts.cpp | 14 ++++++++++++++
llvm/test/Transforms/InstCombine/trunc.ll | 8 ++++----
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index ca42263f47fa6..a1d5c339e4d85 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -86,6 +86,20 @@ static Value *EvaluateInDifferentTypeImpl(Value *V, Type *Ty, bool isSigned,
// This also handles the case of zext(trunc(x)) -> zext(x).
Res = CastInst::CreateIntegerCast(I->getOperand(0), Ty,
Opc == Instruction::SExt);
+ if (auto *Trunc = dyn_cast<TruncInst>(I)) {
+ if (auto *NewTrunc = dyn_cast<TruncInst>(Res)) {
+ if (Trunc->getType()->getScalarSizeInBits() <=
+ Ty->getScalarSizeInBits()) {
+ if (Trunc->hasNoSignedWrap())
+ NewTrunc->setHasNoSignedWrap(true);
+ if (Trunc->hasNoUnsignedWrap())
+ NewTrunc->setHasNoUnsignedWrap(true);
+ }
+ } else if (auto *NewZExt = dyn_cast<ZExtInst>(Res)) {
+ if (Trunc->hasNoUnsignedWrap())
+ NewZExt->setNonNeg();
+ }
+ }
break;
case Instruction::Select: {
Value *True = EvaluateInDifferentTypeImpl(I->getOperand(1), Ty, isSigned,
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index 8984f4a292d20..d03cb571b6452 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1276,7 +1276,7 @@ define i1 @neg_trunc_i1_usub_sat_one_multi_use(i8 %x) {
define i32 @zext_i32_trunc_nuw_i8(i16 %x, i32 %y) {
; CHECK-LABEL: @zext_i32_trunc_nuw_i8(
-; CHECK-NEXT: [[TRUNC1:%.*]] = zext i16 [[X:%.*]] to i32
+; CHECK-NEXT: [[TRUNC1:%.*]] = zext nneg i16 [[X:%.*]] to i32
; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[TRUNC1]]
; CHECK-NEXT: [[E:%.*]] = and i32 [[OR]], 255
; CHECK-NEXT: ret i32 [[E]]
@@ -1290,7 +1290,7 @@ define i32 @zext_i32_trunc_nuw_i8(i16 %x, i32 %y) {
define i16 @zext_i16_trunc_nuw_nsw_i8(i32 %x) {
; CHECK-LABEL: @zext_i16_trunc_nuw_nsw_i8(
-; CHECK-NEXT: [[C:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[C:%.*]] = trunc nuw nsw i32 [[X:%.*]] to i16
; CHECK-NEXT: [[E:%.*]] = and i16 [[C]], 255
; CHECK-NEXT: ret i16 [[E]]
;
@@ -1301,7 +1301,7 @@ define i16 @zext_i16_trunc_nuw_nsw_i8(i32 %x) {
define i16 @zext_i16_trunc_nsw_i8(i32 %x) {
; CHECK-LABEL: @zext_i16_trunc_nsw_i8(
-; CHECK-NEXT: [[C:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[C:%.*]] = trunc nsw i32 [[X:%.*]] to i16
; CHECK-NEXT: [[E:%.*]] = and i16 [[C]], 255
; CHECK-NEXT: ret i16 [[E]]
;
@@ -1312,7 +1312,7 @@ define i16 @zext_i16_trunc_nsw_i8(i32 %x) {
define i16 @zext_i16_trunc_nuw_i8(i32 %x) {
; CHECK-LABEL: @zext_i16_trunc_nuw_i8(
-; CHECK-NEXT: [[C:%.*]] = trunc i32 [[X:%.*]] to i16
+; CHECK-NEXT: [[C:%.*]] = trunc nuw i32 [[X:%.*]] to i16
; CHECK-NEXT: [[E:%.*]] = and i16 [[C]], 255
; CHECK-NEXT: ret i16 [[E]]
;
>From c6c50748af62eb305a77a32670221c40ac9ef0c4 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Mon, 8 Jun 2026 18:15:21 +0200
Subject: [PATCH 3/3] fixup! [InstCombine] Preserve no wrap kinds for trunc
---
.../InstCombine/InstCombineCasts.cpp | 6 ++--
llvm/test/Transforms/InstCombine/trunc.ll | 34 +++++++++++++++++++
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index a1d5c339e4d85..336f2b9d9f28e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -90,10 +90,8 @@ static Value *EvaluateInDifferentTypeImpl(Value *V, Type *Ty, bool isSigned,
if (auto *NewTrunc = dyn_cast<TruncInst>(Res)) {
if (Trunc->getType()->getScalarSizeInBits() <=
Ty->getScalarSizeInBits()) {
- if (Trunc->hasNoSignedWrap())
- NewTrunc->setHasNoSignedWrap(true);
- if (Trunc->hasNoUnsignedWrap())
- NewTrunc->setHasNoUnsignedWrap(true);
+ NewTrunc->setHasNoSignedWrap(Trunc->hasNoSignedWrap());
+ NewTrunc->setHasNoUnsignedWrap(Trunc->hasNoUnsignedWrap());
}
} else if (auto *NewZExt = dyn_cast<ZExtInst>(Res)) {
if (Trunc->hasNoUnsignedWrap())
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index d03cb571b6452..29aff222dbd87 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -1288,6 +1288,20 @@ define i32 @zext_i32_trunc_nuw_i8(i16 %x, i32 %y) {
ret i32 %e
}
+define i32 @neg_zext_i32_trunc_nsw_i8(i16 %x, i32 %y) {
+; CHECK-LABEL: @neg_zext_i32_trunc_nsw_i8(
+; CHECK-NEXT: [[TRUNC1:%.*]] = zext i16 [[X:%.*]] to i32
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[TRUNC1]]
+; CHECK-NEXT: [[E:%.*]] = and i32 [[OR]], 255
+; CHECK-NEXT: ret i32 [[E]]
+;
+ %trunc1 = trunc nsw i16 %x to i8
+ %trunc2 = trunc i32 %y to i8
+ %or = or i8 %trunc1, %trunc2
+ %e = zext i8 %or to i32
+ ret i32 %e
+}
+
define i16 @zext_i16_trunc_nuw_nsw_i8(i32 %x) {
; CHECK-LABEL: @zext_i16_trunc_nuw_nsw_i8(
; CHECK-NEXT: [[C:%.*]] = trunc nuw nsw i32 [[X:%.*]] to i16
@@ -1320,3 +1334,23 @@ define i16 @zext_i16_trunc_nuw_i8(i32 %x) {
%e = zext i8 %c to i16
ret i16 %e
}
+
+define i8 @neg_trunc_i8_trunc_nuw_i16(i32 %x) {
+; CHECK-LABEL: @neg_trunc_i8_trunc_nuw_i16(
+; CHECK-NEXT: [[E:%.*]] = trunc i32 [[X:%.*]] to i8
+; CHECK-NEXT: ret i8 [[E]]
+;
+ %c = trunc nuw i32 %x to i16
+ %e = trunc i16 %c to i8
+ ret i8 %e
+}
+
+define i8 @neg_trunc_nuw_i8_trunc_nuw_i16(i32 %x) {
+; CHECK-LABEL: @neg_trunc_nuw_i8_trunc_nuw_i16(
+; CHECK-NEXT: [[E:%.*]] = trunc i32 [[X:%.*]] to i8
+; CHECK-NEXT: ret i8 [[E]]
+;
+ %c = trunc nuw i32 %x to i16
+ %e = trunc nuw i16 %c to i8
+ ret i8 %e
+}
More information about the llvm-commits
mailing list