mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Merge remote-tracking branch 'origin/trunk' into list-unreachable
This commit is contained in:
commit
6095dcff66
107 changed files with 10287 additions and 9870 deletions
|
@ -17,7 +17,7 @@ use roc_std::RocDec;
|
|||
|
||||
use crate::layout::{CallConv, ReturnMethod, WasmLayout};
|
||||
use crate::low_level::{call_higher_order_lowlevel, LowLevelCall};
|
||||
use crate::storage::{Storage, StoredValue, StoredVarKind};
|
||||
use crate::storage::{AddressValue, Storage, StoredValue, StoredVarKind};
|
||||
use crate::wasm_module::linking::{DataSymbol, WasmObjectSymbol};
|
||||
use crate::wasm_module::sections::{
|
||||
ConstExpr, DataMode, DataSegment, Export, Global, GlobalType, Import, ImportDesc, Limits,
|
||||
|
@ -380,7 +380,7 @@ impl<'a> WasmBackend<'a> {
|
|||
println!("\ngenerating procedure {:?}\n", proc.name);
|
||||
}
|
||||
|
||||
self.append_proc_debug_name(proc.name);
|
||||
self.append_proc_debug_name(proc.name.name());
|
||||
|
||||
self.start_proc(proc);
|
||||
|
||||
|
@ -928,7 +928,7 @@ impl<'a> WasmBackend<'a> {
|
|||
index,
|
||||
field_layouts,
|
||||
structure,
|
||||
} => self.expr_struct_at_index(sym, storage, *index, field_layouts, *structure),
|
||||
} => self.expr_struct_at_index(sym, *index, field_layouts, *structure),
|
||||
|
||||
Expr::Array { elems, elem_layout } => self.expr_array(sym, storage, elem_layout, elems),
|
||||
|
||||
|
@ -953,9 +953,9 @@ impl<'a> WasmBackend<'a> {
|
|||
index,
|
||||
} => self.expr_union_at_index(*structure, *tag_id, union_layout, *index, sym),
|
||||
|
||||
Expr::ExprBox { .. } | Expr::ExprUnbox { .. } => {
|
||||
todo!("Expression `{}`", expr.to_pretty(100))
|
||||
}
|
||||
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,
|
||||
|
@ -1125,9 +1125,10 @@ impl<'a> WasmBackend<'a> {
|
|||
let proc_layout = ProcLayout {
|
||||
arguments: arg_layouts,
|
||||
result: **result,
|
||||
captures_niche: func_sym.captures_niche(),
|
||||
};
|
||||
self.expr_call_by_name(
|
||||
*func_sym,
|
||||
func_sym.name(),
|
||||
&proc_layout,
|
||||
arguments,
|
||||
ret_sym,
|
||||
|
@ -1353,16 +1354,15 @@ impl<'a> WasmBackend<'a> {
|
|||
fn expr_struct_at_index(
|
||||
&mut self,
|
||||
sym: Symbol,
|
||||
storage: &StoredValue,
|
||||
index: u64,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
structure: Symbol,
|
||||
) {
|
||||
self.storage
|
||||
.ensure_value_has_local(&mut self.code_builder, sym, storage.to_owned());
|
||||
let (local_id, mut offset) = match self.storage.get(&structure) {
|
||||
let (from_addr_val, mut offset) = match self.storage.get(&structure) {
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
location.local_and_offset(self.storage.stack_frame_pointer)
|
||||
let (local_id, offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
(AddressValue::NotLoaded(local_id), offset)
|
||||
}
|
||||
|
||||
StoredValue::Local {
|
||||
|
@ -1371,18 +1371,20 @@ impl<'a> WasmBackend<'a> {
|
|||
..
|
||||
} => {
|
||||
debug_assert!(matches!(value_type, ValueType::I32));
|
||||
(*local_id, 0)
|
||||
(AddressValue::NotLoaded(*local_id), 0)
|
||||
}
|
||||
|
||||
StoredValue::VirtualMachineStack { .. } => {
|
||||
internal_error!("ensure_value_has_local didn't work")
|
||||
self.storage
|
||||
.load_symbols(&mut self.code_builder, &[structure]);
|
||||
(AddressValue::Loaded, 0)
|
||||
}
|
||||
};
|
||||
for field in field_layouts.iter().take(index as usize) {
|
||||
offset += field.stack_size(TARGET_INFO);
|
||||
}
|
||||
self.storage
|
||||
.copy_value_from_memory(&mut self.code_builder, sym, local_id, offset);
|
||||
.copy_value_from_memory(&mut self.code_builder, sym, from_addr_val, offset);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
|
@ -1700,20 +1702,83 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
let stores_tag_id_in_pointer = union_layout.stores_tag_id_in_pointer(TARGET_INFO);
|
||||
|
||||
let from_ptr = if stores_tag_id_in_pointer {
|
||||
let ptr = self.storage.create_anonymous_local(ValueType::I32);
|
||||
let from_addr_val = if stores_tag_id_in_pointer {
|
||||
self.code_builder.get_local(tag_local_id);
|
||||
self.code_builder.i32_const(-4); // 11111111...1100
|
||||
self.code_builder.i32_and();
|
||||
self.code_builder.set_local(ptr);
|
||||
ptr
|
||||
AddressValue::Loaded
|
||||
} else {
|
||||
tag_local_id
|
||||
AddressValue::NotLoaded(tag_local_id)
|
||||
};
|
||||
|
||||
let from_offset = tag_offset + field_offset;
|
||||
self.storage.copy_value_from_memory(
|
||||
&mut self.code_builder,
|
||||
symbol,
|
||||
from_addr_val,
|
||||
from_offset,
|
||||
);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* Box
|
||||
*******************************************************************/
|
||||
|
||||
fn expr_box(
|
||||
&mut self,
|
||||
ret_sym: Symbol,
|
||||
arg_sym: Symbol,
|
||||
layout: &Layout<'a>,
|
||||
storage: &StoredValue,
|
||||
) {
|
||||
// create a local variable for the heap pointer
|
||||
let ptr_local_id = match self.storage.ensure_value_has_local(
|
||||
&mut self.code_builder,
|
||||
ret_sym,
|
||||
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 layout {
|
||||
Layout::Boxed(arg) => *arg,
|
||||
_ => internal_error!("ExprBox should always produce a Boxed layout"),
|
||||
};
|
||||
let (size, alignment) = arg_layout.stack_size_and_alignment(TARGET_INFO);
|
||||
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_from_memory(&mut self.code_builder, symbol, from_ptr, from_offset);
|
||||
.copy_value_to_memory(&mut self.code_builder, ptr_local_id, 0, arg_sym);
|
||||
}
|
||||
|
||||
fn expr_unbox(&mut self, ret_sym: Symbol, arg_sym: Symbol) {
|
||||
let (from_addr_val, from_offset) = match self.storage.get(&arg_sym) {
|
||||
StoredValue::VirtualMachineStack { .. } => {
|
||||
self.storage
|
||||
.load_symbols(&mut self.code_builder, &[arg_sym]);
|
||||
(AddressValue::Loaded, 0)
|
||||
}
|
||||
StoredValue::Local { local_id, .. } => (AddressValue::NotLoaded(*local_id), 0),
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
let (local_id, offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
(AddressValue::NotLoaded(local_id), offset)
|
||||
}
|
||||
};
|
||||
|
||||
// Copy the value
|
||||
self.storage.copy_value_from_memory(
|
||||
&mut self.code_builder,
|
||||
ret_sym,
|
||||
from_addr_val,
|
||||
from_offset,
|
||||
);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
|
|
|
@ -184,7 +184,8 @@ pub fn build_app_module<'a>(
|
|||
}
|
||||
|
||||
let (module, called_preload_fns) = backend.finalize();
|
||||
let main_function_index = maybe_main_fn_index.unwrap();
|
||||
let main_function_index =
|
||||
maybe_main_fn_index.expect("The app must expose at least one value to the host");
|
||||
|
||||
(module, called_preload_fns, main_function_index)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use roc_mono::low_level::HigherOrder;
|
|||
|
||||
use crate::backend::{ProcLookupData, ProcSource, WasmBackend};
|
||||
use crate::layout::{CallConv, StackMemoryFormat, WasmLayout};
|
||||
use crate::storage::{StackMemoryLocation, StoredValue};
|
||||
use crate::storage::{AddressValue, StackMemoryLocation, StoredValue};
|
||||
use crate::wasm_module::{Align, LocalId, ValueType};
|
||||
use crate::TARGET_INFO;
|
||||
|
||||
|
@ -235,15 +235,7 @@ impl<'a> LowLevelCall<'a> {
|
|||
self.load_args_and_call_zig(backend, bitcode::STR_STARTS_WITH_SCALAR)
|
||||
}
|
||||
StrEndsWith => self.load_args_and_call_zig(backend, bitcode::STR_ENDS_WITH),
|
||||
StrSplit => {
|
||||
// LLVM implementation (build_str.rs) does the following
|
||||
// 1. Call bitcode::STR_COUNT_SEGMENTS
|
||||
// 2. Allocate a `List Str`
|
||||
// 3. Call bitcode::STR_STR_SPLIT_IN_PLACE
|
||||
// 4. Write the elements and length of the List
|
||||
// To do this here, we need full access to WasmBackend, or we could make a Zig wrapper
|
||||
todo!("{:?}", self.lowlevel);
|
||||
}
|
||||
StrSplit => self.load_args_and_call_zig(backend, bitcode::STR_STR_SPLIT),
|
||||
StrCountGraphemes => {
|
||||
self.load_args_and_call_zig(backend, bitcode::STR_COUNT_GRAPEHEME_CLUSTERS)
|
||||
}
|
||||
|
@ -268,10 +260,30 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
StrFromInt => self.num_to_str(backend),
|
||||
StrFromFloat => self.num_to_str(backend),
|
||||
StrFromUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8),
|
||||
StrFromUtf8 => {
|
||||
/*
|
||||
Low-level op returns a struct with all the data for both Ok and Err.
|
||||
Roc AST wrapper converts this to a tag union, with app-dependent tag IDs.
|
||||
|
||||
fromUtf8C(output: *FromUtf8Result, arg: RocList, update_mode: UpdateMode) callconv(.C) void
|
||||
output: *FromUtf8Result i32
|
||||
arg: RocList i64, i32
|
||||
update_mode: UpdateMode i32
|
||||
*/
|
||||
backend.storage.load_symbols_for_call(
|
||||
backend.env.arena,
|
||||
&mut backend.code_builder,
|
||||
self.arguments,
|
||||
self.ret_symbol,
|
||||
&WasmLayout::new(&self.ret_layout),
|
||||
CallConv::Zig,
|
||||
);
|
||||
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
||||
backend.call_host_fn_after_loading_args(bitcode::STR_FROM_UTF8, 4, false);
|
||||
}
|
||||
StrFromUtf8Range => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8_RANGE),
|
||||
StrTrimLeft => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_LEFT),
|
||||
StrTrimRight => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_RIGHT),
|
||||
StrFromUtf8Range => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8_RANGE),
|
||||
StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8),
|
||||
StrRepeat => self.load_args_and_call_zig(backend, bitcode::STR_REPEAT),
|
||||
StrTrim => self.load_args_and_call_zig(backend, bitcode::STR_TRIM),
|
||||
|
@ -316,14 +328,12 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
// Target element heap pointer
|
||||
backend.code_builder.i32_add(); // base + index*size
|
||||
let elem_heap_ptr = backend.storage.create_anonymous_local(ValueType::I32);
|
||||
backend.code_builder.set_local(elem_heap_ptr);
|
||||
|
||||
// Copy to stack
|
||||
backend.storage.copy_value_from_memory(
|
||||
&mut backend.code_builder,
|
||||
self.ret_symbol,
|
||||
elem_heap_ptr,
|
||||
AddressValue::Loaded,
|
||||
0,
|
||||
);
|
||||
|
||||
|
@ -1728,7 +1738,8 @@ impl<'a> LowLevelCall<'a> {
|
|||
Layout::Builtin(Builtin::Dict(_, _) | Builtin::Set(_) | Builtin::List(_))
|
||||
| Layout::Struct { .. }
|
||||
| Layout::Union(_)
|
||||
| Layout::LambdaSet(_) => {
|
||||
| Layout::LambdaSet(_)
|
||||
| Layout::Boxed(_) => {
|
||||
// Don't want Zig calling convention here, we're calling internal Roc functions
|
||||
backend
|
||||
.storage
|
||||
|
@ -1746,8 +1757,6 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Layout::Boxed(_) => todo!(),
|
||||
|
||||
Layout::RecursivePointer => {
|
||||
internal_error!(
|
||||
"Tried to apply `==` to RecursivePointer values {:?}",
|
||||
|
@ -1964,12 +1973,13 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
let passed_proc_layout = ProcLayout {
|
||||
arguments: argument_layouts,
|
||||
result: *result_layout,
|
||||
captures_niche: fn_name.captures_niche(),
|
||||
};
|
||||
let passed_proc_index = backend
|
||||
.proc_lookup
|
||||
.iter()
|
||||
.position(|ProcLookupData { name, layout, .. }| {
|
||||
name == fn_name && layout == &passed_proc_layout
|
||||
*name == fn_name.name() && layout == &passed_proc_layout
|
||||
})
|
||||
.unwrap();
|
||||
ProcSource::HigherOrderWrapper(passed_proc_index)
|
||||
|
@ -1997,6 +2007,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
ProcLayout {
|
||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||
result: Layout::UNIT,
|
||||
captures_niche: fn_name.captures_niche(),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -76,6 +76,13 @@ impl StoredValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum AddressValue {
|
||||
/// The address value has been loaded to the VM stack
|
||||
Loaded,
|
||||
/// The address value is in a local variable
|
||||
NotLoaded(LocalId),
|
||||
}
|
||||
|
||||
/// Helper structure for WasmBackend, to keep track of how values are stored,
|
||||
/// including the VM stack, local variables, and linear memory
|
||||
#[derive(Debug)]
|
||||
|
@ -610,7 +617,7 @@ impl<'a> Storage<'a> {
|
|||
&mut self,
|
||||
code_builder: &mut CodeBuilder,
|
||||
to_symbol: Symbol,
|
||||
from_ptr: LocalId,
|
||||
from_addr: AddressValue,
|
||||
from_offset: u32,
|
||||
) -> u32 {
|
||||
let to_storage = self.get(&to_symbol).to_owned();
|
||||
|
@ -625,6 +632,16 @@ impl<'a> Storage<'a> {
|
|||
self.stack_frame_pointer = Some(self.get_next_local_id());
|
||||
}
|
||||
|
||||
let from_ptr = match from_addr {
|
||||
AddressValue::NotLoaded(ptr) => ptr,
|
||||
AddressValue::Loaded => {
|
||||
// The `from` address is on the VM stack but we want it in a local for copying
|
||||
let tmp_local = self.create_anonymous_local(PTR_TYPE);
|
||||
code_builder.set_local(tmp_local);
|
||||
tmp_local
|
||||
}
|
||||
};
|
||||
|
||||
let (to_ptr, to_offset) = location.local_and_offset(self.stack_frame_pointer);
|
||||
copy_memory(
|
||||
code_builder,
|
||||
|
@ -648,7 +665,10 @@ impl<'a> Storage<'a> {
|
|||
} => {
|
||||
use crate::wasm_module::Align::*;
|
||||
|
||||
code_builder.get_local(from_ptr);
|
||||
if let AddressValue::NotLoaded(from_ptr) = from_addr {
|
||||
code_builder.get_local(from_ptr);
|
||||
}
|
||||
|
||||
match (value_type, size) {
|
||||
(ValueType::I64, 8) => code_builder.i64_load(Bytes8, from_offset),
|
||||
(ValueType::I32, 4) => code_builder.i32_load(Bytes4, from_offset),
|
||||
|
|
|
@ -76,7 +76,7 @@ pub fn insert_wrapper_for_layout<'a>(
|
|||
bool::insert_wrapper(arena, module, wrapper_name, main_fn_index);
|
||||
}
|
||||
Layout::Union(UnionLayout::NonRecursive(_)) => stack_data_structure(),
|
||||
Layout::Union(_) => {
|
||||
Layout::Union(_) | Layout::Boxed(_) => {
|
||||
i32::insert_wrapper(arena, module, wrapper_name, main_fn_index);
|
||||
}
|
||||
_ => stack_data_structure(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue