Expand description
The passes that run before selection, as a group with a name and a stated membership.
Design: spec/optimizer/36-lowering-and-isel.md section 36.1.
Section 36.1 reads the list of passes gcc runs immediately before pass_expand and draws one
conclusion from it. Nine of them are lowerings, and each one turns a construct into a shape of
control flow or a shape of arithmetic that the expander would otherwise have to invent. The
expander is the wrong place to invent control flow, because by the time it runs the graph is
being consumed rather than edited. That is spec 10.2’s rule arrived at from the other side: a
lowering rule replaces a term with a term and has nowhere to put a block, so any construct whose
lowering is a new shape of control flow is rewritten before selection runs.
Every one of these passes already existed and every one of them was already called from
crate::pipeline, one line at a time, in this order. What did not exist was the thing the
section asks for, which is that they are a group rather than a set of unrelated passes that
happen to run next to each other. The reason gcc’s list is nine passes long is that it grew one
pass at a time over three decades, and a group with a written down membership is the thing that
stops the same happening here.
§The name
The lowering group, which is what gcc calls its own and is what this module is named after. The longer and more honest description section 36.1 gives is everything the selector cannot express, and that is the test for whether something belongs here: not that it is a rewrite of the IR, but that the thing it rewrites is one no rule in the table can be written for.
§What is in it
Step::GROUP, in the order it runs, and that list is the membership. A new lowering is a new
variant of Step and a new line in that list, which is one place rather than whichever line
of the pipeline looked convenient.
§What the order is for
Most of it does not matter and the parts that do are on the variants. The rule behind them is the same one every time: a pass is written about the constructs the machine has, so anything that produces a construct somebody below is written about has to run above them. An integer of forty bits is not a width this machine has, an ordered load is not a load any pass below is written about, and a quad float is not a float the pass that rewrites floats knows anything of.
§What it is not
Not the selector, and not a fixed point. Each step runs once, and a step that produces work for a step above it would be a bug in this order rather than a reason to run the group twice.
Not a promise that the construct is gone either, and this is the part worth reading twice. Every step here has cases it walks away from: a copy too large to be a run of moves, an ordered access wider than the machine does in one go, a conversion the machine already has an instruction for and so has no reason to touch. Some of those are the machine having the construct after all and some of them are a refusal, and a refusal is left standing on purpose, because the selector is what names the construct it had no rule for and that is a better error than a rewrite that guessed.
So what Ran records is what each step found and what it left, and reading one of those is
how you tell the two apart. What the group promises is only that every construct in the list was
put in front of the step that answers for it, which is the thing that stops being true when
somebody adds a lowering to whichever line of the pipeline looked convenient.
Structs§
- Did
- What one step did to one function.
- Lowerings
- What the group did to every function a run lowered, in the order they came through.
- Ran
- What the whole group did to one function.
Enums§
- Step
- One member of the group.
Functions§
- group
- Runs the whole group over one function, in the order
Step::GROUPgives.