Skip to main content

Crate rucc_mir

Crate rucc_mir 

Source
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, $rcx

Both 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.
BlockCall
One arm of a terminator: where it goes, and what it takes with it.
BlockData
One block: what arrives in it, what is in it, and where it goes.
Func
One function, in machine instructions.
Imm
One immediate.
InstBuilder
One instruction being built.
InstData
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.
ParseError
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.md that 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.
print
Every function, as text, which is what --emit=mir writes.
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.
OperandList
A run of operands, which is what an instruction’s operand vector is.