mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
impl and tests for big recursive tag unions
This commit is contained in:
parent
f5578e71b6
commit
e7791443e6
2 changed files with 195 additions and 48 deletions
|
@ -1562,7 +1562,7 @@ impl<
|
||||||
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
||||||
ASM::eq_reg_reg_reg(&mut self.buf, width, dst_reg, dst_reg, tmp_reg);
|
ASM::eq_reg_reg_reg(&mut self.buf, width, dst_reg, dst_reg, tmp_reg);
|
||||||
|
|
||||||
self.free_symbol(&tmp);
|
self.free_symbol(tmp);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let ident_ids = self
|
let ident_ids = self
|
||||||
|
@ -1640,7 +1640,22 @@ impl<
|
||||||
|
|
||||||
self.free_symbol(tmp)
|
self.free_symbol(tmp)
|
||||||
}
|
}
|
||||||
x => todo!("NumNeq: layout, {:?}", x),
|
_ => {
|
||||||
|
// defer to equality
|
||||||
|
|
||||||
|
self.build_eq(dst, src1, src2, arg_layout);
|
||||||
|
|
||||||
|
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
||||||
|
|
||||||
|
self.storage_manager
|
||||||
|
.with_tmp_general_reg(&mut self.buf, |_, buf, tmp| {
|
||||||
|
ASM::mov_reg64_imm64(buf, tmp, -1);
|
||||||
|
ASM::xor_reg64_reg64_reg64(buf, dst_reg, tmp, dst_reg);
|
||||||
|
|
||||||
|
ASM::mov_reg64_imm64(buf, tmp, 1);
|
||||||
|
ASM::and_reg64_reg64_reg64(buf, dst_reg, tmp, dst_reg);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2754,40 +2769,38 @@ impl<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
UnionLayout::Recursive(tag_layouts) => {
|
UnionLayout::Recursive(tag_layouts) => {
|
||||||
if union_layout.stores_tag_id_as_data(self.storage_manager.target_info) {
|
let other_fields = tag_layouts[tag_id as usize];
|
||||||
todo!("big recursive tags")
|
let element_layout = other_fields[index as usize];
|
||||||
} else {
|
|
||||||
let other_fields = tag_layouts[tag_id as usize];
|
|
||||||
let element_layout = other_fields[index as usize];
|
|
||||||
|
|
||||||
let ptr_reg = self
|
let ptr_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, structure);
|
.load_to_general_reg(&mut self.buf, structure);
|
||||||
|
|
||||||
|
// mask out the tag id bits
|
||||||
|
if !union_layout.stores_tag_id_as_data(self.storage_manager.target_info) {
|
||||||
let mask_symbol = self.debug_symbol("tag_id_mask");
|
let mask_symbol = self.debug_symbol("tag_id_mask");
|
||||||
let mask_reg = self
|
let mask_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.claim_general_reg(&mut self.buf, &mask_symbol);
|
.claim_general_reg(&mut self.buf, &mask_symbol);
|
||||||
ASM::mov_reg64_imm64(&mut self.buf, mask_reg, (!0b111) as _);
|
ASM::mov_reg64_imm64(&mut self.buf, mask_reg, (!0b111) as _);
|
||||||
|
|
||||||
// mask out the tag id bits
|
|
||||||
ASM::and_reg64_reg64_reg64(&mut self.buf, ptr_reg, ptr_reg, mask_reg);
|
ASM::and_reg64_reg64_reg64(&mut self.buf, ptr_reg, ptr_reg, mask_reg);
|
||||||
|
|
||||||
let mut offset = 0;
|
|
||||||
for field in &other_fields[..index as usize] {
|
|
||||||
offset += self.layout_interner.stack_size(*field);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::ptr_read(
|
|
||||||
&mut self.buf,
|
|
||||||
&mut self.storage_manager,
|
|
||||||
self.layout_interner,
|
|
||||||
ptr_reg,
|
|
||||||
offset as i32,
|
|
||||||
element_layout,
|
|
||||||
*sym,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut offset = 0;
|
||||||
|
for field in &other_fields[..index as usize] {
|
||||||
|
offset += self.layout_interner.stack_size(*field);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::ptr_read(
|
||||||
|
&mut self.buf,
|
||||||
|
&mut self.storage_manager,
|
||||||
|
self.layout_interner,
|
||||||
|
ptr_reg,
|
||||||
|
offset as i32,
|
||||||
|
element_layout,
|
||||||
|
*sym,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3002,11 +3015,30 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
UnionLayout::Recursive(_) => {
|
UnionLayout::Recursive(_) => {
|
||||||
if union_layout.stores_tag_id_as_data(self.storage_manager.target_info) {
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, sym);
|
||||||
todo!("big recursive tags")
|
|
||||||
} else {
|
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, sym);
|
|
||||||
|
|
||||||
|
let target_info = self.storage_manager.target_info;
|
||||||
|
if union_layout.stores_tag_id_as_data(target_info) {
|
||||||
|
let offset = union_layout
|
||||||
|
.tag_id_offset(self.interner(), target_info)
|
||||||
|
.unwrap() as i32;
|
||||||
|
|
||||||
|
let ptr_reg = self
|
||||||
|
.storage_manager
|
||||||
|
.load_to_general_reg(&mut self.buf, structure);
|
||||||
|
|
||||||
|
match union_layout.tag_id_layout() {
|
||||||
|
Layout::U8 => {
|
||||||
|
ASM::mov_reg8_mem8_offset32(&mut self.buf, dst_reg, ptr_reg, offset);
|
||||||
|
ASM::movzx_reg_reg(&mut self.buf, RegisterWidth::W8, dst_reg, dst_reg)
|
||||||
|
}
|
||||||
|
Layout::U16 => {
|
||||||
|
ASM::mov_reg16_mem16_offset32(&mut self.buf, dst_reg, ptr_reg, offset);
|
||||||
|
ASM::movzx_reg_reg(&mut self.buf, RegisterWidth::W16, dst_reg, dst_reg)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// mask the 3 lowest bits
|
// mask the 3 lowest bits
|
||||||
let tmp = Symbol::DEV_TMP5;
|
let tmp = Symbol::DEV_TMP5;
|
||||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &tmp);
|
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &tmp);
|
||||||
|
@ -3189,33 +3221,73 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UnionLayout::Recursive(tags) => {
|
UnionLayout::Recursive(tags) => {
|
||||||
if union_layout.stores_tag_id_as_data(self.storage_manager.target_info) {
|
self.load_literal_symbols(fields);
|
||||||
todo!("big recursive tags")
|
|
||||||
|
let whole_struct_symbol = self.debug_symbol("whole_struct_symbol");
|
||||||
|
let tag_id_symbol = self.debug_symbol("tag_id_symbol");
|
||||||
|
let other_fields = tags[tag_id as usize];
|
||||||
|
|
||||||
|
let stores_tag_id_as_data =
|
||||||
|
union_layout.stores_tag_id_as_data(self.storage_manager.target_info);
|
||||||
|
|
||||||
|
// construct the payload as a struct on the stack
|
||||||
|
let data_struct_layout = self
|
||||||
|
.layout_interner
|
||||||
|
.insert_no_semantic(LayoutRepr::Struct(other_fields));
|
||||||
|
|
||||||
|
let tag_id_layout = union_layout.tag_id_layout();
|
||||||
|
|
||||||
|
if stores_tag_id_as_data {
|
||||||
|
let inner_struct_symbol = self.debug_symbol("inner_struct_symbol");
|
||||||
|
|
||||||
|
self.storage_manager.create_struct(
|
||||||
|
self.layout_interner,
|
||||||
|
&mut self.buf,
|
||||||
|
&inner_struct_symbol,
|
||||||
|
&data_struct_layout,
|
||||||
|
fields,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.load_literal_i64(&tag_id_symbol, tag_id as _);
|
||||||
|
|
||||||
|
let arena = self.env.arena;
|
||||||
|
let whole_struct_layout = self.layout_interner.insert_no_semantic(
|
||||||
|
LayoutRepr::Struct(arena.alloc([data_struct_layout, tag_id_layout])),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.storage_manager.create_struct(
|
||||||
|
self.layout_interner,
|
||||||
|
&mut self.buf,
|
||||||
|
&whole_struct_symbol,
|
||||||
|
&whole_struct_layout,
|
||||||
|
arena.alloc([inner_struct_symbol, tag_id_symbol]),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.expr_box(*sym, whole_struct_symbol, whole_struct_layout, reuse);
|
||||||
|
|
||||||
|
self.free_symbol(&tag_id_symbol);
|
||||||
|
self.free_symbol(&whole_struct_symbol);
|
||||||
|
self.free_symbol(&inner_struct_symbol);
|
||||||
} else {
|
} else {
|
||||||
let other_fields = tags[tag_id as usize];
|
|
||||||
|
|
||||||
// construct the payload as a struct on the stack
|
|
||||||
let temp_sym = Symbol::DEV_TMP5;
|
|
||||||
let layout = self
|
|
||||||
.layout_interner
|
|
||||||
.insert_no_semantic(LayoutRepr::Struct(other_fields));
|
|
||||||
|
|
||||||
self.load_literal_symbols(fields);
|
self.load_literal_symbols(fields);
|
||||||
self.storage_manager.create_struct(
|
self.storage_manager.create_struct(
|
||||||
self.layout_interner,
|
self.layout_interner,
|
||||||
&mut self.buf,
|
&mut self.buf,
|
||||||
&temp_sym,
|
&whole_struct_symbol,
|
||||||
&layout,
|
&data_struct_layout,
|
||||||
fields,
|
fields,
|
||||||
);
|
);
|
||||||
|
|
||||||
// now effectively box this struct
|
// now effectively box this struct
|
||||||
let untagged_pointer_symbol = self.debug_symbol("untagged_pointer");
|
let untagged_pointer_symbol = self.debug_symbol("untagged_pointer");
|
||||||
self.expr_box(untagged_pointer_symbol, temp_sym, layout, reuse);
|
self.expr_box(
|
||||||
|
untagged_pointer_symbol,
|
||||||
|
whole_struct_symbol,
|
||||||
|
data_struct_layout,
|
||||||
|
reuse,
|
||||||
|
);
|
||||||
|
|
||||||
self.free_symbol(&temp_sym);
|
self.free_symbol(&whole_struct_symbol);
|
||||||
|
|
||||||
let tag_id_symbol = self.debug_symbol("tag_id");
|
|
||||||
|
|
||||||
// finally, we need to tag the pointer
|
// finally, we need to tag the pointer
|
||||||
debug_assert!(tag_id < 8);
|
debug_assert!(tag_id < 8);
|
||||||
|
|
|
@ -2171,7 +2171,7 @@ fn refcount_nullable_unwrapped_needing_no_refcount_issue_5027() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn issue_5162_recast_nested_nullable_unwrapped_layout() {
|
fn issue_5162_recast_nested_nullable_unwrapped_layout() {
|
||||||
with_larger_debug_stack(|| {
|
with_larger_debug_stack(|| {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
@ -2199,7 +2199,7 @@ fn issue_5162_recast_nested_nullable_unwrapped_layout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
fn nullable_wrapped_eq_issue_5434() {
|
fn nullable_wrapped_eq_issue_5434() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -2228,3 +2228,78 @@ fn nullable_wrapped_eq_issue_5434() {
|
||||||
RocStr
|
RocStr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
|
fn recursive_tag_id_in_allocation_basic() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r###"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Value : [
|
||||||
|
A Value,
|
||||||
|
B I64,
|
||||||
|
C I64,
|
||||||
|
D I64,
|
||||||
|
E I64,
|
||||||
|
F I64,
|
||||||
|
G I64,
|
||||||
|
H I64,
|
||||||
|
I I64,
|
||||||
|
]
|
||||||
|
|
||||||
|
x : Value
|
||||||
|
x = H 42
|
||||||
|
|
||||||
|
main =
|
||||||
|
when x is
|
||||||
|
A _ -> "A"
|
||||||
|
B _ -> "B"
|
||||||
|
C _ -> "C"
|
||||||
|
D _ -> "D"
|
||||||
|
E _ -> "E"
|
||||||
|
F _ -> "F"
|
||||||
|
G _ -> "G"
|
||||||
|
H _ -> "H"
|
||||||
|
I _ -> "I"
|
||||||
|
"###
|
||||||
|
),
|
||||||
|
RocStr::from("H"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
|
fn recursive_tag_id_in_allocation_eq() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r###"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Value : [
|
||||||
|
A Value,
|
||||||
|
B I64,
|
||||||
|
C I64,
|
||||||
|
D I64,
|
||||||
|
E I64,
|
||||||
|
F I64,
|
||||||
|
G I64,
|
||||||
|
H I64,
|
||||||
|
I I64,
|
||||||
|
]
|
||||||
|
|
||||||
|
x : Value
|
||||||
|
x = G 42
|
||||||
|
|
||||||
|
y : Value
|
||||||
|
y = H 42
|
||||||
|
|
||||||
|
main = (x == x) && (x != y) && (y == y)
|
||||||
|
"###
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue