Skip to main content

Module rewrite

Module rewrite 

Source
Expand description

Making an assignment true in the function it was worked out for.

Design: spec/10-backend.md section 10.4.

crate::assign says where every value goes and touches nothing. This is the other half: every operand is rewritten to the place its value was given, and the moves that the places do not already say are collected. After it the function names no virtual register and no block asks for anything, which is the point at which machine IR stops being in SSA form and starts being something an encoder could read.

§Why the moves are handed back rather than written

A move is an instruction, and an instruction has an opcode, and an opcode belongs to a target. spec/10-backend.md section 10.8 says no pipeline crate holds target specific code, so this crate is not the one that can write x64.mov. What it hands back is an Edit: a move between two places, the class it is in, and where in the function it goes. rucc-codegen turns each one into whatever its target moves a register with, which for a value on the stack is a load or a store rather than a move at all.

The edits at any one place are in the order they have to be made in. That matters in two places: a spilled operand is read into a scratch register before the instruction that wants it, and a two address instruction’s copy has to come after that read, because what it is copying may be the thing that was just read in.

§What a fixed register turns into

A move each way. The assignment deliberately gave the value some other register, so a division whose dividend has to be in rax gets a move into rax in front of it and a move out of rax behind it. That is the cost of the rule the assignment follows, and it is the rule that keeps the -O0 allocator one pass.

§What an edge turns into

The moves that write the block’s parameters, in an order they can be made in one at a time, which is what crate::moves is for. Where they go depends on the shape of the edge. A block with one successor puts them at its own end, in front of the branch it finishes with, and a block with several puts them at the start of the block the edge goes to, which is safe exactly because that block has no other predecessor. An edge that is critical has neither place to put them and has to have been split before allocation ran, which this checks rather than assumes.

Structs§

Edit
One move the places did not already make true.

Enums§

At
Where an edit goes.

Functions§

rewrite
Rewrites a function to the places it was given, and says what moves are still wanted.