Skip to content

[CodeGen] Allow -enable-ext-tsp-block-placement and -apply-ext-tsp-for-size passed together - #183642

Merged
SharonXSharon merged 1 commit into
llvm:mainfrom
SharonXSharon:llvm
Feb 28, 2026
Merged

SharonXSharon merged 1 commit into
llvm:mainfrom
SharonXSharon:llvm

Conversation

@SharonXSharon

Copy link
Copy Markdown
Contributor

Currently, the asserts fires when both UseExtTspForPerf and UseExtTspForSize are true on a given function.

Ideally, we should allow -enable-ext-tsp-block-placement and -apply-ext-tsp-for-size passed together, meaning run the block placement for performance on hot functions, while run the placement for size on cold functions.

The diff makes UseExtTspForPerf and UseExtTspForSize mutually exclusive per-function: functions with the OptForSize attribute use ext-tsp block placement for size, while the others use ext-tsp block placement for perf.

…for-size` work together

Reorder the computation of `UseExtTspForPerf` and `UseExtTspForSize` so
that when both `-enable-ext-tsp-block-placement` and
`-apply-ext-tsp-for-size` are enabled, they are mutually exclusive
per-function: functions with the `OptForSize` attribute use ext-tsp
block placement for size, while hot functions with profile data use
ext-tsp block placement for perf.

Previously, `UseExtTspForPerf` was computed first without considering
`UseExtTspForSize`, so a function could potentially have both flags set.
Now `UseExtTspForSize` is evaluated first, and `UseExtTspForPerf` is
only set when `!UseExtTspForSize`.
@SharonXSharon
SharonXSharon marked this pull request as ready for review February 26, 2026 23:38
@llvmbot

llvmbot commented Feb 26, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-backend-x86

Author: None (SharonXSharon)

Changes

Currently, the asserts fires when both UseExtTspForPerf and UseExtTspForSize are true on a given function.

Ideally, we should allow -enable-ext-tsp-block-placement and -apply-ext-tsp-for-size passed together, meaning run the block placement for performance on hot functions, while run the placement for size on cold functions.

The diff makes UseExtTspForPerf and UseExtTspForSize mutually exclusive per-function: functions with the OptForSize attribute use ext-tsp block placement for size, while the others use ext-tsp block placement for perf.


Full diff: https://github.com/llvm/llvm-project/pull/183642.diff

2 Files Affected:

  • (modified) llvm/lib/CodeGen/MachineBlockPlacement.cpp (+2-2)
  • (added) llvm/test/CodeGen/X86/code_placement_ext_tsp_size_and_perf.ll (+91)
diff --git a/llvm/lib/CodeGen/MachineBlockPlacement.cpp b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
index 625fba36b3d3a..f0e5e7efd132c 100644
--- a/llvm/lib/CodeGen/MachineBlockPlacement.cpp
+++ b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
@@ -3598,10 +3598,10 @@ bool MachineBlockPlacement::run(MachineFunction &MF) {
   bool UseExtTspForPerf = false;
   bool UseExtTspForSize = false;
   if (3 <= MF.size() && MF.size() <= ExtTspBlockPlacementMaxBlocks) {
+    UseExtTspForSize = OptForSize && ApplyExtTspForSize;
     UseExtTspForPerf =
-        EnableExtTspBlockPlacement &&
+        !UseExtTspForSize && EnableExtTspBlockPlacement &&
         (ApplyExtTspWithoutProfile || MF.getFunction().hasProfileData());
-    UseExtTspForSize = OptForSize && ApplyExtTspForSize;
   }
 
   // Apply tail duplication.
diff --git a/llvm/test/CodeGen/X86/code_placement_ext_tsp_size_and_perf.ll b/llvm/test/CodeGen/X86/code_placement_ext_tsp_size_and_perf.ll
new file mode 100644
index 0000000000000..0980bba58f018
--- /dev/null
+++ b/llvm/test/CodeGen/X86/code_placement_ext_tsp_size_and_perf.ll
@@ -0,0 +1,91 @@
+; RUN: llc -mcpu=corei7 -mtriple=x86_64-linux -verify-machineinstrs -enable-ext-tsp-block-placement -apply-ext-tsp-for-size < %s | FileCheck %s
+
+;; Cold function with optsize: should use ext-tsp for size.
+;; The size-optimized layout keeps the original order (b0, b1, b2) since it
+;; minimizes code size by avoiding extra jumps.
+define void @cold_func() optsize !prof !2 {
+;
+; +-----+
+; | b0  | -+
+; +-----+  |
+;   |      |
+;   | 10   |
+;   v      |
+; +-----+  |
+; | b1  |  | 10000
+; +-----+  |
+;   |      |
+;   | 10   |
+;   v      |
+; +-----+  |
+; | b2  | <+
+; +-----+
+;
+; CHECK-LABEL: cold_func:
+; CHECK: %b0
+; CHECK: %b1
+; CHECK: %b2
+
+b0:
+  %call = call zeroext i1 @a()
+  br i1 %call, label %b1, label %b2, !prof !1
+
+b1:
+  call void @d()
+  call void @d()
+  call void @d()
+  br label %b2
+
+b2:
+  call void @e()
+  ret void
+}
+
+;; Hot function without optsize: should use ext-tsp for perf.
+;; The perf-optimized layout reorders blocks to place the most likely successor
+;; (b2) right after b0, giving b0 -> b2 -> b1.
+define void @hot_func() !prof !3 {
+;
+; +-----+
+; | b0  | -+
+; +-----+  |
+;   |      |
+;   | 40   |
+;   v      |
+; +-----+  |
+; | b1  |  | 100
+; +-----+  |
+;   |      |
+;   | 40   |
+;   v      |
+; +-----+  |
+; | b2  | <+
+; +-----+
+;
+; CHECK-LABEL: hot_func:
+; CHECK: %b0
+; CHECK: %b2
+; CHECK: %b1
+
+b0:
+  %call = call zeroext i1 @a()
+  br i1 %call, label %b1, label %b2, !prof !1
+
+b1:
+  call void @d()
+  call void @d()
+  call void @d()
+  br label %b2
+
+b2:
+  call void @e()
+  ret void
+}
+
+declare zeroext i1 @a()
+declare void @d()
+declare void @e()
+
+!1 = !{!"branch_weights", i32 10, i32 10000}
+!2 = !{!"function_entry_count", i64 1}
+!3 = !{!"function_entry_count", i64 2200}

@SharonXSharon
SharonXSharon merged commit fe76e90 into llvm:main Feb 28, 2026
15 checks passed
sahas3 pushed a commit to sahas3/llvm-project that referenced this pull request Mar 4, 2026
…-for-size` passed together (llvm#183642)

Currently, the asserts fires when both `UseExtTspForPerf` and
`UseExtTspForSize` are true on a given function.

Ideally, we should allow `-enable-ext-tsp-block-placement` and
`-apply-ext-tsp-for-size` passed together, meaning run the block
placement for performance on hot functions, while run the placement for
size on cold functions.

The diff makes `UseExtTspForPerf` and `UseExtTspForSize` mutually
exclusive per-function: functions with the `OptForSize` attribute use
ext-tsp block placement for size, while the others use ext-tsp block
placement for perf.

Co-authored-by: Sharon Xu <sharonxu@fb.com>
sujianIBM pushed a commit to sujianIBM/llvm-project that referenced this pull request Mar 5, 2026
…-for-size` passed together (llvm#183642)

Currently, the asserts fires when both `UseExtTspForPerf` and
`UseExtTspForSize` are true on a given function.

Ideally, we should allow `-enable-ext-tsp-block-placement` and
`-apply-ext-tsp-for-size` passed together, meaning run the block
placement for performance on hot functions, while run the placement for
size on cold functions.

The diff makes `UseExtTspForPerf` and `UseExtTspForSize` mutually
exclusive per-function: functions with the `OptForSize` attribute use
ext-tsp block placement for size, while the others use ext-tsp block
placement for perf.

Co-authored-by: Sharon Xu <sharonxu@fb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants