Skip to content

Commit 9e55e26

Browse files
committed
Add support for an arbitrary number of operands with any constraints to fastalloc
Prior to this commit in fastalloc, Any constraints were allocated just like Reg constraints. Now, rather than treating Reg constraints as equivalent to Any constraints, operands with Reg constraints get their set of available registers separate from operands that have Any constraints. This comes with the drawback of having to reserve registers for the Reg operands and evict vregs in them before processing use and def operands. Any defs that are never used are also allocated directly into spillslots because there is no point allocating them into registers.
1 parent 27a749b commit 9e55e26

File tree

3 files changed

+282
-80
lines changed

3 files changed

+282
-80
lines changed

doc/FASTALLOC.md

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,22 @@ 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`)
45+
## Available PRegs For Use In Instruction (`available_pregs_for_regs`, `available_pregs_for_any`)
4646

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

52-
Prior to the beginning of any instruction's allocation, this set is reset
53-
to include all allocatable physical registers, some of which may already
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
5454
contain a VReg.
5555

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.
60+
5661
## VReg Liverange Location Info (`vreg_to_live_inst_range`)
5762

5863
This is a vector of 3-tuples containing the beginning and the end
@@ -71,11 +76,11 @@ in four phases: selection, assignment, eviction, and edit insertion.
7176

7277
## Allocation Phase: Selection
7378

74-
In this phase, a PReg is selected from `available_pregs` for the
75-
operand based on the operand constraints. Depending on the operand's
76-
position the selected PReg is removed from either the early or late
77-
phase or both, indicating that the PReg is no longer available for
78-
allocation by other operands in that phase.
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.
7984

8085
## Allocation Phase: Assignment
8186

@@ -88,8 +93,9 @@ In this phase, the previous VReg in the allocation assigned to
8893
an operand is evicted, if any.
8994

9095
During eviction, a dedicated spillslot is allocated for the evicted
91-
VReg and an edit is inserted after the instruction to move from the
92-
slot to the allocation it's expected to be in after the instruction.
96+
VReg, if it doesn't have a spillslot yet, and an edit is inserted
97+
after the instruction to move from the slot to the allocation
98+
it's expected to be in after the instruction.
9399

94100
## Allocation Phase: Edit Insertion
95101

@@ -125,32 +131,41 @@ virtual registers will be in their dedicated spillslots.
125131
# Instruction Allocation
126132

127133
To allocate a single instruction, the first step is to reset the
128-
`available_pregs` sets to all allocatable PRegs.
134+
`available_pregs_for_regs` sets to all allocatable PRegs.
129135

130136
Next, the selection phase is carried out for all operands with
131137
fixed register constraints: the registers they are constrained to use are
132-
marked as unavailable in the `available_pregs` set, depending on the
138+
marked as unavailable in the `available_pregs_for_regs` set, depending on the
133139
phase that they are valid in. If the operand is an early use or late
134140
def operand, then the register will be marked as unavailable in the
135141
early set or late set, respectively. Otherwise, the PReg is marked
136142
as unavailable in both the early and late sets, because a PReg
137143
assigned to an early def or late use operand cannot be reused by another
138144
operand in the same instruction.
139145

140-
After selection for fixed register operands, the eviction phase is
146+
Next, all clobbers are removed from the early and late `available_pregs_for_regs`
147+
sets to avoid allocating a clobber to a def.
148+
149+
Next, registers are reserved for register-only operands and marked as
150+
unavailable in `available_pregs_for_regs`.
151+
Then `available_pregs_for_any` for the instruction is derived from
152+
`available_pregs_for_regs` by marking all other registers not reserved as
153+
available. This is to avoid a situation where operands with no
154+
constraints take up all available registers, leaving none for operands
155+
with register-only constraints.
156+
157+
After selection for register-only operands, the eviction phase is
141158
carried out for fixed register operands. Any VReg in their selected
142159
registers, indicated by `vreg_in_preg`, is evicted: a dedicated
143160
spillslot is allocated for the VReg (if it doesn't have one already),
144161
an edit is inserted to move from the slot to the PReg, which is where
145162
the VReg expected to be after the instruction, and its current
146163
allocation in `vreg_allocs` is set to the spillslot.
147-
148-
Next, all clobbers are removed from the early and late `available_pregs`
149-
sets to avoid allocating a clobber to a def.
164+
The same is then done for clobbers, then register-only operands.
150165

151166
Next, the selection, assignment, eviction, and edit insertion phases are
152167
carried out for all def operands. When each def operand's allocation is
153-
complete, the def operands is immediately freed, marking the end of the
168+
complete, the def operand is immediately freed, marking the end of the
154169
VReg's liverange. It is removed from the `live_vregs` set, its allocation
155170
in `vreg_allocs` is set to none, and if it was in a PReg, that PReg's
156171
entry in `vreg_in_preg` is set to none. The selection and eviction phases
@@ -187,7 +202,9 @@ allocation and no edit insertion needs to be done either.
187202
On the other hand, if the VReg's current allocation is not within
188203
constraints, the selection and eviction phases are carried out for
189204
non-fixed operands. First, a set of PRegs that can be drawn from is
190-
created from `available_pregs`. For early uses and late defs,
205+
created from `available_pregs_for_regs` or `available_pregs_for_any`,
206+
depending on whether the operand has a register-only constraint
207+
or no constraint. For early uses and late defs,
191208
this draw-from set is the early set or late set, respectively.
192209
For late uses and early defs, the draw-from set is an intersection
193210
of the available early and late sets (because a PReg used for a late
@@ -196,8 +213,8 @@ likewise, a PReg used for an early def can't be reassigned to another
196213
operand in the late phase).
197214
The LRU for the VReg's regclass is then traversed from the end to find
198215
the least recently used PReg in the draw-from set. Once a PReg is found,
199-
it is marked as the most recently used in the LRU, unavailable in the
200-
`available_pregs` sets, and whatever VReg was in it before is evicted.
216+
it is marked as the most recently used in the LRU, unavailable in both
217+
available pregs sets, and whatever VReg was in it before is evicted.
201218

202219
The assignment phase is carried out next. The final allocation for the
203220
operand is set to the selected register.

src/fastalloc/iter.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ impl<'a> Operands<'a> {
3333
pub fn fixed(&self) -> impl Iterator<Item = (usize, Operand)> + 'a {
3434
self.matches(|op| matches!(op.constraint(), OperandConstraint::FixedReg(_)))
3535
}
36+
37+
pub fn any_reg(&self) -> impl Iterator<Item = (usize, Operand)> + 'a {
38+
self.matches(|op| matches!(op.constraint(), OperandConstraint::Reg))
39+
}
3640
}
3741

3842
impl<'a> core::ops::Index<usize> for Operands<'a> {

0 commit comments

Comments
 (0)