mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
support zero-sized values (empty record, unit type)
They now use no stack space
This commit is contained in:
parent
b93fe4e341
commit
9d1e2a0ef1
3 changed files with 59 additions and 3 deletions
|
@ -27,6 +27,10 @@ pub enum ScopeEntry {
|
||||||
Heap { expr_type: Type, ptr: Value },
|
Heap { expr_type: Type, ptr: Value },
|
||||||
Arg { expr_type: Type, param: Value },
|
Arg { expr_type: Type, param: Value },
|
||||||
Func { sig: Signature, func_id: FuncId },
|
Func { sig: Signature, func_id: FuncId },
|
||||||
|
|
||||||
|
// For empty records and unit types, storing is a no-op and values can be created "out of thin
|
||||||
|
// air". No need to use stack space for them.
|
||||||
|
ZeroSized,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Env<'a> {
|
pub struct Env<'a> {
|
||||||
|
@ -101,13 +105,21 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
let mut scope = im_rc::HashMap::clone(scope);
|
let mut scope = im_rc::HashMap::clone(scope);
|
||||||
let cfg = env.cfg;
|
let cfg = env.cfg;
|
||||||
|
|
||||||
|
let ptr_size = cfg.pointer_bytes() as u32;
|
||||||
for (name, layout, expr) in stores.iter() {
|
for (name, layout, expr) in stores.iter() {
|
||||||
|
let stack_size = layout.stack_size(ptr_size);
|
||||||
|
|
||||||
|
if stack_size == 0 {
|
||||||
|
scope.insert(*name, ScopeEntry::ZeroSized);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let val = build_expr(env, &scope, module, builder, &expr, procs);
|
let val = build_expr(env, &scope, module, builder, &expr, procs);
|
||||||
let expr_type = type_from_layout(cfg, &layout);
|
let expr_type = type_from_layout(cfg, &layout);
|
||||||
|
|
||||||
let slot = builder.create_stack_slot(StackSlotData::new(
|
let slot = builder.create_stack_slot(StackSlotData::new(
|
||||||
StackSlotKind::ExplicitSlot,
|
StackSlotKind::ExplicitSlot,
|
||||||
layout.stack_size(cfg.pointer_bytes() as u32),
|
stack_size,
|
||||||
));
|
));
|
||||||
|
|
||||||
builder.ins().stack_store(val, slot, Offset32::new(0));
|
builder.ins().stack_store(val, slot, Offset32::new(0));
|
||||||
|
@ -168,6 +180,17 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
Some(ScopeEntry::Func { .. }) => {
|
Some(ScopeEntry::Func { .. }) => {
|
||||||
panic!("TODO I don't yet know how to return fn pointers")
|
panic!("TODO I don't yet know how to return fn pointers")
|
||||||
}
|
}
|
||||||
|
Some(ScopeEntry::ZeroSized) => {
|
||||||
|
// Create a slot
|
||||||
|
let slot = builder.create_stack_slot(StackSlotData::new(
|
||||||
|
StackSlotKind::ExplicitSlot,
|
||||||
|
0
|
||||||
|
));
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ins()
|
||||||
|
.stack_addr(env.cfg.pointer_type(), slot, Offset32::new(0))
|
||||||
|
}
|
||||||
None => panic!(
|
None => panic!(
|
||||||
"Could not resolve lookup for {:?} because no ScopeEntry was found for {:?} in scope {:?}",
|
"Could not resolve lookup for {:?} because no ScopeEntry was found for {:?} in scope {:?}",
|
||||||
name, name, scope
|
name, name, scope
|
||||||
|
|
|
@ -227,8 +227,6 @@ mod test_gen {
|
||||||
// Populate Procs and get the low-level Expr from the canonical Expr
|
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||||
let main_body = Expr::new(&arena, &mut subs, loc_expr.value, &mut procs, home, &mut ident_ids, POINTER_SIZE);
|
let main_body = Expr::new(&arena, &mut subs, loc_expr.value, &mut procs, home, &mut ident_ids, POINTER_SIZE);
|
||||||
|
|
||||||
dbg!(&main_body);
|
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
|
@ -1313,6 +1311,39 @@ mod test_gen {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_record() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
v = {}
|
||||||
|
|
||||||
|
1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unit_type() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Unit : [ Unit ]
|
||||||
|
|
||||||
|
v : Unit
|
||||||
|
v = Unit
|
||||||
|
|
||||||
|
1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_record() {
|
fn basic_record() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
|
|
@ -672,6 +672,8 @@ fn from_can<'a>(
|
||||||
Expr::Struct(field_tuples.into_bump_slice())
|
Expr::Struct(field_tuples.into_bump_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmptyRecord => Expr::Struct(&[]),
|
||||||
|
|
||||||
Tag {
|
Tag {
|
||||||
variant_var,
|
variant_var,
|
||||||
name: tag_name,
|
name: tag_name,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue