Expand description
The IR as something a rule can match against, which is rucc_ir::term.
Re-exported rather than reached for through rucc_ir, because this crate had it first and
every caller here says crate::term. It moved down when rucc-opt became the second crate
to match a rule set against the IR, and where it lives is not something a caller of it has
any reason to know.
The IR as something a rule can match against.
Design: spec/10-backend.md section 10.2 and spec/optimizer/13-rewrite-rules.md.
Two rule sets are matched against the IR. rucc-codegen lowers it to machine terms and
rucc-opt rewrites it to more IR, and both of them are asking what an instruction is called
and what its operands are. This is here rather than in either of them so that there is one
answer to that: a rewrite rule and a lowering rule that spelled add.i32 differently would
be two vocabularies over one IR, and the day they drifted apart nothing would say so.
A rule is written about a term and the compiler has no terms. It has a function full of
instructions, and what a pattern is about is one of them together with whatever its operands
were computed from. So this is the Subject the matcher asks its three questions of, and
the answers come out of the IR: nothing is built and nothing is thrown away.
§How an operand is shown
The same IR value can be several different terms. (add.i32 (value.i32 x) (iconst.i32 k))
and (add.i32 (value.i32 x) (value.i32 y)) are two patterns over one instruction, and which
one it is depends on whether the second operand is a constant and on whether the rule that
wants a constant will take this one. (add.i64 (value.i64 x) (mul.i64 (value.i64 y) (iconst.i64 4))) is a third, and it is about two instructions rather than one.
The matcher does not backtrack across alternatives for one node: Subject::head gives one
answer and the walk believes it. So the choice is made before the walk rather than during it.
A Plan says how each operand of the instruction is shown, the caller tries the plans in
order, and the first that matches is the one that fires. There are at most three ways to show
an operand and at most two operands in any pattern either rule set has, so the whole of the
search is a handful of walks over a trie, each of which fails in its first node or two.
§How deep it goes
One level. An operand may be shown as the instruction that computed it, and that instruction’s own operands are shown as a register or as a constant and never expanded again, which is as deep as any pattern in either rule file reaches. A rule set that wants three levels needs this to grow a level, and it would be found by the rule failing to fire rather than by anything going wrong.
Structs§
- Terms
- One instruction of a function, as the terms a rule could match.
Enums§
Constants§
- ADDRESS
- How wide an address is on the machine this lowers for.
- MAX_
ARGS - How many operands of one instruction a plan can speak about.
- PLAIN
- Everything shown as a register, which is the plan that matches when no other does.
Functions§
- float_
slot - Which of the two float widths a type is, or nothing for anything that is not a float.
- head_of
- What an instruction is called in a rule file, or nothing if the rules have no name for it.
- heads
- Every name this module can give an instruction, with the opcode it gives it to.
- slot
- Which of the four widths a type is, or nothing for a width no rule is written at.
Type Aliases§
- Plan
- How every operand of one instruction is shown.