mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-09 21:36:18 +00:00
fix list inc/dec wrt slices
This commit is contained in:
parent
8ba3fd082d
commit
1c6b55584a
1 changed files with 95 additions and 74 deletions
|
@ -719,11 +719,16 @@ fn rc_ptr_from_data_ptr_help<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Pointer {
|
||||||
|
ToData(Symbol),
|
||||||
|
ToRefcount(Symbol),
|
||||||
|
}
|
||||||
|
|
||||||
fn modify_refcount<'a>(
|
fn modify_refcount<'a>(
|
||||||
root: &CodeGenHelp<'a>,
|
root: &CodeGenHelp<'a>,
|
||||||
ident_ids: &mut IdentIds,
|
ident_ids: &mut IdentIds,
|
||||||
ctx: &mut Context<'a>,
|
ctx: &mut Context<'a>,
|
||||||
data_ptr: Symbol,
|
ptr: Pointer,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
following: &'a Stmt<'a>,
|
following: &'a Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
|
@ -731,28 +736,39 @@ fn modify_refcount<'a>(
|
||||||
let zig_call_result = root.create_symbol(ident_ids, "zig_call_result");
|
let zig_call_result = root.create_symbol(ident_ids, "zig_call_result");
|
||||||
match ctx.op {
|
match ctx.op {
|
||||||
HelperOp::Inc => {
|
HelperOp::Inc => {
|
||||||
|
let (op, ptr) = match ptr {
|
||||||
|
Pointer::ToData(s) => (LowLevel::RefCountIncDataPtr, s),
|
||||||
|
Pointer::ToRefcount(s) => (LowLevel::RefCountIncRcPtr, s),
|
||||||
|
};
|
||||||
|
|
||||||
let zig_call_expr = Expr::Call(Call {
|
let zig_call_expr = Expr::Call(Call {
|
||||||
call_type: CallType::LowLevel {
|
call_type: CallType::LowLevel {
|
||||||
op: LowLevel::RefCountIncDataPtr,
|
op,
|
||||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||||
},
|
},
|
||||||
arguments: root.arena.alloc([data_ptr, Symbol::ARG_2]),
|
arguments: root.arena.alloc([ptr, Symbol::ARG_2]),
|
||||||
});
|
});
|
||||||
Stmt::Let(zig_call_result, zig_call_expr, LAYOUT_UNIT, following)
|
Stmt::Let(zig_call_result, zig_call_expr, LAYOUT_UNIT, following)
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperOp::Dec | HelperOp::DecRef(_) => {
|
HelperOp::Dec | HelperOp::DecRef(_) => {
|
||||||
debug_assert!(alignment >= root.target_info.ptr_width() as u32);
|
debug_assert!(alignment >= root.target_info.ptr_width() as u32);
|
||||||
|
|
||||||
|
let (op, ptr) = match ptr {
|
||||||
|
Pointer::ToData(s) => (LowLevel::RefCountDecDataPtr, s),
|
||||||
|
Pointer::ToRefcount(s) => (LowLevel::RefCountDecRcPtr, s),
|
||||||
|
};
|
||||||
|
|
||||||
let alignment_sym = root.create_symbol(ident_ids, "alignment");
|
let alignment_sym = root.create_symbol(ident_ids, "alignment");
|
||||||
let alignment_expr = Expr::Literal(Literal::Int((alignment as i128).to_ne_bytes()));
|
let alignment_expr = Expr::Literal(Literal::Int((alignment as i128).to_ne_bytes()));
|
||||||
let alignment_stmt = |next| Stmt::Let(alignment_sym, alignment_expr, LAYOUT_U32, next);
|
let alignment_stmt = |next| Stmt::Let(alignment_sym, alignment_expr, LAYOUT_U32, next);
|
||||||
|
|
||||||
let zig_call_expr = Expr::Call(Call {
|
let zig_call_expr = Expr::Call(Call {
|
||||||
call_type: CallType::LowLevel {
|
call_type: CallType::LowLevel {
|
||||||
op: LowLevel::RefCountDecDataPtr,
|
op,
|
||||||
update_mode: UpdateModeId::BACKEND_DUMMY,
|
update_mode: UpdateModeId::BACKEND_DUMMY,
|
||||||
},
|
},
|
||||||
arguments: root.arena.alloc([data_ptr, alignment_sym]),
|
arguments: root.arena.alloc([ptr, alignment_sym]),
|
||||||
});
|
});
|
||||||
let zig_call_stmt = Stmt::Let(zig_call_result, zig_call_expr, LAYOUT_UNIT, following);
|
let zig_call_stmt = Stmt::Let(zig_call_result, zig_call_expr, LAYOUT_UNIT, following);
|
||||||
|
|
||||||
|
@ -777,13 +793,6 @@ fn refcount_str<'a>(
|
||||||
let layout_isize = root.layout_isize;
|
let layout_isize = root.layout_isize;
|
||||||
let field_layouts = arena.alloc([Layout::OPAQUE_PTR, layout_isize, layout_isize]);
|
let field_layouts = arena.alloc([Layout::OPAQUE_PTR, layout_isize, layout_isize]);
|
||||||
|
|
||||||
let is_increment = matches!(ctx.op, HelperOp::Inc);
|
|
||||||
|
|
||||||
let (modify_rc_ptr, modify_data_ptr) = match is_increment {
|
|
||||||
true => (LowLevel::RefCountIncRcPtr, LowLevel::RefCountIncDataPtr),
|
|
||||||
false => (LowLevel::RefCountDecRcPtr, LowLevel::RefCountDecDataPtr),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the last word as a signed int
|
// Get the last word as a signed int
|
||||||
let last_word = root.create_symbol(ident_ids, "last_word");
|
let last_word = root.create_symbol(ident_ids, "last_word");
|
||||||
let last_word_expr = Expr::StructAtIndex {
|
let last_word_expr = Expr::StructAtIndex {
|
||||||
|
@ -826,10 +835,7 @@ fn refcount_str<'a>(
|
||||||
};
|
};
|
||||||
let length_stmt = |next| Stmt::Let(length, length_expr, layout_isize, next);
|
let length_stmt = |next| Stmt::Let(length, length_expr, layout_isize, next);
|
||||||
|
|
||||||
let alignment = root.create_symbol(ident_ids, "alignment");
|
let alignment = root.target_info.ptr_width() as u32;
|
||||||
let alignment_int = root.target_info.ptr_width() as u32;
|
|
||||||
let alignment_expr = Expr::Literal(Literal::Int((alignment_int as u128).to_ne_bytes()));
|
|
||||||
let alignment_stmt = |next| Stmt::Let(alignment, alignment_expr, layout_isize, next);
|
|
||||||
|
|
||||||
// let is_slice = lowlevel NumLt length zero
|
// let is_slice = lowlevel NumLt length zero
|
||||||
let is_slice = root.create_symbol(ident_ids, "is_slice");
|
let is_slice = root.create_symbol(ident_ids, "is_slice");
|
||||||
|
@ -840,23 +846,16 @@ fn refcount_str<'a>(
|
||||||
// Branch on seamless slice vs "real" string
|
// Branch on seamless slice vs "real" string
|
||||||
//
|
//
|
||||||
|
|
||||||
let second_argument = match is_increment {
|
let return_unit = arena.alloc(rc_return_stmt(root, ident_ids, ctx));
|
||||||
true => Symbol::ARG_2,
|
|
||||||
false => alignment,
|
|
||||||
};
|
|
||||||
|
|
||||||
// when the string is a slice, the capacity field is a pointer to the refcount
|
// when the string is a slice, the capacity field is a pointer to the refcount
|
||||||
let unit = root.create_symbol(ident_ids, "unit");
|
let slice_branch = modify_refcount(
|
||||||
let slice_branch = let_lowlevel(
|
root,
|
||||||
arena,
|
ident_ids,
|
||||||
Layout::UNIT,
|
ctx,
|
||||||
unit,
|
Pointer::ToRefcount(last_word),
|
||||||
modify_rc_ptr,
|
alignment,
|
||||||
&[last_word, second_argument],
|
return_unit,
|
||||||
arena.alloc(
|
|
||||||
//
|
|
||||||
Stmt::Ret(unit),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Characters pointer for a real string
|
// Characters pointer for a real string
|
||||||
|
@ -868,23 +867,20 @@ fn refcount_str<'a>(
|
||||||
};
|
};
|
||||||
let string_chars_stmt = |next| Stmt::Let(string_chars, string_chars_expr, layout_isize, next);
|
let string_chars_stmt = |next| Stmt::Let(string_chars, string_chars_expr, layout_isize, next);
|
||||||
|
|
||||||
let modify_rc_stmt = let_lowlevel(
|
let modify_refcount_stmt = modify_refcount(
|
||||||
arena,
|
root,
|
||||||
Layout::UNIT,
|
ident_ids,
|
||||||
unit,
|
ctx,
|
||||||
modify_data_ptr,
|
Pointer::ToData(string_chars),
|
||||||
&[string_chars, second_argument],
|
alignment,
|
||||||
arena.alloc(
|
return_unit,
|
||||||
//
|
|
||||||
Stmt::Ret(unit),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let string_branch = arena.alloc(
|
let string_branch = arena.alloc(
|
||||||
//
|
//
|
||||||
string_chars_stmt(arena.alloc(
|
string_chars_stmt(arena.alloc(
|
||||||
//
|
//
|
||||||
modify_rc_stmt,
|
modify_refcount_stmt,
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -912,11 +908,7 @@ fn refcount_str<'a>(
|
||||||
root.arena,
|
root.arena,
|
||||||
is_big_str,
|
is_big_str,
|
||||||
Layout::UNIT,
|
Layout::UNIT,
|
||||||
if is_increment {
|
modify_stmt,
|
||||||
modify_stmt
|
|
||||||
} else {
|
|
||||||
alignment_stmt(arena.alloc(modify_stmt))
|
|
||||||
},
|
|
||||||
root.arena.alloc(rc_return_stmt(root, ident_ids, ctx)),
|
root.arena.alloc(rc_return_stmt(root, ident_ids, ctx)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -999,26 +991,52 @@ fn refcount_list<'a>(
|
||||||
let one_expr = Expr::Literal(Literal::Int(1i128.to_ne_bytes()));
|
let one_expr = Expr::Literal(Literal::Int(1i128.to_ne_bytes()));
|
||||||
let one_stmt = |next| Stmt::Let(one, one_expr, layout_isize, next);
|
let one_stmt = |next| Stmt::Let(one, one_expr, layout_isize, next);
|
||||||
|
|
||||||
// slice_elems = lowlevel NumShiftLeftBy capacity one
|
// ptr_width =
|
||||||
let slice_elems = root.create_symbol(ident_ids, "slice_elems");
|
let ptr_width = root.create_symbol(ident_ids, "ptr_width");
|
||||||
let slice_elems_stmt = |next| {
|
let ptr_width_int = match root.target_info.ptr_width() {
|
||||||
|
PtrWidth::Bytes4 => 4i128,
|
||||||
|
PtrWidth::Bytes8 => 8i128,
|
||||||
|
};
|
||||||
|
let ptr_width_expr = Expr::Literal(Literal::Int(ptr_width_int.to_ne_bytes()));
|
||||||
|
let ptr_width_stmt = |next| Stmt::Let(ptr_width, ptr_width_expr, layout_isize, next);
|
||||||
|
|
||||||
|
let rc_pointer = root.create_symbol(ident_ids, "rc_pointer");
|
||||||
|
let rc_pointer_stmt = move |next| {
|
||||||
|
one_stmt(arena.alloc(
|
||||||
|
//
|
||||||
let_lowlevel(
|
let_lowlevel(
|
||||||
arena,
|
arena,
|
||||||
layout_isize,
|
layout_isize,
|
||||||
slice_elems,
|
rc_pointer,
|
||||||
NumShiftLeftBy,
|
LowLevel::NumShiftLeftBy,
|
||||||
&[capacity, one],
|
&[capacity, one],
|
||||||
next,
|
arena.alloc(next),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
|
let data_pointer = root.create_symbol(ident_ids, "data_pointer");
|
||||||
|
let data_pointer_stmt = move |next| {
|
||||||
|
rc_pointer_stmt(
|
||||||
|
//
|
||||||
|
ptr_width_stmt(arena.alloc(
|
||||||
|
//
|
||||||
|
let_lowlevel(
|
||||||
|
arena,
|
||||||
|
layout_isize,
|
||||||
|
data_pointer,
|
||||||
|
LowLevel::NumAddWrap,
|
||||||
|
&[rc_pointer, ptr_width],
|
||||||
|
arena.alloc(next),
|
||||||
|
),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let slice_branch = one_stmt(arena.alloc(
|
let slice_branch = data_pointer_stmt(
|
||||||
//
|
//
|
||||||
slice_elems_stmt(arena.alloc(
|
Stmt::Jump(jp_elements, arena.alloc([data_pointer])),
|
||||||
//
|
);
|
||||||
Stmt::Jump(jp_elements, arena.alloc([slice_elems])),
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
|
|
||||||
// let list_elems = StructAtIndex 0 structure
|
// let list_elems = StructAtIndex 0 structure
|
||||||
let list_elems = root.create_symbol(ident_ids, "list_elems");
|
let list_elems = root.create_symbol(ident_ids, "list_elems");
|
||||||
|
@ -1052,14 +1070,17 @@ fn refcount_list<'a>(
|
||||||
layout_interner.alignment_bytes(elem_layout),
|
layout_interner.alignment_bytes(elem_layout),
|
||||||
);
|
);
|
||||||
|
|
||||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
let ret_stmt = arena.alloc(rc_return_stmt(root, ident_ids, ctx));
|
||||||
let modify_list = modify_refcount(
|
let mut modify_refcount_stmt =
|
||||||
root,
|
|ptr| modify_refcount(root, ident_ids, ctx, ptr, alignment, ret_stmt);
|
||||||
ident_ids,
|
|
||||||
ctx,
|
let modify_list = Stmt::if_then_else(
|
||||||
elements,
|
arena,
|
||||||
alignment,
|
is_slice,
|
||||||
arena.alloc(ret_stmt),
|
Layout::UNIT,
|
||||||
|
// data_pointer_stmt(modify_refcount_stmt(Pointer::ToData(data_pointer))),
|
||||||
|
modify_refcount_stmt(Pointer::ToData(elements)),
|
||||||
|
arena.alloc(modify_refcount_stmt(Pointer::ToData(elements))),
|
||||||
);
|
);
|
||||||
|
|
||||||
let is_relevant_op = ctx.op.is_dec() || ctx.op.is_inc();
|
let is_relevant_op = ctx.op.is_dec() || ctx.op.is_inc();
|
||||||
|
@ -1652,7 +1673,7 @@ fn refcount_union_rec<'a>(
|
||||||
root,
|
root,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
ctx,
|
ctx,
|
||||||
structure,
|
Pointer::ToData(structure),
|
||||||
alignment,
|
alignment,
|
||||||
root.arena.alloc(ret_stmt),
|
root.arena.alloc(ret_stmt),
|
||||||
)
|
)
|
||||||
|
@ -1750,7 +1771,7 @@ fn refcount_union_tailrec<'a>(
|
||||||
root,
|
root,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
ctx,
|
ctx,
|
||||||
current,
|
Pointer::ToData(current),
|
||||||
alignment,
|
alignment,
|
||||||
root.arena.alloc(loop_or_exit_based_on_next_addr),
|
root.arena.alloc(loop_or_exit_based_on_next_addr),
|
||||||
)
|
)
|
||||||
|
@ -1972,7 +1993,7 @@ fn refcount_boxed<'a>(
|
||||||
root,
|
root,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
ctx,
|
ctx,
|
||||||
outer,
|
Pointer::ToData(outer),
|
||||||
alignment,
|
alignment,
|
||||||
arena.alloc(ret_stmt),
|
arena.alloc(ret_stmt),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue