prepare to drop tag

This commit is contained in:
Folkert 2021-01-17 01:17:26 +01:00
parent c1cf43eda3
commit 897bc41b6b
2 changed files with 111 additions and 84 deletions

View file

@ -28,7 +28,7 @@ use inkwell::debug_info::{
use inkwell::memory_buffer::MemoryBuffer; use inkwell::memory_buffer::MemoryBuffer;
use inkwell::module::{Linkage, Module}; use inkwell::module::{Linkage, Module};
use inkwell::passes::{PassManager, PassManagerBuilder}; use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::types::{BasicTypeEnum, FunctionType, IntType, StructType}; use inkwell::types::{BasicTypeEnum, FunctionType, IntType, PointerType, StructType};
use inkwell::values::BasicValueEnum::{self, *}; use inkwell::values::BasicValueEnum::{self, *};
use inkwell::values::{ use inkwell::values::{
BasicValue, CallSiteValue, FloatValue, FunctionValue, InstructionOpcode, InstructionValue, BasicValue, CallSiteValue, FloatValue, FunctionValue, InstructionOpcode, InstructionValue,
@ -1158,7 +1158,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
return output_type.const_null().into(); return output_type.const_null().into();
} }
debug_assert!(*union_size > 1); // this tag id is not the nullable one. For the type to be recursive, the other
// constructor must have at least one argument!
debug_assert!(!arguments.is_empty());
debug_assert!(*union_size == 2);
let ptr_size = env.ptr_bytes; let ptr_size = env.ptr_bytes;
let ctx = env.context; let ctx = env.context;
@ -1169,16 +1173,10 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
let mut field_types = Vec::with_capacity_in(num_fields, env.arena); let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
let mut field_vals = Vec::with_capacity_in(num_fields, env.arena); let mut field_vals = Vec::with_capacity_in(num_fields, env.arena);
let tag_field_layouts = if let TagName::Closure(_) = tag_name { debug_assert!(!matches!(tag_name, TagName::Closure(_)));
// closures ignore (and do not store) the discriminant
panic!() let tag_field_layouts = &other_fields[0..];
} else { let arguments = &arguments[0..];
if (*tag_id != 0) == *nullable_id {
&[] as &[_]
} else {
other_fields
}
};
debug_assert_eq!(arguments.len(), tag_field_layouts.len()); debug_assert_eq!(arguments.len(), tag_field_layouts.len());
@ -1351,48 +1349,46 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
result result
} }
} }
PointerValue(value) => { PointerValue(value) => match structure_layout {
match structure_layout { Layout::Union(UnionLayout::NullableWrapped { nullable_id, .. })
Layout::Union(UnionLayout::NullableWrapped { nullable_id, .. }) if *index == 0 =>
if *index == 0 => {
let ptr = value;
let is_null = env.builder.build_is_null(ptr, "is_null");
let ctx = env.context;
let then_block = ctx.append_basic_block(parent, "then");
let else_block = ctx.append_basic_block(parent, "else");
let cont_block = ctx.append_basic_block(parent, "cont");
let result = builder.build_alloca(ctx.i64_type(), "result");
env.builder.build_switch(
is_null,
else_block,
&[(ctx.bool_type().const_int(1, false), then_block)],
);
{ {
let ptr = value; env.builder.position_at_end(then_block);
let is_null = env.builder.build_is_null(ptr, "is_null"); let tag_id = ctx.i64_type().const_int(*nullable_id as u64, false);
env.builder.build_store(result, tag_id);
let ctx = env.context; env.builder.build_unconditional_branch(cont_block);
let then_block = ctx.append_basic_block(parent, "then");
let else_block = ctx.append_basic_block(parent, "else");
let cont_block = ctx.append_basic_block(parent, "cont");
let result = builder.build_alloca(ctx.i64_type(), "result");
env.builder.build_switch(
is_null,
else_block,
&[(ctx.bool_type().const_int(1, false), then_block)],
);
{
env.builder.position_at_end(then_block);
let tag_id = ctx.i64_type().const_int(*nullable_id as u64, false);
env.builder.build_store(result, tag_id);
env.builder.build_unconditional_branch(cont_block);
}
{
env.builder.position_at_end(else_block);
let tag_id = extract_tag_discriminant_ptr(env, ptr);
env.builder.build_store(result, tag_id);
env.builder.build_unconditional_branch(cont_block);
}
env.builder.position_at_end(cont_block);
env.builder.build_load(result, "load_result")
} }
Layout::Union(UnionLayout::NullableUnwrapped { nullable_id, .. })
if *index == 0 =>
{ {
env.builder.position_at_end(else_block);
let tag_id = extract_tag_discriminant_ptr(env, ptr);
env.builder.build_store(result, tag_id);
env.builder.build_unconditional_branch(cont_block);
}
env.builder.position_at_end(cont_block);
env.builder.build_load(result, "load_result")
}
Layout::Union(UnionLayout::NullableUnwrapped { nullable_id, .. }) => {
if *index == 0 {
let is_null = env.builder.build_is_null(value, "is_null"); let is_null = env.builder.build_is_null(value, "is_null");
let ctx = env.context; let ctx = env.context;
@ -1406,39 +1402,26 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
else_value, else_value,
"select_tag_id", "select_tag_id",
) )
} } else {
_ => { lookup_at_index_ptr(
let ptr = cast_basic_basic( env,
builder, field_layouts,
value.into(), *index as usize,
struct_type.ptr_type(AddressSpace::Generic).into(), value,
&struct_layout,
struct_type,
) )
.into_pointer_value();
let elem_ptr = builder
.build_struct_gep(ptr, *index as u32, "at_index_struct_gep")
.unwrap();
let result = builder.build_load(elem_ptr, "load_at_index_ptr");
if let Some(Layout::RecursivePointer) =
field_layouts.get(*index as usize)
{
// a recursive field is stored as a `i64*`, to use it we must cast it to
// a pointer to the block of memory representation
cast_basic_basic(
builder,
result,
block_of_memory(env.context, &struct_layout, env.ptr_bytes)
.ptr_type(AddressSpace::Generic)
.into(),
)
} else {
result
}
} }
} }
} _ => lookup_at_index_ptr(
env,
field_layouts,
*index as usize,
value,
&struct_layout,
struct_type,
),
},
_ => panic!("cannot look up index in {:?}", argument), _ => panic!("cannot look up index in {:?}", argument),
} }
} }
@ -1485,6 +1468,45 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
} }
} }
fn lookup_at_index_ptr<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
field_layouts: &[Layout<'_>],
index: usize,
value: PointerValue<'ctx>,
struct_layout: &Layout<'_>,
struct_type: StructType<'ctx>,
) -> BasicValueEnum<'ctx> {
use inkwell::types::BasicType;
let builder = env.builder;
let ptr = cast_basic_basic(
builder,
value.into(),
struct_type.ptr_type(AddressSpace::Generic).into(),
)
.into_pointer_value();
let elem_ptr = builder
.build_struct_gep(ptr, index as u32, "at_index_struct_gep")
.unwrap();
let result = builder.build_load(elem_ptr, "load_at_index_ptr");
if let Some(Layout::RecursivePointer) = field_layouts.get(index as usize) {
// a recursive field is stored as a `i64*`, to use it we must cast it to
// a pointer to the block of memory representation
cast_basic_basic(
builder,
result,
block_of_memory(env.context, &struct_layout, env.ptr_bytes)
.ptr_type(AddressSpace::Generic)
.into(),
)
} else {
result
}
}
pub fn reserve_with_refcount<'a, 'ctx, 'env>( pub fn reserve_with_refcount<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'a>, layout: &Layout<'a>,

View file

@ -1006,6 +1006,8 @@ fn path_to_expr_help<'a>(
break; break;
} }
Some(wrapped) => { Some(wrapped) => {
let index = *index;
let field_layouts = match &layout { let field_layouts = match &layout {
Layout::Union(variant) => { Layout::Union(variant) => {
use UnionLayout::*; use UnionLayout::*;
@ -1037,6 +1039,9 @@ fn path_to_expr_help<'a>(
let tag_id = *tag_id != 0; let tag_id = *tag_id != 0;
if tag_id == *nullable_id { if tag_id == *nullable_id {
// the nullable tag has no fields; we can only lookup its tag id
debug_assert_eq!(index, 0);
// the nullable tag is going to pretend it stores a tag id // the nullable tag is going to pretend it stores a tag id
&*env.arena.alloc([Layout::Builtin(crate::layout::TAG_SIZE)]) &*env.arena.alloc([Layout::Builtin(crate::layout::TAG_SIZE)])
} else { } else {
@ -1051,7 +1056,7 @@ fn path_to_expr_help<'a>(
}; };
debug_assert!( debug_assert!(
*index < field_layouts.len() as u64, index < field_layouts.len() as u64,
"{} {:?} {:?} {:?}", "{} {:?} {:?} {:?}",
index, index,
field_layouts, field_layouts,
@ -1059,13 +1064,13 @@ fn path_to_expr_help<'a>(
tag_id, tag_id,
); );
let inner_layout = match &field_layouts[*index as usize] { let inner_layout = match &field_layouts[index as usize] {
Layout::RecursivePointer => layout.clone(), Layout::RecursivePointer => layout.clone(),
other => other.clone(), other => other.clone(),
}; };
let inner_expr = Expr::AccessAtIndex { let inner_expr = Expr::AccessAtIndex {
index: *index, index,
field_layouts, field_layouts,
structure: symbol, structure: symbol,
wrapped, wrapped,