refactor Access into AccessAtIndex

This commit is contained in:
Folkert 2020-03-22 20:14:15 +01:00
parent 18f34710e1
commit e2a7c970bc
4 changed files with 43 additions and 94 deletions

View file

@ -281,36 +281,6 @@ pub fn build_expr<'a, B: Backend>(
.ins() .ins()
.stack_addr(cfg.pointer_type(), slot, Offset32::new(0)) .stack_addr(cfg.pointer_type(), slot, Offset32::new(0))
} }
Access {
label,
field_layout,
struct_layout: Layout::Struct(sorted_fields),
record,
} => {
let cfg = env.cfg;
// Find the offset we are trying to access
let mut offset = 0;
for (local_label, local_field_layout) in sorted_fields.iter() {
if local_label == label {
break;
}
offset += local_field_layout.stack_size(ptr_bytes);
}
let offset = i32::try_from(offset)
.expect("TODO gracefully handle usize -> i32 conversion in struct access");
let mem_flags = MemFlags::new();
let record = build_expr(env, scope, module, builder, record, procs);
let field_type = type_from_layout(cfg, field_layout);
builder
.ins()
.load(field_type, mem_flags, record, Offset32::new(offset))
}
AccessAtIndex { AccessAtIndex {
index, index,
field_layouts, field_layouts,

View file

@ -72,9 +72,6 @@ pub fn build_expr<'a, 'ctx, 'env>(
build_branch2(env, scope, parent, conditional, procs) build_branch2(env, scope, parent, conditional, procs)
} }
Branches { .. } => {
panic!("TODO build_branches(env, scope, parent, cond_lhs, branches, procs)");
}
Switch { Switch {
cond, cond,
branches, branches,
@ -476,27 +473,6 @@ pub fn build_expr<'a, 'ctx, 'env>(
.unwrap(); .unwrap();
wrapper_val.into_struct_value().into() wrapper_val.into_struct_value().into()
} }
Access {
label,
struct_layout: Layout::Struct(sorted_fields),
record,
..
} => {
let builder = env.builder;
// Get index
let index = sorted_fields
.iter()
.position(|(local_label, _)| local_label == label)
.unwrap() as u32; // TODO
// Get Struct val
let struct_val = build_expr(env, &scope, parent, record, procs).into_struct_value();
builder
.build_extract_value(struct_val, index, "field_access")
.unwrap()
}
AccessAtIndex { AccessAtIndex {
index, index,
expr, expr,

View file

@ -159,16 +159,6 @@ pub enum Expr<'a> {
fail: &'a Expr<'a>, fail: &'a Expr<'a>,
ret_layout: Layout<'a>, ret_layout: Layout<'a>,
}, },
/// More than two conditional branches, e.g. a 3-way when-expression
Branches {
/// The left-hand side of the conditional. We compile this to LLVM once,
/// then reuse it to test against each different compiled cond_rhs value.
cond: &'a Expr<'a>,
/// ( cond_rhs, pass, fail )
branches: &'a [(Expr<'a>, Expr<'a>, Expr<'a>)],
default: &'a Expr<'a>,
ret_layout: Layout<'a>,
},
/// Conditional branches for integers. These are more efficient. /// Conditional branches for integers. These are more efficient.
Switch { Switch {
/// This *must* be an integer, because Switch potentially compiles to a jump table. /// This *must* be an integer, because Switch potentially compiles to a jump table.
@ -190,12 +180,6 @@ pub enum Expr<'a> {
arguments: &'a [(Expr<'a>, Layout<'a>)], arguments: &'a [(Expr<'a>, Layout<'a>)],
}, },
Struct(&'a [(Expr<'a>, Layout<'a>)]), Struct(&'a [(Expr<'a>, Layout<'a>)]),
Access {
label: Lowercase,
field_layout: Layout<'a>,
struct_layout: Layout<'a>,
record: &'a Expr<'a>,
},
AccessAtIndex { AccessAtIndex {
index: u64, index: u64,
field_layouts: &'a [Layout<'a>], field_layouts: &'a [Layout<'a>],
@ -772,14 +756,13 @@ fn from_can<'a>(
Access { Access {
record_var, record_var,
field_var,
field, field,
loc_expr, loc_expr,
.. ..
} => { } => {
let arena = env.arena; let arena = env.arena;
let struct_layout = let record_layout =
match Layout::from_var(arena, record_var, env.subs, env.pointer_size) { match Layout::from_var(arena, record_var, env.subs, env.pointer_size) {
Ok(layout) => layout, Ok(layout) => layout,
Err(()) => { Err(()) => {
@ -788,23 +771,9 @@ fn from_can<'a>(
} }
}; };
let field_layout = match Layout::from_var(arena, field_var, env.subs, env.pointer_size)
{
Ok(layout) => layout,
Err(()) => {
// Invalid field!
panic!("TODO gracefully handle Access with invalid field_layout");
}
};
let record = arena.alloc(from_can(env, loc_expr.value, procs, None)); let record = arena.alloc(from_can(env, loc_expr.value, procs, None));
Expr::Access { record_access_by_field(env, record_layout, record, field)
label: field,
field_layout,
struct_layout,
record,
}
} }
List { List {
@ -841,6 +810,45 @@ fn from_can<'a>(
} }
} }
fn record_access_by_field<'a>(
env: &mut Env<'a, '_>,
record_layout: Layout<'a>,
record_expr: &'a Expr<'a>,
field: Lowercase,
) -> Expr<'a> {
let (field_layouts, index) = match record_layout {
Layout::Struct(sorted_fields) => {
let index = sorted_fields
.iter()
.position(|(local_label, _)| local_label == &field)
.unwrap() as u64;
let mut only_fields = Vec::with_capacity_in(sorted_fields.len(), env.arena);
for (_, field) in sorted_fields.iter() {
only_fields.push(field.clone());
}
(only_fields.into_bump_slice(), index)
}
other => {
// Invalid field!
panic!(
"TODO gracefully handle Access with invalid struct_layout {:?}",
other
);
}
};
Expr::AccessAtIndex {
index,
field_layouts,
expr: record_expr,
is_unwrapped: true,
}
}
fn store_pattern<'a>( fn store_pattern<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
can_pat: &Pattern<'a>, can_pat: &Pattern<'a>,
@ -931,12 +939,7 @@ fn store_record_destruct<'a>(
) -> Result<(), String> { ) -> Result<(), String> {
use Pattern::*; use Pattern::*;
let record = env.arena.alloc(Expr::Load(outer_symbol)); let record = env.arena.alloc(Expr::Load(outer_symbol));
let load = Expr::Access { let load = record_access_by_field(env, struct_layout, record, destruct.label.clone());
label: destruct.label.clone(),
field_layout: destruct.layout.clone(),
struct_layout,
record,
};
match &destruct.guard { match &destruct.guard {
None => { None => {
stored.push((destruct.symbol, destruct.layout.clone(), load)); stored.push((destruct.symbol, destruct.layout.clone(), load));