On 8/7/2026 4:44 PM, wangjue wrote:
Thank you for the suggestion. You're right that raising BRANCH_COST 
sufficiently makes this case if-convert. My concern is that changing it 
globally also affects other expansion and RTL profitability decisions, rather 
than just this particular noce transformation.

Current threshold
I compared the current TARGET_MAX_NOCE_IFCVT_SEQ_COST implementations:
/* Generic default.  */
return BRANCH_COST (true, predictable_p) * COSTS_N_INSNS (3);
/* i386.  */
return BRANCH_COST (true, predictable_p) * COSTS_N_INSNS (2);
/* RISC-V.  */
return COSTS_N_INSNS (BRANCH_COST (true, predictable_p));

With BRANCH_COST == 4, these correspond to thresholds of 48, 32 and 16. This 
made the current RISC-V threshold appear relatively conservative, particularly 
when Zicond is available.
Yea.  It's also worth noting that BRANCH_COST gets used in two very different places.

First way up in the generic/gimple/tree optimizers it's used to drive decisions for if combination, conversion and related transformations.   Then it's used down in the RTL space to drive decisions around if conversion.    I've had a nagging suspicion that we need to break it into two different values.  On our vt1 and vt2 designs we generally found that very aggressive branch costing early tended to hurt performance while very aggressive branch costing in the RTL tended to improve performance.  But we had enough other things to chase down that were more important so we never really did the analysis to confirm what we were seeing in limited testing and draw meaningful conclusions on where to go.



Increasing it globally may therefore generate more branchless code in unrelated 
places, including cases where the branch is actually predicted well by the 
hardware.
Instead, I was considering restricting the adjustment to the RISC-V noce 
threshold:
See above.  Yes, increasing can have unintended consequences.  That would be a secondary benefit of splitting BRANCH_COST into independent knobs for gimple vs RTL -- fewer unintended consequences as you work through issues with adjusting one value for your uarch.

Note that it may still be advantageous to convert things that are well predicted as if-converting will create larger blocks for the compiler's various optimizers to chew on.  It's a behavior I've always been curious to investigate, but it hasn't bubbled up high enough yet on the priority list.  Essentially one behavior we've seen is that LLVM consistently has fewer conditional branches (from a dynamic standpoint), but consistently higher branch mispredicts than GCC compiled code.  We investigated this a few years back (before focusing on vector) -- in x264 LLVM aggressively if-converted the clamp idioms with essentially zero benefit, but missed converting a tough to predict branch elsewhere that was far more important.   I've meant to go back and see if if-converting those clamps in GCC would in turn allow additional downstream optimization opportunities (GCC was if-converting the tougher, more valuable case).
It might also help if you passed along a testcase. I've found many of
the failure to if-convert problems are due to inefficiencies in the
sequences we generate; we can often get if-conversion to fire by
generating better generic sequences and fixing costing goofs elsewhere.
The case is in spec_qsort from 505.mcf_r. It occurs after med3 and its 
comparator have both been inlined into spec_qsort. The relevant call is:
pn = med3 (pn - 2 * d, pn - d, pn, cmp);
After inlining, the same ID condition controls three pointer selections. RTL 
if-conversion initially costs the candidate sequence at 48 cost units, 
equivalent to 12 instructions. A maximum cost of 47 does not trigger the 
conversion, while 48 does.
After later RTL optimization, the final sequence is reduced to:
1 slt
6 czero
3 add
This is 10 instructions, or 40 cost units. It appears that redundant condition 
calculations included in the initial candidate are removed by later passes.
The two preceding abs_cost comparisons remain branches. Only the final ID 
tie-breaker and the three dependent pointer selections are converted.
Yea, that could well be the one I was looking at fairly recently.  At the point where you're considering if-conversion, what values are you selecting across?

The one I remember from mcf was a select across 1, -1.  That was a 4 instruction sequence (slt+li+czero+addi), so cost 16 and thus a BRANCH_COST of 4 to trigger.  The sequence could be improved to a 3 instruction sequence (slt+slli+addi) and thus would start to trigger at a BRANCH_COST of 3.  The testcase ultimately reduced down to something like this:

    int foo(int x, int y) { return (y < x) ? 1 : -1; }

The solution was to improve selection across 2^n and 0, once that was done generic code would subtract 1 from that result giving us an efficient select across 2^n-1 and -1 which obviously includes a select across 1, -1.


Andrea pointed out during that work that defining a spaceship pattern would likely help in meaningful way and is almost certainly correct.  That might be another avenue to explore and would likely help numerous things without doing costing adjustments.

And yes, the if-converted sequence initially tends to have unnecessary copies, extensions, etc that make some sequences look unprofitable to use, but later optimizations would clean things up and they would have been profitable.  I've fixed several bugs in that area recently, though the most serious remains and I haven't found a good solution.  I touched on the problems with this commit:

So what I'd suggest would be to take the case you've found in MCF, reduce it down to a small testcase if possible and we'll start working with that.  We'd probably want that for the final patch anyway as a testcase, so even if we go with your approach on costing, this work would still be desirable.

commit 3ab2199392445f2deb3855dcfe68ecf0fed8466d
Author: Jeff Law <[email protected]>
Date:   Thu Jul 16 06:37:53 2026 -0600

    [RISC-V] Improve costing for if-converted sequences

    So I'm not happy with this entire routine, but after trying to fix things
    right, I'm back to adjusting the cost routine instead.

    The fundamental problem as I see it is the cstore patterns on RISC-V are
    suboptimal.
[ ... ]

The full commit message describes the issues.  I suspect finding a good solution to the problems in that full commit message would significantly help the RTL if-conversion phase make better choices.

Jeff


Reply via email to