Make better use of Layout methods for GetTagId

This commit is contained in:
Brian Carroll 2021-12-12 08:31:45 +00:00
parent b1a2a3ba07
commit 044a2015bb

View file

@ -1,6 +1,7 @@
use bumpalo::{self, collections::Vec}; use bumpalo::{self, collections::Vec};
use code_builder::Align; use code_builder::Align;
use roc_builtins::bitcode::IntWidth;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
use roc_module::symbol::{Interns, Symbol}; use roc_module::symbol::{Interns, Symbol};
@ -653,7 +654,7 @@ impl<'a> WasmBackend<'a> {
Expr::GetTagId { Expr::GetTagId {
structure, structure,
union_layout, union_layout,
} => self.build_get_tag_id(*structure, union_layout, storage), } => self.build_get_tag_id(*structure, union_layout),
Expr::UnionAtIndex { Expr::UnionAtIndex {
structure, structure,
@ -771,44 +772,24 @@ impl<'a> WasmBackend<'a> {
&mut self, &mut self,
structure: Symbol, structure: Symbol,
union_layout: &UnionLayout<'a>, union_layout: &UnionLayout<'a>,
tag_id_storage: &StoredValue,
) { ) {
use UnionLayout::*; use UnionLayout::*;
// Variables to control shared logic
let mut wrapped_tags: Option<&[&[Layout]]> = None;
let mut get_pointer_bits = false;
let mut need_to_close_block = false; let mut need_to_close_block = false;
match union_layout { match union_layout {
NonRecursive(tags) => { NonRecursive(_) => {}
wrapped_tags = Some(*tags); Recursive(_) => {}
}
Recursive(tags) => {
if union_layout.stores_tag_id_as_data(PTR_SIZE) {
wrapped_tags = Some(*tags);
} else {
get_pointer_bits = true;
}
}
NonNullableUnwrapped(_) => { NonNullableUnwrapped(_) => {
self.code_builder.i32_const(0); self.code_builder.i32_const(0);
return;
} }
NullableWrapped { NullableWrapped { nullable_id, .. } => {
nullable_id,
other_tags,
} => {
self.storage self.storage
.load_symbols(&mut self.code_builder, &[structure]); .load_symbols(&mut self.code_builder, &[structure]);
self.code_builder.i32_eqz(); self.code_builder.i32_eqz();
self.code_builder.if_(BlockType::Value(ValueType::I32)); self.code_builder.if_(BlockType::Value(ValueType::I32));
self.code_builder.i32_const(*nullable_id as i32); self.code_builder.i32_const(*nullable_id as i32);
self.code_builder.else_(); self.code_builder.else_();
if union_layout.stores_tag_id_as_data(PTR_SIZE) {
wrapped_tags = Some(*other_tags);
} else {
get_pointer_bits = true;
}
need_to_close_block = true; need_to_close_block = true;
} }
NullableUnwrapped { nullable_id, .. } => { NullableUnwrapped { nullable_id, .. } => {
@ -821,37 +802,27 @@ impl<'a> WasmBackend<'a> {
self.code_builder.i32_const(!(*nullable_id) as i32); self.code_builder.i32_const(!(*nullable_id) as i32);
self.code_builder.end(); self.code_builder.end();
} }
}
// Logic shared between different union layouts
if let Some(tags) = wrapped_tags {
// Fields are wrapped with a tag ID at the end
let (id_type, id_size) =
if let StoredValue::VirtualMachineStack {
value_type, size, ..
} = tag_id_storage
{
(value_type, size)
} else {
internal_error!("Unexpected storage for tag ID {:?}", tag_id_storage);
}; };
let (id_offset, id_align_bytes) = Self::union_fields_size_and_alignment(tags); if union_layout.stores_tag_id_as_data(PTR_SIZE) {
let id_align = Align::from(id_align_bytes); let (total_size, total_alignment) =
Layout::Union(*union_layout).stack_size_and_alignment(PTR_SIZE);
let id_offset = total_size - total_alignment;
let id_align = Align::from(total_alignment);
self.storage self.storage
.load_symbols(&mut self.code_builder, &[structure]); .load_symbols(&mut self.code_builder, &[structure]);
match (id_type, id_size) { match union_layout.tag_id_builtin() {
(ValueType::I32, 1) => self.code_builder.i32_load8_u(id_align, id_offset), Builtin::Bool | Builtin::Int(IntWidth::U8) => {
(ValueType::I32, 2) => self.code_builder.i32_load16_u(id_align, id_offset), self.code_builder.i32_load8_u(id_align, id_offset)
(ValueType::I32, 4) => self.code_builder.i32_load(id_align, id_offset),
(ValueType::I64, 8) => self.code_builder.i64_load(id_align, id_offset),
_ => internal_error!("Invalid tag ID: type={:?} size={}", id_type, id_size),
} }
} else if get_pointer_bits { Builtin::Int(IntWidth::U16) => self.code_builder.i32_load16_u(id_align, id_offset),
Builtin::Int(IntWidth::U32) => self.code_builder.i32_load(id_align, id_offset),
Builtin::Int(IntWidth::U64) => self.code_builder.i64_load(id_align, id_offset),
x => internal_error!("Unexpected layout for tag union id {:?}", x),
}
} else if union_layout.stores_tag_id_in_pointer(PTR_SIZE) {
self.storage self.storage
.load_symbols(&mut self.code_builder, &[structure]); .load_symbols(&mut self.code_builder, &[structure]);
self.code_builder.i32_const(3); self.code_builder.i32_const(3);
@ -912,7 +883,7 @@ impl<'a> WasmBackend<'a> {
let from_ptr = if stores_tag_id_in_pointer { let from_ptr = if stores_tag_id_in_pointer {
let ptr = self.storage.create_anonymous_local(ValueType::I32); let ptr = self.storage.create_anonymous_local(ValueType::I32);
self.code_builder.get_local(tag_local_id); self.code_builder.get_local(tag_local_id);
self.code_builder.i32_const(-4); self.code_builder.i32_const(-4); // 11111111...1100
self.code_builder.i32_and(); self.code_builder.i32_and();
self.code_builder.set_local(ptr); self.code_builder.set_local(ptr);
ptr ptr
@ -1254,7 +1225,7 @@ impl<'a> WasmBackend<'a> {
/// Debug utility /// Debug utility
/// ///
/// if _debug_current_proc_is("#UserApp_foo_1") { /// if self._debug_current_proc_is("#UserApp_foo_1") {
/// self.code_builder._debug_assert_i32(0x1234); /// self.code_builder._debug_assert_i32(0x1234);
/// } /// }
fn _debug_current_proc_is(&self, linker_name: &'static str) -> bool { fn _debug_current_proc_is(&self, linker_name: &'static str) -> bool {