mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Merge remote-tracking branch 'origin/trunk' into mono-if
This commit is contained in:
commit
1a8f380033
5 changed files with 162 additions and 59 deletions
|
@ -193,16 +193,59 @@ pub fn build_expr<'a, B: Backend>(
|
||||||
builder.ins().stack_store(val, slot, Offset32::new(offset));
|
builder.ins().stack_store(val, slot, Offset32::new(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ir_type = type_from_layout(cfg, layout);
|
builder
|
||||||
builder.ins().stack_addr(ir_type, slot, Offset32::new(0))
|
.ins()
|
||||||
|
.stack_addr(cfg.pointer_type(), slot, Offset32::new(0))
|
||||||
|
}
|
||||||
|
Access {
|
||||||
|
label,
|
||||||
|
field_layout,
|
||||||
|
struct_layout: Layout::Struct(fields),
|
||||||
|
record,
|
||||||
|
} => {
|
||||||
|
let cfg = env.cfg;
|
||||||
|
|
||||||
|
// Reconstruct the struct to determine the combined layout
|
||||||
|
// TODO get rid of clones
|
||||||
|
let mut reconstructed_struct_layout =
|
||||||
|
Vec::with_capacity_in(fields.len() + 1, env.arena);
|
||||||
|
for field in fields.iter() {
|
||||||
|
reconstructed_struct_layout.push(field.clone());
|
||||||
|
}
|
||||||
|
reconstructed_struct_layout.push((label.clone(), field_layout.clone()));
|
||||||
|
reconstructed_struct_layout.sort_by(|a, b| {
|
||||||
|
a.0.partial_cmp(&b.0)
|
||||||
|
.expect("TODO: failed to sort struct fields in crane access")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find the offset we are trying to access
|
||||||
|
let mut offset = 0;
|
||||||
|
for (local_label, layout) in reconstructed_struct_layout.iter() {
|
||||||
|
if local_label == label {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let field_size = match layout {
|
||||||
|
Layout::Builtin(Builtin::Int64) => std::mem::size_of::<i64>(),
|
||||||
|
_ => panic!(
|
||||||
|
"Missing struct field size in offset calculation for struct access for {:?}",
|
||||||
|
layout
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
offset += field_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ins()
|
||||||
|
.load(cfg.pointer_type(), mem_flags, record, Offset32::new(offset))
|
||||||
}
|
}
|
||||||
// Access {
|
|
||||||
// label,
|
|
||||||
// field_layout,
|
|
||||||
// struct_layout,
|
|
||||||
// } => {
|
|
||||||
// panic!("I don't yet know how to crane build {:?}", expr);
|
|
||||||
// }
|
|
||||||
Str(str_literal) => {
|
Str(str_literal) => {
|
||||||
if str_literal.is_empty() {
|
if str_literal.is_empty() {
|
||||||
panic!("TODO build an empty string in Crane");
|
panic!("TODO build an empty string in Crane");
|
||||||
|
|
|
@ -10,20 +10,7 @@ pub fn type_from_layout(cfg: TargetFrontendConfig, layout: &Layout<'_>) -> Type
|
||||||
use roc_mono::layout::Layout::*;
|
use roc_mono::layout::Layout::*;
|
||||||
|
|
||||||
match layout {
|
match layout {
|
||||||
Pointer(_) | FunctionPointer(_, _) => cfg.pointer_type(),
|
Pointer(_) | FunctionPointer(_, _) | Struct(_) => cfg.pointer_type(),
|
||||||
Struct(fields) => {
|
|
||||||
// This will change as we add more fields and field types to the tests
|
|
||||||
let naive_all_ints = fields.iter().all(|ref field| match field.1 {
|
|
||||||
Builtin(Int64) => true,
|
|
||||||
_ => false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if naive_all_ints && fields.len() == 3 {
|
|
||||||
types::I64.by(4).unwrap()
|
|
||||||
} else {
|
|
||||||
panic!("TODO layout_to_crane_type for Struct");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Builtin(builtin) => match builtin {
|
Builtin(builtin) => match builtin {
|
||||||
Int64 => types::I64,
|
Int64 => types::I64,
|
||||||
Float64 => types::F64,
|
Float64 => types::F64,
|
||||||
|
|
|
@ -244,6 +244,80 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
BasicValueEnum::PointerValue(ptr)
|
BasicValueEnum::PointerValue(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Struct { fields, .. } => {
|
||||||
|
let ctx = env.context;
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
// Sort the fields
|
||||||
|
let mut sorted_fields = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
|
for field in fields.iter() {
|
||||||
|
sorted_fields.push(field);
|
||||||
|
}
|
||||||
|
sorted_fields.sort_by_key(|k| &k.0);
|
||||||
|
|
||||||
|
// Determine types
|
||||||
|
let mut field_types = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
|
let mut field_vals = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
|
|
||||||
|
for (_, ref inner_expr) in sorted_fields.iter() {
|
||||||
|
let val = build_expr(env, &scope, parent, inner_expr, procs);
|
||||||
|
|
||||||
|
let field_type = match inner_expr {
|
||||||
|
Int(_) => BasicTypeEnum::IntType(ctx.i64_type()),
|
||||||
|
_ => panic!("I don't yet know how to get Inkwell type for {:?}", val),
|
||||||
|
};
|
||||||
|
|
||||||
|
field_types.push(field_type);
|
||||||
|
field_vals.push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the struct_type
|
||||||
|
let struct_type = ctx.struct_type(field_types.into_bump_slice(), false);
|
||||||
|
let mut struct_val = struct_type.const_zero().into();
|
||||||
|
|
||||||
|
// Insert field exprs into struct_val
|
||||||
|
for (index, field_val) in field_vals.into_iter().enumerate() {
|
||||||
|
struct_val = builder
|
||||||
|
.build_insert_value(struct_val, field_val, index as u32, "insert_field")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicValueEnum::StructValue(struct_val.into_struct_value())
|
||||||
|
}
|
||||||
|
Access {
|
||||||
|
label,
|
||||||
|
field_layout,
|
||||||
|
struct_layout: Layout::Struct(fields),
|
||||||
|
record,
|
||||||
|
} => {
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
// Reconstruct struct layout
|
||||||
|
let mut reconstructed_struct_layout =
|
||||||
|
Vec::with_capacity_in(fields.len() + 1, env.arena);
|
||||||
|
for field in fields.iter() {
|
||||||
|
reconstructed_struct_layout.push(field.clone());
|
||||||
|
}
|
||||||
|
reconstructed_struct_layout.push((label.clone(), field_layout.clone()));
|
||||||
|
reconstructed_struct_layout.sort_by(|a, b| {
|
||||||
|
a.0.partial_cmp(&b.0)
|
||||||
|
.expect("TODO: failed to sort struct fields in crane access")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get index
|
||||||
|
let index = reconstructed_struct_layout
|
||||||
|
.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()
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("I don't yet know how to LLVM build {:?}", expr);
|
panic!("I don't yet know how to LLVM build {:?}", expr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1013,41 +1013,36 @@ mod test_gen {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn basic_record() {
|
fn basic_record() {
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// point = { x: 15, y: 17, z: 19 }
|
{ y: 17, x: 15, z: 19 }.x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
15,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
|
||||||
// point.x
|
assert_evals_to!(
|
||||||
// "#
|
indoc!(
|
||||||
// ),
|
r#"
|
||||||
// 15,
|
{ x: 15, y: 17, z: 19 }.y
|
||||||
// i64
|
"#
|
||||||
// );
|
),
|
||||||
|
17,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// point = { x: 15, y: 17, z: 19 }
|
{ x: 15, y: 17, z: 19 }.z
|
||||||
|
"#
|
||||||
// point.y
|
),
|
||||||
// "#
|
19,
|
||||||
// ),
|
i64
|
||||||
// 17,
|
);
|
||||||
// i64
|
}
|
||||||
// );
|
|
||||||
// assert_evals_to!(
|
|
||||||
// indoc!(
|
|
||||||
// r#"
|
|
||||||
// point = { x: 15, y: 17, z: 19 }
|
|
||||||
|
|
||||||
// point.z
|
|
||||||
// "#
|
|
||||||
// ),
|
|
||||||
// 19,
|
|
||||||
// i64
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,7 @@ pub enum Expr<'a> {
|
||||||
label: Lowercase,
|
label: Lowercase,
|
||||||
field_layout: Layout<'a>,
|
field_layout: Layout<'a>,
|
||||||
struct_layout: Layout<'a>,
|
struct_layout: Layout<'a>,
|
||||||
|
record: &'a Expr<'a>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Array {
|
Array {
|
||||||
|
@ -680,7 +681,7 @@ fn from_can<'a>(
|
||||||
ext_var,
|
ext_var,
|
||||||
field_var,
|
field_var,
|
||||||
field,
|
field,
|
||||||
..
|
loc_expr,
|
||||||
} => {
|
} => {
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
|
||||||
|
@ -701,10 +702,13 @@ fn from_can<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let record = arena.alloc(from_can(env, loc_expr.value, procs, None));
|
||||||
|
|
||||||
Expr::Access {
|
Expr::Access {
|
||||||
label: field,
|
label: field,
|
||||||
field_layout,
|
field_layout,
|
||||||
struct_layout,
|
struct_layout,
|
||||||
|
record,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue