[llvm] [InstCombine] Canonicalize `switch(C-X)` to `switch(X)` (PR #77051)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 4 23:06:35 PST 2024


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/77051

This patch canonicalizes `switch(C-X)` to `switch(X)`.

Compile-time impact: http://llvm-compile-time-tracker.com/compare.php?from=7954c57124b495fbdc73674d71f2e366e4afe522&to=31a9adff1e633f0f3c423fb8487fc15d17e171f2&stat=instructions:u
|stage1-O3|stage1-ReleaseThinLTO|stage1-ReleaseLTO-g|stage1-O0-g|stage2-O3|stage2-O0-g|stage2-clang|
|--|--|--|--|--|--|--|
|-0.01%|+0.02%|+0.02%|+0.05%|-0.07%|-0.02%|-0.02%|

Related patch: https://github.com/llvm/llvm-project/pull/76988


>From dc2f8119338dd1a94d363f3f4cb4fc88da29433a Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 5 Jan 2024 14:34:32 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.

---
 .../test/Transforms/InstCombine/switch-sub.ll | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/switch-sub.ll

diff --git a/llvm/test/Transforms/InstCombine/switch-sub.ll b/llvm/test/Transforms/InstCombine/switch-sub.ll
new file mode 100644
index 00000000000000..99160356ae1726
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/switch-sub.ll
@@ -0,0 +1,91 @@
+; 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_neg(i32 %a) {
+; CHECK-LABEL: define i1 @test_switch_with_neg(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_NEG:%.*]] = sub i32 0, [[A]]
+; CHECK-NEXT:    switch i32 [[A_NEG]], 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 true
+; CHECK:       sw.default:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %a.neg = sub i32 0, %a
+  switch i32 %a.neg, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 true
+sw.default:
+  ret i1 false
+}
+
+define i1 @test_switch_with_sub(i32 %a) {
+; CHECK-LABEL: define i1 @test_switch_with_sub(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_NEG:%.*]] = sub i32 37, [[A]]
+; CHECK-NEXT:    switch i32 [[A_NEG]], 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 true
+; CHECK:       sw.default:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %a.neg = sub i32 37, %a
+  switch i32 %a.neg, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 true
+sw.default:
+  ret i1 false
+}
+
+; Negative tests
+
+define i1 @test_switch_with_sub_nonconst(i32 %a, i32 %b) {
+; CHECK-LABEL: define i1 @test_switch_with_sub_nonconst(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_NEG:%.*]] = sub i32 [[B]], [[A]]
+; CHECK-NEXT:    switch i32 [[A_NEG]], 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 true
+; CHECK:       sw.default:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %a.neg = sub i32 %b, %a
+  switch i32 %a.neg, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 true
+sw.default:
+  ret i1 false
+}

>From 31a9adff1e633f0f3c423fb8487fc15d17e171f2 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 5 Jan 2024 14:44:40 +0800
Subject: [PATCH 2/2] [InstCombine] Fold `switch(C-X)` to `switch(X)`

---
 .../InstCombine/InstructionCombining.cpp       | 12 ++++++++++++
 llvm/test/Transforms/InstCombine/switch-sub.ll | 18 ++++++++----------
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index f3181dc14792c8..b45c6784b85b6f 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3208,6 +3208,18 @@ Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
     return replaceOperand(SI, 0, Op0);
   }
 
+  ConstantInt *SubLHS;
+  if (match(Cond, m_Sub(m_ConstantInt(SubLHS), m_Value(Op0)))) {
+    // Change 'switch (1-X) case 1:' into 'switch (X) case 0'.
+    for (auto Case : SI.cases()) {
+      Constant *NewCase = ConstantExpr::getSub(SubLHS, Case.getCaseValue());
+      assert(isa<ConstantInt>(NewCase) &&
+             "Result of expression should be constant");
+      Case.setValue(cast<ConstantInt>(NewCase));
+    }
+    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/switch-sub.ll b/llvm/test/Transforms/InstCombine/switch-sub.ll
index 99160356ae1726..3fedfddeb7c0fe 100644
--- a/llvm/test/Transforms/InstCombine/switch-sub.ll
+++ b/llvm/test/Transforms/InstCombine/switch-sub.ll
@@ -5,11 +5,10 @@ define i1 @test_switch_with_neg(i32 %a) {
 ; CHECK-LABEL: define i1 @test_switch_with_neg(
 ; CHECK-SAME: i32 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[A_NEG:%.*]] = sub i32 0, [[A]]
-; CHECK-NEXT:    switch i32 [[A_NEG]], 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 i32 [[A]], 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 true
@@ -34,11 +33,10 @@ define i1 @test_switch_with_sub(i32 %a) {
 ; CHECK-LABEL: define i1 @test_switch_with_sub(
 ; CHECK-SAME: i32 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[A_NEG:%.*]] = sub i32 37, [[A]]
-; CHECK-NEXT:    switch i32 [[A_NEG]], 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 i32 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[SW_BB:%.*]]
+; CHECK-NEXT:      i32 -1, label [[SW_BB]]
+; CHECK-NEXT:      i32 -2, label [[SW_BB]]
 ; CHECK-NEXT:    ]
 ; CHECK:       sw.bb:
 ; CHECK-NEXT:    ret i1 true



More information about the llvm-commits mailing list