[llvm] [InstCombine] Fold `switch(zext/sext(X))` into `switch(X)` (PR #76988)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 5 10:41:43 PST 2024
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/76988
>From d3e89f1e22743c9d033cd2c32ce8a99a5681f38d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 5 Jan 2024 23:19:44 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.
---
.../InstCombine/switch-zext-sext.ll | 123 ++++++++++++++++++
.../Transforms/PhaseOrdering/switch-sext.ll | 58 +++++++++
2 files changed, 181 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/switch-zext-sext.ll
create mode 100644 llvm/test/Transforms/PhaseOrdering/switch-sext.ll
diff --git a/llvm/test/Transforms/InstCombine/switch-zext-sext.ll b/llvm/test/Transforms/InstCombine/switch-zext-sext.ll
new file mode 100644
index 00000000000000..5e5303a1109e9c
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/switch-zext-sext.ll
@@ -0,0 +1,123 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt %s -passes=instcombine -S | FileCheck %s
+
+define i1 @test_switch_with_zext(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_zext(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i16 37, label [[SW_BB:%.*]]
+; CHECK-NEXT: i16 38, label [[SW_BB]]
+; CHECK-NEXT: i16 39, label [[SW_BB]]
+; CHECK-NEXT: ]
+; CHECK: sw.bb:
+; CHECK-NEXT: ret i1 [[B]]
+; CHECK: sw.default:
+; CHECK-NEXT: ret i1 [[C]]
+;
+entry:
+ %a.ext = zext i16 %a to i32
+ switch i32 %a.ext, label %sw.default [
+ i32 37, label %sw.bb
+ i32 38, label %sw.bb
+ i32 39, label %sw.bb
+ ]
+
+sw.bb:
+ ret i1 %b
+sw.default:
+ ret i1 %c
+}
+
+define i1 @test_switch_with_sext(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_sext(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A_EXT:%.*]] = sext i16 [[A]] to i32
+; CHECK-NEXT: switch i32 [[A_EXT]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i32 37, label [[SW_BB:%.*]]
+; CHECK-NEXT: i32 38, label [[SW_BB]]
+; CHECK-NEXT: i32 39, label [[SW_BB]]
+; CHECK-NEXT: ]
+; CHECK: sw.bb:
+; CHECK-NEXT: ret i1 [[B]]
+; CHECK: sw.default:
+; CHECK-NEXT: ret i1 [[C]]
+;
+entry:
+ %a.ext = sext i16 %a to i32
+ switch i32 %a.ext, label %sw.default [
+ i32 37, label %sw.bb
+ i32 38, label %sw.bb
+ i32 39, label %sw.bb
+ ]
+
+sw.bb:
+ ret i1 %b
+sw.default:
+ ret i1 %c
+}
+
+; Negative tests
+
+define i1 @test_switch_with_zext_unreachable_case(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_zext_unreachable_case(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A_EXT:%.*]] = zext i16 [[A]] to i32
+; CHECK-NEXT: switch i32 [[A_EXT]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i32 37, label [[SW_BB:%.*]]
+; CHECK-NEXT: i32 38, label [[SW_BB]]
+; CHECK-NEXT: i32 39, label [[SW_BB]]
+; CHECK-NEXT: i32 65537, label [[SW_BB]]
+; CHECK-NEXT: ]
+; CHECK: sw.bb:
+; CHECK-NEXT: ret i1 [[B]]
+; CHECK: sw.default:
+; CHECK-NEXT: ret i1 [[C]]
+;
+entry:
+ %a.ext = zext i16 %a to i32
+ switch i32 %a.ext, label %sw.default [
+ i32 37, label %sw.bb
+ i32 38, label %sw.bb
+ i32 39, label %sw.bb
+ i32 65537, label %sw.bb
+ ]
+
+sw.bb:
+ ret i1 %b
+sw.default:
+ ret i1 %c
+}
+
+define i1 @test_switch_with_sext_unreachable_case(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_sext_unreachable_case(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A_EXT:%.*]] = sext i16 [[A]] to i32
+; CHECK-NEXT: switch i32 [[A_EXT]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i32 37, label [[SW_BB:%.*]]
+; CHECK-NEXT: i32 38, label [[SW_BB]]
+; CHECK-NEXT: i32 39, label [[SW_BB]]
+; CHECK-NEXT: i32 -65537, label [[SW_BB]]
+; CHECK-NEXT: ]
+; CHECK: sw.bb:
+; CHECK-NEXT: ret i1 [[B]]
+; CHECK: sw.default:
+; CHECK-NEXT: ret i1 [[C]]
+;
+entry:
+ %a.ext = sext i16 %a to i32
+ switch i32 %a.ext, label %sw.default [
+ i32 37, label %sw.bb
+ i32 38, label %sw.bb
+ i32 39, label %sw.bb
+ i32 -65537, label %sw.bb
+ ]
+
+sw.bb:
+ ret i1 %b
+sw.default:
+ ret i1 %c
+}
diff --git a/llvm/test/Transforms/PhaseOrdering/switch-sext.ll b/llvm/test/Transforms/PhaseOrdering/switch-sext.ll
new file mode 100644
index 00000000000000..764f26f11adb4f
--- /dev/null
+++ b/llvm/test/Transforms/PhaseOrdering/switch-sext.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -S -passes='default<O3>' < %s | FileCheck %s
+
+define i8 @test_switch_with_sext_phi(i8 %code) {
+; CHECK-LABEL: define i8 @test_switch_with_sext_phi(
+; CHECK-SAME: i8 [[CODE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[CODE]] to i32
+; CHECK-NEXT: switch i32 [[CONV]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i32 105, label [[SW_EPILOG:%.*]]
+; CHECK-NEXT: i32 73, label [[SW_BB1:%.*]]
+; CHECK-NEXT: i32 108, label [[SW_BB2:%.*]]
+; CHECK-NEXT: i32 76, label [[SW_BB3:%.*]]
+; CHECK-NEXT: i32 63, label [[SW_BB4:%.*]]
+; CHECK-NEXT: ]
+; CHECK: sw.bb1:
+; CHECK-NEXT: br label [[SW_EPILOG]]
+; CHECK: sw.bb2:
+; CHECK-NEXT: br label [[SW_EPILOG]]
+; CHECK: sw.bb3:
+; CHECK-NEXT: br label [[SW_EPILOG]]
+; CHECK: sw.bb4:
+; CHECK-NEXT: br label [[SW_EPILOG]]
+; CHECK: sw.default:
+; CHECK-NEXT: br label [[SW_EPILOG]]
+; CHECK: sw.epilog:
+; CHECK-NEXT: [[PEP_CODE:%.*]] = phi i8 [ [[CODE]], [[SW_DEFAULT]] ], [ 63, [[SW_BB4]] ], [ 81, [[SW_BB3]] ], [ 113, [[SW_BB2]] ], [ 73, [[SW_BB1]] ], [ 105, [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret i8 [[PEP_CODE]]
+;
+entry:
+ %conv = sext i8 %code to i32
+ switch i32 %conv, label %sw.default [
+ i32 105, label %sw.epilog
+ i32 73, label %sw.bb1
+ i32 108, label %sw.bb2
+ i32 76, label %sw.bb3
+ i32 63, label %sw.bb4
+ ]
+
+sw.bb1:
+ br label %sw.epilog
+
+sw.bb2:
+ br label %sw.epilog
+
+sw.bb3:
+ br label %sw.epilog
+
+sw.bb4:
+ br label %sw.epilog
+
+sw.default:
+ br label %sw.epilog
+
+sw.epilog:
+ %pep_code = phi i8 [ %code, %sw.default ], [ 63, %sw.bb4 ], [ 81, %sw.bb3 ], [ 113, %sw.bb2 ], [ 73, %sw.bb1 ], [ 105, %entry ]
+ ret i8 %pep_code
+}
>From bd90b60fd2108c154fc00482ef73cb35507c9c29 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 5 Jan 2024 23:33:21 +0800
Subject: [PATCH 2/2] [InstCombine] Canonicalize `switch(zext/sext(X))` to
`switch(X)`
---
.../InstCombine/InstructionCombining.cpp | 19 ++++++++++++
llvm/test/Transforms/InstCombine/phi.ll | 30 ++++++++-----------
.../InstCombine/switch-zext-sext.ll | 9 +++---
.../Transforms/PhaseOrdering/switch-sext.ll | 20 ++++---------
4 files changed, 41 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index e845bf38df2dfd..7f2018b3a19958 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3247,6 +3247,25 @@ Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
}
}
+ // Fold switch(zext/sext(X)) into switch(X) if possible.
+ if (match(Cond, m_ZExtOrSExt(m_Value(Op0)))) {
+ bool IsZExt = isa<ZExtInst>(Cond);
+ Type *SrcTy = Op0->getType();
+ unsigned NewWidth = SrcTy->getScalarSizeInBits();
+
+ if (all_of(SI.cases(), [&](const auto &Case) {
+ const APInt &CaseVal = Case.getCaseValue()->getValue();
+ return IsZExt ? CaseVal.isIntN(NewWidth)
+ : CaseVal.isSignedIntN(NewWidth);
+ })) {
+ for (auto &Case : SI.cases()) {
+ APInt TruncatedCase = Case.getCaseValue()->getValue().trunc(NewWidth);
+ Case.setValue(ConstantInt::get(SI.getContext(), TruncatedCase));
+ }
+ return replaceOperand(SI, 0, Op0);
+ }
+ }
+
KnownBits Known = computeKnownBits(Cond, 0, &SI);
unsigned LeadingKnownZeros = Known.countMinLeadingZeros();
unsigned LeadingKnownOnes = Known.countMinLeadingOnes();
diff --git a/llvm/test/Transforms/InstCombine/phi.ll b/llvm/test/Transforms/InstCombine/phi.ll
index 90818771675b2e..717f4c682a1530 100644
--- a/llvm/test/Transforms/InstCombine/phi.ll
+++ b/llvm/test/Transforms/InstCombine/phi.ll
@@ -996,10 +996,9 @@ done:
define i1 @PR24766(i8 %x1, i8 %x2, i8 %condition) {
; CHECK-LABEL: @PR24766(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[CONDITION:%.*]] to i32
-; CHECK-NEXT: switch i32 [[CONV]], label [[EPILOG:%.*]] [
-; CHECK-NEXT: i32 0, label [[SW1:%.*]]
-; CHECK-NEXT: i32 1, label [[SW2:%.*]]
+; CHECK-NEXT: switch i8 [[CONDITION:%.*]], label [[EPILOG:%.*]] [
+; CHECK-NEXT: i8 0, label [[SW1:%.*]]
+; CHECK-NEXT: i8 1, label [[SW2:%.*]]
; CHECK-NEXT: ]
; CHECK: sw1:
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X1:%.*]], [[X2:%.*]]
@@ -1040,10 +1039,9 @@ epilog:
define i1 @PR24766_no_constants(i8 %x1, i8 %x2, i8 %condition, i1 %another_condition) {
; CHECK-LABEL: @PR24766_no_constants(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[CONDITION:%.*]] to i32
-; CHECK-NEXT: switch i32 [[CONV]], label [[EPILOG:%.*]] [
-; CHECK-NEXT: i32 0, label [[SW1:%.*]]
-; CHECK-NEXT: i32 1, label [[SW2:%.*]]
+; CHECK-NEXT: switch i8 [[CONDITION:%.*]], label [[EPILOG:%.*]] [
+; CHECK-NEXT: i8 0, label [[SW1:%.*]]
+; CHECK-NEXT: i8 1, label [[SW2:%.*]]
; CHECK-NEXT: ]
; CHECK: sw1:
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X1:%.*]], [[X2:%.*]]
@@ -1085,10 +1083,9 @@ epilog:
define i1 @PR24766_two_constants(i8 %x1, i8 %x2, i8 %condition) {
; CHECK-LABEL: @PR24766_two_constants(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[CONDITION:%.*]] to i32
-; CHECK-NEXT: switch i32 [[CONV]], label [[EPILOG:%.*]] [
-; CHECK-NEXT: i32 0, label [[SW1:%.*]]
-; CHECK-NEXT: i32 1, label [[SW2:%.*]]
+; CHECK-NEXT: switch i8 [[CONDITION:%.*]], label [[EPILOG:%.*]] [
+; CHECK-NEXT: i8 0, label [[SW1:%.*]]
+; CHECK-NEXT: i8 1, label [[SW2:%.*]]
; CHECK-NEXT: ]
; CHECK: sw1:
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X1:%.*]], [[X2:%.*]]
@@ -1128,11 +1125,10 @@ epilog:
define i1 @PR24766_two_constants_two_var(i8 %x1, i8 %x2, i8 %condition) {
; CHECK-LABEL: @PR24766_two_constants_two_var(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[CONDITION:%.*]] to i32
-; CHECK-NEXT: switch i32 [[CONV]], label [[EPILOG:%.*]] [
-; CHECK-NEXT: i32 0, label [[SW1:%.*]]
-; CHECK-NEXT: i32 1, label [[SW2:%.*]]
-; CHECK-NEXT: i32 2, label [[SW3:%.*]]
+; CHECK-NEXT: switch i8 [[CONDITION:%.*]], label [[EPILOG:%.*]] [
+; CHECK-NEXT: i8 0, label [[SW1:%.*]]
+; CHECK-NEXT: i8 1, label [[SW2:%.*]]
+; CHECK-NEXT: i8 2, label [[SW3:%.*]]
; CHECK-NEXT: ]
; CHECK: sw1:
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[X1:%.*]], [[X2:%.*]]
diff --git a/llvm/test/Transforms/InstCombine/switch-zext-sext.ll b/llvm/test/Transforms/InstCombine/switch-zext-sext.ll
index 5e5303a1109e9c..c09441352acc0e 100644
--- a/llvm/test/Transforms/InstCombine/switch-zext-sext.ll
+++ b/llvm/test/Transforms/InstCombine/switch-zext-sext.ll
@@ -33,11 +33,10 @@ define i1 @test_switch_with_sext(i16 %a, i1 %b, i1 %c) {
; CHECK-LABEL: define i1 @test_switch_with_sext(
; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[A_EXT:%.*]] = sext i16 [[A]] to i32
-; CHECK-NEXT: switch i32 [[A_EXT]], label [[SW_DEFAULT:%.*]] [
-; CHECK-NEXT: i32 37, label [[SW_BB:%.*]]
-; CHECK-NEXT: i32 38, label [[SW_BB]]
-; CHECK-NEXT: i32 39, label [[SW_BB]]
+; CHECK-NEXT: switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT: i16 37, label [[SW_BB:%.*]]
+; CHECK-NEXT: i16 38, label [[SW_BB]]
+; CHECK-NEXT: i16 39, label [[SW_BB]]
; CHECK-NEXT: ]
; CHECK: sw.bb:
; CHECK-NEXT: ret i1 [[B]]
diff --git a/llvm/test/Transforms/PhaseOrdering/switch-sext.ll b/llvm/test/Transforms/PhaseOrdering/switch-sext.ll
index 764f26f11adb4f..e39771b629e013 100644
--- a/llvm/test/Transforms/PhaseOrdering/switch-sext.ll
+++ b/llvm/test/Transforms/PhaseOrdering/switch-sext.ll
@@ -2,29 +2,19 @@
; RUN: opt -S -passes='default<O3>' < %s | FileCheck %s
define i8 @test_switch_with_sext_phi(i8 %code) {
-; CHECK-LABEL: define i8 @test_switch_with_sext_phi(
+; CHECK-LABEL: define noundef i8 @test_switch_with_sext_phi(
; CHECK-SAME: i8 [[CODE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[CODE]] to i32
-; CHECK-NEXT: switch i32 [[CONV]], label [[SW_DEFAULT:%.*]] [
-; CHECK-NEXT: i32 105, label [[SW_EPILOG:%.*]]
-; CHECK-NEXT: i32 73, label [[SW_BB1:%.*]]
-; CHECK-NEXT: i32 108, label [[SW_BB2:%.*]]
-; CHECK-NEXT: i32 76, label [[SW_BB3:%.*]]
-; CHECK-NEXT: i32 63, label [[SW_BB4:%.*]]
+; CHECK-NEXT: switch i8 [[CODE]], label [[SW_EPILOG:%.*]] [
+; CHECK-NEXT: i8 76, label [[SW_BB3:%.*]]
+; CHECK-NEXT: i8 108, label [[SW_BB2:%.*]]
; CHECK-NEXT: ]
-; CHECK: sw.bb1:
-; CHECK-NEXT: br label [[SW_EPILOG]]
; CHECK: sw.bb2:
; CHECK-NEXT: br label [[SW_EPILOG]]
; CHECK: sw.bb3:
; CHECK-NEXT: br label [[SW_EPILOG]]
-; CHECK: sw.bb4:
-; CHECK-NEXT: br label [[SW_EPILOG]]
-; CHECK: sw.default:
-; CHECK-NEXT: br label [[SW_EPILOG]]
; CHECK: sw.epilog:
-; CHECK-NEXT: [[PEP_CODE:%.*]] = phi i8 [ [[CODE]], [[SW_DEFAULT]] ], [ 63, [[SW_BB4]] ], [ 81, [[SW_BB3]] ], [ 113, [[SW_BB2]] ], [ 73, [[SW_BB1]] ], [ 105, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[PEP_CODE:%.*]] = phi i8 [ 81, [[SW_BB3]] ], [ 113, [[SW_BB2]] ], [ [[CODE]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i8 [[PEP_CODE]]
;
entry:
More information about the llvm-commits
mailing list