[llvm] [SimplifyCFG] Do not run `simplifySwitchOfPowersOfTwo` in early invocations (PR #145477)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 24 07:16:51 PDT 2025


https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/145477

>From f2b8ed3854e691bae94d737ca61b1b44233d8203 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 24 Jun 2025 15:55:00 +0200
Subject: [PATCH 1/2] [PhaseOrdering] Introduce test for PR145477 (NFC)

---
 .../X86/simplifycfg-switch-powers-two-late.ll | 76 +++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll

diff --git a/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll b/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll
new file mode 100644
index 0000000000000..d31621536e289
--- /dev/null
+++ b/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes="default<O2>" -S < %s | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @simplifycfg_switch_power_two_late_optimized(i64 %x, ptr noalias dereferenceable(8) %y, ptr %z) {
+; CHECK-LABEL: define void @simplifycfg_switch_power_two_late_optimized(
+; CHECK-SAME: i64 [[X:%.*]], ptr noalias readonly captures(none) dereferenceable(8) [[Y:%.*]], ptr [[Z:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ALLOC1:%.*]] = alloca [24 x i8], align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = and i64 [[X]], 1
+; CHECK-NEXT:    [[SWITCH_NOT:%.*]] = icmp eq i64 [[TMP0]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[Z]], null
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[SWITCH_NOT]], i1 undef, i1 [[TMP1]]
+; CHECK-NEXT:    br i1 [[SPEC_SELECT]], label %[[EXIT:.*]], label %[[OPAQUE_CALL:.*]]
+; CHECK:       [[OPAQUE_CALL]]:
+; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[Y]], align 8
+; CHECK-NEXT:    store i64 [[TMP2]], ptr [[ALLOC1]], align 8
+; CHECK-NEXT:    [[PTR_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[ALLOC1]], i64 16
+; CHECK-NEXT:    store ptr [[Z]], ptr [[PTR_IDX]], align 8
+; CHECK-NEXT:    call void @opaque(ptr nonnull [[ALLOC1]])
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %alloc1 = alloca [24 x i8], align 8
+  %alloc2 = alloca [8 x i8], align 8
+  %alloc3 = alloca [8 x i8], align 8
+  store i64 %x, ptr %alloc3, align 8
+  %val = load i64, ptr %alloc3, align 8
+  switch i64 %val, label %bb.default [
+  i64 1, label %bb.1
+  i64 2, label %bb.2
+  i64 4, label %bb.3
+  i64 8, label %bb.4
+  ]
+
+bb.default:                                       ; preds = %continue, %entry
+  unreachable
+
+bb.1:                                             ; preds = %entry
+  store ptr %z, ptr %alloc2, align 8
+  br label %continue
+
+bb.2:                                             ; preds = %entry
+  br label %continue
+
+bb.3:                                             ; preds = %entry
+  br label %continue
+
+bb.4:                                             ; preds = %entry
+  br label %continue
+
+continue:                                         ; preds = %bb.4, %bb.3, %bb.2, %bb.1
+  %val2 = load ptr, ptr %alloc2, align 8
+  %cast = ptrtoint ptr %val2 to i64
+  %icmp = icmp eq i64 %cast, 0
+  %cond = select i1 %icmp, i64 0, i64 1
+  switch i64 %cond, label %bb.default [
+  i64 0, label %exit
+  i64 1, label %opaque.call
+  ]
+
+opaque.call:                                      ; preds = %continue
+  call void @llvm.memcpy.p0.p0.i64(ptr %alloc1, ptr align 8 %y, i64 8, i1 false)
+  %ptr.idx = getelementptr inbounds i8, ptr %alloc1, i64 16
+  store ptr %z, ptr %ptr.idx, align 8
+  call void @opaque(ptr %alloc1)
+  br label %exit
+
+exit:                                             ; preds = %opaque.call
+  ret void
+}
+
+declare void @opaque(ptr)

>From 319ccfbd107206f6bda516adb291b3f150643edf Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Tue, 24 Jun 2025 15:59:29 +0200
Subject: [PATCH 2/2] [SimplifyCFG] Do not run `simplifySwitchOfPowersOfTwo` in
 early invocations

It may be desirable not to carry out `simplifySwitchOfPowersOfTwo`
transform during early pipeline invocations, so as to let other
optimizations occur first.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp                    | 5 ++++-
 .../PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll  | 5 ++---
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index e205551658aa5..4f3bfcff03d1c 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7604,7 +7604,10 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
       switchToLookupTable(SI, Builder, DTU, DL, TTI))
     return requestResimplify();
 
-  if (simplifySwitchOfPowersOfTwo(SI, Builder, DL, TTI))
+  // Do not transform the switch into a `cttz` and a reduced table on early
+  // invocations.
+  if (Options.ConvertSwitchToLookupTable &&
+      simplifySwitchOfPowersOfTwo(SI, Builder, DL, TTI))
     return requestResimplify();
 
   if (reduceSwitchRange(SI, Builder, DL, TTI))
diff --git a/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll b/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll
index d31621536e289..20f82fb7d980e 100644
--- a/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll
+++ b/llvm/test/Transforms/PhaseOrdering/X86/simplifycfg-switch-powers-two-late.ll
@@ -8,10 +8,9 @@ define void @simplifycfg_switch_power_two_late_optimized(i64 %x, ptr noalias der
 ; CHECK-SAME: i64 [[X:%.*]], ptr noalias readonly captures(none) dereferenceable(8) [[Y:%.*]], ptr [[Z:%.*]]) local_unnamed_addr {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[ALLOC1:%.*]] = alloca [24 x i8], align 8
-; CHECK-NEXT:    [[TMP0:%.*]] = and i64 [[X]], 1
-; CHECK-NEXT:    [[SWITCH_NOT:%.*]] = icmp eq i64 [[TMP0]], 0
+; CHECK-NEXT:    [[SWITCH:%.*]] = icmp eq i64 [[X]], 1
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq ptr [[Z]], null
-; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[SWITCH_NOT]], i1 undef, i1 [[TMP1]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 [[TMP1]], i1 undef
 ; CHECK-NEXT:    br i1 [[SPEC_SELECT]], label %[[EXIT:.*]], label %[[OPAQUE_CALL:.*]]
 ; CHECK:       [[OPAQUE_CALL]]:
 ; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[Y]], align 8



More information about the llvm-commits mailing list