[llvm] [InstCombine] Use common flags for shl in shl/trunc fold. (PR #221769)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 7 08:55:57 PDT 2026
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/221769
As pointed out post-commit in
https://github.com/llvm/llvm-project/pull/219443, whether the flags from
the trunc can be transferred directly to the shl depends on the involved
types: https://alive2.llvm.org/ce/z/zN_TFq
For now, just use the common flags.
>From 91a961ed5449f7592fd7bb21108c2d9e46674003 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 7 Sep 2026 16:46:38 +0100
Subject: [PATCH 1/2] [InstCombine] Add test for incorrectly preserving flags.
---
llvm/test/Transforms/InstCombine/trunc.ll | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index 59c0f83b0e60c..868f3a7ebd666 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -708,6 +708,17 @@ define i32 @trunc_nuw_shl_nsw_3_i32_i64(i64 %val) {
ret i32 %trunc
}
+define i4 @trunc_nuw_shl_i6_to_i4(i6 %x, i6 %y) {
+; CHECK-LABEL: @trunc_nuw_shl_i6_to_i4(
+; CHECK-NEXT: [[X_TR:%.*]] = trunc i6 [[X:%.*]] to i4
+; CHECK-NEXT: [[TRUNC:%.*]] = shl nuw i4 [[X_TR]], 3
+; CHECK-NEXT: ret i4 [[TRUNC]]
+;
+ %shl = shl i6 %x, 3
+ %trunc = trunc nuw i6 %shl to i4
+ ret i4 %trunc
+}
+
define i16 @trunc_shl_15_i16_i64(i64 %val) {
; CHECK-LABEL: @trunc_shl_15_i16_i64(
; CHECK-NEXT: [[VAL_TR:%.*]] = trunc i64 [[VAL:%.*]] to i16
@@ -1553,3 +1564,4 @@ define i1 @neg_trunc_nuw_lshr(i8 %x, i8 %c) {
%ret = trunc nuw i8 %lshr to i1
ret i1 %ret
}
+
>From 5e23c6b4a8138774b81dafbb36835cae4a334e2f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 7 Sep 2026 16:42:39 +0100
Subject: [PATCH 2/2] [InstCombine] Use common flags for shl in shl/trunc fold.
As pointed out post-commit in
https://github.com/llvm/llvm-project/pull/219443, whether the flags from
the trunc can be transferred directly to the shl depends on the involved
types: https://alive2.llvm.org/ce/z/zN_TFq
For now, just use the common flags.
---
llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 8 +++-----
llvm/test/Transforms/InstCombine/trunc.ll | 9 ++++-----
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index fb56bcc6bea26..54d811fa3e923 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1236,18 +1236,16 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
APInt Threshold = APInt(C->getType()->getScalarSizeInBits(), DestWidth);
if (match(C, m_SpecificInt_ICMP(ICmpInst::ICMP_ULT, Threshold))) {
// If neither the wide shift nor the truncate wrap, propagate the wrap
- // flags on the new truncate.
+ // flags on the new truncate and shift.
auto *WideShl = cast<OverflowingBinaryOperator>(Src);
bool NUW = Trunc.hasNoUnsignedWrap() && WideShl->hasNoUnsignedWrap();
bool NSW = Trunc.hasNoSignedWrap() && WideShl->hasNoSignedWrap();
Value *NewTrunc = Builder.CreateTrunc(A, DestTy, A->getName() + ".tr",
/*IsNUW=*/NUW, /*IsNSW=*/NSW);
- // The original flags from the truncate can be propagated directly to
- // the shift.
auto *NewShl = BinaryOperator::Create(
Instruction::Shl, NewTrunc, ConstantExpr::getTrunc(C, DestTy));
- NewShl->setHasNoUnsignedWrap(Trunc.hasNoUnsignedWrap());
- NewShl->setHasNoSignedWrap(Trunc.hasNoSignedWrap());
+ NewShl->setHasNoUnsignedWrap(NUW);
+ NewShl->setHasNoSignedWrap(NSW);
return NewShl;
}
}
diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll
index 868f3a7ebd666..9e41544043d51 100644
--- a/llvm/test/Transforms/InstCombine/trunc.ll
+++ b/llvm/test/Transforms/InstCombine/trunc.ll
@@ -664,7 +664,7 @@ define i32 @trunc_nuw_shl_nuw_nsw_3_i32_i64(i64 %val) {
define i32 @trunc_nuw_nsw_shl_nsw_3_i32_i64(i64 %val) {
; CHECK-LABEL: @trunc_nuw_nsw_shl_nsw_3_i32_i64(
; CHECK-NEXT: [[VAL_TR:%.*]] = trunc nsw i64 [[VAL:%.*]] to i32
-; CHECK-NEXT: [[TRUNC:%.*]] = shl nuw nsw i32 [[VAL_TR]], 3
+; CHECK-NEXT: [[TRUNC:%.*]] = shl nsw i32 [[VAL_TR]], 3
; CHECK-NEXT: ret i32 [[TRUNC]]
;
%shl = shl nsw i64 %val, 3
@@ -676,7 +676,7 @@ define i32 @trunc_nuw_nsw_shl_nsw_3_i32_i64(i64 %val) {
define i32 @trunc_nuw_shl_3_i32_i64(i64 %val) {
; CHECK-LABEL: @trunc_nuw_shl_3_i32_i64(
; CHECK-NEXT: [[VAL_TR:%.*]] = trunc i64 [[VAL:%.*]] to i32
-; CHECK-NEXT: [[TRUNC:%.*]] = shl nuw i32 [[VAL_TR]], 3
+; CHECK-NEXT: [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 3
; CHECK-NEXT: ret i32 [[TRUNC]]
;
%shl = shl i64 %val, 3
@@ -700,7 +700,7 @@ define i32 @trunc_shl_nuw_nsw_3_i32_i64(i64 %val) {
define i32 @trunc_nuw_shl_nsw_3_i32_i64(i64 %val) {
; CHECK-LABEL: @trunc_nuw_shl_nsw_3_i32_i64(
; CHECK-NEXT: [[VAL_TR:%.*]] = trunc i64 [[VAL:%.*]] to i32
-; CHECK-NEXT: [[TRUNC:%.*]] = shl nuw i32 [[VAL_TR]], 3
+; CHECK-NEXT: [[TRUNC:%.*]] = shl i32 [[VAL_TR]], 3
; CHECK-NEXT: ret i32 [[TRUNC]]
;
%shl = shl nsw i64 %val, 3
@@ -711,7 +711,7 @@ define i32 @trunc_nuw_shl_nsw_3_i32_i64(i64 %val) {
define i4 @trunc_nuw_shl_i6_to_i4(i6 %x, i6 %y) {
; CHECK-LABEL: @trunc_nuw_shl_i6_to_i4(
; CHECK-NEXT: [[X_TR:%.*]] = trunc i6 [[X:%.*]] to i4
-; CHECK-NEXT: [[TRUNC:%.*]] = shl nuw i4 [[X_TR]], 3
+; CHECK-NEXT: [[TRUNC:%.*]] = shl i4 [[X_TR]], 3
; CHECK-NEXT: ret i4 [[TRUNC]]
;
%shl = shl i6 %x, 3
@@ -1564,4 +1564,3 @@ define i1 @neg_trunc_nuw_lshr(i8 %x, i8 %c) {
%ret = trunc nuw i8 %lshr to i1
ret i1 %ret
}
-
More information about the llvm-commits
mailing list