[llvm] [X86][CostModel] Estimate the codesize cost of switch (PR #163569)

Hongyu Chen via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 15 12:17:01 PDT 2025


https://github.com/XChy updated https://github.com/llvm/llvm-project/pull/163569

>From ffc4e6ddc6418962c3e45e6d9c13430136794368 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Wed, 15 Oct 2025 22:30:35 +0800
Subject: [PATCH 1/2] [X86] Estimate the codesize cost of switch

---
 .../lib/Target/X86/X86TargetTransformInfo.cpp |  17 +
 llvm/test/Analysis/CostModel/X86/switch.ll    | 411 ++++++++++++++++++
 2 files changed, 428 insertions(+)
 create mode 100644 llvm/test/Analysis/CostModel/X86/switch.ll

diff --git a/llvm/lib/Target/X86/X86TargetTransformInfo.cpp b/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
index 3d8d0a236a3c1..22a646f10507d 100644
--- a/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
+++ b/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
@@ -6155,6 +6155,23 @@ X86TTIImpl::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
 InstructionCost X86TTIImpl::getCFInstrCost(unsigned Opcode,
                                            TTI::TargetCostKind CostKind,
                                            const Instruction *I) const {
+  if (Opcode == Instruction::Switch && CostKind == TTI::TCK_CodeSize) {
+    unsigned JumpTableSize, NumSuccs = I->getNumSuccessors();
+    getEstimatedNumberOfCaseClusters(*cast<SwitchInst>(I), JumpTableSize,
+                                     nullptr, nullptr);
+    // A trivial unconditional branch.
+    if (NumSuccs == 1)
+      return TTI::TCC_Basic;
+
+    // Assume that lowering the switch block is implemented by binary search if
+    // no jump table is generated.
+    if (JumpTableSize == 0)
+      return llvm::Log2_32_Ceil(NumSuccs) * 2 * TTI::TCC_Basic;
+
+    // Indirect branch + default compare + default jump
+    return 3 * TTI::TCC_Basic;
+  }
+
   if (CostKind != TTI::TCK_RecipThroughput)
     return Opcode == Instruction::PHI ? TTI::TCC_Free : TTI::TCC_Basic;
   // Branches are assumed to be predicted.
diff --git a/llvm/test/Analysis/CostModel/X86/switch.ll b/llvm/test/Analysis/CostModel/X86/switch.ll
new file mode 100644
index 0000000000000..e668e365e899d
--- /dev/null
+++ b/llvm/test/Analysis/CostModel/X86/switch.ll
@@ -0,0 +1,411 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes="print<cost-model>" -cost-kind=throughput 2>&1 -disable-output -mtriple=x86_64-unknown-linux-gnu | FileCheck %s -check-prefixes=CHECK,THROUGHPUT
+; RUN: opt < %s -passes="print<cost-model>" -cost-kind=latency 2>&1 -disable-output -mtriple=x86_64-unknown-linux-gnu | FileCheck %s -check-prefixes=CHECK,LATENCY
+; RUN: opt < %s -passes="print<cost-model>" -cost-kind=code-size 2>&1 -disable-output -mtriple=x86_64-unknown-linux-gnu | FileCheck %s -check-prefixes=CHECK,CODESIZE
+
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+
+define i32 @single_succ_switch(i32 %x) {
+; THROUGHPUT-LABEL: 'single_succ_switch'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+;
+; LATENCY-LABEL: 'single_succ_switch'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+;
+; CODESIZE-LABEL: 'single_succ_switch'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+;
+entry:
+  switch i32 %x, label %default [
+  ]
+default:
+  ret i32 1
+}
+
+define i32 @dense_switch(i32 %x) {
+; THROUGHPUT-LABEL: 'dense_switch'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:      i32 0, label %bb0
+; THROUGHPUT-NEXT:      i32 1, label %bb1
+; THROUGHPUT-NEXT:      i32 2, label %bb2
+; THROUGHPUT-NEXT:      i32 3, label %bb3
+; THROUGHPUT-NEXT:      i32 4, label %bb4
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 0
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 2
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 3
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 4
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; LATENCY-LABEL: 'dense_switch'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:      i32 0, label %bb0
+; LATENCY-NEXT:      i32 1, label %bb1
+; LATENCY-NEXT:      i32 2, label %bb2
+; LATENCY-NEXT:      i32 3, label %bb3
+; LATENCY-NEXT:      i32 4, label %bb4
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; CODESIZE-LABEL: 'dense_switch'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:      i32 0, label %bb0
+; CODESIZE-NEXT:      i32 1, label %bb1
+; CODESIZE-NEXT:      i32 2, label %bb2
+; CODESIZE-NEXT:      i32 3, label %bb3
+; CODESIZE-NEXT:      i32 4, label %bb4
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %bb0
+    i32 1, label %bb1
+    i32 2, label %bb2
+    i32 3, label %bb3
+    i32 4, label %bb4
+  ]
+bb0:
+  ret i32 0
+bb1:
+  ret i32 1
+bb2:
+  ret i32 2
+bb3:
+  ret i32 3
+bb4:
+  ret i32 4
+default:
+  unreachable
+}
+
+define i32 @sparse_switch(i32 %x) {
+; THROUGHPUT-LABEL: 'sparse_switch'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:      i32 0, label %bb0
+; THROUGHPUT-NEXT:      i32 100, label %bb1
+; THROUGHPUT-NEXT:      i32 200, label %bb2
+; THROUGHPUT-NEXT:      i32 300, label %bb3
+; THROUGHPUT-NEXT:      i32 400, label %bb4
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 0
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 2
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 3
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 4
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; LATENCY-LABEL: 'sparse_switch'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:      i32 0, label %bb0
+; LATENCY-NEXT:      i32 100, label %bb1
+; LATENCY-NEXT:      i32 200, label %bb2
+; LATENCY-NEXT:      i32 300, label %bb3
+; LATENCY-NEXT:      i32 400, label %bb4
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; CODESIZE-LABEL: 'sparse_switch'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:      i32 0, label %bb0
+; CODESIZE-NEXT:      i32 100, label %bb1
+; CODESIZE-NEXT:      i32 200, label %bb2
+; CODESIZE-NEXT:      i32 300, label %bb3
+; CODESIZE-NEXT:      i32 400, label %bb4
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %bb0
+    i32 100, label %bb1
+    i32 200, label %bb2
+    i32 300, label %bb3
+    i32 400, label %bb4
+  ]
+bb0:
+  ret i32 0
+bb1:
+  ret i32 1
+bb2:
+  ret i32 2
+bb3:
+  ret i32 3
+bb4:
+  ret i32 4
+default:
+  unreachable
+}
+
+define i32 @dense_big_switch(i32 %x) {
+; THROUGHPUT-LABEL: 'dense_big_switch'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:      i32 0, label %bb0
+; THROUGHPUT-NEXT:      i32 1, label %bb1
+; THROUGHPUT-NEXT:      i32 2, label %bb2
+; THROUGHPUT-NEXT:      i32 3, label %bb3
+; THROUGHPUT-NEXT:      i32 4, label %bb4
+; THROUGHPUT-NEXT:      i32 5, label %bb5
+; THROUGHPUT-NEXT:      i32 6, label %bb6
+; THROUGHPUT-NEXT:      i32 7, label %bb7
+; THROUGHPUT-NEXT:      i32 8, label %bb8
+; THROUGHPUT-NEXT:      i32 9, label %bb9
+; THROUGHPUT-NEXT:      i32 10, label %bb10
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 0
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 2
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 3
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 4
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 5
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 6
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 7
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 8
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 9
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 10
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; LATENCY-LABEL: 'dense_big_switch'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:      i32 0, label %bb0
+; LATENCY-NEXT:      i32 1, label %bb1
+; LATENCY-NEXT:      i32 2, label %bb2
+; LATENCY-NEXT:      i32 3, label %bb3
+; LATENCY-NEXT:      i32 4, label %bb4
+; LATENCY-NEXT:      i32 5, label %bb5
+; LATENCY-NEXT:      i32 6, label %bb6
+; LATENCY-NEXT:      i32 7, label %bb7
+; LATENCY-NEXT:      i32 8, label %bb8
+; LATENCY-NEXT:      i32 9, label %bb9
+; LATENCY-NEXT:      i32 10, label %bb10
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 6
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 7
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 8
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 9
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 10
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; CODESIZE-LABEL: 'dense_big_switch'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:      i32 0, label %bb0
+; CODESIZE-NEXT:      i32 1, label %bb1
+; CODESIZE-NEXT:      i32 2, label %bb2
+; CODESIZE-NEXT:      i32 3, label %bb3
+; CODESIZE-NEXT:      i32 4, label %bb4
+; CODESIZE-NEXT:      i32 5, label %bb5
+; CODESIZE-NEXT:      i32 6, label %bb6
+; CODESIZE-NEXT:      i32 7, label %bb7
+; CODESIZE-NEXT:      i32 8, label %bb8
+; CODESIZE-NEXT:      i32 9, label %bb9
+; CODESIZE-NEXT:      i32 10, label %bb10
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 6
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 7
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 8
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 9
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 10
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %bb0
+    i32 1, label %bb1
+    i32 2, label %bb2
+    i32 3, label %bb3
+    i32 4, label %bb4
+    i32 5, label %bb5
+    i32 6, label %bb6
+    i32 7, label %bb7
+    i32 8, label %bb8
+    i32 9, label %bb9
+    i32 10, label %bb10
+  ]
+bb0:
+  ret i32 0
+bb1:
+  ret i32 1
+bb2:
+  ret i32 2
+bb3:
+  ret i32 3
+bb4:
+  ret i32 4
+bb5:
+  ret i32 5
+bb6:
+  ret i32 6
+bb7:
+  ret i32 7
+bb8:
+  ret i32 8
+bb9:
+  ret i32 9
+bb10:
+  ret i32 10
+default:
+  unreachable
+}
+
+define i32 @sparse_big_switch(i32 %x) {
+; THROUGHPUT-LABEL: 'sparse_big_switch'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:      i32 0, label %bb0
+; THROUGHPUT-NEXT:      i32 100, label %bb1
+; THROUGHPUT-NEXT:      i32 200, label %bb2
+; THROUGHPUT-NEXT:      i32 300, label %bb3
+; THROUGHPUT-NEXT:      i32 400, label %bb4
+; THROUGHPUT-NEXT:      i32 500, label %bb5
+; THROUGHPUT-NEXT:      i32 600, label %bb6
+; THROUGHPUT-NEXT:      i32 700, label %bb7
+; THROUGHPUT-NEXT:      i32 800, label %bb8
+; THROUGHPUT-NEXT:      i32 900, label %bb9
+; THROUGHPUT-NEXT:      i32 1000, label %bb10
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 0
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 2
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 3
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 4
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 5
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 6
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 7
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 8
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 9
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 10
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; LATENCY-LABEL: 'sparse_big_switch'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:      i32 0, label %bb0
+; LATENCY-NEXT:      i32 100, label %bb1
+; LATENCY-NEXT:      i32 200, label %bb2
+; LATENCY-NEXT:      i32 300, label %bb3
+; LATENCY-NEXT:      i32 400, label %bb4
+; LATENCY-NEXT:      i32 500, label %bb5
+; LATENCY-NEXT:      i32 600, label %bb6
+; LATENCY-NEXT:      i32 700, label %bb7
+; LATENCY-NEXT:      i32 800, label %bb8
+; LATENCY-NEXT:      i32 900, label %bb9
+; LATENCY-NEXT:      i32 1000, label %bb10
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 6
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 7
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 8
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 9
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 10
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+; CODESIZE-LABEL: 'sparse_big_switch'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 8 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:      i32 0, label %bb0
+; CODESIZE-NEXT:      i32 100, label %bb1
+; CODESIZE-NEXT:      i32 200, label %bb2
+; CODESIZE-NEXT:      i32 300, label %bb3
+; CODESIZE-NEXT:      i32 400, label %bb4
+; CODESIZE-NEXT:      i32 500, label %bb5
+; CODESIZE-NEXT:      i32 600, label %bb6
+; CODESIZE-NEXT:      i32 700, label %bb7
+; CODESIZE-NEXT:      i32 800, label %bb8
+; CODESIZE-NEXT:      i32 900, label %bb9
+; CODESIZE-NEXT:      i32 1000, label %bb10
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 6
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 7
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 8
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 9
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 10
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %bb0
+    i32 100, label %bb1
+    i32 200, label %bb2
+    i32 300, label %bb3
+    i32 400, label %bb4
+    i32 500, label %bb5
+    i32 600, label %bb6
+    i32 700, label %bb7
+    i32 800, label %bb8
+    i32 900, label %bb9
+    i32 1000, label %bb10
+  ]
+bb0:
+  ret i32 0
+bb1:
+  ret i32 1
+bb2:
+  ret i32 2
+bb3:
+  ret i32 3
+bb4:
+  ret i32 4
+bb5:
+  ret i32 5
+bb6:
+  ret i32 6
+bb7:
+  ret i32 7
+bb8:
+  ret i32 8
+bb9:
+  ret i32 9
+bb10:
+  ret i32 10
+default:
+  unreachable
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}

>From 90ce69869072c78acc4c3214b3ebe2dbec3223ce Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Thu, 16 Oct 2025 03:16:42 +0800
Subject: [PATCH 2/2] resolve comments

---
 llvm/include/llvm/CodeGen/BasicTTIImpl.h      |  37 +++++
 .../lib/Target/X86/X86TargetTransformInfo.cpp |  18 +--
 llvm/test/Analysis/CostModel/X86/switch.ll    | 150 +++++++++++++++++-
 3 files changed, 182 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 42ddb32d24093..ed7658ad62f8d 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1365,6 +1365,43 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
   InstructionCost
   getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
                  const Instruction *I = nullptr) const override {
+    if (Opcode == Instruction::Switch && CostKind == TTI::TCK_CodeSize && I) {
+      const SwitchInst *SI = cast<SwitchInst>(I);
+      unsigned JumpTableSize, NumSuccs = I->getNumSuccessors();
+      auto BrCost = thisT()->getCFInstrCost(Instruction::Br, CostKind);
+      if (SI->defaultDestUnreachable())
+        NumSuccs--;
+
+      // An unreachable switch
+      if (NumSuccs == 0)
+        return TTI::TCC_Free;
+
+      // A trivial unconditional branch.
+      if (NumSuccs == 1)
+        return BrCost;
+
+      thisT()->getEstimatedNumberOfCaseClusters(*SI, JumpTableSize, nullptr,
+                                                nullptr);
+      Type *BoolTy = IntegerType::get(SI->getContext(), 1);
+      Type *CondTy = SI->getCondition()->getType();
+      auto CmpCost = thisT()->getCmpSelInstrCost(
+          BinaryOperator::ICmp, BoolTy, CondTy, CmpInst::ICMP_UGT, CostKind);
+
+      // Assume that lowering the switch block is implemented by binary search
+      // if no jump table is generated.
+      if (JumpTableSize == 0)
+        return llvm::Log2_32_Ceil(NumSuccs) * (CmpCost + BrCost);
+
+      // Cost for jump table: load + jump + default compare + default jump
+      Type *EntryTy = PointerType::get(SI->getContext(), 0);
+      Align Alignment = thisT()->DL.getABITypeAlign(EntryTy);
+      auto LoadCost = thisT()->getMemoryOpCost(Instruction::Load, EntryTy,
+                                               Alignment, 0, CostKind);
+
+      return LoadCost + BrCost +
+             (SI->defaultDestUnreachable() ? 0 : (CmpCost + BrCost));
+    }
+
     return BaseT::getCFInstrCost(Opcode, CostKind, I);
   }
 
diff --git a/llvm/lib/Target/X86/X86TargetTransformInfo.cpp b/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
index 22a646f10507d..1cdb4397a4683 100644
--- a/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
+++ b/llvm/lib/Target/X86/X86TargetTransformInfo.cpp
@@ -6155,22 +6155,8 @@ X86TTIImpl::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
 InstructionCost X86TTIImpl::getCFInstrCost(unsigned Opcode,
                                            TTI::TargetCostKind CostKind,
                                            const Instruction *I) const {
-  if (Opcode == Instruction::Switch && CostKind == TTI::TCK_CodeSize) {
-    unsigned JumpTableSize, NumSuccs = I->getNumSuccessors();
-    getEstimatedNumberOfCaseClusters(*cast<SwitchInst>(I), JumpTableSize,
-                                     nullptr, nullptr);
-    // A trivial unconditional branch.
-    if (NumSuccs == 1)
-      return TTI::TCC_Basic;
-
-    // Assume that lowering the switch block is implemented by binary search if
-    // no jump table is generated.
-    if (JumpTableSize == 0)
-      return llvm::Log2_32_Ceil(NumSuccs) * 2 * TTI::TCC_Basic;
-
-    // Indirect branch + default compare + default jump
-    return 3 * TTI::TCC_Basic;
-  }
+  if (Opcode == Instruction::Switch)
+    return BaseT::getCFInstrCost(Opcode, CostKind, I);
 
   if (CostKind != TTI::TCK_RecipThroughput)
     return Opcode == Instruction::PHI ? TTI::TCC_Free : TTI::TCC_Basic;
diff --git a/llvm/test/Analysis/CostModel/X86/switch.ll b/llvm/test/Analysis/CostModel/X86/switch.ll
index e668e365e899d..ae0f6fe78d8d0 100644
--- a/llvm/test/Analysis/CostModel/X86/switch.ll
+++ b/llvm/test/Analysis/CostModel/X86/switch.ll
@@ -7,7 +7,7 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 
 define i32 @single_succ_switch(i32 %x) {
 ; THROUGHPUT-LABEL: 'single_succ_switch'
-; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
 ; THROUGHPUT-NEXT:    ]
 ; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
 ;
@@ -30,7 +30,7 @@ default:
 
 define i32 @dense_switch(i32 %x) {
 ; THROUGHPUT-LABEL: 'dense_switch'
-; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
 ; THROUGHPUT-NEXT:      i32 0, label %bb0
 ; THROUGHPUT-NEXT:      i32 1, label %bb1
 ; THROUGHPUT-NEXT:      i32 2, label %bb2
@@ -60,7 +60,7 @@ define i32 @dense_switch(i32 %x) {
 ; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
 ;
 ; CODESIZE-LABEL: 'dense_switch'
-; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: switch i32 %x, label %default [
 ; CODESIZE-NEXT:      i32 0, label %bb0
 ; CODESIZE-NEXT:      i32 1, label %bb1
 ; CODESIZE-NEXT:      i32 2, label %bb2
@@ -96,9 +96,77 @@ default:
   unreachable
 }
 
+define i32 @dense_switch_reachable_default(i32 %x) {
+; THROUGHPUT-LABEL: 'dense_switch_reachable_default'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:      i32 0, label %bb0
+; THROUGHPUT-NEXT:      i32 1, label %bb1
+; THROUGHPUT-NEXT:      i32 2, label %bb2
+; THROUGHPUT-NEXT:      i32 3, label %bb3
+; THROUGHPUT-NEXT:      i32 4, label %bb4
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 0
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 2
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 3
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 4
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 5
+;
+; LATENCY-LABEL: 'dense_switch_reachable_default'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:      i32 0, label %bb0
+; LATENCY-NEXT:      i32 1, label %bb1
+; LATENCY-NEXT:      i32 2, label %bb2
+; LATENCY-NEXT:      i32 3, label %bb3
+; LATENCY-NEXT:      i32 4, label %bb4
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+;
+; CODESIZE-LABEL: 'dense_switch_reachable_default'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 4 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:      i32 0, label %bb0
+; CODESIZE-NEXT:      i32 1, label %bb1
+; CODESIZE-NEXT:      i32 2, label %bb2
+; CODESIZE-NEXT:      i32 3, label %bb3
+; CODESIZE-NEXT:      i32 4, label %bb4
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %bb0
+    i32 1, label %bb1
+    i32 2, label %bb2
+    i32 3, label %bb3
+    i32 4, label %bb4
+  ]
+bb0:
+  ret i32 0
+bb1:
+  ret i32 1
+bb2:
+  ret i32 2
+bb3:
+  ret i32 3
+bb4:
+  ret i32 4
+default:
+  ret i32 5
+}
+
 define i32 @sparse_switch(i32 %x) {
 ; THROUGHPUT-LABEL: 'sparse_switch'
-; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
 ; THROUGHPUT-NEXT:      i32 0, label %bb0
 ; THROUGHPUT-NEXT:      i32 100, label %bb1
 ; THROUGHPUT-NEXT:      i32 200, label %bb2
@@ -164,9 +232,77 @@ default:
   unreachable
 }
 
+define i32 @sparse_switch_reachable_default(i32 %x) {
+; THROUGHPUT-LABEL: 'sparse_switch_reachable_default'
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:      i32 0, label %bb0
+; THROUGHPUT-NEXT:      i32 100, label %bb1
+; THROUGHPUT-NEXT:      i32 200, label %bb2
+; THROUGHPUT-NEXT:      i32 300, label %bb3
+; THROUGHPUT-NEXT:      i32 400, label %bb4
+; THROUGHPUT-NEXT:    ]
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 0
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 1
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 2
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 3
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 4
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: ret i32 5
+;
+; LATENCY-LABEL: 'sparse_switch_reachable_default'
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
+; LATENCY-NEXT:      i32 0, label %bb0
+; LATENCY-NEXT:      i32 100, label %bb1
+; LATENCY-NEXT:      i32 200, label %bb2
+; LATENCY-NEXT:      i32 300, label %bb3
+; LATENCY-NEXT:      i32 400, label %bb4
+; LATENCY-NEXT:    ]
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+;
+; CODESIZE-LABEL: 'sparse_switch_reachable_default'
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 6 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:      i32 0, label %bb0
+; CODESIZE-NEXT:      i32 100, label %bb1
+; CODESIZE-NEXT:      i32 200, label %bb2
+; CODESIZE-NEXT:      i32 300, label %bb3
+; CODESIZE-NEXT:      i32 400, label %bb4
+; CODESIZE-NEXT:    ]
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 0
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 1
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 2
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 3
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 4
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: ret i32 5
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %bb0
+    i32 100, label %bb1
+    i32 200, label %bb2
+    i32 300, label %bb3
+    i32 400, label %bb4
+  ]
+bb0:
+  ret i32 0
+bb1:
+  ret i32 1
+bb2:
+  ret i32 2
+bb3:
+  ret i32 3
+bb4:
+  ret i32 4
+default:
+  ret i32 5
+}
+
 define i32 @dense_big_switch(i32 %x) {
 ; THROUGHPUT-LABEL: 'dense_big_switch'
-; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
 ; THROUGHPUT-NEXT:      i32 0, label %bb0
 ; THROUGHPUT-NEXT:      i32 1, label %bb1
 ; THROUGHPUT-NEXT:      i32 2, label %bb2
@@ -220,7 +356,7 @@ define i32 @dense_big_switch(i32 %x) {
 ; LATENCY-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: unreachable
 ;
 ; CODESIZE-LABEL: 'dense_big_switch'
-; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 3 for instruction: switch i32 %x, label %default [
+; CODESIZE-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: switch i32 %x, label %default [
 ; CODESIZE-NEXT:      i32 0, label %bb0
 ; CODESIZE-NEXT:      i32 1, label %bb1
 ; CODESIZE-NEXT:      i32 2, label %bb2
@@ -288,7 +424,7 @@ default:
 
 define i32 @sparse_big_switch(i32 %x) {
 ; THROUGHPUT-LABEL: 'sparse_big_switch'
-; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 0 for instruction: switch i32 %x, label %default [
+; THROUGHPUT-NEXT:  Cost Model: Found an estimated cost of 1 for instruction: switch i32 %x, label %default [
 ; THROUGHPUT-NEXT:      i32 0, label %bb0
 ; THROUGHPUT-NEXT:      i32 100, label %bb1
 ; THROUGHPUT-NEXT:      i32 200, label %bb2



More information about the llvm-commits mailing list