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

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 5 05:03:29 PST 2024


Author: Yingwei Zheng
Date: 2024-01-05T21:03:24+08:00
New Revision: f7f7574afe4cfc11ebe5d8cb811d5cd28dc862f6

URL: https://github.com/llvm/llvm-project/commit/f7f7574afe4cfc11ebe5d8cb811d5cd28dc862f6
DIFF: https://github.com/llvm/llvm-project/commit/f7f7574afe4cfc11ebe5d8cb811d5cd28dc862f6.diff

LOG: [InstCombine] Canonicalize `switch(C-X)` to `switch(X)` (#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%|

Added: 
    llvm/test/Transforms/InstCombine/switch-sub.ll

Modified: 
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Removed: 
    


################################################################################
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
new file mode 100644
index 00000000000000..3fedfddeb7c0fe
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/switch-sub.ll
@@ -0,0 +1,89 @@
+; 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:    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
+; 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:    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
+; 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
+}


        


More information about the llvm-commits mailing list