Am 06.06.26 um 00:17 schrieb Jeffrey Law:

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.

At no point I proposed to introduce costing.

All I said is that match.pd /is/ doing "optimizations" without using
any metric, which is a correct statement as far as I know.

And without a metric, you have no idea where you are heading.
That works for trivial cases like x * 0 = 0, and when all the
dozens of targets behave similar in this regard.

There are cases though where different targets means different metrics.

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.

Hence not that different to my proposal of a target-specific match.pd.

The difference is that I proposed a different location, namely at
match.pd time.  The reason is that it's enough to sort out some
bad apples like PR118012 etc.; the target's match.pd would just take
precedence over the middle end's.  For example, to reject a pattern:

(simplify
 (pattern)
 (scratch))

The target could use any means it likes to work out which patterns
to reject, or which patterns to map to which other patterns.

The assumption is that gimple's match.pd is good in almost all cases,
and thus all a target has to do is to "override" some detrimental rules.

Additional benefits:

- A target could fold build-ins.  Currently, a target can only fold
  MD build-ins in TARGET_FOLD_BUILTIN.

- A target could map, say, adddi3 to a lib call.  Currently, that's not
  possible and would require change optabs and what not.

The issue with running target match.pd right before expand is that some
of the bad apples may have already been transformed to something else,
and the pattern that matched in match.pd isn't there any more at expand.

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.

Ok, would be great to see progress at that front.

Johann

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

Reply via email to