mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Merge remote-tracking branch 'origin/trunk' into array-wrappers
This commit is contained in:
commit
8d4331f903
41 changed files with 2057 additions and 723 deletions
|
@ -120,9 +120,7 @@ pub fn build_expr<'a, B: Backend>(
|
|||
let fn_id = match scope.get(name) {
|
||||
Some(ScopeEntry::Func{ func_id, .. }) => *func_id,
|
||||
other => panic!(
|
||||
"FunctionPointer could not find function named {:?} in scope; instead, found {:?} in scope {:?}",
|
||||
name, other, scope
|
||||
),
|
||||
"FunctionPointer could not find function named {:?} declared in scope (and it was not special-cased in crane::build as a builtin); instead, found {:?} in scope {:?}", name, other, scope),
|
||||
};
|
||||
|
||||
let func_ref = module.declare_func_in_func(fn_id, &mut builder.func);
|
||||
|
@ -161,7 +159,10 @@ pub fn build_expr<'a, B: Backend>(
|
|||
Some(ScopeEntry::Func { .. }) => {
|
||||
panic!("TODO I don't yet know how to return fn pointers")
|
||||
}
|
||||
None => panic!("Could not find a var for {:?} in scope {:?}", name, scope),
|
||||
None => panic!(
|
||||
"Could not resolve lookup for {:?} because no ScopeEntry was found for {:?} in scope {:?}",
|
||||
name, name, scope
|
||||
),
|
||||
},
|
||||
Struct { layout, fields } => {
|
||||
let cfg = env.cfg;
|
||||
|
@ -194,16 +195,59 @@ pub fn build_expr<'a, B: Backend>(
|
|||
builder.ins().stack_store(val, slot, Offset32::new(offset));
|
||||
}
|
||||
|
||||
let ir_type = type_from_layout(cfg, layout);
|
||||
builder.ins().stack_addr(ir_type, slot, Offset32::new(0))
|
||||
builder
|
||||
.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) => {
|
||||
if str_literal.is_empty() {
|
||||
panic!("TODO build an empty string in Crane");
|
||||
|
@ -572,20 +616,34 @@ fn call_by_name<'a, B: Backend>(
|
|||
procs: &Procs<'a>,
|
||||
) -> Value {
|
||||
match symbol {
|
||||
Symbol::NUM_ADD => {
|
||||
Symbol::INT_ADD | Symbol::NUM_ADD => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
|
||||
builder.ins().iadd(a, b)
|
||||
}
|
||||
Symbol::NUM_SUB => {
|
||||
Symbol::FLOAT_ADD => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
|
||||
builder.ins().fadd(a, b)
|
||||
}
|
||||
Symbol::INT_SUB | Symbol::NUM_SUB => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
|
||||
builder.ins().isub(a, b)
|
||||
}
|
||||
Symbol::FLOAT_SUB => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
let b = build_arg(&args[1], env, scope, module, builder, procs);
|
||||
|
||||
builder.ins().fsub(a, b)
|
||||
}
|
||||
Symbol::NUM_MUL => {
|
||||
debug_assert!(args.len() == 2);
|
||||
let a = build_arg(&args[0], env, scope, module, builder, procs);
|
||||
|
|
|
@ -10,23 +10,12 @@ pub fn type_from_layout(cfg: TargetFrontendConfig, layout: &Layout<'_>) -> Type
|
|||
use roc_mono::layout::Layout::*;
|
||||
|
||||
match layout {
|
||||
Pointer(_) | FunctionPointer(_, _) => 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");
|
||||
}
|
||||
}
|
||||
Pointer(_) | FunctionPointer(_, _) | Struct(_) => cfg.pointer_type(),
|
||||
Builtin(builtin) => match builtin {
|
||||
Int64 => types::I64,
|
||||
Float64 => types::F64,
|
||||
Bool(_, _) => types::B1,
|
||||
Byte(_) => types::I8,
|
||||
Str | EmptyStr | Map(_, _) | EmptyMap | Set(_) | EmptySet | List(_) | EmptyList => {
|
||||
cfg.pointer_type()
|
||||
}
|
||||
|
|
|
@ -284,6 +284,80 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
|||
BasicValueEnum::StructValue(struct_val.into_struct_value())
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -576,35 +650,57 @@ fn call_with_args<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
match symbol {
|
||||
Symbol::NUM_ADD => {
|
||||
Symbol::INT_ADD | Symbol::NUM_ADD => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let int_val = env.builder.build_int_add(
|
||||
args[0].into_int_value(),
|
||||
args[1].into_int_value(),
|
||||
"ADD_I64",
|
||||
"add_i64",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
}
|
||||
Symbol::NUM_SUB => {
|
||||
Symbol::FLOAT_ADD => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let float_val = env.builder.build_float_add(
|
||||
args[0].into_float_value(),
|
||||
args[1].into_float_value(),
|
||||
"add_f64",
|
||||
);
|
||||
|
||||
BasicValueEnum::FloatValue(float_val)
|
||||
}
|
||||
Symbol::INT_SUB | Symbol::NUM_SUB => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let int_val = env.builder.build_int_sub(
|
||||
args[0].into_int_value(),
|
||||
args[1].into_int_value(),
|
||||
"SUB_I64",
|
||||
"sub_I64",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
}
|
||||
Symbol::FLOAT_SUB => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let float_val = env.builder.build_float_sub(
|
||||
args[0].into_float_value(),
|
||||
args[1].into_float_value(),
|
||||
"sub_f64",
|
||||
);
|
||||
|
||||
BasicValueEnum::FloatValue(float_val)
|
||||
}
|
||||
Symbol::NUM_MUL => {
|
||||
debug_assert!(args.len() == 2);
|
||||
|
||||
let int_val = env.builder.build_int_mul(
|
||||
args[0].into_int_value(),
|
||||
args[1].into_int_value(),
|
||||
"MUL_I64",
|
||||
"mul_i64",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
|
@ -614,7 +710,7 @@ fn call_with_args<'a, 'ctx, 'env>(
|
|||
|
||||
let int_val = env
|
||||
.builder
|
||||
.build_int_neg(args[0].into_int_value(), "NEGATE_I64");
|
||||
.build_int_neg(args[0].into_int_value(), "negate_i64");
|
||||
|
||||
BasicValueEnum::IntValue(int_val)
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ pub fn basic_type_from_layout<'ctx>(
|
|||
Builtin(builtin) => match builtin {
|
||||
Int64 => context.i64_type().as_basic_type_enum(),
|
||||
Float64 => context.f64_type().as_basic_type_enum(),
|
||||
Bool(_, _) => context.bool_type().as_basic_type_enum(),
|
||||
Byte(_) => context.i8_type().as_basic_type_enum(),
|
||||
Str | EmptyStr => context
|
||||
.i8_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue