use Box instead of a tag to read the refcount

This commit is contained in:
Folkert 2023-04-27 20:42:09 +02:00
parent ca7ba45955
commit a61e7a696d
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
2 changed files with 86 additions and 30 deletions

View file

@ -41,6 +41,10 @@ impl HelperOp {
fn is_decref(&self) -> bool { fn is_decref(&self) -> bool {
matches!(self, Self::DecRef(_)) matches!(self, Self::DecRef(_))
} }
fn is_dec(&self) -> bool {
matches!(self, Self::Dec)
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -81,7 +85,6 @@ pub struct CodeGenHelp<'a> {
home: ModuleId, home: ModuleId,
target_info: TargetInfo, target_info: TargetInfo,
layout_isize: InLayout<'a>, layout_isize: InLayout<'a>,
union_refcount: UnionLayout<'a>,
specializations: Vec<'a, Specialization<'a>>, specializations: Vec<'a, Specialization<'a>>,
debug_recursion_depth: usize, debug_recursion_depth: usize,
} }
@ -90,15 +93,11 @@ impl<'a> CodeGenHelp<'a> {
pub fn new(arena: &'a Bump, target_info: TargetInfo, home: ModuleId) -> Self { pub fn new(arena: &'a Bump, target_info: TargetInfo, home: ModuleId) -> Self {
let layout_isize = Layout::isize(target_info); let layout_isize = Layout::isize(target_info);
// Refcount is a boxed isize. TODO: use the new Box layout when dev backends support it
let union_refcount = UnionLayout::NonNullableUnwrapped(arena.alloc([layout_isize]));
CodeGenHelp { CodeGenHelp {
arena, arena,
home, home,
target_info, target_info,
layout_isize, layout_isize,
union_refcount,
specializations: Vec::with_capacity_in(16, arena), specializations: Vec::with_capacity_in(16, arena),
debug_recursion_depth: 0, debug_recursion_depth: 0,
} }

View file

@ -186,6 +186,56 @@ pub fn refcount_generic<'a>(
} }
} }
fn if_unique<'a>(
root: &mut CodeGenHelp<'a>,
ident_ids: &mut IdentIds,
value: Symbol,
when_unique: impl FnOnce(JoinPointId) -> Stmt<'a>,
when_done: Stmt<'a>,
) -> Stmt<'a> {
// joinpoint f =
// <when_done>
// in
// if is_unique <value> then
// <when_unique>(f)
// else
// jump f
let joinpoint = root.create_symbol(ident_ids, "is_unique_joinpoint");
let joinpoint = JoinPointId(joinpoint);
let is_unique = root.create_symbol(ident_ids, "is_unique");
let mut stmt = Stmt::Switch {
cond_symbol: is_unique,
cond_layout: Layout::BOOL,
branches: root
.arena
.alloc([(true as _, BranchInfo::None, when_unique(joinpoint))]),
default_branch: (
BranchInfo::None,
root.arena.alloc(Stmt::Jump(joinpoint, &[])),
),
ret_layout: Layout::UNIT,
};
stmt = Stmt::Join {
id: joinpoint,
parameters: &[],
body: root.arena.alloc(when_done),
remainder: root.arena.alloc(stmt),
};
let_lowlevel(
root.arena,
root.layout_isize,
is_unique,
LowLevel::RefCountIsUnique,
&[value],
root.arena.alloc(stmt),
)
}
pub fn refcount_reset_proc_body<'a>( pub fn refcount_reset_proc_body<'a>(
root: &mut CodeGenHelp<'a>, root: &mut CodeGenHelp<'a>,
ident_ids: &mut IdentIds, ident_ids: &mut IdentIds,
@ -348,12 +398,8 @@ pub fn refcount_reset_proc_body<'a>(
); );
// Refcount value // Refcount value
let rc_expr = Expr::UnionAtIndex { let rc_expr = Expr::ExprUnbox { symbol: rc_ptr };
structure: rc_ptr,
tag_id: 0,
union_layout: root.union_refcount,
index: 0,
};
let rc_stmt = Stmt::Let( let rc_stmt = Stmt::Let(
rc, rc,
rc_expr, rc_expr,
@ -361,6 +407,9 @@ pub fn refcount_reset_proc_body<'a>(
root.arena.alloc(refcount_1_stmt), root.arena.alloc(refcount_1_stmt),
); );
// a Box never masks bits
let mask_lower_bits = false;
// Refcount pointer // Refcount pointer
let rc_ptr_stmt = { let rc_ptr_stmt = {
rc_ptr_from_data_ptr_help( rc_ptr_from_data_ptr_help(
@ -368,7 +417,7 @@ pub fn refcount_reset_proc_body<'a>(
ident_ids, ident_ids,
structure, structure,
rc_ptr, rc_ptr,
union_layout.stores_tag_id_in_pointer(root.target_info), mask_lower_bits,
root.arena.alloc(rc_stmt), root.arena.alloc(rc_stmt),
addr, addr,
recursion_ptr, recursion_ptr,
@ -508,12 +557,8 @@ pub fn refcount_resetref_proc_body<'a>(
); );
// Refcount value // Refcount value
let rc_expr = Expr::UnionAtIndex { let rc_expr = Expr::ExprUnbox { symbol: rc_ptr };
structure: rc_ptr,
tag_id: 0,
union_layout: root.union_refcount,
index: 0,
};
let rc_stmt = Stmt::Let( let rc_stmt = Stmt::Let(
rc, rc,
rc_expr, rc_expr,
@ -521,6 +566,9 @@ pub fn refcount_resetref_proc_body<'a>(
root.arena.alloc(refcount_1_stmt), root.arena.alloc(refcount_1_stmt),
); );
// a Box never masks bits
let mask_lower_bits = false;
// Refcount pointer // Refcount pointer
let rc_ptr_stmt = { let rc_ptr_stmt = {
rc_ptr_from_data_ptr_help( rc_ptr_from_data_ptr_help(
@ -528,7 +576,7 @@ pub fn refcount_resetref_proc_body<'a>(
ident_ids, ident_ids,
structure, structure,
rc_ptr, rc_ptr,
union_layout.stores_tag_id_in_pointer(root.target_info), mask_lower_bits,
root.arena.alloc(rc_stmt), root.arena.alloc(rc_stmt),
addr, addr,
recursion_ptr, recursion_ptr,
@ -1813,7 +1861,8 @@ fn refcount_boxed<'a>(
Layout::OPAQUE_PTR, Layout::OPAQUE_PTR,
); );
if layout_interner.is_refcounted(inner_layout) && !ctx.op.is_decref() { // decrement the inner value if the operation is a decrement and the box itself is unique
if layout_interner.is_refcounted(inner_layout) && ctx.op.is_dec() {
let inner = root.create_symbol(ident_ids, "inner"); let inner = root.create_symbol(ident_ids, "inner");
let inner_expr = Expr::ExprUnbox { symbol: outer }; let inner_expr = Expr::ExprUnbox { symbol: outer };
@ -1829,6 +1878,11 @@ fn refcount_boxed<'a>(
) )
.unwrap(); .unwrap();
if_unique(
root,
ident_ids,
outer,
|id| {
Stmt::Let( Stmt::Let(
inner, inner,
inner_expr, inner_expr,
@ -1837,9 +1891,12 @@ fn refcount_boxed<'a>(
mod_inner_unit, mod_inner_unit,
mod_inner_expr, mod_inner_expr,
LAYOUT_UNIT, LAYOUT_UNIT,
arena.alloc(get_rc_and_modify_outer), arena.alloc(Stmt::Jump(id, &[])),
)), )),
) )
},
get_rc_and_modify_outer,
)
} else { } else {
get_rc_and_modify_outer get_rc_and_modify_outer
} }