[llvm] [SimplifyCFG][profcheck] Synthesize profile for `br (X == 0 | X == 1), T, F1 -> switch (PR #161549)
Mircea Trofin via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 1 09:57:19 PDT 2025
https://github.com/mtrofin updated https://github.com/llvm/llvm-project/pull/161549
>From 2d42032dcf855d31185fbb397a8103f86061af48 Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Tue, 30 Sep 2025 16:21:27 -0700
Subject: [PATCH] [SimplifyCFG][profcheck] Synthesize profile for `br (X == 0 |
X == 1), T, F1 -> switch
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 30 ++++++++++++++-----
.../Transforms/SimplifyCFG/switch_create.ll | 27 ++++++++++++-----
2 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 4d1f768e2177a..df436d0f68028 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -5148,14 +5148,18 @@ bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI,
if (ExtraCase && Values.size() < 2)
return false;
- // TODO: Preserve branch weight metadata, similarly to how
- // foldValueComparisonIntoPredecessors preserves it.
+ SmallVector<uint32_t> BranchWeights;
+ const bool HasProfile = !ProfcheckDisableMetadataFixes &&
+ extractBranchWeights(*BI, BranchWeights);
// Figure out which block is which destination.
BasicBlock *DefaultBB = BI->getSuccessor(1);
BasicBlock *EdgeBB = BI->getSuccessor(0);
- if (!TrueWhenEqual)
+ if (!TrueWhenEqual) {
std::swap(DefaultBB, EdgeBB);
+ if (HasProfile)
+ std::swap(BranchWeights[0], BranchWeights[1]);
+ }
BasicBlock *BB = BI->getParent();
@@ -5186,10 +5190,11 @@ bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI,
if (!isGuaranteedNotToBeUndefOrPoison(ExtraCase, AC, BI, nullptr))
ExtraCase = Builder.CreateFreeze(ExtraCase);
- if (TrueWhenEqual)
- Builder.CreateCondBr(ExtraCase, EdgeBB, NewBB);
- else
- Builder.CreateCondBr(ExtraCase, NewBB, EdgeBB);
+ // We don't have any info about this condition.
+ auto *Br = TrueWhenEqual ? Builder.CreateCondBr(ExtraCase, EdgeBB, NewBB)
+ : Builder.CreateCondBr(ExtraCase, NewBB, EdgeBB);
+ setExplicitlyUnknownBranchWeightsIfProfiled(*Br, *NewBB->getParent(),
+ DEBUG_TYPE);
OldTI->eraseFromParent();
@@ -5216,6 +5221,17 @@ bool SimplifyCFGOpt::simplifyBranchOnICmpChain(BranchInst *BI,
// Create the new switch instruction now.
SwitchInst *New = Builder.CreateSwitch(CompVal, DefaultBB, Values.size());
+ if (HasProfile) {
+ // We know the weight of the default case. We don't know the weight of the
+ // other cases, but rather than completely loose profiling info, we split
+ // the remaining probability equally over them.
+ SmallVector<uint32_t> NewWeights(Values.size() + 1);
+ NewWeights[0] = BranchWeights[1]; // this is the default, and we swapped if
+ // TrueWhenEqual.
+ for (auto &V : drop_begin(NewWeights))
+ V = BranchWeights[0] / Values.size();
+ setBranchWeights(*New, NewWeights, /*IsExpected=*/false);
+ }
// Add all of the 'cases' to the switch instruction.
for (ConstantInt *Val : Values)
diff --git a/llvm/test/Transforms/SimplifyCFG/switch_create.ll b/llvm/test/Transforms/SimplifyCFG/switch_create.ll
index 18c4ade46162c..ef5aee68e268e 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch_create.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch_create.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -switch-range-to-icmp < %s | FileCheck %s
; RUN: opt -S -data-layout="p:32:32-p1:16:16" -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -switch-range-to-icmp < %s | FileCheck -check-prefix=CHECK -check-prefix=DL %s
@@ -6,12 +6,12 @@ declare void @foo1()
declare void @foo2()
-define void @test1(i32 %V) {
+define void @test1(i32 %V) !prof !0 {
; CHECK-LABEL: @test1(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[F:%.*]] [
; CHECK-NEXT: i32 17, label [[T:%.*]]
; CHECK-NEXT: i32 4, label [[T]]
-; CHECK-NEXT: ]
+; CHECK-NEXT: ], !prof [[PROF1:![0-9]+]]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: T:
@@ -24,7 +24,7 @@ define void @test1(i32 %V) {
%C1 = icmp eq i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp eq i32 %V, 17 ; <i1> [#uses=1]
%CN = or i1 %C1, %C2 ; <i1> [#uses=1]
- br i1 %CN, label %T, label %F
+ br i1 %CN, label %T, label %F, !prof !1
T: ; preds = %0
call void @foo1( )
ret void
@@ -116,12 +116,12 @@ F: ; preds = %0
ret void
}
-define void @test2(i32 %V) {
+define void @test2(i32 %V) !prof !0 {
; CHECK-LABEL: @test2(
; CHECK-NEXT: switch i32 [[V:%.*]], label [[T:%.*]] [
; CHECK-NEXT: i32 17, label [[F:%.*]]
; CHECK-NEXT: i32 4, label [[F]]
-; CHECK-NEXT: ]
+; CHECK-NEXT: ], !prof [[PROF2:![0-9]+]]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: T:
@@ -134,7 +134,7 @@ define void @test2(i32 %V) {
%C1 = icmp ne i32 %V, 4 ; <i1> [#uses=1]
%C2 = icmp ne i32 %V, 17 ; <i1> [#uses=1]
%CN = and i1 %C1, %C2 ; <i1> [#uses=1]
- br i1 %CN, label %T, label %F
+ br i1 %CN, label %T, label %F, !prof !1
T: ; preds = %0
call void @foo1( )
ret void
@@ -1313,3 +1313,16 @@ if.then:
if.end:
ret void
}
+
+!0 = !{!"function_entry_count", i32 100}
+!1 = !{!"branch_weights", i32 6, i32 10}
+;.
+; DL: attributes #[[ATTR0:[0-9]+]] = { noredzone nounwind ssp }
+; DL: attributes #[[ATTR1:[0-9]+]] = { nounwind }
+; DL: attributes #[[ATTR2]] = { noredzone nounwind }
+; DL: attributes #[[ATTR3]] = { noredzone }
+;.
+; DL: [[META0:![0-9]+]] = !{!"function_entry_count", i32 100}
+; DL: [[PROF1]] = !{!"branch_weights", i32 10, i32 3, i32 3}
+; DL: [[PROF2]] = !{!"branch_weights", i32 6, i32 5, i32 5}
+;.
More information about the llvm-commits
mailing list