CT_00_055 -- Zicond with if-conversion improvements (GCC)
About
The ZiCondops extension provides a conditional zero primitive upon which subsets of conditional move and conditional arithmetic/logical operations can be implemented. Transforming control flow into conditional operations can improve code performance by eliminating branch mispredict costs as well as reducing the load on the branch predictors. The earlier in the optimizer pipeline these transformations are performed the more likely they are to expose secondary optimization opportunities as well since the transformations result in larger basic blocks (a fundamental unit of code most compiler optimizations work on).
This item is meant to track additional opportunities to optimize code using the zicond extension
Improve gimple if-conversion and gimple→rtl expansion
Conditional moves can be expressed in multiple forms in gimple. The multiplication by a boolean variant could have initial RTL generation step improved to first try conditional move expanders, then fall back to other approaches
Proof of concept code exists
Recognize multiply variant and rewrite into COND_EXPR
Adjust gimple→rtl expansion to try and avoid regressions on targets without conditional moves
But still needs work as it's regressing, even on risc-v targets
Adjustment of gimple if-converter to handle sign bit test selecting across various constant scenarios can pick up more cases. For example selecting between 0 and a constant with a run of on bits in the LSB or MSB.
Upstream agreement on form (use COND_EXPR form rather than shifts)
Implement in match.pd framework (initial POC was done in phi-opt)
Expander work to handle the various constants we can select across
Improvement of if-conversion pass in GCC
Resolve implementation details for condzero_arith code to use more efficient sequences than generalized conditional moves when possible
Handle SUBREG and zero/sign extended objects
Requires adjustments to the conditional execution pass in RTL
extensions probably aren't hard to support, subregs will require deeper thought
Biggest issues here may all be in the code to handle #8 below If-convert the conditional in the move_one_fast loop of deepsjeng
Two approaches
Improve min/max discovery in gimple which should simplify the conditional code to optimizable form in the RTL if-converter code
Improve the RTL if-converter code to better handle multiple if-convertable instrutions
Add backend pattern to recognize an if-then-else as a min/max
Robin has submitted some code for this, but it needs to be adjusted for reviewer feedback
Cost model adjustments
Costing the generated conditional move sequence needs adjustments. There are often insns that appear in the sequence that have a high probability of being removed by later passes (particularly register allocation and const/copy propagation). These can throw off the initial costing and need adjustments
As touched on in upstream bug 112462, when we have a condition other than (reg) eq/ne (const_int 0) we need to bump the rtx_cost of using zicond as the condition will need canonicalization.
Similarly we may need to bump the rtx_cost depending on the true/false arms
May want to do some refactoring so that we can share code across costing & expansion.
Relax predicate on conditional move expander to allow more constants. The general idea is to be able to select more efficient sequences in special cases. For example given two constants C1 and C2. If the sum of the costs of computing C1 and C2 is greater than the cost of computing C1 by 2 insns or more, then it may be profitable to compute C1 and conditionally add (C2 - C1) to the result.
When one arm of a conditional move can be trivially derived from the other, say by adding a small constant, we can emit a single zicond + adjustment rather than a fully generalized conditional move via 2 zicond instructions. Conceptually this is similar to how we handle something like x = cond ? C1 : C2, we just need to detect it earlier. See these examples on godbolt.
Matching this style would be one approach and probably generally profitable for the first case: (set (reg:DI 135 [ <retval> ]) (plus:DI (if_then_else:DI (reg:DI 145) (const_int 0 [0]) (reg:DI 143)) (reg:DI 147))) Obviously we could replace the PLUS with a variety of operators. Another approach would likely be to match (which falls into the sub-word cases) (set (reg:DI 147) (if_then_else:DI (reg:DI 145) (sign_extend:DI (plus:SI (subreg:SI (reg:DI 138) 0) (const_int 5 [0x5]))) (const_int 0 [0])))Selecting between constants based on output of a sign bit test.
-1, 2^n is srai+bset – best handled in rtl ifcvt
~(2^n), 0 is srai+bclr – best handled in rtl ifcvt
-1, simm12 is srai+ori – best handled in rtl ifcvt
simm12, 0 is srai+andi – best handled in rtl ifcvt
high bits set, 0 is srai+sll – must be handled in gimple
low bits set, 0 is srai+srl – must be handled in gimple
Stakeholders/Partners
RISE:
Ventana: Raphael Zinsly, Jeff Law, Robin Dapp ESWIN: Fei Gao
External:
Dependencies
Status
Development | IN PROGRESS |
|
|---|---|---|
Development Timeline | 1H2025 |
|
Upstreaming | IN PROGRESS
|
|
Upstream Version | gcc-16 (target) (Spring 2026)
|
|
Contacts | Raphael Zinsly (Ventana) Jeff Law (Ventana) |
|
Dependencies | None |
|
Updates
Jul 16, 2025
Remaining items from 1H2025 rolled into new task