make arbitrary AccessAtIndex work

it now uses that actual layout, not a hardcoded one
This commit is contained in:
Folkert 2020-03-19 00:25:16 +01:00
parent f3f135eca5
commit b93fe4e341
6 changed files with 78 additions and 147 deletions

View file

@ -205,7 +205,7 @@ pub fn build_expr<'a, B: Backend>(
.ins()
.stack_addr(cfg.pointer_type(), slot, Offset32::new(0))
}
Tag { union_size, tag_layout, arguments , ..} if *union_size == 1 => {
Tag { tag_layout, arguments , tag_id, union_size, .. } => {
let cfg = env.cfg;
let ptr_bytes = cfg.pointer_bytes() as u32;
@ -220,11 +220,18 @@ pub fn build_expr<'a, B: Backend>(
slot_size
));
let it = std::iter::empty().chain(arguments.iter());
// Create instructions for storing each field's expression
let mut offset = 0;
for (field_expr, field_layout) in it {
// still need to insert the tag discriminator for non-single unions
// when there are no arguments, e.g. `Nothing : Maybe a`
if *union_size > 1 {
let val = builder.ins().iconst(types::I64, *tag_id as i64);
builder.ins().stack_store(val, slot, Offset32::new(0));
offset += ptr_bytes;
}
for (field_expr, field_layout) in arguments.iter() {
let val = build_expr(env, &scope, module, builder, field_expr, procs);
let field_size = field_layout.stack_size(ptr_bytes);
@ -236,42 +243,6 @@ pub fn build_expr<'a, B: Backend>(
offset += field_size;
}
builder
.ins()
.stack_addr(cfg.pointer_type(), slot, Offset32::new(0))
}
Tag { tag_id, tag_layout, arguments , ..} => {
let cfg = env.cfg;
let ptr_bytes = cfg.pointer_bytes() as u32;
// NOTE: all variants of a tag union must have the same size, so (among other things)
// it's easy to quickly index them in arrays. Therefore the size of this tag doens't
// depend on the tag arguments, but solely on the layout of the whole tag union
let slot_size = tag_layout.stack_size(ptr_bytes);
// Create a slot
let slot = builder.create_stack_slot(StackSlotData::new(
StackSlotKind::ExplicitSlot,
slot_size
));
// put the discriminant in the first slot
let discriminant = (Expr::Int(*tag_id as i64), Layout::Builtin(Builtin::Int64));
let it = std::iter::once(&discriminant).chain(arguments.iter());
// Create instructions for storing each field's expression
let mut offset = 0;
for (field_expr, field_layout) in it {
let val = build_expr(env, &scope, module, builder, field_expr, procs);
let field_size = field_layout.stack_size(ptr_bytes);
let field_offset = i32::try_from(offset)
.expect("TODO handle field size conversion to i32");
builder.ins().stack_store(val, slot, Offset32::new(field_offset));
offset += field_size;
}
builder
.ins()
@ -337,6 +308,7 @@ pub fn build_expr<'a, B: Backend>(
let mut offset = 0;
for (field_index, field_layout) in field_layouts.iter().enumerate() {
if *index == field_index as u64 {
let offset = i32::try_from(offset)

View file

@ -352,18 +352,16 @@ pub fn build_expr<'a, 'ctx, 'env>(
BasicValueEnum::StructValue(struct_val.into_struct_value())
}
Tag {
tag_id,
arguments,
tag_layout,
union_size,
tag_id,
..
} => {
let ptr_size = env.pointer_bytes;
let whole_size = tag_layout.stack_size(ptr_size);
let mut filler = tag_layout.stack_size(ptr_size);
// put the discriminant in the first slot
let discriminant = (Expr::Int(*tag_id as i64), Layout::Builtin(Builtin::Int64));
let it = std::iter::once(&discriminant).chain(arguments.iter());
let ctx = env.context;
let builder = env.builder;
@ -373,7 +371,24 @@ pub fn build_expr<'a, 'ctx, 'env>(
let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
let mut field_vals = Vec::with_capacity_in(num_fields, env.arena);
for (field_expr, field_layout) in it {
// insert the discriminant value
if *union_size > 1 {
let val = env
.context
.i64_type()
.const_int(*tag_id as u64, true)
.into();
let field_type = env.context.i64_type().into();
field_types.push(field_type);
field_vals.push(val);
let field_size = ptr_size;
filler -= field_size;
}
for (field_expr, field_layout) in arguments.iter() {
let val = build_expr(env, &scope, parent, field_expr, procs);
let field_type = basic_type_from_layout(env.arena, env.context, &field_layout);