Skip to main content

Module lowering

Module lowering 

Source
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::GROUP gives.