fix list inc/dec wrt slices

This commit is contained in:
Folkert 2023-05-07 21:19:05 +02:00
parent 8ba3fd082d
commit 1c6b55584a
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -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),
); );