[llvm] [CodeGen] Resolve Fixme: Use similar heuristics to IfConversion for isFormingBranchFromSelectProfitable (PR #145890)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 26 06:14:32 PDT 2025
https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/145890
None
>From bedc228b99131dbcd862ab1d0a78f61ca9acba34 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Thu, 26 Jun 2025 09:13:38 -0400
Subject: [PATCH] [CodeGen] Resolve Fixme: Use similar heuristics to
IfConversion for isFormingBranchFromSelectProfitable
---
llvm/lib/CodeGen/CodeGenPrepare.cpp | 104 ++++++++++++++++++++++------
1 file changed, 84 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 43574a54c37dd..5d7e61da7b914 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -7364,6 +7364,7 @@ static bool sinkSelectOperand(const TargetTransformInfo *TTI, Value *V) {
}
/// Returns true if a SelectInst should be turned into an explicit branch.
+/// Uses IfConversion-style cost analysis to make the decision.
static bool isFormingBranchFromSelectProfitable(const TargetTransformInfo *TTI,
const TargetLowering *TLI,
SelectInst *SI) {
@@ -7371,37 +7372,100 @@ static bool isFormingBranchFromSelectProfitable(const TargetTransformInfo *TTI,
if (!TLI->isPredictableSelectExpensive())
return false;
- // FIXME: This should use the same heuristics as IfConversion to determine
- // whether a select is better represented as a branch.
+ // Use IfConversion-style cost analysis to determine profitability.
+ // This incorporates instruction costs, branch probabilities, and
+ // target-specific profitability analysis similar to IfConversion.
- // If metadata tells us that the select condition is obviously predictable,
- // then we want to replace the select with a branch.
- uint64_t TrueWeight, FalseWeight;
- if (extractBranchWeights(*SI, TrueWeight, FalseWeight)) {
+ // Get branch probability information if available
+ uint64_t TrueWeight = 1, FalseWeight = 1;
+ bool HasWeights = extractBranchWeights(*SI, TrueWeight, FalseWeight);
+
+ BranchProbability TrueProbability = BranchProbability::getUnknown();
+ if (HasWeights && (TrueWeight + FalseWeight) > 0) {
+ TrueProbability = BranchProbability::getBranchProbability(
+ TrueWeight, TrueWeight + FalseWeight);
+ }
+
+ // Analyze instruction costs similar to IfConversion's cost model
+ InstructionCost SelectCost =
+ TTI->getCFInstrCost(Instruction::Select, TTI::TCK_SizeAndLatency);
+
+ // Estimate branch cost including potential misprediction penalty
+ InstructionCost BranchCost =
+ TTI->getCFInstrCost(Instruction::Br, TTI::TCK_SizeAndLatency);
+
+ // Factor in predictability - highly predictable branches are cheaper
+ if (HasWeights) {
uint64_t Max = std::max(TrueWeight, FalseWeight);
uint64_t Sum = TrueWeight + FalseWeight;
- if (Sum != 0) {
+ if (Sum > 0) {
auto Probability = BranchProbability::getBranchProbability(Max, Sum);
- if (Probability > TTI->getPredictableBranchThreshold())
- return true;
+ if (Probability > TTI->getPredictableBranchThreshold()) {
+ // Highly predictable - reduce effective branch cost
+ BranchCost = BranchCost / 2;
+ } else {
+ // Unpredictable - add misprediction penalty
+ BranchCost += TTI->getBranchMispredictPenalty();
+ }
}
+ } else {
+ // No branch weight info - assume unpredictable, add misprediction penalty
+ BranchCost += TTI->getBranchMispredictPenalty();
}
+ // Consider operand costs - expensive operands benefit from branching
+ // as they can be sunk to avoid speculative execution
+ InstructionCost TrueOpCost = 0, FalseOpCost = 0;
+ if (sinkSelectOperand(TTI, SI->getTrueValue())) {
+ if (auto *TrueInst = dyn_cast<Instruction>(SI->getTrueValue())) {
+ TrueOpCost = TTI->getInstructionCost(
+ TrueInst, TargetTransformInfo::TCK_SizeAndLatency);
+ }
+ }
+ if (sinkSelectOperand(TTI, SI->getFalseValue())) {
+ if (auto *FalseInst = dyn_cast<Instruction>(SI->getFalseValue())) {
+ FalseOpCost = TTI->getInstructionCost(
+ FalseInst, TargetTransformInfo::TCK_SizeAndLatency);
+ }
+ }
+
+ // If we have expensive operands that can be sunk, branching is beneficial
+ InstructionCost SinkBenefit = 0;
+ if (HasWeights && (TrueWeight + FalseWeight) > 0) {
+ // Weight the benefit by probability of avoiding the expensive operand
+ if (TrueOpCost > 0) {
+ auto FalseProbability = BranchProbability::getBranchProbability(
+ FalseWeight, TrueWeight + FalseWeight);
+ SinkBenefit += TrueOpCost * FalseProbability.getNumerator() /
+ FalseProbability.getDenominator();
+ }
+ if (FalseOpCost > 0) {
+ SinkBenefit += FalseOpCost * TrueProbability.getNumerator() /
+ TrueProbability.getDenominator();
+ }
+ } else {
+ // No probability info - assume 50/50 distribution
+ SinkBenefit = (TrueOpCost + FalseOpCost) / 2;
+ }
+
+ // Check if condition has multiple uses (similar to IfConversion's checks)
CmpInst *Cmp = dyn_cast<CmpInst>(SI->getCondition());
+ if (!Cmp || !Cmp->hasOneUse()) {
+ // Multiple uses mean the condition will be live anyway,
+ // reducing the benefit of branching
+ return SinkBenefit > SelectCost;
+ }
- // If a branch is predictable, an out-of-order CPU can avoid blocking on its
- // comparison condition. If the compare has more than one use, there's
- // probably another cmov or setcc around, so it's not worth emitting a branch.
- if (!Cmp || !Cmp->hasOneUse())
- return false;
+ // Final cost comparison: Branch is profitable if total branch cost
+ // (including condition computation) is less than select cost minus
+ // the benefit from sinking expensive operands
+ InstructionCost ConditionCost =
+ TTI->getInstructionCost(Cmp, TargetTransformInfo::TCK_SizeAndLatency);
- // If either operand of the select is expensive and only needed on one side
- // of the select, we should form a branch.
- if (sinkSelectOperand(TTI, SI->getTrueValue()) ||
- sinkSelectOperand(TTI, SI->getFalseValue()))
- return true;
+ InstructionCost TotalBranchCost = BranchCost + ConditionCost;
+ InstructionCost EffectiveSelectCost = SelectCost - SinkBenefit;
- return false;
+ return TotalBranchCost < EffectiveSelectCost;
}
/// If \p isTrue is true, return the true value of \p SI, otherwise return
More information about the llvm-commits
mailing list