Skip to content

Commit 40c642d

Browse files
committed
update fastalloc doc
1 parent 33d9e4f commit 40c642d

File tree

2 files changed

+134
-118
lines changed

2 files changed

+134
-118
lines changed

doc/FASTALLOC.md

Lines changed: 132 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,14 @@ During allocation, it's necessary to determine which VReg is in a PReg
4242
to generate the right move(s) for eviction.
4343
`vreg_in_preg` is a vector that stores this information.
4444

45-
## Available PRegs For Use In Instruction (`available_pregs_for_regs`, `available_pregs_for_any`)
45+
## Available PRegs For Use In Instruction (`available_pregs`)
4646

47-
These are a 2-tuples of `PRegSet`s, a bitset of physical registers, one for
48-
the instruction's early phase and one for the late phase.
49-
They are used to determine which registers are available for use in the
50-
early/late phases of an instruction.
47+
This is a 2-tuple of PRegSets, a bitset of physical registers, one for the
48+
instruction's early phase and one for the late phase. They are used to determine
49+
which registers are available for use in the early/late phases of an instruction.
5150

52-
Prior to the beginning of any instruction's allocation, `available_pregs_for_regs`
53-
is reset to include all allocatable physical registers, some of which may already
54-
contain a VReg.
55-
56-
The two sets have the same function, except that `available_pregs_for_regs` is
57-
used to determine which registers are available for operands with a register-only
58-
constraint while `available_pregs_for_any` is used to determine which registers
59-
are available for operands with no constraints.
51+
Prior to the beginning of any instruction's allocation, this set is reset to
52+
include all allocatable physical registers, some of which may already contain a VReg.
6053

6154
## VReg Liverange Location Info (`vreg_to_live_inst_range`)
6255

@@ -66,6 +59,35 @@ to be in throughout that liverange.
6659
This is used to build the debug locations vector after allocation
6760
is complete.
6861

62+
## Number of Available Registers (`num_available_registers`)
63+
64+
These are counters that keep track of the number of registers that
65+
can be allocated to any-reg and anywhere operands for int, float and
66+
vector registers, in the late, early and both phases of an instruction.
67+
68+
Prior to the beginning of any instruction, this set is reset to
69+
include the number of all allocatable physical registers.
70+
71+
## Number of Any-Reg Operands (`num_any_reg_operands`)
72+
73+
These are counters that keep track of the number of any-reg
74+
operands that are yet to be allocated in an instruction.
75+
76+
It is closely associated with `num_available_registers` and
77+
are used together for the same purpose.
78+
The two counters are used together to avoid allocating too many
79+
registers to anywhere operands when any-reg operands need them.
80+
When register reservations are made, the corresponding number
81+
of available registers in `num_available_registers` are decremented.
82+
When an any-reg operand is allocated, the corresponding
83+
`num_any_reg_operands` is decremented.
84+
The sole purpose of this is so that when anywhere operands are
85+
allocated, a check can be made to see if the available registers
86+
`num_available_registers` are enough to cover the remaining
87+
any-reg operands in the instruction `num_any_reg_operands`,
88+
to determine whether or not it is safe to allocate a register to
89+
the operand instead of a spillslot.
90+
6991
# Allocation Process Breakdown
7092

7193
Allocation proceeds in reverse: from the last block to the first block,
@@ -76,11 +98,11 @@ in four phases: selection, assignment, eviction, and edit insertion.
7698

7799
## Allocation Phase: Selection
78100

79-
In this phase, a PReg is selected from `available_pregs_for_regs` or
80-
`available_pregs_for_any` for the operand based on the operand constraints.
81-
Depending on the operand's position, the selected PReg is removed from either
82-
the early or late phase or both, indicating that the PReg is no longer available
83-
for allocation by other operands in that phase.
101+
In this phase, a PReg is selected from available_pregs for the operand
102+
based on the operand constraints. Depending on the operand's position
103+
the selected PReg is removed from either the early or late phase or both,
104+
indicating that the PReg is no longer available for allocation by other
105+
operands in that phase.
84106

85107
## Allocation Phase: Assignment
86108

@@ -128,118 +150,112 @@ arguments will be in their dedicated spillslots.
128150
4. At the beginning of a block, all branch parameters and livein
129151
virtual registers will be in their dedicated spillslots.
130152

131-
There is an exception to invariant 3: if a branch instruction defines
153+
There is an exception to invariant 2 and 3: if a branch instruction defines
132154
the VReg used as a branch arg, then there may be no opportunity for
133155
the VReg to be placed in its spillslot.
134156

135157
# Instruction Allocation
136158

137-
To allocate a single instruction, the first step is to reset the
138-
`available_pregs_for_regs` sets to all allocatable PRegs.
139-
140-
Next, the selection phase is carried out for all operands with
141-
fixed register constraints: the registers they are constrained to use are
142-
marked as unavailable in the `available_pregs_for_regs` set, depending on the
143-
phase that they are valid in. If the operand is an early use or late
144-
def operand, then the register will be marked as unavailable in the
145-
early set or late set, respectively. Otherwise, the PReg is marked
146-
as unavailable in both the early and late sets, because a PReg
147-
assigned to an early def or late use operand cannot be reused by another
148-
operand in the same instruction.
149-
150-
Next, all clobbers are removed from the early and late `available_pregs_for_regs`
151-
sets to avoid allocating a clobber to a def.
152-
153-
Next, registers are reserved for register-only operands and marked as
154-
unavailable in `available_pregs_for_regs`.
155-
Then `available_pregs_for_any` for the instruction is derived from
156-
`available_pregs_for_regs` by marking all other registers not reserved as
157-
available. This is to avoid a situation where operands with no
158-
constraints take up all available registers, leaving none for operands
159-
with register-only constraints.
160-
161-
After selection for register-only operands, the eviction phase is
162-
carried out for fixed register operands. Any VReg in their selected
163-
registers, indicated by `vreg_in_preg`, is evicted: a dedicated
164-
spillslot is allocated for the VReg (if it doesn't have one already),
165-
an edit is inserted to move from the slot to the PReg, which is where
166-
the VReg expected to be after the instruction, and its current
167-
allocation in `vreg_allocs` is set to the spillslot.
168-
The same is then done for clobbers, then register-only operands.
169-
170-
Next, the selection, assignment, eviction, and edit insertion phases are
171-
carried out for all def operands. When each def operand's allocation is
172-
complete, the def operand is immediately freed, marking the end of the
173-
VReg's liverange. It is removed from the `live_vregs` set, its allocation
174-
in `vreg_allocs` is set to none, and if it was in a PReg, that PReg's
175-
entry in `vreg_in_preg` is set to none. The selection and eviction phases
176-
are omitted if the operand has a fixed constraint, as those phases have
177-
already been carried out.
178-
179-
Next, the selection, assignment, and eviction phases are carried out for all
180-
use operands. As with def operands, the selection and eviction phases are
181-
omitted if the operand has a fixed constraint, as those phases have already
182-
been carried out.
183-
184-
Then the edit insertion phase is carried out for all use operands.
185-
186-
Lastly, if the instruction being processed is a branch instruction, the
187-
parallel move resolver is used to insert edits before the instruction
188-
to move from the branch arguments spillslots to the block parameter
189-
spillslots.
159+
To allocate a single instruction, the first step is to reset the
160+
`available_pregs` sets to all allocatable PRegs.
161+
162+
Next, the selection phase is carried out for all operands with
163+
fixed register constraints: the registers they are constrained
164+
to use are marked as unavailable in the `available_pregs` set,
165+
depending on the phase that they are valid in. If the operand
166+
is an early use or late def operand, then the register will be
167+
marked as unavailable in the early set or late set, respectively.
168+
Otherwise, the PReg is marked as unavailable in both the early
169+
and late sets, because a PReg assigned to an early def or late
170+
use operand cannot be reused by another operand in the same instruction.
171+
172+
After selection for fixed register operands, the eviction phase
173+
is carried out for fixed register operands. Any VReg in their
174+
selected registers, indicated by vreg_in_preg, is evicted: a
175+
dedicated spillslot is allocated for the VReg (if it doesn't
176+
have one already), an edit is inserted to move from the slot to
177+
the PReg, which is where the VReg expected to be after the instruction,
178+
and its current allocation in vreg_allocs is set to the spillslot.
179+
180+
Next, all clobbers are removed from the late `available_pregs` set
181+
to avoid allocating a clobber to a late operand.
182+
183+
Next, the selection, assignment, eviction, and edit insertion
184+
phases are carried out for all late operands, both defs and uses.
185+
Then the early operands are processed in the same manner, after the
186+
late operands.
187+
188+
In both late and early processing, when a def operand's
189+
allocation is complete, the def operand is immediately freed,
190+
marking the end of the VReg's liverange. It is removed from the
191+
`live_vregs` set, its allocation in `vreg_allocs` is set to none,
192+
and if it was in a PReg, that PReg's entry in `vreg_in_preg` is
193+
set to none. The selection and eviction phases are omitted if the
194+
operand has a fixed constraint, as those phases have already been
195+
carried out.
196+
197+
When a use operand is processed, the selection, assignment, and eviction
198+
phases only are carried out. As with def operands, the selection and
199+
eviction phases are omitted if the operand has a fixed constraint, as
200+
those phases have already been carried out.
201+
202+
After the late and early operands have completed processing,
203+
the edit insertion phase is carried out for all use operands.
204+
205+
Lastly, if the instruction being processed is a branch instruction,
206+
the parallel move resolver is used to insert edits before the instruction
207+
to move from the branch arguments spillslots to the block parameter spillslots.
190208

191209
## Operand Allocation
192210

193211
During the allocation of an operand, a check is first made to
194212
see if the VReg's current allocation as indicated in
195213
`vreg_allocs` is within the operand constraints.
196214

197-
If it is, the assignment phase is carried out, setting the final
198-
allocation output's entry for that operand to the allocation.
199-
The selection phase is carried out, marking the PReg
200-
(if the allocation is a PReg) as unavailable in the respective
201-
early/late sets. The state of the LRUs is also updated to reflect
202-
the new most recently used PReg.
203-
No eviction needs to be done since the VReg is already in the
204-
allocation and no edit insertion needs to be done either.
205-
206-
On the other hand, if the VReg's current allocation is not within
207-
constraints, the selection and eviction phases are carried out for
208-
non-fixed operands. First, a set of PRegs that can be drawn from is
209-
created from `available_pregs_for_regs` or `available_pregs_for_any`,
210-
depending on whether the operand has a register-only constraint
211-
or no constraint. For early uses and late defs,
212-
this draw-from set is the early set or late set, respectively.
213-
For late uses and early defs, the draw-from set is an intersection
214-
of the available early and late sets (because a PReg used for a late
215-
use can't be reassigned to another operand in the early phase;
216-
likewise, a PReg used for an early def can't be reassigned to another
217-
operand in the late phase).
218-
The LRU for the VReg's regclass is then traversed from the end to find
219-
the least recently used PReg in the draw-from set. Once a PReg is found,
220-
it is marked as the most recently used in the LRU, unavailable in both
221-
available pregs sets, and whatever VReg was in it before is evicted.
222-
223-
The assignment phase is carried out next. The final allocation for the
215+
If it is, the assignment phase is carried out, setting the
216+
final allocation output's entry for that operand to the allocation.
217+
The selection phase is carried out, marking the PReg (if the
218+
allocation is a PReg) as unavailable in the respective early/late
219+
sets. The state of the LRUs is also updated to reflect the new
220+
most recently used PReg. No eviction needs to be done since the
221+
VReg is already in the allocation and no edit insertion needs to
222+
be done either.
223+
224+
On the other hand, if the VReg's current allocation is not within
225+
constraints, the selection and eviction phases are carried out
226+
for non-fixed operands. First, a set of PRegs that can be drawn
227+
from is created from `available_pregs`. For early uses and late
228+
defs, this draw-from set is the early set or late set, respectively.
229+
For late uses and early defs, the draw-from set is an intersection
230+
of the available early and late sets (because a PReg used for a
231+
late use can't be reassigned to another operand in the early phase;
232+
likewise, a PReg used for an early def can't be reassigned to another
233+
operand in the late phase). The LRU for the VReg's regclass is then
234+
traversed from the end to find the least recently used PReg in the
235+
draw-from set. Once a PReg is found, it is marked as the most recently
236+
used in the LRU, unavailable in the `available_pregs` sets, and whatever
237+
VReg was in it before is evicted.
238+
239+
The assignment phase is carried out next. The final allocation for the
224240
operand is set to the selected register.
225241

226-
If the newly allocated operand has not been allocated before, that is,
227-
this is the first use/def of the VReg encountered; the VReg is
228-
inserted into `live_vregs` and marked as the value in the allocated
229-
PReg in `vreg_in_preg`.
230-
231-
Otherwise, if the VReg has been allocated before, then an edit will need
232-
to be inserted to ensure that the dataflow remains correct.
233-
The edit insertion phase is now carried out if the operand is a def
234-
operand: an edit is inserted after the instruction to move from the
235-
new allocation to the allocation it's expected to be in after the
236-
instruction.
237-
238-
The edit insertion phase for use operands is done after all operands
239-
have been processed. Edits are inserted to move from the current
240-
allocations in `vreg_allocs` to the final allocated position before
241-
the instruction. This is to account for the possibility of multiple
242-
uses of the same operand in the instruction.
242+
If the newly allocated operand has not been allocated before,
243+
that is, this is the first use/def of the VReg encountered;
244+
the VReg is inserted into live_vregs and marked as the value
245+
in the allocated PReg in vreg_in_preg.
246+
247+
Otherwise, if the VReg has been allocated before, then an edit
248+
will need to be inserted to ensure that the dataflow remains correct.
249+
The edit insertion phase is now carried out if the operand is a
250+
def operand: an edit is inserted after the instruction to move
251+
from the new allocation to the allocation it's expected to be
252+
in after the instruction.
253+
254+
The edit insertion phase for use operands is done after all
255+
operands have been processed. Edits are inserted to move from
256+
the current allocations in `vreg_allocs` to the final allocated
257+
position before the instruction. This is to account for the
258+
possibility of multiple uses of the same operand in the instruction.
243259

244260
## Reuse Operands
245261

src/fastalloc/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,8 @@ impl<'a, F: Function> Env<'a, F> {
583583
self.vreg_in_preg[preg.index()] == op.vreg() &&
584584
// If it's a late operand, it shouldn't be allocated to a
585585
// clobber. For example:
586-
// use v0 (fixed: p0), late use v1
587-
// If p0 is a clobber, then v1 shouldn't be allocated to it.
586+
// use v0 (fixed: p0), late use v0
587+
// If p0 is a clobber, then v0 shouldn't be allocated to it.
588588
(op.pos() != OperandPos::Late || !self.func.inst_clobbers(inst).contains(preg))
589589
} else {
590590
true

0 commit comments

Comments
 (0)