Expand description
The machine IR, still in SSA, and its printer and parser.
Design: spec/10-backend.md. Layer rank 9, see spec/18-package-layout.md.
MIR is the second representation. It is still a control flow graph of blocks and it is still in SSA form, but the instructions are the target’s instructions and the operands are registers drawn from the target’s register classes. Instruction selection produces it, the allocator rewrites it, and the encoder reads it.
Nothing in this crate knows what any instruction means. An opcode is a name, an operand is a
register with a class and a role, and that is all a pass over MIR needs in order to move
instructions, split live ranges or insert a spill. What the opcodes mean is in the target’s
rule set, which is what the selector was compiled from, and in the encoder, which is
generated from the same description. That is what spec/10-backend.md section 10.8 means
when it says no pipeline crate holds target-specific code.
§The shape of an instruction
An opcode, an operand vector, an optional immediate, an optional memory addressing mode, and
the symbol it names. Twenty-four bytes. The operands are in one order, the ones the
instruction writes and then the ones it reads, with the registers a memory operand names
last, and InstBuilder is what keeps them that way.
Where an instruction goes is on its block rather than on the instruction, in the order the
terminator’s own arms run, which is regalloc2’s arrangement and the one the allocator
interface in spec/10-backend.md section 10.4 follows. Where an instruction came from is a
parallel array, reached by Func::span, for the same reason rucc-ir puts it there.
§Before and after allocation
mfunc @scale { mfunc @scale {
block0(%0:gpr, %1:gpr): block0:
%2:gpr = x64.mov_ri 4 $rcx = x64.mov_ri 4
%3:gpr(reuse 1) = x64.imul_rr ... $rax = x64.imul_rr $rax, $rcxBoth are the same text form, printed by print() and read by parse(), and both round-trip
byte for byte. That is what --emit=mir and --emit=mir-final are, and it is what lets a
test of the allocator state its input by writing one down.
§Status
The representation, the printer and the parser are here. What comes next in M3 is the
lowering that produces MIR, the frame layout and the allocator that rewrite it, and the
encoder that reads it. Two things a call needs are deliberately not here yet, because they
belong with the ABI lowering that is the next piece rather than with the representation: the
set of registers a call clobbers, and the stack slots a frame is made of.
Every crate in the workspace is published, and publishing implies a promise. This one is
tier 3: its Rust API is explicitly unstable and will change without a major version bump.
Depend on the rucc binary’s behaviour, not on this.
Structs§
- Amode
- A memory addressing mode, as the instruction holds it.
- Block
Call - One arm of a terminator: where it goes, and what it takes with it.
- Block
Data - One block: what arrives in it, what is in it, and where it goes.
- Func
- One function, in machine instructions.
- Imm
- One immediate.
- Inst
Builder - One instruction being built.
- Inst
Data - One instruction.
- Mem
- A memory addressing mode as a caller writes one down.
- Opcode
- Which instruction this is.
- Operand
- One operand of one instruction.
- Param
- One parameter of a block: the register the value arrives in, and its class.
- Parse
Error - Why a text could not be read.
- Printer
- A function being written out.
- Reg
- A register, either one the allocator has still to place or one it has placed.
Enums§
- Constraint
- Where an operand is allowed to live.
- Role
- What an instruction does with an operand.
Constants§
- MILESTONE
- The milestone in
spec/17-milestones.mdthat fills this crate in.
Functions§
- defs
- Whether an operand is one the instruction writes, for a printer or a pass that splits the operand vector at the point the writes stop.
- parse
- Reads every function in the text the printer writes.
- Every function, as text, which is what
--emit=mirwrites. - print_
func - One function, as text.
Type Aliases§
- Block
- One basic block, in the function that owns it.
- ImmRef
- One immediate, in the function’s immediate table.
- Inst
- One instruction, in the function that owns it.
- MemRef
- One addressing mode, in the function’s table of them.
- Operand
List - A run of operands, which is what an instruction’s operand vector is.