mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
load/store all tags in llvm
This commit is contained in:
parent
6253d2d1af
commit
165c5d8363
2 changed files with 130 additions and 36 deletions
|
@ -11,7 +11,7 @@ use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
||||||
use crate::llvm::convert::{
|
use crate::llvm::convert::{
|
||||||
basic_type_from_layout, collection_wrapper, get_array_type, get_fn_type,
|
basic_type_from_layout, collection_wrapper, get_array_type, get_fn_type,
|
||||||
};
|
};
|
||||||
use roc_collections::all::ImMap;
|
use roc_collections::all::{ImMap, MutMap};
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::expr::{Expr, Proc, Procs};
|
use roc_mono::expr::{Expr, Proc, Procs};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout};
|
||||||
|
@ -359,6 +359,100 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
BasicValueEnum::StructValue(struct_val.into_struct_value())
|
BasicValueEnum::StructValue(struct_val.into_struct_value())
|
||||||
}
|
}
|
||||||
|
Tag {
|
||||||
|
tag_id,
|
||||||
|
arguments,
|
||||||
|
tag_layout,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
// TODO make dynamic
|
||||||
|
let ptr_size = 8;
|
||||||
|
|
||||||
|
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::Byte(*tag_id),
|
||||||
|
Layout::Builtin(Builtin::Byte(MutMap::default())),
|
||||||
|
);
|
||||||
|
let it = std::iter::once(&discriminant).chain(arguments.iter());
|
||||||
|
// let it = arguments.iter();
|
||||||
|
|
||||||
|
let ctx = env.context;
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
// Determine types
|
||||||
|
let num_fields = arguments.len() + 1;
|
||||||
|
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 {
|
||||||
|
let val = build_expr(env, &scope, parent, field_expr, procs);
|
||||||
|
let field_type = basic_type_from_layout(env.arena, env.context, &field_layout);
|
||||||
|
|
||||||
|
field_types.push(field_type);
|
||||||
|
field_vals.push(val);
|
||||||
|
|
||||||
|
let field_size = field_layout.stack_size(ptr_size);
|
||||||
|
filler -= field_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if filler > 0 {
|
||||||
|
field_types.push(env.context.i8_type().array_type(filler).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// How we create tag values
|
||||||
|
//
|
||||||
|
// The memory layout of tags can be different. e.g. in
|
||||||
|
//
|
||||||
|
// [ Ok Int, Err Str ]
|
||||||
|
//
|
||||||
|
// the `Ok` tag stores a 64-bit integer, the `Err` tag stores a struct.
|
||||||
|
// All tags of a union must have the same length, for easy addressing (e.g. array lookups).
|
||||||
|
// So we need to ask for the maximum of all tag's sizes, but for most tags won't use
|
||||||
|
// all that memory, and certainly won't use it in the same way (the tags have fields of
|
||||||
|
// different types/sizes)
|
||||||
|
//
|
||||||
|
// In llvm, we must be explicit about the type of value we're creating: we can't just
|
||||||
|
// make a unspecified block of memory. So what we do is create a byte array of the
|
||||||
|
// desired size. Then when we know which tag we have (which is here, in this function),
|
||||||
|
// we need to cast that down to the array of bytes that llvm expects
|
||||||
|
//
|
||||||
|
// There is the bitcast instruction, but it doesn't work for arrays. So we need to jump
|
||||||
|
// through some hoops using store and load to get this to work.
|
||||||
|
//
|
||||||
|
// This tricks comes from
|
||||||
|
// https://github.com/raviqqe/ssf/blob/bc32aae68940d5bddf5984128e85af75ca4f4686/ssf-llvm/src/expression_compiler.rs#L116
|
||||||
|
|
||||||
|
let struct_pointer = builder.build_alloca(ctx.i8_type().array_type(whole_size), "");
|
||||||
|
|
||||||
|
builder.build_store(
|
||||||
|
builder
|
||||||
|
.build_bitcast(
|
||||||
|
struct_pointer,
|
||||||
|
struct_val
|
||||||
|
.into_struct_value()
|
||||||
|
.get_type()
|
||||||
|
.ptr_type(inkwell::AddressSpace::Generic),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
.into_pointer_value(),
|
||||||
|
struct_val,
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build_load(struct_pointer, "")
|
||||||
|
}
|
||||||
Access {
|
Access {
|
||||||
label,
|
label,
|
||||||
field_layout,
|
field_layout,
|
||||||
|
|
|
@ -1181,41 +1181,41 @@ mod test_gen {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn applied_tag_nothing() {
|
fn applied_tag_nothing() {
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// Maybe a : [ Just a, Nothing ]
|
Maybe a : [ Just a, Nothing ]
|
||||||
//
|
|
||||||
// x : Maybe Int
|
x : Maybe Int
|
||||||
// x = Nothing
|
x = Nothing
|
||||||
//
|
|
||||||
// 0x1
|
0x1
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// 1,
|
1,
|
||||||
// i64
|
i64
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn applied_tag_just() {
|
fn applied_tag_just() {
|
||||||
// assert_evals_to!(
|
assert_evals_to!(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// Maybe a : [ Just a, Nothing ]
|
Maybe a : [ Just a, Nothing ]
|
||||||
//
|
|
||||||
// y : Maybe Int
|
y : Maybe Int
|
||||||
// y = Just 0x4
|
y = Just 0x4
|
||||||
//
|
|
||||||
// 0x1
|
0x1
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// 1,
|
1,
|
||||||
// i64
|
i64
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn when_on_result() {
|
// fn when_on_result() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue