///|
/// The values definitely present in each physical location at a CFG point.
/// The allocator and VCode verifiers use the same transfer and join rules.
pub struct AllocationContents[V] {
priv values : Map[(Int32, Int32), Array[V]]
}
///|
fn allocation_location_key(location : AllocationLocation) -> (Int32, Int32) {
if location.is_register() {
let reg = location.register_unchecked()
match reg.class {
Int => (0, reg.id)
FpVector => (1, reg.id)
Float => (1, reg.id)
Vector => (2, reg.id)
}
} else {
(3, location.spill_index_unchecked())
}
}
///|
pub fn[V] AllocationContents::new() -> AllocationContents[V] {
{ values: Map([]), }
}
///|
pub fn[V] AllocationContents::copy(
self : AllocationContents[V],
) -> AllocationContents[V] {
let values : Map[(Int32, Int32), Array[V]] = Map([])
for key, value in self.values {
values[key] = value.copy()
}
{ values, }
}
///|
pub fn[V : Eq] AllocationContents::equals(
self : AllocationContents[V],
other : AllocationContents[V],
) -> Bool {
if self.values.length() != other.values.length() {
return false
}
for key, values in self.values {
guard other.values.get(key) is Some(other_values) else { return false }
if values.length() != other_values.length() ||
!values.all(value => other_values.contains(value)) {
return false
}
}
true
}
///|
pub fn[V : Eq] AllocationContents::meet_with(
self : AllocationContents[V],
other : AllocationContents[V],
) -> Unit {
for key in self.values.keys().to_array() {
match other.values.get(key) {
None => self.values.remove(key)
Some(other_values) => {
let retained = self.values[key].filter(value => {
other_values.contains(value)
})
if retained.is_empty() {
self.values.remove(key)
} else {
self.values[key] = retained
}
}
}
}
}
///|
pub fn[V : Eq] AllocationContents::remove_value(
self : AllocationContents[V],
value : V,
) -> Unit {
for key in self.values.keys().to_array() {
self.values[key].retain(other => other != value)
if self.values[key].is_empty() {
self.values.remove(key)
}
}
}
///|
pub fn[V] AllocationContents::remove_register(
self : AllocationContents[V],
reg : PhysicalReg,
) -> Unit {
self.values.remove(allocation_location_key(AllocationLocation::reg(reg)))
}
///|
pub fn[V : Eq] AllocationContents::contains(
self : AllocationContents[V],
value : V,
location : AllocationLocation,
) -> Bool {
self.values
.get(allocation_location_key(location))
.map(values => values.contains(value))
.unwrap_or(false)
}
///|
pub fn[V] AllocationContents::set(
self : AllocationContents[V],
value : V,
location : AllocationLocation,
) -> Unit {
self.values[allocation_location_key(location)] = [value]
}
///|
/// Copy every alias of a location from the incoming state of a move.
pub fn[V] AllocationContents::copy_location_from(
self : AllocationContents[V],
source : AllocationContents[V],
from : AllocationLocation,
to : AllocationLocation,
) -> Unit {
self.values[allocation_location_key(to)] = source.values[allocation_location_key(
from,
)].copy()
}
///|
/// Name an existing value at a block parameter's home after a parallel rename.
pub fn[V : Eq] AllocationContents::add_alias(
self : AllocationContents[V],
value : V,
location : AllocationLocation,
) -> Unit {
let key = allocation_location_key(location)
match self.values.get(key) {
Some(aliases) => if !aliases.contains(value) { aliases.push(value) }
None => self.values[key] = [value]
}
}