Merge branch 'trunk' of github.com:rtfeldman/roc into wasm-tags

This commit is contained in:
Brian Carroll 2021-12-09 09:26:54 +00:00
commit 3f7b3bef87
13 changed files with 559 additions and 131 deletions

View file

@ -7,6 +7,7 @@ use roc_module::symbol::{Interns, Symbol};
use roc_mono::gen_refcount::{RefcountProcGenerator, REFCOUNT_MAX};
use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt};
use roc_mono::layout::{Builtin, Layout, LayoutIds, TagIdIntType, UnionLayout};
use roc_reporting::internal_error;
use crate::layout::{CallConv, ReturnMethod, WasmLayout};
use crate::low_level::{decode_low_level, LowlevelBuildResult};
@ -200,19 +201,17 @@ impl<'a> WasmBackend<'a> {
***********************************************************/
pub fn build_proc(&mut self, proc: &Proc<'a>) -> Result<(), String> {
pub fn build_proc(&mut self, proc: &Proc<'a>) {
// println!("\ngenerating procedure {:?}\n", proc.name);
self.start_proc(proc);
self.build_stmt(&proc.body, &proc.ret_layout)?;
self.build_stmt(&proc.body, &proc.ret_layout);
self.finalize_proc()?;
self.finalize_proc();
self.reset();
// println!("\nfinished generating {:?}\n", proc.name);
Ok(())
}
fn start_proc(&mut self, proc: &Proc<'a>) {
@ -243,7 +242,7 @@ impl<'a> WasmBackend<'a> {
});
}
fn finalize_proc(&mut self) -> Result<(), String> {
fn finalize_proc(&mut self) {
// end the block from start_proc, to ensure all paths pop stack memory (if any)
self.end_block();
@ -253,8 +252,6 @@ impl<'a> WasmBackend<'a> {
self.storage.stack_frame_size,
self.storage.stack_frame_pointer,
);
Ok(())
}
/**********************************************************
@ -278,7 +275,7 @@ impl<'a> WasmBackend<'a> {
self.code_builder.end();
}
fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> {
fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) {
match stmt {
Stmt::Let(_, _, _, _) => {
let mut current_stmt = stmt;
@ -294,7 +291,7 @@ impl<'a> WasmBackend<'a> {
let sym_storage = self.storage.allocate(&wasm_layout, *sym, kind);
self.build_expr(sym, expr, layout, &sym_storage)?;
self.build_expr(sym, expr, layout, &sym_storage);
// If this value is stored in the VM stack, we need code_builder to track it
// (since every instruction can change the VM stack)
@ -309,8 +306,7 @@ impl<'a> WasmBackend<'a> {
current_stmt = *following;
}
self.build_stmt(current_stmt, ret_layout)?;
Ok(())
self.build_stmt(current_stmt, ret_layout);
}
Stmt::Ret(sym) => {
@ -346,8 +342,6 @@ impl<'a> WasmBackend<'a> {
}
// jump to the "stack frame pop" code at the end of the function
self.code_builder.br(self.block_depth - 1);
Ok(())
}
Stmt::Switch {
@ -415,7 +409,7 @@ impl<'a> WasmBackend<'a> {
}
// if we never jumped because a value matched, we're in the default case
self.build_stmt(default_branch.1, ret_layout)?;
self.build_stmt(default_branch.1, ret_layout);
// now put in the actual body of each branch in order
// (the first branch would have broken out of 1 block,
@ -423,10 +417,8 @@ impl<'a> WasmBackend<'a> {
for (_, _, branch) in branches.iter() {
self.end_block();
self.build_stmt(branch, ret_layout)?;
self.build_stmt(branch, ret_layout);
}
Ok(())
}
Stmt::Join {
id,
@ -456,7 +448,7 @@ impl<'a> WasmBackend<'a> {
self.joinpoint_label_map
.insert(*id, (self.block_depth, jp_param_storages));
self.build_stmt(remainder, ret_layout)?;
self.build_stmt(remainder, ret_layout);
self.end_block();
@ -469,12 +461,10 @@ impl<'a> WasmBackend<'a> {
};
self.start_loop(loop_block_type);
self.build_stmt(body, ret_layout)?;
self.build_stmt(body, ret_layout);
// ends the loop
self.end_block();
Ok(())
}
Stmt::Jump(id, arguments) => {
let (target, param_storages) = self.joinpoint_label_map[id].clone();
@ -492,8 +482,6 @@ impl<'a> WasmBackend<'a> {
// jump
let levels = self.block_depth - target;
self.code_builder.br(levels);
Ok(())
}
Stmt::Refcounting(modify, following) => {
@ -535,11 +523,10 @@ impl<'a> WasmBackend<'a> {
}));
}
self.build_stmt(&rc_stmt, ret_layout)?;
Ok(())
self.build_stmt(&rc_stmt, ret_layout);
}
x => Err(format!("statement not yet implemented: {:?}", x)),
x => todo!("statement {:?}", x),
}
}
@ -555,7 +542,7 @@ impl<'a> WasmBackend<'a> {
expr: &Expr<'a>,
layout: &Layout<'a>,
storage: &StoredValue,
) -> Result<(), String> {
) {
let wasm_layout = WasmLayout::new(layout);
match expr {
Expr::Literal(lit) => self.load_literal(lit, storage, *sym, layout),
@ -591,13 +578,14 @@ impl<'a> WasmBackend<'a> {
num_wasm_args,
has_return_val,
);
return Ok(());
return;
}
}
unreachable!(
internal_error!(
"Could not find procedure {:?}\nKnown procedures: {:?}",
func_sym, self.proc_symbols
func_sym,
self.proc_symbols
);
}
@ -605,7 +593,7 @@ impl<'a> WasmBackend<'a> {
self.build_low_level(*lowlevel, arguments, *sym, wasm_layout)
}
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
x => todo!("call type {:?}", x),
},
Expr::Struct(fields) => self.create_struct(sym, layout, fields),
@ -628,12 +616,11 @@ impl<'a> WasmBackend<'a> {
offset,
);
} else {
unreachable!("Unexpected storage for {:?}", structure)
internal_error!("Unexpected storage for {:?}", structure)
}
Ok(())
}
Expr::Array { .. } => Err(format!("Expression is not yet implemented {:?}", expr)),
Expr::Array { .. } => todo!("Expression {:?}", expr),
Expr::EmptyArray => {
if let StoredValue::StackMemory { location, .. } = storage {
@ -646,10 +633,8 @@ impl<'a> WasmBackend<'a> {
self.code_builder.get_local(local_id);
self.code_builder.i64_const(0);
self.code_builder.i64_store(Align::Bytes4, offset);
Ok(())
} else {
unreachable!("Unexpected storage for {:?}", sym)
internal_error!("Unexpected storage for {:?}", sym)
}
}
@ -658,12 +643,9 @@ impl<'a> WasmBackend<'a> {
tag_id,
arguments,
..
} => {
self.build_tag(tag_layout, *tag_id, arguments, storage);
Ok(())
}
} => self.build_tag(tag_layout, *tag_id, arguments, storage),
x => Err(format!("Expression is not yet implemented {:?}", x)),
x => todo!("Expression {:?}", x),
}
}
@ -679,7 +661,7 @@ impl<'a> WasmBackend<'a> {
let (local_id, offset) = if let StoredValue::StackMemory { location, .. } = stored {
location.local_and_offset(self.storage.stack_frame_pointer)
} else {
panic!("NonRecursive Tag should always be stored in StackMemory");
internal_error!("NonRecursive Tag should always be stored in StackMemory");
};
let mut field_offset = offset;
@ -710,7 +692,7 @@ impl<'a> WasmBackend<'a> {
}
}
}
_ => unimplemented!("Tag with layout {:?}", union_layout),
_ => todo!("Tag with layout {:?}", union_layout),
}
}
@ -720,7 +702,7 @@ impl<'a> WasmBackend<'a> {
arguments: &'a [Symbol],
return_sym: Symbol,
return_layout: WasmLayout,
) -> Result<(), String> {
) {
let (param_types, ret_type) = self.storage.load_symbols_for_call(
self.env.arena,
&mut self.code_builder,
@ -740,15 +722,13 @@ impl<'a> WasmBackend<'a> {
use LowlevelBuildResult::*;
match build_result {
Done => Ok(()),
Done => {}
BuiltinCall(name) => {
self.call_zig_builtin(name, param_types, ret_type);
Ok(())
}
NotImplemented => Err(format!(
"Low level operation {:?} is not yet implemented",
lowlevel
)),
NotImplemented => {
todo!("Low level operation {:?}", lowlevel)
}
}
}
@ -758,8 +738,8 @@ impl<'a> WasmBackend<'a> {
storage: &StoredValue,
sym: Symbol,
layout: &Layout<'a>,
) -> Result<(), String> {
let not_supported_error = || panic!("Literal value {:?} is not yet implemented", lit);
) {
let not_supported_error = || todo!("Literal value {:?}", lit);
match storage {
StoredValue::VirtualMachineStack { value_type, .. } => {
@ -770,9 +750,7 @@ impl<'a> WasmBackend<'a> {
(Literal::Int(x), ValueType::I32) => self.code_builder.i32_const(*x as i32),
(Literal::Bool(x), ValueType::I32) => self.code_builder.i32_const(*x as i32),
(Literal::Byte(x), ValueType::I32) => self.code_builder.i32_const(*x as i32),
_ => {
return not_supported_error();
}
_ => not_supported_error(),
};
}
@ -822,16 +800,11 @@ impl<'a> WasmBackend<'a> {
self.code_builder.i32_store(Align::Bytes4, offset + 4);
};
}
_ => {
return not_supported_error();
}
_ => not_supported_error(),
},
_ => {
return not_supported_error();
}
_ => not_supported_error(),
};
Ok(())
}
/// Look up a string constant in our internal data structures
@ -852,9 +825,10 @@ impl<'a> WasmBackend<'a> {
let elements_addr = *segment_offset + CONST_SEGMENT_BASE_ADDR;
(*linker_sym_index as u32, elements_addr)
}
_ => unreachable!(
_ => internal_error!(
"Compiler bug: Invalid linker symbol info for string {:?}:\n{:?}",
string, syminfo
string,
syminfo
),
}
}
@ -894,12 +868,7 @@ impl<'a> WasmBackend<'a> {
}
}
fn create_struct(
&mut self,
sym: &Symbol,
layout: &Layout<'a>,
fields: &'a [Symbol],
) -> Result<(), String> {
fn create_struct(&mut self, sym: &Symbol, layout: &Layout<'a>, fields: &'a [Symbol]) {
// TODO: we just calculated storage and now we're getting it out of a map
// Not passing it as an argument because I'm trying to match Backend method signatures
let storage = self.storage.get(sym).to_owned();
@ -922,15 +891,9 @@ impl<'a> WasmBackend<'a> {
} else {
// Zero-size struct. No code to emit.
// These values are purely conceptual, they only exist internally in the compiler
return Ok(());
}
}
_ => {
return Err(format!(
"Cannot create struct {:?} with storage {:?}",
sym, storage
));
}
_ => internal_error!("Cannot create struct {:?} with storage {:?}", sym, storage),
};
} else {
// Struct expression but not Struct layout => single element. Copy it.
@ -938,7 +901,6 @@ impl<'a> WasmBackend<'a> {
self.storage
.clone_value(&mut self.code_builder, &storage, &field_storage, fields[0]);
}
Ok(())
}
/// Generate a call instruction to a Zig builtin function.
@ -958,7 +920,7 @@ impl<'a> WasmBackend<'a> {
SymInfo::Function(WasmObjectSymbol::Imported { index, .. }) => {
(*index, *sym_idx as u32)
}
x => unreachable!("Invalid linker symbol for builtin {}: {:?}", name, x),
x => internal_error!("Invalid linker symbol for builtin {}: {:?}", name, x),
},
None => {