On 6/5/2026 3:25 AM, Georg-Johann Lay via Gcc wrote:
In match.pd there are two kinds of patterns: Canonicalizations
and optimizations.
While canonicalizations simplify the compile task by reducing
combinatorial complexity, optimization patterns try to improve
code performance.
The trouble with the optimization patterns is that they operate blindly,
not considering costs or target capabilities in any way.
[ ... ]
This would go against guiding principles in the gimple phases.
Essentially we very much have avoided things like target costing in
gimple. That's part of what makes gimple transformations predictable
and relatively easy to evaluate.
What we have talked about, but never taken to proof of concept was the
ability for the targets to have a rewriting pass that ran immediately
before conversion to RTL. The idea was to transform gimple into forms
the target preferred and it was meant to be driven by a match.pd like
framework.
It's not perfect, but that's the best idea in this space so far.
Particularly bad example are patterns of the form
/* (zero_one == 0) ? y : z <op> y -> ((typeof(y))zero_one * z) <op> y */
/* (zero_one != 0) ? z <op> y : y -> ((typeof(y))zero_one * z) <op> y */
that map single-bit tests to multiplications, even on machines where
multiplication is very expensive, and even when a target doesn't support
multiplications.
I've argued that the multiplication form of conditional moves is bad and
that we should canonicalize to a standard looking target = test ?
trueval : falseval form.
What stands in the way of that is the RTL expansion path doesn't do a
particularly good job with those forms on targets without a conditional
move pattern. Raphael made an attempt to fix this a year or two ago,
but it had a few problems that needed to be sorted out. I'd have to
re-familiarize myself with those problems.
But obviously that's just one example. But it shows that there is a
path forward without breaking the core ideas behind the gimple framework.
jeff