Merge remote-tracking branch 'origin/main' into abilities-syntax

This commit is contained in:
Richard Feldman 2023-08-10 20:29:27 -04:00
commit 2da41be29f
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B
524 changed files with 47536 additions and 15089 deletions

View file

@ -1,9 +1,9 @@
use bitvec::vec::BitVec;
use bumpalo::collections::{String, Vec};
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_collections::all::MutMap;
use roc_error_macros::internal_error;
use roc_error_macros::{internal_error, todo_lambda_erasure};
use roc_module::low_level::{LowLevel, LowLevelWrapperType};
use roc_module::symbol::{Interns, Symbol};
use roc_mono::code_gen_help::{CodeGenHelp, HelperOp, REFCOUNT_MAX};
@ -313,7 +313,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
if let Ok(sym_index) = self.module.linking.find_internal_symbol(START) {
let fn_index = match self.module.linking.symbol_table[sym_index] {
SymInfo::Function(WasmObjectSymbol::ExplicitlyNamed { index, .. }) => index,
_ => panic!("linker symbol `{}` is not a function", START),
_ => panic!("linker symbol `{START}` is not a function"),
};
self.module.export.append(Export {
name: START,
@ -463,7 +463,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
if DEBUG_SETTINGS.storage_map {
println!("\nStorage:");
for (sym, storage) in self.storage.symbol_storage_map.iter() {
println!("{:?} => {:?}", sym, storage);
println!("{sym:?} => {storage:?}");
}
}
}
@ -509,7 +509,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
.last()
.map(|l| self.layout_interner.get_repr(*l))
{
Some(LayoutRepr::Boxed(inner)) => WasmLayout::new(self.layout_interner, inner),
Some(LayoutRepr::Ptr(inner)) => WasmLayout::new(self.layout_interner, inner),
x => internal_error!("Higher-order wrapper: invalid return layout {:?}", x),
};
@ -540,8 +540,8 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
}
let inner_layout = match self.layout_interner.get_repr(*wrapper_arg) {
LayoutRepr::Boxed(inner) => inner,
x => internal_error!("Expected a Boxed layout, got {:?}", x),
LayoutRepr::Ptr(inner) => inner,
x => internal_error!("Expected a Ptr layout, got {:?}", x),
};
if self.layout_interner.stack_size(inner_layout) == 0 {
continue;
@ -634,8 +634,8 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
}
let inner_layout = match self.layout_interner.get_repr(value_layout) {
LayoutRepr::Boxed(inner) => inner,
x => internal_error!("Expected a Boxed layout, got {:?}", x),
LayoutRepr::Ptr(inner) => inner,
x => internal_error!("Expected a Ptr layout, got {:?}", x),
};
self.code_builder.get_local(LocalId(1));
self.dereference_boxed_value(inner_layout);
@ -719,7 +719,10 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
Stmt::Jump(id, arguments) => self.stmt_jump(*id, arguments),
Stmt::Refcounting(modify, following) => self.stmt_refcounting(modify, following),
Stmt::Refcounting(modify, following) => match modify {
ModifyRc::Free(symbol) => self.stmt_refcounting_free(*symbol, following),
_ => self.stmt_refcounting(modify, following),
},
Stmt::Dbg { .. } => todo!("dbg is not implemented in the wasm backend"),
Stmt::Expect { .. } => todo!("expect is not implemented in the wasm backend"),
@ -999,6 +1002,43 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
self.stmt(rc_stmt);
}
fn stmt_refcounting_free(&mut self, value: Symbol, following: &'a Stmt<'a>) {
let layout = self.storage.symbol_layouts[&value];
let alignment = self.layout_interner.allocation_alignment_bytes(layout);
// Get pointer and offset
let value_storage = self.storage.get(&value).to_owned();
let stored_with_local =
self.storage
.ensure_value_has_local(&mut self.code_builder, value, value_storage);
let (tag_local_id, tag_offset) = match stored_with_local {
StoredValue::StackMemory { location, .. } => {
location.local_and_offset(self.storage.stack_frame_pointer)
}
StoredValue::Local { local_id, .. } => (local_id, 0),
StoredValue::VirtualMachineStack { .. } => {
internal_error!("{:?} should have a local variable", value)
}
};
// load pointer, and add the offset to the pointer
self.code_builder.get_local(tag_local_id);
if tag_offset > 0 {
self.code_builder.i32_const(tag_offset as i32);
self.code_builder.i32_add();
}
// NOTE: UTILS_FREE_DATA_PTR clears any tag id bits
// push the allocation's alignment
self.code_builder.i32_const(alignment as i32);
self.call_host_fn_after_loading_args(bitcode::UTILS_FREE_DATA_PTR, 2, false);
self.stmt(following);
}
pub fn stmt_internal_error(&mut self, msg: &'a str) {
let msg_sym = self.create_symbol("panic_str");
let msg_storage = self.storage.allocate_var(
@ -1064,8 +1104,11 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
tag_layout: union_layout,
tag_id,
arguments,
..
} => self.expr_tag(union_layout, *tag_id, arguments, sym, storage, None),
reuse,
} => {
let reuse = reuse.map(|ru| ru.symbol);
self.expr_tag(union_layout, *tag_id, arguments, sym, storage, reuse)
}
Expr::GetTagId {
structure,
@ -1079,22 +1122,33 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
index,
} => self.expr_union_at_index(*structure, *tag_id, union_layout, *index, sym),
Expr::ExprBox { symbol: arg_sym } => self.expr_box(sym, *arg_sym, layout, storage),
Expr::ExprUnbox { symbol: arg_sym } => self.expr_unbox(sym, *arg_sym),
Expr::Reuse {
tag_layout,
Expr::UnionFieldPtrAtIndex {
structure,
tag_id,
arguments,
symbol: reused,
..
} => self.expr_tag(tag_layout, *tag_id, arguments, sym, storage, Some(*reused)),
union_layout,
index,
} => self.expr_union_field_ptr_at_index(
*structure,
*tag_id,
union_layout,
*index,
sym,
storage,
),
Expr::FunctionPointer { .. } => todo_lambda_erasure!(),
Expr::ErasedMake { .. } => todo_lambda_erasure!(),
Expr::ErasedLoad { .. } => todo_lambda_erasure!(),
Expr::Reset { symbol: arg, .. } => self.expr_reset(*arg, sym, storage),
Expr::ResetRef { symbol: arg, .. } => self.expr_resetref(*arg, sym, storage),
Expr::Alloca {
initializer,
element_layout,
} => self.expr_alloca(*initializer, *element_layout, sym, storage),
Expr::RuntimeErrorFunction(_) => {
todo!("Expression `{}`", expr.to_pretty(100, false))
}
@ -1277,6 +1331,10 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
)
}
CallType::ByPointer { .. } => {
todo_lambda_erasure!()
}
CallType::LowLevel { op: lowlevel, .. } => {
self.expr_call_low_level(*lowlevel, arguments, ret_sym, ret_layout, ret_storage)
}
@ -1384,7 +1442,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
.host_lookup
.iter()
.find(|(fn_name, _)| *fn_name == name)
.unwrap_or_else(|| panic!("The Roc app tries to call `{}` but I can't find it!", name));
.unwrap_or_else(|| panic!("The Roc app tries to call `{name}` but I can't find it!"));
self.called_fns.set(*fn_index as usize, true);
@ -1574,7 +1632,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
ListLiteralElement::Literal(lit) => {
// This has no Symbol but our storage methods expect one.
// Let's just pretend it was defined in a `Let`.
let debug_name = format!("{:?}_{}", sym, i);
let debug_name = format!("{sym:?}_{i}");
let elem_sym = self.create_symbol(&debug_name);
let expr = Expr::Literal(*lit);
@ -1641,7 +1699,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
let stores_tag_id_as_data = union_layout.stores_tag_id_as_data(TARGET_INFO);
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(TARGET_INFO);
let (data_size, data_alignment) =
union_layout.data_size_and_alignment(self.layout_interner, TARGET_INFO);
union_layout.data_size_and_alignment(self.layout_interner);
// We're going to use the pointer many times, so put it in a local variable
let stored_with_local =
@ -1693,10 +1751,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
// Store the tag ID (if any)
if stores_tag_id_as_data {
let id_offset = data_offset
+ union_layout
.tag_id_offset(self.layout_interner, TARGET_INFO)
.unwrap();
let id_offset = data_offset + union_layout.tag_id_offset(self.layout_interner).unwrap();
let id_align = union_layout.discriminant().alignment_bytes();
let id_align = Align::from(id_align);
@ -1779,9 +1834,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
};
if union_layout.stores_tag_id_as_data(TARGET_INFO) {
let id_offset = union_layout
.tag_id_offset(self.layout_interner, TARGET_INFO)
.unwrap();
let id_offset = union_layout.tag_id_offset(self.layout_interner).unwrap();
let id_align = union_layout.discriminant().alignment_bytes();
let id_align = Align::from(id_align);
@ -1881,44 +1934,92 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
);
}
/*******************************************************************
* Box
*******************************************************************/
fn expr_box(
fn expr_union_field_ptr_at_index(
&mut self,
ret_sym: Symbol,
arg_sym: Symbol,
layout: InLayout<'a>,
structure: Symbol,
tag_id: TagIdIntType,
union_layout: &UnionLayout<'a>,
index: u64,
symbol: Symbol,
storage: &StoredValue,
) {
// create a local variable for the heap pointer
let ptr_local_id = match self.storage.ensure_value_has_local(
use UnionLayout::*;
debug_assert!(!union_layout.tag_is_null(tag_id));
let tag_index = tag_id as usize;
let field_layouts = match union_layout {
NonRecursive(tags) => tags[tag_index],
Recursive(tags) => tags[tag_index],
NonNullableUnwrapped(layouts) => *layouts,
NullableWrapped {
other_tags,
nullable_id,
} => {
let index = if tag_index > *nullable_id as usize {
tag_index - 1
} else {
tag_index
};
other_tags[index]
}
NullableUnwrapped { other_fields, .. } => *other_fields,
};
let field_offset: u32 = field_layouts
.iter()
.take(index as usize)
.map(|field_layout| self.layout_interner.stack_size(*field_layout))
.sum();
// Get pointer and offset to the tag's data
let structure_storage = self.storage.get(&structure).to_owned();
let stored_with_local = self.storage.ensure_value_has_local(
&mut self.code_builder,
ret_sym,
structure,
structure_storage,
);
let (tag_local_id, tag_offset) = match stored_with_local {
StoredValue::StackMemory { location, .. } => {
location.local_and_offset(self.storage.stack_frame_pointer)
}
StoredValue::Local { local_id, .. } => (local_id, 0),
StoredValue::VirtualMachineStack { .. } => {
internal_error!("{:?} should have a local variable", structure)
}
};
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(TARGET_INFO);
let from_offset = tag_offset + field_offset;
self.code_builder.get_local(tag_local_id);
if stores_tag_id_in_pointer {
self.code_builder.i32_const(-4); // 11111111...1100
self.code_builder.i32_and();
}
self.code_builder.i32_const(from_offset as _);
self.code_builder.i32_add();
let symbol_local = match self.storage.ensure_value_has_local(
&mut self.code_builder,
symbol,
storage.clone(),
) {
StoredValue::Local { local_id, .. } => local_id,
_ => internal_error!("A heap pointer will always be an i32"),
};
// allocate heap memory and load its data address onto the value stack
let arg_layout = match self.layout_interner.get_repr(layout) {
LayoutRepr::Boxed(arg) => arg,
_ => internal_error!("ExprBox should always produce a Boxed layout"),
};
let (size, alignment) = self.layout_interner.stack_size_and_alignment(arg_layout);
self.allocate_with_refcount(Some(size), alignment, 1);
// store the pointer value from the value stack into the local variable
self.code_builder.set_local(ptr_local_id);
// copy the argument to the pointer address
self.storage
.copy_value_to_memory(&mut self.code_builder, ptr_local_id, 0, arg_sym);
self.code_builder.set_local(symbol_local);
}
fn expr_unbox(&mut self, ret_sym: Symbol, arg_sym: Symbol) {
/*******************************************************************
* Box
*******************************************************************/
pub(crate) fn ptr_load(&mut self, ret_sym: Symbol, arg_sym: Symbol) {
let (from_addr_val, from_offset) = match self.storage.get(&arg_sym) {
StoredValue::VirtualMachineStack { .. } => {
self.storage
@ -2049,6 +2150,48 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
);
}
fn expr_alloca(
&mut self,
initializer: Option<Symbol>,
element_layout: InLayout<'a>,
ret_symbol: Symbol,
ret_storage: &StoredValue,
) {
// Alloca : a -> Ptr a
let (size, alignment_bytes) = self
.layout_interner
.stack_size_and_alignment(element_layout);
let (frame_ptr, offset) = self
.storage
.allocate_anonymous_stack_memory(size, alignment_bytes);
// write the default value into the stack memory
if let Some(initializer) = initializer {
self.storage.copy_value_to_memory(
&mut self.code_builder,
frame_ptr,
offset,
initializer,
);
}
// create a local variable for the pointer
let ptr_local_id = match self.storage.ensure_value_has_local(
&mut self.code_builder,
ret_symbol,
ret_storage.clone(),
) {
StoredValue::Local { local_id, .. } => local_id,
_ => internal_error!("A pointer will always be an i32"),
};
self.code_builder.get_local(frame_ptr);
self.code_builder.i32_const(offset as i32);
self.code_builder.i32_add();
self.code_builder.set_local(ptr_local_id);
}
/// Generate a refcount helper procedure and return a pointer (table index) to it
/// This allows it to be indirectly called from Zig code
pub fn get_refcount_fn_index(&mut self, layout: InLayout<'a>, op: HelperOp) -> u32 {
@ -2067,10 +2210,15 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
self.register_helper_proc(spec_sym, spec_layout, ProcSource::Helper);
}
let layout_repr = self.layout_interner.runtime_representation(layout);
let same_layout =
|layout| self.layout_interner.runtime_representation(layout) == layout_repr;
let proc_index = self
.proc_lookup
.iter()
.position(|lookup| lookup.name == proc_symbol && lookup.layout.arguments[0] == layout)
.position(|lookup| {
lookup.name == proc_symbol && same_layout(lookup.layout.arguments[0])
})
.unwrap();
self.fn_index_offset + proc_index as u32

View file

@ -322,10 +322,7 @@ impl<'a> CodeBuilder<'a> {
self.add_insertion(pushed_at, SETLOCAL, local_id.0);
} else {
if DEBUG_SETTINGS.instructions {
println!(
"{:?} has been popped implicitly. Leaving it on the stack.",
symbol
);
println!("{symbol:?} has been popped implicitly. Leaving it on the stack.");
}
self.add_insertion(pushed_at, TEELOCAL, local_id.0);
}
@ -501,9 +498,7 @@ impl<'a> CodeBuilder<'a> {
debug_assert!(
stack_size >= pops,
"Wasm value stack underflow. Tried to pop {} but only {} available",
pops,
stack_size
"Wasm value stack underflow. Tried to pop {pops} but only {stack_size} available"
);
let new_len = stack_size - pops;
@ -517,11 +512,7 @@ impl<'a> CodeBuilder<'a> {
/// Plain instruction without any immediates
fn inst(&mut self, opcode: OpCode, pops: usize, push: bool) {
self.inst_base(opcode, pops, push);
log_instruction!(
"{:10}\t\t{:?}",
format!("{:?}", opcode),
self.vm_block_stack
);
log_instruction!("{:10}\t\t{:?}", format!("{opcode:?}"), self.vm_block_stack);
}
/// Block instruction
@ -538,7 +529,7 @@ impl<'a> CodeBuilder<'a> {
value_stack: Vec::with_capacity_in(8, self.arena),
});
log_instruction!("{:10}\t{:?}", format!("{:?}", opcode), &self.vm_block_stack);
log_instruction!("{:10}\t{:?}", format!("{opcode:?}"), &self.vm_block_stack);
}
fn inst_imm32(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u32) {
@ -546,7 +537,7 @@ impl<'a> CodeBuilder<'a> {
self.code.encode_u32(immediate);
log_instruction!(
"{:10}\t{}\t{:?}",
format!("{:?}", opcode),
format!("{opcode:?}"),
immediate,
self.vm_block_stack
);
@ -558,7 +549,7 @@ impl<'a> CodeBuilder<'a> {
self.code.encode_u32(offset);
log_instruction!(
"{:10} {:?} {}\t{:?}",
format!("{:?}", opcode),
format!("{opcode:?}"),
align,
offset,
self.vm_block_stack
@ -654,7 +645,7 @@ impl<'a> CodeBuilder<'a> {
log_instruction!(
"{:10}\t{}\t{:?}",
format!("{:?}", CALL),
format!("{CALL:?}"),
function_index,
self.vm_block_stack
);
@ -725,7 +716,7 @@ impl<'a> CodeBuilder<'a> {
{
log_instruction!(
"{:10}\t{}\t{:?}",
format!("{:?}", opcode),
format!("{opcode:?}"),
x,
self.vm_block_stack
);

View file

@ -1,4 +1,5 @@
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_error_macros::todo_lambda_erasure;
use roc_mono::layout::{InLayout, LayoutInterner, LayoutRepr, STLayoutInterner, UnionLayout};
use crate::{PTR_SIZE, PTR_TYPE};
@ -97,8 +98,10 @@ impl WasmLayout {
| NullableWrapped { .. }
| NullableUnwrapped { .. },
)
| LayoutRepr::Boxed(_)
| LayoutRepr::Ptr(_)
| LayoutRepr::RecursivePointer(_) => Self::Primitive(PTR_TYPE, PTR_SIZE),
LayoutRepr::FunctionPointer(_) => todo_lambda_erasure!(),
LayoutRepr::Erased(_) => todo_lambda_erasure!(),
}
}

View file

@ -1,7 +1,7 @@
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_error_macros::internal_error;
use roc_error_macros::{internal_error, todo_lambda_erasure};
use roc_module::low_level::LowLevel;
use roc_module::symbol::Symbol;
use roc_mono::code_gen_help::HelperOp;
@ -12,7 +12,7 @@ use roc_mono::low_level::HigherOrder;
use crate::backend::{ProcLookupData, ProcSource, WasmBackend};
use crate::layout::{CallConv, StackMemoryFormat, WasmLayout};
use crate::storage::{AddressValue, StackMemoryLocation, StoredValue};
use crate::{PTR_TYPE, TARGET_INFO};
use crate::PTR_TYPE;
use roc_wasm_module::{Align, LocalId, ValueType};
/// Number types used for Wasm code gen
@ -281,8 +281,8 @@ impl<'a> LowLevelCall<'a> {
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
backend.call_host_fn_after_loading_args(bitcode::STR_FROM_UTF8_RANGE, 6, false);
}
StrTrimLeft => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_LEFT),
StrTrimRight => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_RIGHT),
StrTrimStart => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_START),
StrTrimEnd => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_END),
StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8),
StrReserve => self.load_args_and_call_zig(backend, bitcode::STR_RESERVE),
StrReleaseExcessCapacity => {
@ -365,7 +365,7 @@ impl<'a> LowLevelCall<'a> {
);
// Increment refcount
if self.ret_layout_raw.is_refcounted() {
if self.ret_layout_raw.is_refcounted(backend.layout_interner) {
let inc_fn = backend.get_refcount_fn_index(self.ret_layout, HelperOp::Inc);
backend.code_builder.get_local(elem_local);
backend.code_builder.i32_const(1);
@ -398,14 +398,13 @@ impl<'a> LowLevelCall<'a> {
{
let list_offset = 0;
let elem_offset = LayoutRepr::Builtin(Builtin::List(list_elem))
.stack_size(backend.layout_interner, TARGET_INFO);
.stack_size(backend.layout_interner);
(list_offset, elem_offset, f2)
}
(_, LayoutRepr::Builtin(Builtin::List(list_elem)))
if l1 == backend.layout_interner.get_repr(list_elem) =>
{
let list_offset =
l1.stack_size(backend.layout_interner, TARGET_INFO);
let list_offset = l1.stack_size(backend.layout_interner);
let elem_offset = 0;
(list_offset, elem_offset, f1)
}
@ -468,7 +467,7 @@ impl<'a> LowLevelCall<'a> {
let elem_layout = unwrap_list_elem_layout(self.ret_layout_raw);
let elem_layout = backend.layout_interner.get_repr(elem_layout);
let (elem_width, elem_align) =
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
elem_layout.stack_size_and_alignment(backend.layout_interner);
// Zig arguments Wasm types
// (return pointer) i32
@ -507,7 +506,7 @@ impl<'a> LowLevelCall<'a> {
let elem_layout = unwrap_list_elem_layout(self.ret_layout_raw);
let elem_layout = backend.layout_interner.get_repr(elem_layout);
let (elem_width, elem_align) =
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
elem_layout.stack_size_and_alignment(backend.layout_interner);
backend.code_builder.i32_const(elem_align as i32);
backend.code_builder.i32_const(elem_width as i32);
@ -523,7 +522,7 @@ impl<'a> LowLevelCall<'a> {
let elem_layout = unwrap_list_elem_layout(self.ret_layout_raw);
let elem_layout = backend.layout_interner.get_repr(elem_layout);
let (elem_width, elem_align) =
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
elem_layout.stack_size_and_alignment(backend.layout_interner);
// Zig arguments Wasm types
// (return pointer) i32
@ -564,7 +563,7 @@ impl<'a> LowLevelCall<'a> {
let elem_layout = unwrap_list_elem_layout(self.ret_layout_raw);
let elem_layout = backend.layout_interner.get_repr(elem_layout);
let (elem_width, elem_align) =
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
elem_layout.stack_size_and_alignment(backend.layout_interner);
// Zig arguments Wasm types
// (return pointer) i32
@ -1692,10 +1691,8 @@ impl<'a> LowLevelCall<'a> {
// In most languages this operation is for signed numbers, but Roc defines it on all integers.
// So the argument is implicitly converted to signed before the shift operator.
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
let bit_width = 8 * self
.ret_layout_raw
.stack_size(backend.layout_interner, TARGET_INFO)
as i32;
let bit_width =
8 * self.ret_layout_raw.stack_size(backend.layout_interner) as i32;
if bit_width < 32 && !symbol_is_signed_int(backend, num) {
// Sign-extend the number by shifting left and right again
backend
@ -1741,9 +1738,7 @@ impl<'a> LowLevelCall<'a> {
// In most languages this operation is for unsigned numbers, but Roc defines it on all integers.
// So the argument is implicitly converted to unsigned before the shift operator.
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
let bit_width = 8 * self
.ret_layout_raw
.stack_size(backend.layout_interner, TARGET_INFO);
let bit_width = 8 * self.ret_layout_raw.stack_size(backend.layout_interner);
if bit_width < 32 && symbol_is_signed_int(backend, num) {
let mask = (1 << bit_width) - 1;
@ -1965,7 +1960,38 @@ impl<'a> LowLevelCall<'a> {
backend.storage.load_symbols(code_builder, self.arguments);
}
PtrWrite => todo!("{:?}", self.lowlevel),
PtrStore => {
// PtrStore : Ptr a, a -> {}
let ptr = self.arguments[0];
let value = self.arguments[1];
let (ptr_local_id, offset) = match backend.storage.get(&ptr) {
StoredValue::Local { local_id, .. } => (*local_id, 0),
_ => internal_error!("A pointer will always be an i32"),
};
// copy the argument to the pointer address
backend.storage.copy_value_to_memory(
&mut backend.code_builder,
ptr_local_id,
offset,
value,
);
}
PtrLoad => backend.ptr_load(self.ret_symbol, self.arguments[0]),
PtrClearTagId => {
let ptr = self.arguments[0];
let ptr_local_id = match backend.storage.get(&ptr) {
StoredValue::Local { local_id, .. } => *local_id,
_ => internal_error!("A pointer will always be an i32"),
};
backend.code_builder.get_local(ptr_local_id);
backend.code_builder.i32_const(-4); // 11111111...1100
backend.code_builder.i32_and();
}
Hash => todo!("{:?}", self.lowlevel),
@ -1986,6 +2012,10 @@ impl<'a> LowLevelCall<'a> {
StoredValue::StackMemory { .. } => { /* do nothing */ }
},
DictPseudoSeed => self.load_args_and_call_zig(backend, bitcode::UTILS_DICT_PSEUDO_SEED),
SetJmp | LongJmp | SetLongJmpBuffer => {
unreachable!("only inserted in dev backend codegen")
}
}
}
@ -2001,8 +2031,7 @@ impl<'a> LowLevelCall<'a> {
.runtime_representation(backend.storage.symbol_layouts[&self.arguments[1]]);
debug_assert_eq!(
arg_layout_raw, other_arg_layout,
"Cannot do `==` comparison on different types: {:?} vs {:?}",
arg_layout, other_arg_layout
"Cannot do `==` comparison on different types: {arg_layout:?} vs {other_arg_layout:?}"
);
let invert_result = matches!(self.lowlevel, LowLevel::NotEq);
@ -2035,7 +2064,7 @@ impl<'a> LowLevelCall<'a> {
| LayoutRepr::Struct { .. }
| LayoutRepr::Union(_)
| LayoutRepr::LambdaSet(_)
| LayoutRepr::Boxed(_) => {
| LayoutRepr::Ptr(_) => {
// Don't want Zig calling convention here, we're calling internal Roc functions
backend
.storage
@ -2059,6 +2088,9 @@ impl<'a> LowLevelCall<'a> {
self.arguments,
)
}
LayoutRepr::FunctionPointer(_) => todo_lambda_erasure!(),
LayoutRepr::Erased(_) => todo_lambda_erasure!(),
}
}
@ -2440,7 +2472,7 @@ pub fn call_higher_order_lowlevel<'a>(
}
}
};
let wrapper_sym = backend.create_symbol(&format!("#wrap#{:?}", fn_name));
let wrapper_sym = backend.create_symbol(&format!("#wrap#{fn_name:?}"));
let wrapper_layout = {
let mut wrapper_arg_layouts: Vec<InLayout<'a>> =
Vec::with_capacity_in(argument_layouts.len() + 1, backend.env.arena);
@ -2455,7 +2487,7 @@ pub fn call_higher_order_lowlevel<'a>(
argument_layouts.iter().take(n_non_closure_args).map(|lay| {
backend
.layout_interner
.insert_direct_no_semantic(LayoutRepr::Boxed(*lay))
.insert_direct_no_semantic(LayoutRepr::Ptr(*lay))
});
wrapper_arg_layouts.push(wrapped_captures_layout);
@ -2467,7 +2499,7 @@ pub fn call_higher_order_lowlevel<'a>(
wrapper_arg_layouts.push(
backend
.layout_interner
.insert_direct_no_semantic(LayoutRepr::Boxed(*result_layout)),
.insert_direct_no_semantic(LayoutRepr::Ptr(*result_layout)),
);
ProcLayout {
arguments: wrapper_arg_layouts.into_bump_slice(),
@ -2561,7 +2593,7 @@ pub fn call_higher_order_lowlevel<'a>(
);
let elem_layout = backend.layout_interner.get_repr(elem_layout);
let (element_width, alignment) =
elem_layout.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
elem_layout.stack_size_and_alignment(backend.layout_interner);
let cb = &mut backend.code_builder;
@ -2630,7 +2662,7 @@ fn list_map_n<'a>(
let elem_ret = unwrap_list_elem_layout(backend.layout_interner.get_repr(return_layout));
let elem_ret = backend.layout_interner.get_repr(elem_ret);
let (elem_ret_size, elem_ret_align) =
elem_ret.stack_size_and_alignment(backend.layout_interner, TARGET_INFO);
elem_ret.stack_size_and_alignment(backend.layout_interner);
let cb = &mut backend.code_builder;

View file

@ -78,7 +78,7 @@ pub fn insert_wrapper_for_layout<'a>(
bool::insert_wrapper(arena, module, wrapper_name, main_fn_index);
}
LayoutRepr::Union(UnionLayout::NonRecursive(_)) => stack_data_structure(),
LayoutRepr::Union(_) | LayoutRepr::Boxed(_) => {
LayoutRepr::Union(_) => {
i32::insert_wrapper(arena, module, wrapper_name, main_fn_index);
}
_ => stack_data_structure(),