mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
all gen-dev tests work again
This commit is contained in:
parent
5e4f43e1d8
commit
fdacfce108
2 changed files with 106 additions and 26 deletions
|
@ -3,9 +3,9 @@ const builtin = @import("builtin");
|
||||||
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||||
const Monotonic = std.builtin.AtomicOrder.Monotonic;
|
const Monotonic = std.builtin.AtomicOrder.Monotonic;
|
||||||
|
|
||||||
const DEBUG_INCDEC = true;
|
const DEBUG_INCDEC = false;
|
||||||
const DEBUG_TESTING_ALLOC = false;
|
const DEBUG_TESTING_ALLOC = false;
|
||||||
const DEBUG_ALLOC = true;
|
const DEBUG_ALLOC = false;
|
||||||
|
|
||||||
pub fn WithOverflow(comptime T: type) type {
|
pub fn WithOverflow(comptime T: type) type {
|
||||||
return extern struct { value: T, has_overflowed: bool };
|
return extern struct { value: T, has_overflowed: bool };
|
||||||
|
|
|
@ -1318,7 +1318,7 @@ impl<
|
||||||
size: u32,
|
size: u32,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let base_offset = self.claim_stack_size_with_alignment(size, Ord::min(alignment, 8));
|
let base_offset = self.claim_stack_size_with_alignment(size, alignment);
|
||||||
self.symbol_storage_map
|
self.symbol_storage_map
|
||||||
.insert(sym, Stack(Complex { base_offset, size }));
|
.insert(sym, Stack(Complex { base_offset, size }));
|
||||||
self.allocation_map
|
self.allocation_map
|
||||||
|
@ -1341,10 +1341,12 @@ impl<
|
||||||
base_offset
|
base_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
/// claim_stack_size claims `amount` bytes from the stack
|
fn claim_stack_size_with_alignment_help(
|
||||||
/// This may be free space in the stack or result in increasing the stack size.
|
free_stack_chunks: &mut Vec<'a, (i32, u32)>,
|
||||||
/// It returns base pointer relative offset of the new data.
|
stack_size: &mut u32,
|
||||||
fn claim_stack_size_with_alignment(&mut self, amount: u32, alignment: u32) -> i32 {
|
amount: u32,
|
||||||
|
alignment: u32,
|
||||||
|
) -> i32 {
|
||||||
debug_assert_ne!(amount, 0);
|
debug_assert_ne!(amount, 0);
|
||||||
|
|
||||||
pub const fn next_multiple_of(lhs: u32, rhs: u32) -> u32 {
|
pub const fn next_multiple_of(lhs: u32, rhs: u32) -> u32 {
|
||||||
|
@ -1354,55 +1356,69 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn is_multiple_of(lhs: u32, rhs: u32) -> bool {
|
pub const fn is_multiple_of(lhs: i32, rhs: i32) -> bool {
|
||||||
match rhs {
|
match rhs {
|
||||||
0 => false,
|
0 => false,
|
||||||
_ => lhs % rhs == 0,
|
_ => lhs % rhs == 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// round value to alignment.
|
// round value to the alignment.
|
||||||
let amount = next_multiple_of(amount, alignment);
|
let amount = next_multiple_of(amount, alignment);
|
||||||
|
|
||||||
let alignment_correction = next_multiple_of(self.stack_size, alignment) - self.stack_size;
|
let chunk_fits = |(offset, size): &(i32, u32)| {
|
||||||
|
*size >= amount && is_multiple_of(*offset, alignment as i32)
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(fitting_chunk) = self
|
// padding on the stack to make sure an allocation is aligned
|
||||||
.free_stack_chunks
|
let padding = next_multiple_of(*stack_size, alignment) - *stack_size;
|
||||||
|
|
||||||
|
if let Some(fitting_chunk) = free_stack_chunks
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_, (offset, size))| {
|
.filter(|(_, chunk)| chunk_fits(chunk))
|
||||||
*size >= amount && is_multiple_of((*offset).abs() as u32, alignment)
|
|
||||||
})
|
|
||||||
.min_by_key(|(_, (_, size))| size)
|
.min_by_key(|(_, (_, size))| size)
|
||||||
{
|
{
|
||||||
let (pos, (offset, size)) = fitting_chunk;
|
let (pos, (offset, size)) = fitting_chunk;
|
||||||
let (offset, size) = (*offset, *size);
|
let (offset, size) = (*offset, *size);
|
||||||
|
|
||||||
if size == amount {
|
if size == amount {
|
||||||
self.free_stack_chunks.remove(pos);
|
// fill the whole chunk precisely
|
||||||
debug_assert_eq!(offset % alignment as i32, 0);
|
free_stack_chunks.remove(pos);
|
||||||
offset
|
offset
|
||||||
} else {
|
} else {
|
||||||
let (prev_offset, prev_size) = self.free_stack_chunks[pos];
|
// use part of this chunk
|
||||||
self.free_stack_chunks[pos] = (prev_offset + amount as i32, prev_size - amount);
|
let (prev_offset, prev_size) = free_stack_chunks[pos];
|
||||||
debug_assert_eq!(prev_offset % alignment as i32, 0);
|
free_stack_chunks[pos] = (prev_offset + amount as i32, prev_size - amount);
|
||||||
prev_offset
|
prev_offset
|
||||||
}
|
}
|
||||||
} else if let Some(new_size) = self.stack_size.checked_add(alignment_correction + amount) {
|
} else if let Some(new_size) = stack_size.checked_add(padding + amount) {
|
||||||
// Since stack size is u32, but the max offset is i32, if we pass i32 max, we have overflowed.
|
// Since stack size is u32, but the max offset is i32, if we pass i32 max, we have overflowed.
|
||||||
if new_size > i32::MAX as u32 {
|
if new_size > i32::MAX as u32 {
|
||||||
internal_error!("Ran out of stack space");
|
internal_error!("Ran out of stack space");
|
||||||
} else {
|
} else {
|
||||||
self.stack_size = new_size;
|
*stack_size = new_size;
|
||||||
let offset = -(self.stack_size as i32);
|
-(*stack_size as i32)
|
||||||
debug_assert_eq!(offset % alignment as i32, 0);
|
|
||||||
offset
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
internal_error!("Ran out of stack space");
|
internal_error!("Ran out of stack space");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn claim_stack_size_with_alignment(&mut self, amount: u32, alignment: u32) -> i32 {
|
||||||
|
// because many instructions work on 8 bytes, we play it safe and make all stack
|
||||||
|
// allocations a multiple of 8 bits wide. This is of course slightly suboptimal
|
||||||
|
// if you want to improve this, good luck!
|
||||||
|
let alignment = Ord::max(8, alignment);
|
||||||
|
|
||||||
|
// the helper is just for testing in this case
|
||||||
|
Self::claim_stack_size_with_alignment_help(
|
||||||
|
&mut self.free_stack_chunks,
|
||||||
|
&mut self.stack_size,
|
||||||
|
amount,
|
||||||
|
alignment,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn free_symbol(&mut self, sym: &Symbol) {
|
pub fn free_symbol(&mut self, sym: &Symbol) {
|
||||||
if self.join_param_map.remove(&JoinPointId(*sym)).is_some() {
|
if self.join_param_map.remove(&JoinPointId(*sym)).is_some() {
|
||||||
// This is a join point and will not be in the storage map.
|
// This is a join point and will not be in the storage map.
|
||||||
|
@ -1569,3 +1585,67 @@ fn is_primitive(layout_interner: &mut STLayoutInterner<'_>, layout: InLayout<'_>
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::generic64::x86_64::{
|
||||||
|
X86_64Assembler, X86_64FloatReg, X86_64GeneralReg, X86_64SystemV,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
type SystemVStorageManager<'a, 'r> =
|
||||||
|
StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, X86_64Assembler, X86_64SystemV>;
|
||||||
|
|
||||||
|
fn claim_helper(
|
||||||
|
mut free_stack_chunks: Vec<'_, (i32, u32)>,
|
||||||
|
mut stack_size: u32,
|
||||||
|
amount: u32,
|
||||||
|
alignment: u32,
|
||||||
|
) -> (u32, i32, Vec<'_, (i32, u32)>) {
|
||||||
|
let offset = SystemVStorageManager::claim_stack_size_with_alignment_help(
|
||||||
|
&mut free_stack_chunks,
|
||||||
|
&mut stack_size,
|
||||||
|
amount,
|
||||||
|
alignment,
|
||||||
|
);
|
||||||
|
|
||||||
|
(stack_size, offset, free_stack_chunks)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn claim_stack_memory() {
|
||||||
|
use bumpalo::vec;
|
||||||
|
let arena = bumpalo::Bump::new();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
claim_helper(vec![in &arena;], 24, 8, 8),
|
||||||
|
(32, -32, vec![in &arena;]),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
claim_helper(vec![in &arena;], 8, 8, 8),
|
||||||
|
(16, -16, vec![in &arena;]),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
claim_helper(vec![in &arena; (-16, 8)], 56, 4, 4),
|
||||||
|
(56, -16, vec![in &arena; (-12, 4)])
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
claim_helper(vec![in &arena; (-24, 16)], 32, 8, 8),
|
||||||
|
(32, -24, vec![in &arena; (-16, 8)])
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
claim_helper(vec![in &arena; ], 0, 2, 1),
|
||||||
|
(2, -2, vec![in &arena;])
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
claim_helper(vec![in &arena; (-8, 2)], 16, 2, 1),
|
||||||
|
(16, -8, vec![in &arena; ])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue