From 46a09d81e80b0d1b700648e307f94703f0614c0b Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 9 Nov 2021 17:25:18 +0100 Subject: [PATCH 01/19] cli improvements, added examples to nightly package --- Earthfile | 6 ++++-- cli/src/lib.rs | 8 ++++++-- cli/src/main.rs | 13 +++++++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Earthfile b/Earthfile index e2cb8fc9b8..5ba59c5991 100644 --- a/Earthfile +++ b/Earthfile @@ -108,12 +108,14 @@ test-all: build-nightly-release: FROM +test-rust - COPY --dir .git ./ + COPY --dir .git LICENSE LEGAL_DETAILS ./ # version.txt is used by the CLI: roc --version RUN printf "nightly pre-release, built from commit " > version.txt RUN git log --pretty=format:'%h' -n 1 >> version.txt + RUN printf " on: " >> version.txt + RUN date >> version.txt RUN cargo build --features with_sound --release - RUN cd ./target/release && tar -czvf roc_linux_x86_64.tar.gz ./roc + RUN cd ./target/release && tar -czvf roc_linux_x86_64.tar.gz ./roc ../../LICENSE ../../LEGAL_DETAILS ../../examples/hello-world ../../examples/hello-rust ../../examples/hello-zig ../../compiler/builtins/bitcode/src/ ../../roc_std SAVE ARTIFACT ./target/release/roc_linux_x86_64.tar.gz AS LOCAL roc_linux_x86_64.tar.gz # compile everything needed for benchmarks and output a self-contained dir from which benchmarks can be run. diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 3c0bf5381a..d942dae20e 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -23,6 +23,7 @@ pub const CMD_REPL: &str = "repl"; pub const CMD_EDIT: &str = "edit"; pub const CMD_DOCS: &str = "docs"; pub const CMD_CHECK: &str = "check"; +pub const CMD_VERSION: &str = "version"; pub const FLAG_DEBUG: &str = "debug"; pub const FLAG_DEV: &str = "dev"; @@ -103,8 +104,11 @@ pub fn build_app<'a>() -> App<'a> { .subcommand(App::new(CMD_REPL) .about("Launch the interactive Read Eval Print Loop (REPL)") ) + .subcommand(App::new(CMD_VERSION) + .about("Print version information") + ) .subcommand(App::new(CMD_CHECK) - .about("Build a binary from the given .roc file, but don't run it") + .about("When developing, it's recommended to run `check` before `build`. It may provide a useful error message in cases where `build` panics") .arg( Arg::new(FLAG_TIME) .long(FLAG_TIME) @@ -190,7 +194,7 @@ pub fn build_app<'a>() -> App<'a> { if cfg!(feature = "editor") { app.subcommand( - App::new(CMD_EDIT).about("Launch the Roc editor").arg( + App::new(CMD_EDIT).about("Launch the Roc editor (Work In Progress)").arg( Arg::new(DIRECTORY_OR_FILES) .index(1) .multiple_values(true) diff --git a/cli/src/main.rs b/cli/src/main.rs index 0143bbf3af..acd974029a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,13 +1,13 @@ use roc_cli::build::check_file; -use roc_cli::{ - build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL, - DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE, -}; +use roc_cli::{BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL, CMD_VERSION, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE, build_app, docs, repl}; use roc_load::file::LoadingProblem; use std::fs::{self, FileType}; use std::io; use std::path::{Path, PathBuf}; +#[macro_use] +extern crate const_format; + #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -122,6 +122,11 @@ fn main() -> io::Result<()> { Ok(0) } + Some(CMD_VERSION) => { + println!("roc {}", concatcp!(include_str!("../../version.txt"), "\n")); + + Ok(0) + } _ => unreachable!(), }?; From f5dc3ac3aa78433a29bc30b81ab25340e97f9b51 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 10 Nov 2021 10:07:13 +0100 Subject: [PATCH 02/19] fmt --- cli/src/lib.rs | 16 +++++++++------- cli/src/main.rs | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index d942dae20e..543f24981a 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -194,13 +194,15 @@ pub fn build_app<'a>() -> App<'a> { if cfg!(feature = "editor") { app.subcommand( - App::new(CMD_EDIT).about("Launch the Roc editor (Work In Progress)").arg( - Arg::new(DIRECTORY_OR_FILES) - .index(1) - .multiple_values(true) - .required(false) - .about("(optional) The directory or files to open on launch."), - ), + App::new(CMD_EDIT) + .about("Launch the Roc editor (Work In Progress)") + .arg( + Arg::new(DIRECTORY_OR_FILES) + .index(1) + .multiple_values(true) + .required(false) + .about("(optional) The directory or files to open on launch."), + ), ) } else { app diff --git a/cli/src/main.rs b/cli/src/main.rs index acd974029a..ef946b8470 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,5 +1,8 @@ use roc_cli::build::check_file; -use roc_cli::{BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL, CMD_VERSION, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE, build_app, docs, repl}; +use roc_cli::{ + build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL, + CMD_VERSION, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE, +}; use roc_load::file::LoadingProblem; use std::fs::{self, FileType}; use std::io; From 51b607632234bc63a257d99b64dacdeb2790143a Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 09:20:31 +0000 Subject: [PATCH 03/19] stack pointer: use constants & add a comment --- compiler/gen_wasm/src/backend.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 791dfffc04..374e026198 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -24,7 +24,7 @@ use crate::wasm_module::{ }; use crate::{ copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_TYPE, - STACK_POINTER_NAME, + STACK_POINTER_GLOBAL_ID, STACK_POINTER_NAME, }; /// The memory address where the constants data will be loaded during module instantiation. @@ -84,12 +84,12 @@ impl<'a> WasmBackend<'a> { exports.push(Export { name: STACK_POINTER_NAME.to_string(), ty: ExportType::Global, - index: 0, + index: STACK_POINTER_GLOBAL_ID, }); linker_symbols.push(SymInfo::Global(WasmObjectSymbol::Defined { - flags: WASM_SYM_BINDING_WEAK, - index: 0, + flags: WASM_SYM_BINDING_WEAK, // TODO: this works but means external .o files decide how much stack we have! + index: STACK_POINTER_GLOBAL_ID, name: STACK_POINTER_NAME.to_string(), })); From ec03b7b12ab097afdcf798b64e41dc38eda507f4 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 10:42:06 +0000 Subject: [PATCH 04/19] Move lowlevel calls to their own module of gen_wasm --- compiler/gen_wasm/src/backend.rs | 120 ++++++++--------------------- compiler/gen_wasm/src/lib.rs | 1 + compiler/gen_wasm/src/low_level.rs | 86 +++++++++++++++++++++ 3 files changed, 118 insertions(+), 89 deletions(-) create mode 100644 compiler/gen_wasm/src/low_level.rs diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 374e026198..3b9452d3c7 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -1,14 +1,13 @@ use bumpalo::{self, collections::Vec}; use code_builder::Align; -use roc_builtins::bitcode::{self, FloatWidth}; use roc_collections::all::MutMap; -use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, Stmt}; use roc_mono::layout::{Layout, LayoutIds}; use crate::layout::WasmLayout; +use crate::low_level::{build_call_low_level, LowlevelBuildResult}; use crate::storage::{Storage, StoredValue, StoredValueKind}; use crate::wasm_module::linking::{ DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK, @@ -487,7 +486,29 @@ impl<'a> WasmBackend<'a> { } CallType::LowLevel { op: lowlevel, .. } => { - self.build_call_low_level(lowlevel, arguments, layout) + let return_layout = WasmLayout::new(layout); + self.storage.load_symbols(&mut self.code_builder, arguments); + + let build_result = build_call_low_level( + &mut self.code_builder, + &mut self.storage, + lowlevel, + arguments, + &return_layout, + ); + use LowlevelBuildResult::*; + + match build_result { + WasmInstructions => Ok(()), + BuiltinCall(name) => { + self.call_imported_builtin(name, arguments, &return_layout); + Ok(()) + } + NotImplemented => Err(format!( + "Low level operation {:?} is not yet implemented", + lowlevel + )), + } } x => Err(format!("the call type, {:?}, is not yet implemented", x)), }, @@ -665,90 +686,11 @@ impl<'a> WasmBackend<'a> { Ok(()) } - fn build_call_low_level( - &mut self, - lowlevel: &LowLevel, - args: &'a [Symbol], - return_layout: &Layout<'a>, - ) -> Result<(), String> { - self.storage.load_symbols(&mut self.code_builder, args); - let wasm_layout = WasmLayout::new(return_layout); - let ret_type = wasm_layout.value_type(); - - let panic_ret_type = || panic!("Invalid return type for {:?}: {:?}", lowlevel, ret_type); - - match lowlevel { - LowLevel::NumAdd => match ret_type { - ValueType::I32 => self.code_builder.i32_add(), - ValueType::I64 => self.code_builder.i64_add(), - ValueType::F32 => self.code_builder.f32_add(), - ValueType::F64 => self.code_builder.f64_add(), - }, - LowLevel::NumSub => match ret_type { - ValueType::I32 => self.code_builder.i32_sub(), - ValueType::I64 => self.code_builder.i64_sub(), - ValueType::F32 => self.code_builder.f32_sub(), - ValueType::F64 => self.code_builder.f64_sub(), - }, - LowLevel::NumMul => match ret_type { - ValueType::I32 => self.code_builder.i32_mul(), - ValueType::I64 => self.code_builder.i64_mul(), - ValueType::F32 => self.code_builder.f32_mul(), - ValueType::F64 => self.code_builder.f64_mul(), - }, - LowLevel::NumGt => match self.get_uniform_arg_type(args) { - ValueType::I32 => self.code_builder.i32_gt_s(), - ValueType::I64 => self.code_builder.i64_gt_s(), - ValueType::F32 => self.code_builder.f32_gt(), - ValueType::F64 => self.code_builder.f64_gt(), - }, - LowLevel::Eq => match self.get_uniform_arg_type(args) { - ValueType::I32 => self.code_builder.i32_eq(), - ValueType::I64 => self.code_builder.i64_eq(), - ValueType::F32 => self.code_builder.f32_eq(), - ValueType::F64 => self.code_builder.f64_eq(), - }, - LowLevel::NumNeg => match ret_type { - ValueType::I32 => { - self.code_builder.i32_const(-1); - self.code_builder.i32_mul(); - } - ValueType::I64 => { - self.code_builder.i64_const(-1); - self.code_builder.i64_mul(); - } - ValueType::F32 => self.code_builder.f32_neg(), - ValueType::F64 => self.code_builder.f64_neg(), - }, - LowLevel::NumAtan => { - let name = match ret_type { - ValueType::F32 => &bitcode::NUM_ATAN[FloatWidth::F32], - ValueType::F64 => &bitcode::NUM_ATAN[FloatWidth::F64], - _ => panic_ret_type(), - }; - self.call_imported_builtin(name, &[ret_type], Some(ret_type)); - } - _ => { - return Err(format!("unsupported low-level op {:?}", lowlevel)); - } - }; - Ok(()) - } - - /// Get the ValueType for a set of arguments that are required to have the same type - fn get_uniform_arg_type(&self, args: &'a [Symbol]) -> ValueType { - let value_type = self.storage.get(&args[0]).value_type(); - for arg in args.iter().skip(1) { - debug_assert!(self.storage.get(arg).value_type() == value_type); - } - value_type - } - fn call_imported_builtin( &mut self, name: &'a str, - arg_types: &[ValueType], - ret_type: Option, + arguments: &[Symbol], + ret_layout: &WasmLayout, ) { let (fn_index, linker_symbol_index) = match self.builtin_sym_index_map.get(name) { Some(sym_idx) => match &self.linker_symbols[*sym_idx] { @@ -759,11 +701,11 @@ impl<'a> WasmBackend<'a> { }, None => { - let mut param_types = Vec::with_capacity_in(arg_types.len(), self.env.arena); - param_types.extend_from_slice(arg_types); + let mut param_types = Vec::with_capacity_in(arguments.len(), self.env.arena); + param_types.extend(arguments.iter().map(|a| self.storage.get(a).value_type())); let signature_index = self.module.types.insert(Signature { param_types, - ret_type, + ret_type: Some(ret_layout.value_type()), // TODO: handle builtins with no return value }); let import_index = self.module.import.entries.len() as u32; @@ -787,8 +729,8 @@ impl<'a> WasmBackend<'a> { self.code_builder.call( fn_index, linker_symbol_index, - arg_types.len(), - ret_type.is_some(), + arguments.len(), + true, // TODO: handle builtins with no return value ); } } diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 6fcad7c739..a495132e7d 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,5 +1,6 @@ mod backend; mod layout; +mod low_level; mod storage; pub mod wasm_module; diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs new file mode 100644 index 0000000000..48d47afe22 --- /dev/null +++ b/compiler/gen_wasm/src/low_level.rs @@ -0,0 +1,86 @@ +use roc_builtins::bitcode::{self, FloatWidth}; +use roc_module::low_level::LowLevel; +use roc_module::symbol::Symbol; + +use crate::layout::WasmLayout; +use crate::storage::Storage; +use crate::wasm_module::{CodeBuilder, ValueType}; + +pub enum LowlevelBuildResult { + WasmInstructions, + BuiltinCall(&'static str), + NotImplemented, +} + +pub fn build_call_low_level<'a>( + code_builder: &mut CodeBuilder<'a>, + storage: &mut Storage<'a>, + lowlevel: &LowLevel, + args: &'a [Symbol], + ret_layout: &WasmLayout, +) -> LowlevelBuildResult { + use LowlevelBuildResult::*; + + let panic_ret_type = || panic!("Invalid return layout for {:?}: {:?}", lowlevel, ret_layout); + + match lowlevel { + LowLevel::NumAdd => match ret_layout.value_type() { + ValueType::I32 => code_builder.i32_add(), + ValueType::I64 => code_builder.i64_add(), + ValueType::F32 => code_builder.f32_add(), + ValueType::F64 => code_builder.f64_add(), + }, + LowLevel::NumSub => match ret_layout.value_type() { + ValueType::I32 => code_builder.i32_sub(), + ValueType::I64 => code_builder.i64_sub(), + ValueType::F32 => code_builder.f32_sub(), + ValueType::F64 => code_builder.f64_sub(), + }, + LowLevel::NumMul => match ret_layout.value_type() { + ValueType::I32 => code_builder.i32_mul(), + ValueType::I64 => code_builder.i64_mul(), + ValueType::F32 => code_builder.f32_mul(), + ValueType::F64 => code_builder.f64_mul(), + }, + LowLevel::NumGt => match storage.get(&args[0]).value_type() { + ValueType::I32 => code_builder.i32_gt_s(), + ValueType::I64 => code_builder.i64_gt_s(), + ValueType::F32 => code_builder.f32_gt(), + ValueType::F64 => code_builder.f64_gt(), + }, + LowLevel::Eq => match storage.get(&args[0]).value_type() { + ValueType::I32 => code_builder.i32_eq(), + ValueType::I64 => code_builder.i64_eq(), + ValueType::F32 => code_builder.f32_eq(), + ValueType::F64 => code_builder.f64_eq(), + }, + LowLevel::NumNeg => match ret_layout.value_type() { + // TODO: it would be better to subtract the arg from zero. + // But we'd need to insert the zero constant *before* the argument + // in the VM stack, and we don't have a good way to do that yet! + // Before solving this one case, let's see what other issues we run into. + ValueType::I32 => { + code_builder.i32_const(-1); + code_builder.i32_mul(); + } + ValueType::I64 => { + code_builder.i64_const(-1); + code_builder.i64_mul(); + } + ValueType::F32 => code_builder.f32_neg(), + ValueType::F64 => code_builder.f64_neg(), + }, + LowLevel::NumAtan => { + let name: &'static str = match ret_layout.value_type() { + ValueType::F32 => &bitcode::NUM_ATAN[FloatWidth::F32], + ValueType::F64 => &bitcode::NUM_ATAN[FloatWidth::F64], + _ => panic_ret_type(), + }; + return BuiltinCall(name); + } + _ => { + return NotImplemented; + } + }; + WasmInstructions +} From 6421ff07a57155c8c8e7016ea1ee4d199ad9082f Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 10:47:01 +0000 Subject: [PATCH 05/19] Use shorter notation for enums in lowlevel module --- compiler/gen_wasm/src/low_level.rs | 70 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 48d47afe22..76a10f2def 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -1,10 +1,10 @@ use roc_builtins::bitcode::{self, FloatWidth}; -use roc_module::low_level::LowLevel; +use roc_module::low_level::{LowLevel, LowLevel::*}; use roc_module::symbol::Symbol; use crate::layout::WasmLayout; use crate::storage::Storage; -use crate::wasm_module::{CodeBuilder, ValueType}; +use crate::wasm_module::{CodeBuilder, ValueType::*}; pub enum LowlevelBuildResult { WasmInstructions, @@ -24,56 +24,56 @@ pub fn build_call_low_level<'a>( let panic_ret_type = || panic!("Invalid return layout for {:?}: {:?}", lowlevel, ret_layout); match lowlevel { - LowLevel::NumAdd => match ret_layout.value_type() { - ValueType::I32 => code_builder.i32_add(), - ValueType::I64 => code_builder.i64_add(), - ValueType::F32 => code_builder.f32_add(), - ValueType::F64 => code_builder.f64_add(), + NumAdd => match ret_layout.value_type() { + I32 => code_builder.i32_add(), + I64 => code_builder.i64_add(), + F32 => code_builder.f32_add(), + F64 => code_builder.f64_add(), }, - LowLevel::NumSub => match ret_layout.value_type() { - ValueType::I32 => code_builder.i32_sub(), - ValueType::I64 => code_builder.i64_sub(), - ValueType::F32 => code_builder.f32_sub(), - ValueType::F64 => code_builder.f64_sub(), + NumSub => match ret_layout.value_type() { + I32 => code_builder.i32_sub(), + I64 => code_builder.i64_sub(), + F32 => code_builder.f32_sub(), + F64 => code_builder.f64_sub(), }, - LowLevel::NumMul => match ret_layout.value_type() { - ValueType::I32 => code_builder.i32_mul(), - ValueType::I64 => code_builder.i64_mul(), - ValueType::F32 => code_builder.f32_mul(), - ValueType::F64 => code_builder.f64_mul(), + NumMul => match ret_layout.value_type() { + I32 => code_builder.i32_mul(), + I64 => code_builder.i64_mul(), + F32 => code_builder.f32_mul(), + F64 => code_builder.f64_mul(), }, - LowLevel::NumGt => match storage.get(&args[0]).value_type() { - ValueType::I32 => code_builder.i32_gt_s(), - ValueType::I64 => code_builder.i64_gt_s(), - ValueType::F32 => code_builder.f32_gt(), - ValueType::F64 => code_builder.f64_gt(), + NumGt => match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_gt_s(), + I64 => code_builder.i64_gt_s(), + F32 => code_builder.f32_gt(), + F64 => code_builder.f64_gt(), }, - LowLevel::Eq => match storage.get(&args[0]).value_type() { - ValueType::I32 => code_builder.i32_eq(), - ValueType::I64 => code_builder.i64_eq(), - ValueType::F32 => code_builder.f32_eq(), - ValueType::F64 => code_builder.f64_eq(), + Eq => match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_eq(), + I64 => code_builder.i64_eq(), + F32 => code_builder.f32_eq(), + F64 => code_builder.f64_eq(), }, - LowLevel::NumNeg => match ret_layout.value_type() { + NumNeg => match ret_layout.value_type() { // TODO: it would be better to subtract the arg from zero. // But we'd need to insert the zero constant *before* the argument // in the VM stack, and we don't have a good way to do that yet! // Before solving this one case, let's see what other issues we run into. - ValueType::I32 => { + I32 => { code_builder.i32_const(-1); code_builder.i32_mul(); } - ValueType::I64 => { + I64 => { code_builder.i64_const(-1); code_builder.i64_mul(); } - ValueType::F32 => code_builder.f32_neg(), - ValueType::F64 => code_builder.f64_neg(), + F32 => code_builder.f32_neg(), + F64 => code_builder.f64_neg(), }, - LowLevel::NumAtan => { + NumAtan => { let name: &'static str = match ret_layout.value_type() { - ValueType::F32 => &bitcode::NUM_ATAN[FloatWidth::F32], - ValueType::F64 => &bitcode::NUM_ATAN[FloatWidth::F64], + F32 => &bitcode::NUM_ATAN[FloatWidth::F32], + F64 => &bitcode::NUM_ATAN[FloatWidth::F64], _ => panic_ret_type(), }; return BuiltinCall(name); From 9f5d3f521b27470debc0566e77b2d3110f6b86af Mon Sep 17 00:00:00 2001 From: satotake Date: Wed, 10 Nov 2021 13:16:57 +0000 Subject: [PATCH 06/19] Implement `List.sublist` --- compiler/builtins/src/std.rs | 16 ++++++++++ compiler/can/src/builtins.rs | 49 ++++++++++++++++++++++++++++++ compiler/module/src/symbol.rs | 1 + compiler/solve/tests/solve_expr.rs | 12 ++++++++ compiler/test_gen/src/gen_list.rs | 40 ++++++++++++++++++++++++ 5 files changed, 118 insertions(+) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index e58b83639d..790ad8eb97 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -985,6 +985,22 @@ pub fn types() -> MutMap { Box::new(list_type(flex(TVAR1))), ); + // sublist : List elem, { start : Nat, len : Nat } -> List elem + add_top_level_function_type!( + Symbol::LIST_SUBLIST, + vec![ + list_type(flex(TVAR1)), + SolvedType::Record { + fields: vec![ + ("start".into(), RecordField::Required(nat_type())), + ("len".into(), RecordField::Required(nat_type())), + ], + ext: Box::new(SolvedType::EmptyRecord), + }, + ], + Box::new(list_type(flex(TVAR1))), + ); + // drop : List elem, Nat -> List elem add_top_level_function_type!( Symbol::LIST_DROP, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 1894f09284..db85daa989 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -93,6 +93,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_MAP4 => list_map4, LIST_TAKE_FIRST => list_take_first, LIST_TAKE_LAST => list_take_last, + LIST_SUBLIST => list_sublist, LIST_DROP => list_drop, LIST_DROP_AT => list_drop_at, LIST_DROP_FIRST => list_drop_first, @@ -2054,6 +2055,54 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +/// List.sublist : List elem, { start : Nat, len : Nat } -> List elem +fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def { + let list_var = var_store.fresh(); + let rec_var = var_store.fresh(); + + let sym_list = Symbol::ARG_1; + let sym_rec = Symbol::ARG_2; + + let start_var = var_store.fresh(); + let len_var = var_store.fresh(); + + let get_start = Access { + record_var: rec_var, + ext_var: var_store.fresh(), + field_var: var_store.fresh(), + loc_expr: Box::new(no_region(Var(sym_rec))), + field: "start".into(), + }; + + let get_len = Access { + record_var: rec_var, + ext_var: var_store.fresh(), + field_var: var_store.fresh(), + loc_expr: Box::new(no_region(Var(sym_rec))), + field: "len".into(), + }; + + let body_drop = RunLowLevel { + op: LowLevel::ListDrop, + args: vec![(list_var, Var(sym_list)), (start_var, get_start)], + ret_var: list_var, + }; + + let body_take = RunLowLevel { + op: LowLevel::ListTakeFirst, + args: vec![(list_var, body_drop), (len_var, get_len)], + ret_var: list_var, + }; + + defn( + symbol, + vec![(list_var, sym_list), (rec_var, sym_rec)], + var_store, + body_take, + list_var, + ) +} + /// List.drop : List elem, Nat -> List elem fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 1cc1cd15a4..d08f074c75 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1069,6 +1069,7 @@ define_builtins! { 46 LIST_TAKE_LAST: "takeLast" 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find + 49 LIST_SUBLIST: "sublist" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index fac5c31b4d..5f205bab17 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3769,6 +3769,18 @@ mod solve_expr { ); } + #[test] + fn list_sublist() { + infer_eq_without_problem( + indoc!( + r#" + List.sublist + "# + ), + "List a, { start : Nat, len : Nat } -> List a", + ); + } + #[test] fn list_drop_last() { infer_eq_without_problem( diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index baf17d2b41..521a96db84 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -208,6 +208,46 @@ fn list_take_last() { ); } +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn list_sublist() { + assert_evals_to!( + "List.sublist [1, 2, 3] { start: 0 , len: 2 } ", + RocList::from_slice(&[1, 2]), + RocList + ); + assert_evals_to!( + "List.sublist [1, 2, 3] { start: 1 , len: 2 } ", + RocList::from_slice(&[2, 3]), + RocList + ); + assert_evals_to!( + "List.sublist [1, 2, 3] { start: 2 , len: 2 } ", + RocList::from_slice(&[3]), + RocList + ); + assert_evals_to!( + "List.sublist [1, 2, 3] { start: 3 , len: 2 } ", + RocList::from_slice(&[]), + RocList + ); + assert_evals_to!( + "List.sublist [] { start: 1 , len: 1 } ", + RocList::from_slice(&[]), + RocList + ); + assert_evals_to!( + "List.sublist [1, 2, 3] { start: 1 , len: 0 } ", + RocList::from_slice(&[]), + RocList + ); + assert_evals_to!( + "List.sublist [1, 2, 3] { start: 0 , len: 5 } ", + RocList::from_slice(&[1, 2, 3]), + RocList + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn list_drop() { From 7c95189e4a1f7f8413be4593b7d396d09d71de80 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 14:21:32 +0000 Subject: [PATCH 07/19] Get lots of Num lowlevel ops working --- compiler/gen_wasm/src/backend.rs | 2 +- compiler/gen_wasm/src/layout.rs | 8 + compiler/gen_wasm/src/lib.rs | 10 +- compiler/gen_wasm/src/low_level.rs | 324 ++++++++++++++++-- .../gen_wasm/src/wasm_module/code_builder.rs | 1 + compiler/gen_wasm/src/wasm_module/opcodes.rs | 184 ++++++++++ compiler/test_gen/src/gen_num.rs | 64 ++-- 7 files changed, 532 insertions(+), 61 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 3b9452d3c7..3b4da4a465 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -499,7 +499,7 @@ impl<'a> WasmBackend<'a> { use LowlevelBuildResult::*; match build_result { - WasmInstructions => Ok(()), + Done => Ok(()), BuiltinCall(name) => { self.call_imported_builtin(name, arguments, &return_layout); Ok(()) diff --git a/compiler/gen_wasm/src/layout.rs b/compiler/gen_wasm/src/layout.rs index 49b2b6be93..2cd562dcc8 100644 --- a/compiler/gen_wasm/src/layout.rs +++ b/compiler/gen_wasm/src/layout.rs @@ -71,6 +71,14 @@ impl WasmLayout { } } + pub fn size(&self) -> u32 { + match self { + Self::Primitive(_, size) => *size, + Self::StackMemory { size, .. } => *size, + Self::HeapMemory => PTR_SIZE, + } + } + pub fn is_stack_memory(&self) -> bool { matches!(self, Self::StackMemory { .. }) } diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index a495132e7d..c1f2eec941 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -127,7 +127,15 @@ pub fn copy_memory(code_builder: &mut CodeBuilder, config: CopyMemoryConfig) { /// Round up to alignment_bytes (which must be a power of 2) pub fn round_up_to_alignment(unaligned: i32, alignment_bytes: i32) -> i32 { - debug_assert!(alignment_bytes.count_ones() == 1); + if alignment_bytes <= 1 { + return unaligned; + } + if alignment_bytes.count_ones() != 1 { + panic!( + "Cannot align to {} bytes. Not a power of 2.", + alignment_bytes + ); + } let mut aligned = unaligned; aligned += alignment_bytes - 1; // if lower bits are non-zero, push it over the next boundary aligned &= -alignment_bytes; // mask with a flag that has upper bits 1, lower bits 0 diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index 76a10f2def..a1e556e33b 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -4,10 +4,13 @@ use roc_module::symbol::Symbol; use crate::layout::WasmLayout; use crate::storage::Storage; -use crate::wasm_module::{CodeBuilder, ValueType::*}; +use crate::wasm_module::{ + CodeBuilder, + ValueType::{self, *}, +}; pub enum LowlevelBuildResult { - WasmInstructions, + Done, BuiltinCall(&'static str), NotImplemented, } @@ -24,63 +27,330 @@ pub fn build_call_low_level<'a>( let panic_ret_type = || panic!("Invalid return layout for {:?}: {:?}", lowlevel, ret_layout); match lowlevel { + StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt + | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 + | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen + | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat + | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 + | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk | ListWalkUntil + | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith | ListTakeFirst + | ListTakeLast | ListDrop | ListDropAt | ListSwap | ListAny | ListFindUnsafe | DictSize + | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe | DictKeys + | DictValues | DictUnion | DictIntersection | DictDifference | DictWalk | SetFromList => { + return NotImplemented; + } + NumAdd => match ret_layout.value_type() { I32 => code_builder.i32_add(), I64 => code_builder.i64_add(), F32 => code_builder.f32_add(), F64 => code_builder.f64_add(), }, + NumAddWrap => match ret_layout.value_type() { + I32 => { + code_builder.i32_add(); + wrap_i32(code_builder, ret_layout.size()); + } + I64 => code_builder.i64_add(), + F32 => code_builder.f32_add(), + F64 => code_builder.f64_add(), + }, + NumAddChecked => return NotImplemented, NumSub => match ret_layout.value_type() { I32 => code_builder.i32_sub(), I64 => code_builder.i64_sub(), F32 => code_builder.f32_sub(), F64 => code_builder.f64_sub(), }, + NumSubWrap => match ret_layout.value_type() { + I32 => { + code_builder.i32_sub(); + wrap_i32(code_builder, ret_layout.size()); + } + I64 => code_builder.i64_sub(), + F32 => code_builder.f32_sub(), + F64 => code_builder.f64_sub(), + }, + NumSubChecked => return NotImplemented, NumMul => match ret_layout.value_type() { I32 => code_builder.i32_mul(), I64 => code_builder.i64_mul(), F32 => code_builder.f32_mul(), F64 => code_builder.f64_mul(), }, + NumMulWrap => match ret_layout.value_type() { + I32 => { + code_builder.i32_mul(); + wrap_i32(code_builder, ret_layout.size()); + } + I64 => code_builder.i64_mul(), + F32 => code_builder.f32_mul(), + F64 => code_builder.f64_mul(), + }, + NumMulChecked => return NotImplemented, NumGt => match storage.get(&args[0]).value_type() { I32 => code_builder.i32_gt_s(), I64 => code_builder.i64_gt_s(), F32 => code_builder.f32_gt(), F64 => code_builder.f64_gt(), }, - Eq => match storage.get(&args[0]).value_type() { - I32 => code_builder.i32_eq(), - I64 => code_builder.i64_eq(), - F32 => code_builder.f32_eq(), - F64 => code_builder.f64_eq(), + NumGte => match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_ge_s(), + I64 => code_builder.i64_ge_s(), + F32 => code_builder.f32_ge(), + F64 => code_builder.f64_ge(), }, - NumNeg => match ret_layout.value_type() { - // TODO: it would be better to subtract the arg from zero. - // But we'd need to insert the zero constant *before* the argument - // in the VM stack, and we don't have a good way to do that yet! - // Before solving this one case, let's see what other issues we run into. + NumLt => match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_lt_s(), + I64 => code_builder.i64_lt_s(), + F32 => code_builder.f32_lt(), + F64 => code_builder.f64_lt(), + }, + NumLte => match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_le_s(), + I64 => code_builder.i64_le_s(), + F32 => code_builder.f32_le(), + F64 => code_builder.f64_le(), + }, + NumCompare => return NotImplemented, + NumDivUnchecked => match ret_layout.value_type() { + I32 => code_builder.i32_div_s(), + I64 => code_builder.i64_div_s(), + F32 => code_builder.f32_div(), + F64 => code_builder.f64_div(), + }, + NumDivCeilUnchecked => return NotImplemented, + NumRemUnchecked => match ret_layout.value_type() { + I32 => code_builder.i32_rem_s(), + I64 => code_builder.i64_rem_s(), + F32 => return NotImplemented, + F64 => return NotImplemented, + }, + NumIsMultipleOf => return NotImplemented, + NumAbs => match ret_layout.value_type() { I32 => { - code_builder.i32_const(-1); - code_builder.i32_mul(); + code_builder.i32_const(0); + storage.load_symbols(code_builder, args); + code_builder.i32_sub(); + storage.load_symbols(code_builder, args); + code_builder.i32_const(0); + code_builder.i32_ge_s(); + code_builder.select(); } I64 => { - code_builder.i64_const(-1); - code_builder.i64_mul(); + code_builder.i64_const(0); + storage.load_symbols(code_builder, args); + code_builder.i64_sub(); + storage.load_symbols(code_builder, args); + code_builder.i64_const(0); + code_builder.i64_ge_s(); + code_builder.select(); + } + F32 => code_builder.f32_abs(), + F64 => code_builder.f64_abs(), + }, + NumNeg => { + match ret_layout.value_type() { + I32 => { + // Unfortunate local.set/local.get + code_builder.i32_const(0); + storage.load_symbols(code_builder, args); + code_builder.i32_sub(); + } + I64 => { + // Unfortunate local.set/local.get + code_builder.i64_const(0); + storage.load_symbols(code_builder, args); + code_builder.i64_sub(); + } + F32 => code_builder.f32_neg(), + F64 => code_builder.f64_neg(), + } + } + NumSin => return NotImplemented, + NumCos => return NotImplemented, + NumSqrtUnchecked => return NotImplemented, + NumLogUnchecked => return NotImplemented, + NumRound => match ret_layout.value_type() { + I32 => code_builder.f32_nearest(), + I64 => code_builder.f64_nearest(), + F32 => {} + F64 => {} + }, + NumToFloat => match (ret_layout.value_type(), storage.get(&args[0]).value_type()) { + (F32, I32) => code_builder.f32_convert_s_i32(), + (F32, I64) => code_builder.f32_convert_s_i64(), + (F32, F32) => {} + (F32, F64) => code_builder.f32_demote_f64(), + (F64, I32) => code_builder.f64_convert_s_i32(), + (F64, I64) => code_builder.f64_convert_s_i64(), + (F64, F32) => code_builder.f64_promote_f32(), + (F64, F64) => {} + _ => panic_ret_type(), + }, + NumPow => return NotImplemented, + NumCeiling => match ret_layout.value_type() { + I32 => { + code_builder.f32_ceil(); + code_builder.i32_trunc_s_f32() + } + I64 => { + code_builder.f64_ceil(); + code_builder.i64_trunc_s_f64() + } + _ => panic_ret_type(), + }, + NumPowInt => return NotImplemented, + NumFloor => match ret_layout.value_type() { + I32 => { + code_builder.f32_floor(); + code_builder.i32_trunc_s_f32() + } + I64 => { + code_builder.f64_floor(); + code_builder.i64_trunc_s_f64() + } + _ => panic_ret_type(), + }, + NumIsFinite => match ret_layout.value_type() { + I32 => code_builder.i32_const(1), + I64 => code_builder.i32_const(1), + F32 => { + code_builder.i32_reinterpret_f32(); + code_builder.i32_const(0x7f800000); + code_builder.i32_and(); + code_builder.i32_const(0x7f800000); + code_builder.i32_ne(); + } + F64 => { + code_builder.i64_reinterpret_f64(); + code_builder.i64_const(0x7ff0000000000000); + code_builder.i64_and(); + code_builder.i64_const(0x7ff0000000000000); + code_builder.i64_ne(); } - F32 => code_builder.f32_neg(), - F64 => code_builder.f64_neg(), }, NumAtan => { - let name: &'static str = match ret_layout.value_type() { - F32 => &bitcode::NUM_ATAN[FloatWidth::F32], - F64 => &bitcode::NUM_ATAN[FloatWidth::F64], + let width = float_width_from_layout(ret_layout); + return BuiltinCall(&bitcode::NUM_ATAN[width]); + } + NumAcos => { + let width = float_width_from_layout(ret_layout); + return BuiltinCall(&bitcode::NUM_ACOS[width]); + } + NumAsin => { + let width = float_width_from_layout(ret_layout); + return BuiltinCall(&bitcode::NUM_ASIN[width]); + } + NumBytesToU16 => return NotImplemented, + NumBytesToU32 => return NotImplemented, + NumBitwiseAnd => match ret_layout.value_type() { + I32 => code_builder.i32_and(), + I64 => code_builder.i64_and(), + _ => panic_ret_type(), + }, + NumBitwiseXor => match ret_layout.value_type() { + I32 => code_builder.i32_xor(), + I64 => code_builder.i64_xor(), + _ => panic_ret_type(), + }, + NumBitwiseOr => match ret_layout.value_type() { + I32 => code_builder.i32_or(), + I64 => code_builder.i64_or(), + _ => panic_ret_type(), + }, + NumShiftLeftBy => { + // Unfortunate local.set/local.get + storage.load_symbols(code_builder, &[args[1], args[0]]); + match ret_layout.value_type() { + I32 => code_builder.i32_shl(), + I64 => code_builder.i64_shl(), _ => panic_ret_type(), - }; - return BuiltinCall(name); + } } - _ => { - return NotImplemented; + NumShiftRightBy => match ret_layout.value_type() { + I32 => code_builder.i32_shr_s(), + I64 => code_builder.i64_shr_s(), + _ => panic_ret_type(), + }, + NumShiftRightZfBy => match ret_layout.value_type() { + I32 => code_builder.i32_shr_u(), + I64 => code_builder.i64_shr_u(), + _ => panic_ret_type(), + }, + NumIntCast => match (ret_layout.value_type(), storage.get(&args[0]).value_type()) { + (I32, I32) => {} + (I32, I64) => code_builder.i32_wrap_i64(), + (I32, F32) => code_builder.i32_trunc_s_f32(), + (I32, F64) => code_builder.i32_trunc_s_f64(), + + (I64, I32) => code_builder.i64_extend_s_i32(), + (I64, I64) => {} + (I64, F32) => code_builder.i64_trunc_s_f32(), + (I64, F64) => code_builder.i64_trunc_s_f64(), + + (F32, I32) => code_builder.f32_convert_s_i32(), + (F32, I64) => code_builder.f32_convert_s_i64(), + (F32, F32) => {} + (F32, F64) => code_builder.f32_demote_f64(), + + (F64, I32) => code_builder.f64_convert_s_i32(), + (F64, I64) => code_builder.f64_convert_s_i64(), + (F64, F32) => code_builder.f64_promote_f32(), + (F64, F64) => {} + }, + Eq => { + // TODO: For non-number types, this will implement pointer equality, which is wrong + match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_eq(), + I64 => code_builder.i64_eq(), + F32 => code_builder.f32_eq(), + F64 => code_builder.f64_eq(), + } } - }; - WasmInstructions + NotEq => { + // TODO: For non-number types, this will implement pointer inequality, which is wrong + match storage.get(&args[0]).value_type() { + I32 => code_builder.i32_ne(), + I64 => code_builder.i64_ne(), + F32 => code_builder.f32_ne(), + F64 => code_builder.f64_ne(), + } + } + And => code_builder.i32_and(), + Or => code_builder.i32_or(), + Not => code_builder.i32_eqz(), + Hash => return NotImplemented, + ExpectTrue => return NotImplemented, + } + Done +} + +/// Wrap an integer whose Wasm representation is i32 +fn wrap_i32(code_builder: &mut CodeBuilder, size: u32) { + match size { + 1 => { + // Underlying Roc value is i8 + code_builder.i32_const(24); + code_builder.i32_shl(); + code_builder.i32_const(24); + code_builder.i32_shr_s(); + } + 2 => { + // Underlying Roc value is i16 + code_builder.i32_const(16); + code_builder.i32_shl(); + code_builder.i32_const(16); + code_builder.i32_shr_s(); + } + _ => {} // the only other possible value is 4, and i32 wraps natively + } +} + +fn float_width_from_layout(wasm_layout: &WasmLayout) -> FloatWidth { + if wasm_layout.value_type() == ValueType::F32 { + FloatWidth::F32 + } else { + FloatWidth::F64 + } } diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index fd0466fecd..0cc1bcead3 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -439,6 +439,7 @@ impl<'a> CodeBuilder<'a> { if push { self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE); } + self.code.push(opcode); } diff --git a/compiler/gen_wasm/src/wasm_module/opcodes.rs b/compiler/gen_wasm/src/wasm_module/opcodes.rs index 714889bdae..c545bc204f 100644 --- a/compiler/gen_wasm/src/wasm_module/opcodes.rs +++ b/compiler/gen_wasm/src/wasm_module/opcodes.rs @@ -176,3 +176,187 @@ pub const I32REINTERPRETF32: u8 = 0xbc; pub const I64REINTERPRETF64: u8 = 0xbd; pub const F32REINTERPRETI32: u8 = 0xbe; pub const F64REINTERPRETI64: u8 = 0xbf; + +pub fn dbg_opcode_name(opcode: u8) -> &'static str { + match opcode { + UNREACHABLE => "UNREACHABLE", + NOP => "NOP", + BLOCK => "BLOCK", + LOOP => "LOOP", + IF => "IF", + ELSE => "ELSE", + END => "END", + BR => "BR", + BRIF => "BRIF", + BRTABLE => "BRTABLE", + RETURN => "RETURN", + CALL => "CALL", + CALLINDIRECT => "CALLINDIRECT", + DROP => "DROP", + SELECT => "SELECT", + GETLOCAL => "GETLOCAL", + SETLOCAL => "SETLOCAL", + TEELOCAL => "TEELOCAL", + GETGLOBAL => "GETGLOBAL", + SETGLOBAL => "SETGLOBAL", + I32LOAD => "I32LOAD", + I64LOAD => "I64LOAD", + F32LOAD => "F32LOAD", + F64LOAD => "F64LOAD", + I32LOAD8S => "I32LOAD8S", + I32LOAD8U => "I32LOAD8U", + I32LOAD16S => "I32LOAD16S", + I32LOAD16U => "I32LOAD16U", + I64LOAD8S => "I64LOAD8S", + I64LOAD8U => "I64LOAD8U", + I64LOAD16S => "I64LOAD16S", + I64LOAD16U => "I64LOAD16U", + I64LOAD32S => "I64LOAD32S", + I64LOAD32U => "I64LOAD32U", + I32STORE => "I32STORE", + I64STORE => "I64STORE", + F32STORE => "F32STORE", + F64STORE => "F64STORE", + I32STORE8 => "I32STORE8", + I32STORE16 => "I32STORE16", + I64STORE8 => "I64STORE8", + I64STORE16 => "I64STORE16", + I64STORE32 => "I64STORE32", + CURRENTMEMORY => "CURRENTMEMORY", + GROWMEMORY => "GROWMEMORY", + I32CONST => "I32CONST", + I64CONST => "I64CONST", + F32CONST => "F32CONST", + F64CONST => "F64CONST", + I32EQZ => "I32EQZ", + I32EQ => "I32EQ", + I32NE => "I32NE", + I32LTS => "I32LTS", + I32LTU => "I32LTU", + I32GTS => "I32GTS", + I32GTU => "I32GTU", + I32LES => "I32LES", + I32LEU => "I32LEU", + I32GES => "I32GES", + I32GEU => "I32GEU", + I64EQZ => "I64EQZ", + I64EQ => "I64EQ", + I64NE => "I64NE", + I64LTS => "I64LTS", + I64LTU => "I64LTU", + I64GTS => "I64GTS", + I64GTU => "I64GTU", + I64LES => "I64LES", + I64LEU => "I64LEU", + I64GES => "I64GES", + I64GEU => "I64GEU", + + F32EQ => "F32EQ", + F32NE => "F32NE", + F32LT => "F32LT", + F32GT => "F32GT", + F32LE => "F32LE", + F32GE => "F32GE", + + F64EQ => "F64EQ", + F64NE => "F64NE", + F64LT => "F64LT", + F64GT => "F64GT", + F64LE => "F64LE", + F64GE => "F64GE", + + I32CLZ => "I32CLZ", + I32CTZ => "I32CTZ", + I32POPCNT => "I32POPCNT", + I32ADD => "I32ADD", + I32SUB => "I32SUB", + I32MUL => "I32MUL", + I32DIVS => "I32DIVS", + I32DIVU => "I32DIVU", + I32REMS => "I32REMS", + I32REMU => "I32REMU", + I32AND => "I32AND", + I32OR => "I32OR", + I32XOR => "I32XOR", + I32SHL => "I32SHL", + I32SHRS => "I32SHRS", + I32SHRU => "I32SHRU", + I32ROTL => "I32ROTL", + I32ROTR => "I32ROTR", + + I64CLZ => "I64CLZ", + I64CTZ => "I64CTZ", + I64POPCNT => "I64POPCNT", + I64ADD => "I64ADD", + I64SUB => "I64SUB", + I64MUL => "I64MUL", + I64DIVS => "I64DIVS", + I64DIVU => "I64DIVU", + I64REMS => "I64REMS", + I64REMU => "I64REMU", + I64AND => "I64AND", + I64OR => "I64OR", + I64XOR => "I64XOR", + I64SHL => "I64SHL", + I64SHRS => "I64SHRS", + I64SHRU => "I64SHRU", + I64ROTL => "I64ROTL", + I64ROTR => "I64ROTR", + F32ABS => "F32ABS", + F32NEG => "F32NEG", + F32CEIL => "F32CEIL", + F32FLOOR => "F32FLOOR", + F32TRUNC => "F32TRUNC", + F32NEAREST => "F32NEAREST", + F32SQRT => "F32SQRT", + F32ADD => "F32ADD", + F32SUB => "F32SUB", + F32MUL => "F32MUL", + F32DIV => "F32DIV", + F32MIN => "F32MIN", + F32MAX => "F32MAX", + F32COPYSIGN => "F32COPYSIGN", + F64ABS => "F64ABS", + F64NEG => "F64NEG", + F64CEIL => "F64CEIL", + F64FLOOR => "F64FLOOR", + F64TRUNC => "F64TRUNC", + F64NEAREST => "F64NEAREST", + F64SQRT => "F64SQRT", + F64ADD => "F64ADD", + F64SUB => "F64SUB", + F64MUL => "F64MUL", + F64DIV => "F64DIV", + F64MIN => "F64MIN", + F64MAX => "F64MAX", + F64COPYSIGN => "F64COPYSIGN", + + I32WRAPI64 => "I32WRAPI64", + I32TRUNCSF32 => "I32TRUNCSF32", + I32TRUNCUF32 => "I32TRUNCUF32", + I32TRUNCSF64 => "I32TRUNCSF64", + I32TRUNCUF64 => "I32TRUNCUF64", + I64EXTENDSI32 => "I64EXTENDSI32", + I64EXTENDUI32 => "I64EXTENDUI32", + I64TRUNCSF32 => "I64TRUNCSF32", + I64TRUNCUF32 => "I64TRUNCUF32", + I64TRUNCSF64 => "I64TRUNCSF64", + I64TRUNCUF64 => "I64TRUNCUF64", + F32CONVERTSI32 => "F32CONVERTSI32", + F32CONVERTUI32 => "F32CONVERTUI32", + F32CONVERTSI64 => "F32CONVERTSI64", + F32CONVERTUI64 => "F32CONVERTUI64", + F32DEMOTEF64 => "F32DEMOTEF64", + F64CONVERTSI32 => "F64CONVERTSI32", + F64CONVERTUI32 => "F64CONVERTUI32", + F64CONVERTSI64 => "F64CONVERTSI64", + F64CONVERTUI64 => "F64CONVERTUI64", + F64PROMOTEF32 => "F64PROMOTEF32", + + I32REINTERPRETF32 => "I32REINTERPRETF32", + I64REINTERPRETF64 => "I64REINTERPRETF64", + F32REINTERPRETI32 => "F32REINTERPRETI32", + F64REINTERPRETI64 => "F64REINTERPRETI64", + _ => "(unknown)", + } +} diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index f1f0bdd27b..e46e359375 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -530,7 +530,7 @@ fn f64_round() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))] fn f64_abs() { assert_evals_to!("Num.abs -4.7", 4.7, f64); assert_evals_to!("Num.abs 5.8", 5.8, f64); @@ -539,7 +539,7 @@ fn f64_abs() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn i64_abs() { assert_evals_to!("Num.abs -6", 6, i64); assert_evals_to!("Num.abs 7", 7, i64); @@ -767,7 +767,7 @@ fn gen_dec_neq() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_wrap_int_neq() { assert_evals_to!( indoc!( @@ -950,14 +950,14 @@ fn gen_rem_div_by_zero_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_zero_i64() { assert_evals_to!("Num.isZero 0", true, bool); assert_evals_to!("Num.isZero 1", false, bool); } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_positive_i64() { assert_evals_to!("Num.isPositive 0", false, bool); assert_evals_to!("Num.isPositive 1", true, bool); @@ -965,7 +965,7 @@ fn gen_is_positive_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_negative_i64() { assert_evals_to!("Num.isNegative 0", false, bool); assert_evals_to!("Num.isNegative 3", false, bool); @@ -973,7 +973,7 @@ fn gen_is_negative_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_positive_f64() { assert_evals_to!("Num.isPositive 0.0", false, bool); assert_evals_to!("Num.isPositive 4.7", true, bool); @@ -981,7 +981,7 @@ fn gen_is_positive_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_negative_f64() { assert_evals_to!("Num.isNegative 0.0", false, bool); assert_evals_to!("Num.isNegative 9.9", false, bool); @@ -989,7 +989,7 @@ fn gen_is_negative_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_zero_f64() { assert_evals_to!("Num.isZero 0", true, bool); assert_evals_to!("Num.isZero 0_0", true, bool); @@ -998,14 +998,14 @@ fn gen_is_zero_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_odd() { assert_evals_to!("Num.isOdd 4", false, bool); assert_evals_to!("Num.isOdd 5", true, bool); } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_is_even() { assert_evals_to!("Num.isEven 6", true, bool); assert_evals_to!("Num.isEven 7", false, bool); @@ -1033,7 +1033,7 @@ fn tan() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn bitwise_and() { assert_evals_to!("Num.bitwiseAnd 20 20", 20, i64); assert_evals_to!("Num.bitwiseAnd 25 10", 8, i64); @@ -1041,7 +1041,7 @@ fn bitwise_and() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn bitwise_xor() { assert_evals_to!("Num.bitwiseXor 20 20", 0, i64); assert_evals_to!("Num.bitwiseXor 15 14", 1, i64); @@ -1050,14 +1050,14 @@ fn bitwise_xor() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn bitwise_or() { assert_evals_to!("Num.bitwiseOr 1 1", 1, i64); assert_evals_to!("Num.bitwiseOr 1 2", 3, i64); } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn lt_i64() { assert_evals_to!("1 < 2", true, bool); assert_evals_to!("1 < 1", false, bool); @@ -1084,7 +1084,7 @@ fn gt_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gte_i64() { assert_evals_to!("1 >= 1", true, bool); assert_evals_to!("1 >= 2", false, bool); @@ -1093,7 +1093,7 @@ fn gte_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn lt_f64() { assert_evals_to!("1.1 < 1.2", true, bool); assert_evals_to!("1.1 < 1.1", false, bool); @@ -1102,7 +1102,7 @@ fn lt_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn lte_f64() { assert_evals_to!("1.1 <= 1.1", true, bool); assert_evals_to!("1.2 <= 1.1", false, bool); @@ -1120,7 +1120,7 @@ fn gt_f64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gte_f64() { assert_evals_to!("1.1 >= 1.1", true, bool); assert_evals_to!("1.1 >= 1.2", false, bool); @@ -1214,7 +1214,7 @@ fn tail_call_elimination() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-wasm"))] fn int_negate() { assert_evals_to!("Num.neg 123", -123, i64); assert_evals_to!("Num.neg Num.maxInt", -i64::MAX, i64); @@ -1272,19 +1272,19 @@ fn gen_basic_fn() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn int_to_float() { assert_evals_to!("Num.toFloat 0x9", 9.0, f64); } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn num_to_float() { assert_evals_to!("Num.toFloat 9", 9.0, f64); } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn float_to_float() { assert_evals_to!("Num.toFloat 0.5", 0.5, f64); } @@ -1312,13 +1312,13 @@ fn pow() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn ceiling() { assert_evals_to!("Num.ceiling 1.1", 2, i64); } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn floor() { assert_evals_to!("Num.floor 1.9", 1, i64); } @@ -1379,7 +1379,7 @@ fn int_add_checked() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn int_add_wrap() { assert_evals_to!( indoc!( @@ -1483,7 +1483,7 @@ fn int_sub_overflow() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn int_sub_wrap() { assert_evals_to!( indoc!( @@ -1628,7 +1628,7 @@ fn float_negative_mul_overflow() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn int_mul_wrap() { assert_evals_to!( indoc!( @@ -1698,7 +1698,7 @@ fn float_mul_checked() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn shift_left_by() { assert_evals_to!("Num.shiftLeftBy 0 0b0000_0001", 0b0000_0001, i64); assert_evals_to!("Num.shiftLeftBy 1 0b0000_0001", 0b0000_0010, i64); @@ -1706,7 +1706,7 @@ fn shift_left_by() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[ignore] fn shift_right_by() { // Sign Extended Right Shift @@ -1716,7 +1716,7 @@ fn shift_right_by() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[ignore] fn shift_right_zf_by() { // Logical Right Shift @@ -1921,7 +1921,7 @@ fn bytes_to_u32_random_u8s() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn when_on_i32() { assert_evals_to!( indoc!( From c0a362dc1af79b3037b9beea2174eeaaf1708450 Mon Sep 17 00:00:00 2001 From: satotake Date: Wed, 10 Nov 2021 14:32:22 +0000 Subject: [PATCH 08/19] fix solve_expr test --- compiler/solve/tests/solve_expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index 5f205bab17..c87276963e 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -3777,7 +3777,7 @@ mod solve_expr { List.sublist "# ), - "List a, { start : Nat, len : Nat } -> List a", + "List a, { len : Nat, start : Nat } -> List a", ); } From 5632e3159de2008a97223a71ddc84fad5b206b54 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 10 Nov 2021 16:00:22 +0100 Subject: [PATCH 09/19] remove im dependency where not needed --- Cargo.lock | 18 ------------------ cli/Cargo.toml | 2 -- compiler/build/Cargo.toml | 2 -- compiler/can/Cargo.toml | 2 -- compiler/can/src/def.rs | 6 +++--- compiler/can/src/expr.rs | 4 ++-- compiler/fmt/Cargo.toml | 2 -- compiler/gen_dev/Cargo.toml | 2 -- compiler/gen_llvm/Cargo.toml | 2 -- compiler/reporting/Cargo.toml | 2 -- compiler/test_gen/Cargo.toml | 2 -- editor/Cargo.toml | 2 -- 12 files changed, 5 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2aedb0b824..cd9b4274b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3122,8 +3122,6 @@ name = "roc_build" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "libloading 0.7.1", "roc_builtins", @@ -3164,8 +3162,6 @@ name = "roc_can" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "indoc", "pretty_assertions", "roc_builtins", @@ -3187,8 +3183,6 @@ dependencies = [ "cli_utils", "const_format", "criterion", - "im", - "im-rc", "indoc", "inkwell 0.1.0", "libloading 0.7.1", @@ -3298,8 +3292,6 @@ dependencies = [ "fs_extra", "futures", "glyph_brush", - "im", - "im-rc", "libc", "log", "nonempty", @@ -3339,8 +3331,6 @@ name = "roc_fmt" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "indoc", "pretty_assertions", "roc_collections", @@ -3354,8 +3344,6 @@ name = "roc_gen_dev" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "object 0.26.2", "roc_builtins", "roc_can", @@ -3377,8 +3365,6 @@ name = "roc_gen_llvm" version = "0.1.0" dependencies = [ "bumpalo", - "im", - "im-rc", "inkwell 0.1.0", "morphic_lib", "roc_builtins", @@ -3531,8 +3517,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "distance", - "im", - "im-rc", "indoc", "pretty_assertions", "roc_builtins", @@ -4074,8 +4058,6 @@ version = "0.1.0" dependencies = [ "bumpalo", "either", - "im", - "im-rc", "indoc", "inkwell 0.1.0", "libc", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 090688d80a..0d8ac9ce0e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -68,8 +68,6 @@ clap = { version = "= 3.0.0-beta.5", default-features = false, features = ["std" const_format = "0.2.22" rustyline = { git = "https://github.com/rtfeldman/rustyline", tag = "prompt-fix" } rustyline-derive = { git = "https://github.com/rtfeldman/rustyline", tag = "prompt-fix" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } libloading = "0.7.1" mimalloc = { version = "0.1.26", default-features = false } diff --git a/compiler/build/Cargo.toml b/compiler/build/Cargo.toml index 80c87fe626..3a9e19187f 100644 --- a/compiler/build/Cargo.toml +++ b/compiler/build/Cargo.toml @@ -24,8 +24,6 @@ roc_gen_wasm = { path = "../gen_wasm", optional = true } roc_gen_dev = { path = "../gen_dev", default-features = false } roc_reporting = { path = "../reporting" } roc_std = { path = "../../roc_std" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } libloading = "0.7.1" tempfile = "3.2.0" diff --git a/compiler/can/Cargo.toml b/compiler/can/Cargo.toml index e71e5b7c64..2e8bd639dd 100644 --- a/compiler/can/Cargo.toml +++ b/compiler/can/Cargo.toml @@ -14,8 +14,6 @@ roc_problem = { path = "../problem" } roc_types = { path = "../types" } roc_builtins = { path = "../builtins" } ven_graph = { path = "../../vendor/pathfinding" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } [dev-dependencies] diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index d74a8434ac..76bc58ae4e 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -872,7 +872,7 @@ fn canonicalize_pending_def<'a>( // TODO try to remove this .clone()! value: loc_can_expr.value.clone(), }, - pattern_vars: im::HashMap::clone(&vars_by_symbol), + pattern_vars: vars_by_symbol.clone(), annotation: Some(Annotation { signature: typ.clone(), introduced_variables: output.introduced_variables.clone(), @@ -1093,7 +1093,7 @@ fn canonicalize_pending_def<'a>( // TODO try to remove this .clone()! value: loc_can_expr.value.clone(), }, - pattern_vars: im::HashMap::clone(&vars_by_symbol), + pattern_vars: vars_by_symbol.clone(), annotation: Some(Annotation { signature: typ.clone(), introduced_variables: output.introduced_variables.clone(), @@ -1231,7 +1231,7 @@ fn canonicalize_pending_def<'a>( region: loc_can_expr.region, value: loc_can_expr.value.clone(), }, - pattern_vars: im::HashMap::clone(&vars_by_symbol), + pattern_vars: vars_by_symbol.clone(), annotation: None, }, ); diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index d22ee4c3f5..4e96b58e51 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -952,7 +952,7 @@ pub fn local_successors<'a>( references: &'a References, closures: &'a MutMap, ) -> ImSet { - let mut answer = im_rc::hashset::HashSet::clone(&references.lookups); + let mut answer = references.lookups.clone(); for call_symbol in references.calls.iter() { answer = answer.union(call_successors(*call_symbol, closures)); @@ -962,7 +962,7 @@ pub fn local_successors<'a>( } fn call_successors(call_symbol: Symbol, closures: &MutMap) -> ImSet { - let mut answer = im_rc::hashset::HashSet::default(); + let mut answer = ImSet::default(); let mut seen = MutSet::default(); let mut queue = vec![call_symbol]; diff --git a/compiler/fmt/Cargo.toml b/compiler/fmt/Cargo.toml index 3817722747..6b19b61815 100644 --- a/compiler/fmt/Cargo.toml +++ b/compiler/fmt/Cargo.toml @@ -10,8 +10,6 @@ roc_collections = { path = "../collections" } roc_region = { path = "../region" } roc_module = { path = "../module" } roc_parse = { path = "../parse" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } [dev-dependencies] diff --git a/compiler/gen_dev/Cargo.toml b/compiler/gen_dev/Cargo.toml index 9922b67100..2f5bc78dba 100644 --- a/compiler/gen_dev/Cargo.toml +++ b/compiler/gen_dev/Cargo.toml @@ -16,8 +16,6 @@ roc_builtins = { path = "../builtins" } roc_unify = { path = "../unify" } roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } target-lexicon = "0.12.2" # TODO: Deal with the update of object to 0.27. diff --git a/compiler/gen_llvm/Cargo.toml b/compiler/gen_llvm/Cargo.toml index 10cae674a5..a53a1d692d 100644 --- a/compiler/gen_llvm/Cargo.toml +++ b/compiler/gen_llvm/Cargo.toml @@ -18,8 +18,6 @@ roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } roc_std = { path = "../../roc_std" } morphic_lib = { path = "../../vendor/morphic_lib" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } inkwell = { path = "../../vendor/inkwell" } target-lexicon = "0.12.2" diff --git a/compiler/reporting/Cargo.toml b/compiler/reporting/Cargo.toml index a0f87252e1..35df3f33ae 100644 --- a/compiler/reporting/Cargo.toml +++ b/compiler/reporting/Cargo.toml @@ -16,8 +16,6 @@ roc_can = { path = "../can" } roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } ven_pretty = { path = "../../vendor/pretty" } -im = "15.0.0" -im-rc = "15.0.0" distance = "0.4.0" bumpalo = { version = "3.8.0", features = ["collections"] } diff --git a/compiler/test_gen/Cargo.toml b/compiler/test_gen/Cargo.toml index ce94be492d..9e1a5d5aba 100644 --- a/compiler/test_gen/Cargo.toml +++ b/compiler/test_gen/Cargo.toml @@ -29,8 +29,6 @@ roc_can = { path = "../can" } roc_parse = { path = "../parse" } roc_build = { path = "../build" } roc_std = { path = "../../roc_std" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } either = "1.6.1" libc = "0.2.106" diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 3ceb01e33d..69c00607c2 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -32,8 +32,6 @@ roc_unify = { path = "../compiler/unify" } roc_reporting = { path = "../compiler/reporting" } roc_solve = { path = "../compiler/solve" } ven_graph = { path = "../vendor/pathfinding" } -im = "15.0.0" -im-rc = "15.0.0" bumpalo = { version = "3.8.0", features = ["collections"] } arraystring = "0.3.0" libc = "0.2.106" From 2262dcb3f992df3a49c686c92ce2eb160d439c4c Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 10 Nov 2021 16:25:03 +0100 Subject: [PATCH 10/19] clean up some other dependencies --- Cargo.lock | 11 ---------- compiler/gen_llvm/Cargo.toml | 10 --------- compiler/mono/Cargo.toml | 7 ------ compiler/mono/src/expand_rc.rs | 40 +++++++++++++++++++++++++++++++++- compiler/mono/src/ir.rs | 34 ----------------------------- compiler/mono/src/lib.rs | 1 - 6 files changed, 39 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd9b4274b6..1c987c0452 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3368,17 +3368,10 @@ dependencies = [ "inkwell 0.1.0", "morphic_lib", "roc_builtins", - "roc_can", "roc_collections", "roc_module", "roc_mono", - "roc_parse", - "roc_problem", - "roc_region", - "roc_solve", "roc_std", - "roc_types", - "roc_unify", "target-lexicon", ] @@ -3464,20 +3457,16 @@ version = "0.1.0" dependencies = [ "bumpalo", "hashbrown 0.11.2", - "linked-hash-map", "morphic_lib", - "roc_builtins", "roc_can", "roc_collections", "roc_module", - "roc_parse", "roc_problem", "roc_region", "roc_solve", "roc_std", "roc_types", "roc_unify", - "ven_ena", "ven_graph", "ven_pretty", ] diff --git a/compiler/gen_llvm/Cargo.toml b/compiler/gen_llvm/Cargo.toml index a53a1d692d..5ae5f0abac 100644 --- a/compiler/gen_llvm/Cargo.toml +++ b/compiler/gen_llvm/Cargo.toml @@ -8,21 +8,11 @@ edition = "2018" [dependencies] roc_collections = { path = "../collections" } -roc_region = { path = "../region" } roc_module = { path = "../module" } -roc_problem = { path = "../problem" } -roc_types = { path = "../types" } roc_builtins = { path = "../builtins" } -roc_unify = { path = "../unify" } -roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } roc_std = { path = "../../roc_std" } morphic_lib = { path = "../../vendor/morphic_lib" } bumpalo = { version = "3.8.0", features = ["collections"] } inkwell = { path = "../../vendor/inkwell" } target-lexicon = "0.12.2" - -[dev-dependencies] -roc_can = { path = "../can" } -roc_parse = { path = "../parse" } -bumpalo = { version = "3.8.0", features = ["collections"] } diff --git a/compiler/mono/Cargo.toml b/compiler/mono/Cargo.toml index 1771141780..6075ecb44c 100644 --- a/compiler/mono/Cargo.toml +++ b/compiler/mono/Cargo.toml @@ -19,11 +19,4 @@ ven_pretty = { path = "../../vendor/pretty" } morphic_lib = { path = "../../vendor/morphic_lib" } bumpalo = { version = "3.8.0", features = ["collections"] } hashbrown = { version = "0.11.2", features = [ "bumpalo" ] } -ven_ena = { path = "../../vendor/ena" } ven_graph = { path = "../../vendor/pathfinding" } -linked-hash-map = "0.5.4" - -[dev-dependencies] -roc_builtins = { path = "../builtins" } -roc_parse = { path = "../parse" } -roc_solve = { path = "../solve" } diff --git a/compiler/mono/src/expand_rc.rs b/compiler/mono/src/expand_rc.rs index 2812252285..9e311f2ed9 100644 --- a/compiler/mono/src/expand_rc.rs +++ b/compiler/mono/src/expand_rc.rs @@ -1,8 +1,46 @@ +/// UNUSED +/// +/// but kept for future reference +/// +/// +// pub fn optimize_refcount_operations<'i, T>( +// arena: &'a Bump, +// home: ModuleId, +// ident_ids: &'i mut IdentIds, +// procs: &mut MutMap>, +// ) { +// use crate::expand_rc; +// +// let deferred = expand_rc::Deferred { +// inc_dec_map: Default::default(), +// assignments: Vec::new_in(arena), +// decrefs: Vec::new_in(arena), +// }; +// +// let mut env = expand_rc::Env { +// home, +// arena, +// ident_ids, +// layout_map: Default::default(), +// alias_map: Default::default(), +// constructor_map: Default::default(), +// deferred, +// }; +// +// for (_, proc) in procs.iter_mut() { +// let b = expand_rc::expand_and_cancel_proc( +// &mut env, +// arena.alloc(proc.body.clone()), +// proc.args, +// ); +// proc.body = b.clone(); +// } +// } use crate::ir::{BranchInfo, Expr, ModifyRc, Stmt}; use crate::layout::{Layout, UnionLayout}; use bumpalo::collections::Vec; use bumpalo::Bump; -use linked_hash_map::LinkedHashMap; +// use linked_hash_map::LinkedHashMap; use roc_collections::all::MutMap; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index bb84793eac..c0c02f3466 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -370,40 +370,6 @@ impl<'a> Proc<'a> { } } - pub fn optimize_refcount_operations<'i, T>( - arena: &'a Bump, - home: ModuleId, - ident_ids: &'i mut IdentIds, - procs: &mut MutMap>, - ) { - use crate::expand_rc; - - let deferred = expand_rc::Deferred { - inc_dec_map: Default::default(), - assignments: Vec::new_in(arena), - decrefs: Vec::new_in(arena), - }; - - let mut env = expand_rc::Env { - home, - arena, - ident_ids, - layout_map: Default::default(), - alias_map: Default::default(), - constructor_map: Default::default(), - deferred, - }; - - for (_, proc) in procs.iter_mut() { - let b = expand_rc::expand_and_cancel_proc( - &mut env, - arena.alloc(proc.body.clone()), - proc.args, - ); - proc.body = b.clone(); - } - } - fn make_tail_recursive(&mut self, env: &mut Env<'a, '_>) { let mut args = Vec::with_capacity_in(self.args.len(), env.arena); let mut proc_args = Vec::with_capacity_in(self.args.len(), env.arena); diff --git a/compiler/mono/src/lib.rs b/compiler/mono/src/lib.rs index 659b3f7cc8..b1986bc2f8 100644 --- a/compiler/mono/src/lib.rs +++ b/compiler/mono/src/lib.rs @@ -4,7 +4,6 @@ pub mod alias_analysis; pub mod borrow; -pub mod expand_rc; pub mod inc_dec; pub mod ir; pub mod layout; From 06a6e8545be7a52eb72c4145ea66034e2f5e7533 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 15:32:45 +0000 Subject: [PATCH 11/19] FIXME for wasm NumRound --- compiler/gen_wasm/src/low_level.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index a1e556e33b..b3d2ae6626 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -171,12 +171,16 @@ pub fn build_call_low_level<'a>( NumCos => return NotImplemented, NumSqrtUnchecked => return NotImplemented, NumLogUnchecked => return NotImplemented, - NumRound => match ret_layout.value_type() { - I32 => code_builder.f32_nearest(), - I64 => code_builder.f64_nearest(), - F32 => {} - F64 => {} - }, + NumRound => { + // FIXME + // thread 'gen_num::f64_round' panicked at 'called `Result::unwrap()` on an `Err` value: + // Io(Os { code: 2, kind: NotFound, message: "No such file or directory" })', + // compiler/test_gen/src/helpers/wasm.rs:185:53 + // Note: Wasm has a `nearest` op, but it does round-to-even when fraction is exactly 0.5 + // which fails tests. Will this do? Or is specific behaviour important? + let width = float_width_from_layout(ret_layout); + return BuiltinCall(&bitcode::NUM_ROUND[width]); + } NumToFloat => match (ret_layout.value_type(), storage.get(&args[0]).value_type()) { (F32, I32) => code_builder.f32_convert_s_i32(), (F32, I64) => code_builder.f32_convert_s_i64(), From 0ce0e337cd934bcb64a7ece11711f9481349e8c2 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 15:46:34 +0000 Subject: [PATCH 12/19] Enable more tests --- compiler/test_gen/src/gen_num.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index e46e359375..adbeac667c 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -713,7 +713,7 @@ fn gen_int_eq() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn gen_int_neq() { assert_evals_to!( indoc!( @@ -1066,7 +1066,7 @@ fn lt_i64() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn lte_i64() { assert_evals_to!("1 <= 1", true, bool); assert_evals_to!("2 <= 1", false, bool); @@ -1944,7 +1944,7 @@ fn when_on_i32() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn when_on_i16() { assert_evals_to!( indoc!( From 86de39e7f8a8e7c469f97c0d83f2b2e04afa6033 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 20:11:27 +0000 Subject: [PATCH 13/19] Add missing lowlevel from match --- compiler/gen_wasm/src/low_level.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/gen_wasm/src/low_level.rs b/compiler/gen_wasm/src/low_level.rs index b3d2ae6626..48eafa1621 100644 --- a/compiler/gen_wasm/src/low_level.rs +++ b/compiler/gen_wasm/src/low_level.rs @@ -28,7 +28,7 @@ pub fn build_call_low_level<'a>( match lowlevel { StrConcat | StrJoinWith | StrIsEmpty | StrStartsWith | StrStartsWithCodePt - | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 + | StrEndsWith | StrSplit | StrCountGraphemes | StrFromInt | StrFromUtf8 | StrTrimLeft | StrFromUtf8Range | StrToUtf8 | StrRepeat | StrFromFloat | StrTrim | ListLen | ListGetUnsafe | ListSet | ListSingle | ListRepeat | ListReverse | ListConcat | ListContains | ListAppend | ListPrepend | ListJoin | ListRange | ListMap | ListMap2 From 830003c9a34473ea839cb25665929c75113ed4ae Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 10 Nov 2021 20:11:43 +0000 Subject: [PATCH 14/19] Change wasm opcodes to an enum --- .../gen_wasm/src/wasm_module/code_builder.rs | 30 +- compiler/gen_wasm/src/wasm_module/opcodes.rs | 530 ++++++------------ compiler/gen_wasm/src/wasm_module/sections.rs | 12 +- 3 files changed, 196 insertions(+), 376 deletions(-) diff --git a/compiler/gen_wasm/src/wasm_module/code_builder.rs b/compiler/gen_wasm/src/wasm_module/code_builder.rs index 0cc1bcead3..559221bb0b 100644 --- a/compiler/gen_wasm/src/wasm_module/code_builder.rs +++ b/compiler/gen_wasm/src/wasm_module/code_builder.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use roc_module::symbol::Symbol; use super::linking::{IndexRelocType, OffsetRelocType, RelocationEntry}; -use super::opcodes::*; +use super::opcodes::{OpCode, OpCode::*}; use super::serialize::{SerialBuffer, Serialize}; use crate::{round_up_to_alignment, FRAME_ALIGNMENT_BYTES, STACK_POINTER_GLOBAL_ID}; @@ -244,7 +244,7 @@ impl<'a> CodeBuilder<'a> { // Symbol is not on top of the stack. Find it. if let Some(found_index) = self.vm_stack.iter().rposition(|&s| s == symbol) { // Insert a local.set where the value was created - self.add_insertion(pushed_at, SETLOCAL, next_local_id.0); + self.add_insertion(pushed_at, SETLOCAL as u8, next_local_id.0); // Take the value out of the stack where local.set was inserted self.vm_stack.remove(found_index); @@ -267,7 +267,7 @@ impl<'a> CodeBuilder<'a> { Popped { pushed_at } => { // This Symbol is being used for a second time // Insert a local.tee where it was pushed, so we don't interfere with the first usage - self.add_insertion(pushed_at, TEELOCAL, next_local_id.0); + self.add_insertion(pushed_at, TEELOCAL as u8, next_local_id.0); // Insert a local.get at the current position self.get_local(next_local_id); @@ -331,14 +331,14 @@ impl<'a> CodeBuilder<'a> { fn build_stack_frame_push(&mut self, frame_size: i32, frame_pointer: LocalId) { // Can't use the usual instruction methods because they push to self.code. // This is the only case where we push instructions somewhere different. - self.preamble.push(GETGLOBAL); + self.preamble.push(GETGLOBAL as u8); self.preamble.encode_u32(STACK_POINTER_GLOBAL_ID); - self.preamble.push(I32CONST); + self.preamble.push(I32CONST as u8); self.preamble.encode_i32(frame_size); - self.preamble.push(I32SUB); - self.preamble.push(TEELOCAL); + self.preamble.push(I32SUB as u8); + self.preamble.push(TEELOCAL as u8); self.preamble.encode_u32(frame_pointer.0); - self.preamble.push(SETGLOBAL); + self.preamble.push(SETGLOBAL as u8); self.preamble.encode_u32(STACK_POINTER_GLOBAL_ID); } @@ -366,7 +366,7 @@ impl<'a> CodeBuilder<'a> { self.build_stack_frame_pop(aligned_size, frame_ptr_id); } - self.code.push(END); + self.code.push(END as u8); let inner_len = self.preamble.len() + self.code.len() + self.insert_bytes.len(); self.inner_length.encode_u32(inner_len as u32); @@ -433,28 +433,28 @@ impl<'a> CodeBuilder<'a> { /// Base method for generating instructions /// Emits the opcode and simulates VM stack push/pop - fn inst(&mut self, opcode: u8, pops: usize, push: bool) { + fn inst(&mut self, opcode: OpCode, pops: usize, push: bool) { let new_len = self.vm_stack.len() - pops as usize; self.vm_stack.truncate(new_len); if push { self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE); } - self.code.push(opcode); + self.code.push(opcode as u8); } - fn inst_imm8(&mut self, opcode: u8, pops: usize, push: bool, immediate: u8) { + fn inst_imm8(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u8) { self.inst(opcode, pops, push); self.code.push(immediate); } // public for use in test code - pub fn inst_imm32(&mut self, opcode: u8, pops: usize, push: bool, immediate: u32) { + pub fn inst_imm32(&mut self, opcode: OpCode, pops: usize, push: bool, immediate: u32) { self.inst(opcode, pops, push); self.code.encode_u32(immediate); } - fn inst_mem(&mut self, opcode: u8, pops: usize, push: bool, align: Align, offset: u32) { + fn inst_mem(&mut self, opcode: OpCode, pops: usize, push: bool, align: Align, offset: u32) { self.inst(opcode, pops, push); self.code.push(align as u8); self.code.encode_u32(offset); @@ -527,7 +527,7 @@ impl<'a> CodeBuilder<'a> { if has_return_val { self.vm_stack.push(Symbol::WASM_ANONYMOUS_STACK_VALUE); } - self.code.push(CALL); + self.code.push(CALL as u8); // Write the index of the function to be called. // Also make a RelocationEntry so the linker can see that this byte offset relates to a function by name. diff --git a/compiler/gen_wasm/src/wasm_module/opcodes.rs b/compiler/gen_wasm/src/wasm_module/opcodes.rs index c545bc204f..895cf1e5f7 100644 --- a/compiler/gen_wasm/src/wasm_module/opcodes.rs +++ b/compiler/gen_wasm/src/wasm_module/opcodes.rs @@ -1,362 +1,182 @@ -pub const UNREACHABLE: u8 = 0x00; -pub const NOP: u8 = 0x01; -pub const BLOCK: u8 = 0x02; -pub const LOOP: u8 = 0x03; -pub const IF: u8 = 0x04; -pub const ELSE: u8 = 0x05; -pub const END: u8 = 0x0b; -pub const BR: u8 = 0x0c; -pub const BRIF: u8 = 0x0d; -pub const BRTABLE: u8 = 0x0e; -pub const RETURN: u8 = 0x0f; -pub const CALL: u8 = 0x10; -pub const CALLINDIRECT: u8 = 0x11; -pub const DROP: u8 = 0x1a; -pub const SELECT: u8 = 0x1b; -pub const GETLOCAL: u8 = 0x20; -pub const SETLOCAL: u8 = 0x21; -pub const TEELOCAL: u8 = 0x22; -pub const GETGLOBAL: u8 = 0x23; -pub const SETGLOBAL: u8 = 0x24; -pub const I32LOAD: u8 = 0x28; -pub const I64LOAD: u8 = 0x29; -pub const F32LOAD: u8 = 0x2a; -pub const F64LOAD: u8 = 0x2b; -pub const I32LOAD8S: u8 = 0x2c; -pub const I32LOAD8U: u8 = 0x2d; -pub const I32LOAD16S: u8 = 0x2e; -pub const I32LOAD16U: u8 = 0x2f; -pub const I64LOAD8S: u8 = 0x30; -pub const I64LOAD8U: u8 = 0x31; -pub const I64LOAD16S: u8 = 0x32; -pub const I64LOAD16U: u8 = 0x33; -pub const I64LOAD32S: u8 = 0x34; -pub const I64LOAD32U: u8 = 0x35; -pub const I32STORE: u8 = 0x36; -pub const I64STORE: u8 = 0x37; -pub const F32STORE: u8 = 0x38; -pub const F64STORE: u8 = 0x39; -pub const I32STORE8: u8 = 0x3a; -pub const I32STORE16: u8 = 0x3b; -pub const I64STORE8: u8 = 0x3c; -pub const I64STORE16: u8 = 0x3d; -pub const I64STORE32: u8 = 0x3e; -pub const CURRENTMEMORY: u8 = 0x3f; -pub const GROWMEMORY: u8 = 0x40; -pub const I32CONST: u8 = 0x41; -pub const I64CONST: u8 = 0x42; -pub const F32CONST: u8 = 0x43; -pub const F64CONST: u8 = 0x44; -pub const I32EQZ: u8 = 0x45; -pub const I32EQ: u8 = 0x46; -pub const I32NE: u8 = 0x47; -pub const I32LTS: u8 = 0x48; -pub const I32LTU: u8 = 0x49; -pub const I32GTS: u8 = 0x4a; -pub const I32GTU: u8 = 0x4b; -pub const I32LES: u8 = 0x4c; -pub const I32LEU: u8 = 0x4d; -pub const I32GES: u8 = 0x4e; -pub const I32GEU: u8 = 0x4f; -pub const I64EQZ: u8 = 0x50; -pub const I64EQ: u8 = 0x51; -pub const I64NE: u8 = 0x52; -pub const I64LTS: u8 = 0x53; -pub const I64LTU: u8 = 0x54; -pub const I64GTS: u8 = 0x55; -pub const I64GTU: u8 = 0x56; -pub const I64LES: u8 = 0x57; -pub const I64LEU: u8 = 0x58; -pub const I64GES: u8 = 0x59; -pub const I64GEU: u8 = 0x5a; +#[repr(u8)] +#[derive(Debug)] +pub enum OpCode { + UNREACHABLE = 0x00, + NOP = 0x01, + BLOCK = 0x02, + LOOP = 0x03, + IF = 0x04, + ELSE = 0x05, + END = 0x0b, + BR = 0x0c, + BRIF = 0x0d, + BRTABLE = 0x0e, + RETURN = 0x0f, + CALL = 0x10, + CALLINDIRECT = 0x11, + DROP = 0x1a, + SELECT = 0x1b, + GETLOCAL = 0x20, + SETLOCAL = 0x21, + TEELOCAL = 0x22, + GETGLOBAL = 0x23, + SETGLOBAL = 0x24, + I32LOAD = 0x28, + I64LOAD = 0x29, + F32LOAD = 0x2a, + F64LOAD = 0x2b, + I32LOAD8S = 0x2c, + I32LOAD8U = 0x2d, + I32LOAD16S = 0x2e, + I32LOAD16U = 0x2f, + I64LOAD8S = 0x30, + I64LOAD8U = 0x31, + I64LOAD16S = 0x32, + I64LOAD16U = 0x33, + I64LOAD32S = 0x34, + I64LOAD32U = 0x35, + I32STORE = 0x36, + I64STORE = 0x37, + F32STORE = 0x38, + F64STORE = 0x39, + I32STORE8 = 0x3a, + I32STORE16 = 0x3b, + I64STORE8 = 0x3c, + I64STORE16 = 0x3d, + I64STORE32 = 0x3e, + CURRENTMEMORY = 0x3f, + GROWMEMORY = 0x40, + I32CONST = 0x41, + I64CONST = 0x42, + F32CONST = 0x43, + F64CONST = 0x44, + I32EQZ = 0x45, + I32EQ = 0x46, + I32NE = 0x47, + I32LTS = 0x48, + I32LTU = 0x49, + I32GTS = 0x4a, + I32GTU = 0x4b, + I32LES = 0x4c, + I32LEU = 0x4d, + I32GES = 0x4e, + I32GEU = 0x4f, + I64EQZ = 0x50, + I64EQ = 0x51, + I64NE = 0x52, + I64LTS = 0x53, + I64LTU = 0x54, + I64GTS = 0x55, + I64GTU = 0x56, + I64LES = 0x57, + I64LEU = 0x58, + I64GES = 0x59, + I64GEU = 0x5a, -pub const F32EQ: u8 = 0x5b; -pub const F32NE: u8 = 0x5c; -pub const F32LT: u8 = 0x5d; -pub const F32GT: u8 = 0x5e; -pub const F32LE: u8 = 0x5f; -pub const F32GE: u8 = 0x60; + F32EQ = 0x5b, + F32NE = 0x5c, + F32LT = 0x5d, + F32GT = 0x5e, + F32LE = 0x5f, + F32GE = 0x60, -pub const F64EQ: u8 = 0x61; -pub const F64NE: u8 = 0x62; -pub const F64LT: u8 = 0x63; -pub const F64GT: u8 = 0x64; -pub const F64LE: u8 = 0x65; -pub const F64GE: u8 = 0x66; + F64EQ = 0x61, + F64NE = 0x62, + F64LT = 0x63, + F64GT = 0x64, + F64LE = 0x65, + F64GE = 0x66, -pub const I32CLZ: u8 = 0x67; -pub const I32CTZ: u8 = 0x68; -pub const I32POPCNT: u8 = 0x69; -pub const I32ADD: u8 = 0x6a; -pub const I32SUB: u8 = 0x6b; -pub const I32MUL: u8 = 0x6c; -pub const I32DIVS: u8 = 0x6d; -pub const I32DIVU: u8 = 0x6e; -pub const I32REMS: u8 = 0x6f; -pub const I32REMU: u8 = 0x70; -pub const I32AND: u8 = 0x71; -pub const I32OR: u8 = 0x72; -pub const I32XOR: u8 = 0x73; -pub const I32SHL: u8 = 0x74; -pub const I32SHRS: u8 = 0x75; -pub const I32SHRU: u8 = 0x76; -pub const I32ROTL: u8 = 0x77; -pub const I32ROTR: u8 = 0x78; + I32CLZ = 0x67, + I32CTZ = 0x68, + I32POPCNT = 0x69, + I32ADD = 0x6a, + I32SUB = 0x6b, + I32MUL = 0x6c, + I32DIVS = 0x6d, + I32DIVU = 0x6e, + I32REMS = 0x6f, + I32REMU = 0x70, + I32AND = 0x71, + I32OR = 0x72, + I32XOR = 0x73, + I32SHL = 0x74, + I32SHRS = 0x75, + I32SHRU = 0x76, + I32ROTL = 0x77, + I32ROTR = 0x78, -pub const I64CLZ: u8 = 0x79; -pub const I64CTZ: u8 = 0x7a; -pub const I64POPCNT: u8 = 0x7b; -pub const I64ADD: u8 = 0x7c; -pub const I64SUB: u8 = 0x7d; -pub const I64MUL: u8 = 0x7e; -pub const I64DIVS: u8 = 0x7f; -pub const I64DIVU: u8 = 0x80; -pub const I64REMS: u8 = 0x81; -pub const I64REMU: u8 = 0x82; -pub const I64AND: u8 = 0x83; -pub const I64OR: u8 = 0x84; -pub const I64XOR: u8 = 0x85; -pub const I64SHL: u8 = 0x86; -pub const I64SHRS: u8 = 0x87; -pub const I64SHRU: u8 = 0x88; -pub const I64ROTL: u8 = 0x89; -pub const I64ROTR: u8 = 0x8a; -pub const F32ABS: u8 = 0x8b; -pub const F32NEG: u8 = 0x8c; -pub const F32CEIL: u8 = 0x8d; -pub const F32FLOOR: u8 = 0x8e; -pub const F32TRUNC: u8 = 0x8f; -pub const F32NEAREST: u8 = 0x90; -pub const F32SQRT: u8 = 0x91; -pub const F32ADD: u8 = 0x92; -pub const F32SUB: u8 = 0x93; -pub const F32MUL: u8 = 0x94; -pub const F32DIV: u8 = 0x95; -pub const F32MIN: u8 = 0x96; -pub const F32MAX: u8 = 0x97; -pub const F32COPYSIGN: u8 = 0x98; -pub const F64ABS: u8 = 0x99; -pub const F64NEG: u8 = 0x9a; -pub const F64CEIL: u8 = 0x9b; -pub const F64FLOOR: u8 = 0x9c; -pub const F64TRUNC: u8 = 0x9d; -pub const F64NEAREST: u8 = 0x9e; -pub const F64SQRT: u8 = 0x9f; -pub const F64ADD: u8 = 0xa0; -pub const F64SUB: u8 = 0xa1; -pub const F64MUL: u8 = 0xa2; -pub const F64DIV: u8 = 0xa3; -pub const F64MIN: u8 = 0xa4; -pub const F64MAX: u8 = 0xa5; -pub const F64COPYSIGN: u8 = 0xa6; + I64CLZ = 0x79, + I64CTZ = 0x7a, + I64POPCNT = 0x7b, + I64ADD = 0x7c, + I64SUB = 0x7d, + I64MUL = 0x7e, + I64DIVS = 0x7f, + I64DIVU = 0x80, + I64REMS = 0x81, + I64REMU = 0x82, + I64AND = 0x83, + I64OR = 0x84, + I64XOR = 0x85, + I64SHL = 0x86, + I64SHRS = 0x87, + I64SHRU = 0x88, + I64ROTL = 0x89, + I64ROTR = 0x8a, + F32ABS = 0x8b, + F32NEG = 0x8c, + F32CEIL = 0x8d, + F32FLOOR = 0x8e, + F32TRUNC = 0x8f, + F32NEAREST = 0x90, + F32SQRT = 0x91, + F32ADD = 0x92, + F32SUB = 0x93, + F32MUL = 0x94, + F32DIV = 0x95, + F32MIN = 0x96, + F32MAX = 0x97, + F32COPYSIGN = 0x98, + F64ABS = 0x99, + F64NEG = 0x9a, + F64CEIL = 0x9b, + F64FLOOR = 0x9c, + F64TRUNC = 0x9d, + F64NEAREST = 0x9e, + F64SQRT = 0x9f, + F64ADD = 0xa0, + F64SUB = 0xa1, + F64MUL = 0xa2, + F64DIV = 0xa3, + F64MIN = 0xa4, + F64MAX = 0xa5, + F64COPYSIGN = 0xa6, -pub const I32WRAPI64: u8 = 0xa7; -pub const I32TRUNCSF32: u8 = 0xa8; -pub const I32TRUNCUF32: u8 = 0xa9; -pub const I32TRUNCSF64: u8 = 0xaa; -pub const I32TRUNCUF64: u8 = 0xab; -pub const I64EXTENDSI32: u8 = 0xac; -pub const I64EXTENDUI32: u8 = 0xad; -pub const I64TRUNCSF32: u8 = 0xae; -pub const I64TRUNCUF32: u8 = 0xaf; -pub const I64TRUNCSF64: u8 = 0xb0; -pub const I64TRUNCUF64: u8 = 0xb1; -pub const F32CONVERTSI32: u8 = 0xb2; -pub const F32CONVERTUI32: u8 = 0xb3; -pub const F32CONVERTSI64: u8 = 0xb4; -pub const F32CONVERTUI64: u8 = 0xb5; -pub const F32DEMOTEF64: u8 = 0xb6; -pub const F64CONVERTSI32: u8 = 0xb7; -pub const F64CONVERTUI32: u8 = 0xb8; -pub const F64CONVERTSI64: u8 = 0xb9; -pub const F64CONVERTUI64: u8 = 0xba; -pub const F64PROMOTEF32: u8 = 0xbb; + I32WRAPI64 = 0xa7, + I32TRUNCSF32 = 0xa8, + I32TRUNCUF32 = 0xa9, + I32TRUNCSF64 = 0xaa, + I32TRUNCUF64 = 0xab, + I64EXTENDSI32 = 0xac, + I64EXTENDUI32 = 0xad, + I64TRUNCSF32 = 0xae, + I64TRUNCUF32 = 0xaf, + I64TRUNCSF64 = 0xb0, + I64TRUNCUF64 = 0xb1, + F32CONVERTSI32 = 0xb2, + F32CONVERTUI32 = 0xb3, + F32CONVERTSI64 = 0xb4, + F32CONVERTUI64 = 0xb5, + F32DEMOTEF64 = 0xb6, + F64CONVERTSI32 = 0xb7, + F64CONVERTUI32 = 0xb8, + F64CONVERTSI64 = 0xb9, + F64CONVERTUI64 = 0xba, + F64PROMOTEF32 = 0xbb, -pub const I32REINTERPRETF32: u8 = 0xbc; -pub const I64REINTERPRETF64: u8 = 0xbd; -pub const F32REINTERPRETI32: u8 = 0xbe; -pub const F64REINTERPRETI64: u8 = 0xbf; - -pub fn dbg_opcode_name(opcode: u8) -> &'static str { - match opcode { - UNREACHABLE => "UNREACHABLE", - NOP => "NOP", - BLOCK => "BLOCK", - LOOP => "LOOP", - IF => "IF", - ELSE => "ELSE", - END => "END", - BR => "BR", - BRIF => "BRIF", - BRTABLE => "BRTABLE", - RETURN => "RETURN", - CALL => "CALL", - CALLINDIRECT => "CALLINDIRECT", - DROP => "DROP", - SELECT => "SELECT", - GETLOCAL => "GETLOCAL", - SETLOCAL => "SETLOCAL", - TEELOCAL => "TEELOCAL", - GETGLOBAL => "GETGLOBAL", - SETGLOBAL => "SETGLOBAL", - I32LOAD => "I32LOAD", - I64LOAD => "I64LOAD", - F32LOAD => "F32LOAD", - F64LOAD => "F64LOAD", - I32LOAD8S => "I32LOAD8S", - I32LOAD8U => "I32LOAD8U", - I32LOAD16S => "I32LOAD16S", - I32LOAD16U => "I32LOAD16U", - I64LOAD8S => "I64LOAD8S", - I64LOAD8U => "I64LOAD8U", - I64LOAD16S => "I64LOAD16S", - I64LOAD16U => "I64LOAD16U", - I64LOAD32S => "I64LOAD32S", - I64LOAD32U => "I64LOAD32U", - I32STORE => "I32STORE", - I64STORE => "I64STORE", - F32STORE => "F32STORE", - F64STORE => "F64STORE", - I32STORE8 => "I32STORE8", - I32STORE16 => "I32STORE16", - I64STORE8 => "I64STORE8", - I64STORE16 => "I64STORE16", - I64STORE32 => "I64STORE32", - CURRENTMEMORY => "CURRENTMEMORY", - GROWMEMORY => "GROWMEMORY", - I32CONST => "I32CONST", - I64CONST => "I64CONST", - F32CONST => "F32CONST", - F64CONST => "F64CONST", - I32EQZ => "I32EQZ", - I32EQ => "I32EQ", - I32NE => "I32NE", - I32LTS => "I32LTS", - I32LTU => "I32LTU", - I32GTS => "I32GTS", - I32GTU => "I32GTU", - I32LES => "I32LES", - I32LEU => "I32LEU", - I32GES => "I32GES", - I32GEU => "I32GEU", - I64EQZ => "I64EQZ", - I64EQ => "I64EQ", - I64NE => "I64NE", - I64LTS => "I64LTS", - I64LTU => "I64LTU", - I64GTS => "I64GTS", - I64GTU => "I64GTU", - I64LES => "I64LES", - I64LEU => "I64LEU", - I64GES => "I64GES", - I64GEU => "I64GEU", - - F32EQ => "F32EQ", - F32NE => "F32NE", - F32LT => "F32LT", - F32GT => "F32GT", - F32LE => "F32LE", - F32GE => "F32GE", - - F64EQ => "F64EQ", - F64NE => "F64NE", - F64LT => "F64LT", - F64GT => "F64GT", - F64LE => "F64LE", - F64GE => "F64GE", - - I32CLZ => "I32CLZ", - I32CTZ => "I32CTZ", - I32POPCNT => "I32POPCNT", - I32ADD => "I32ADD", - I32SUB => "I32SUB", - I32MUL => "I32MUL", - I32DIVS => "I32DIVS", - I32DIVU => "I32DIVU", - I32REMS => "I32REMS", - I32REMU => "I32REMU", - I32AND => "I32AND", - I32OR => "I32OR", - I32XOR => "I32XOR", - I32SHL => "I32SHL", - I32SHRS => "I32SHRS", - I32SHRU => "I32SHRU", - I32ROTL => "I32ROTL", - I32ROTR => "I32ROTR", - - I64CLZ => "I64CLZ", - I64CTZ => "I64CTZ", - I64POPCNT => "I64POPCNT", - I64ADD => "I64ADD", - I64SUB => "I64SUB", - I64MUL => "I64MUL", - I64DIVS => "I64DIVS", - I64DIVU => "I64DIVU", - I64REMS => "I64REMS", - I64REMU => "I64REMU", - I64AND => "I64AND", - I64OR => "I64OR", - I64XOR => "I64XOR", - I64SHL => "I64SHL", - I64SHRS => "I64SHRS", - I64SHRU => "I64SHRU", - I64ROTL => "I64ROTL", - I64ROTR => "I64ROTR", - F32ABS => "F32ABS", - F32NEG => "F32NEG", - F32CEIL => "F32CEIL", - F32FLOOR => "F32FLOOR", - F32TRUNC => "F32TRUNC", - F32NEAREST => "F32NEAREST", - F32SQRT => "F32SQRT", - F32ADD => "F32ADD", - F32SUB => "F32SUB", - F32MUL => "F32MUL", - F32DIV => "F32DIV", - F32MIN => "F32MIN", - F32MAX => "F32MAX", - F32COPYSIGN => "F32COPYSIGN", - F64ABS => "F64ABS", - F64NEG => "F64NEG", - F64CEIL => "F64CEIL", - F64FLOOR => "F64FLOOR", - F64TRUNC => "F64TRUNC", - F64NEAREST => "F64NEAREST", - F64SQRT => "F64SQRT", - F64ADD => "F64ADD", - F64SUB => "F64SUB", - F64MUL => "F64MUL", - F64DIV => "F64DIV", - F64MIN => "F64MIN", - F64MAX => "F64MAX", - F64COPYSIGN => "F64COPYSIGN", - - I32WRAPI64 => "I32WRAPI64", - I32TRUNCSF32 => "I32TRUNCSF32", - I32TRUNCUF32 => "I32TRUNCUF32", - I32TRUNCSF64 => "I32TRUNCSF64", - I32TRUNCUF64 => "I32TRUNCUF64", - I64EXTENDSI32 => "I64EXTENDSI32", - I64EXTENDUI32 => "I64EXTENDUI32", - I64TRUNCSF32 => "I64TRUNCSF32", - I64TRUNCUF32 => "I64TRUNCUF32", - I64TRUNCSF64 => "I64TRUNCSF64", - I64TRUNCUF64 => "I64TRUNCUF64", - F32CONVERTSI32 => "F32CONVERTSI32", - F32CONVERTUI32 => "F32CONVERTUI32", - F32CONVERTSI64 => "F32CONVERTSI64", - F32CONVERTUI64 => "F32CONVERTUI64", - F32DEMOTEF64 => "F32DEMOTEF64", - F64CONVERTSI32 => "F64CONVERTSI32", - F64CONVERTUI32 => "F64CONVERTUI32", - F64CONVERTSI64 => "F64CONVERTSI64", - F64CONVERTUI64 => "F64CONVERTUI64", - F64PROMOTEF32 => "F64PROMOTEF32", - - I32REINTERPRETF32 => "I32REINTERPRETF32", - I64REINTERPRETF64 => "I64REINTERPRETF64", - F32REINTERPRETI32 => "F32REINTERPRETI32", - F64REINTERPRETI64 => "F64REINTERPRETI64", - _ => "(unknown)", - } + I32REINTERPRETF32 = 0xbc, + I64REINTERPRETF64 = 0xbd, + F32REINTERPRETI32 = 0xbe, + F64REINTERPRETI64 = 0xbf, } diff --git a/compiler/gen_wasm/src/wasm_module/sections.rs b/compiler/gen_wasm/src/wasm_module/sections.rs index dc0b3ec978..2ff0805604 100644 --- a/compiler/gen_wasm/src/wasm_module/sections.rs +++ b/compiler/gen_wasm/src/wasm_module/sections.rs @@ -4,7 +4,7 @@ use bumpalo::Bump; use super::linking::{ IndexRelocType, LinkingSection, RelocationEntry, RelocationSection, SymInfo, WasmObjectSymbol, }; -use super::opcodes; +use super::opcodes::OpCode; use super::serialize::{SerialBuffer, Serialize}; use super::{CodeBuilder, ValueType}; @@ -353,23 +353,23 @@ impl Serialize for ConstExpr { fn serialize(&self, buffer: &mut T) { match self { ConstExpr::I32(x) => { - buffer.append_u8(opcodes::I32CONST); + buffer.append_u8(OpCode::I32CONST as u8); buffer.encode_i32(*x); } ConstExpr::I64(x) => { - buffer.append_u8(opcodes::I64CONST); + buffer.append_u8(OpCode::I64CONST as u8); buffer.encode_i64(*x); } ConstExpr::F32(x) => { - buffer.append_u8(opcodes::F32CONST); + buffer.append_u8(OpCode::F32CONST as u8); buffer.encode_f32(*x); } ConstExpr::F64(x) => { - buffer.append_u8(opcodes::F64CONST); + buffer.append_u8(OpCode::F64CONST as u8); buffer.encode_f64(*x); } } - buffer.append_u8(opcodes::END); + buffer.append_u8(OpCode::END as u8); } } From 5d7b4b7ad0f5bcc8cd7b8b43377bb61b6e9e49e9 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 10 Nov 2021 22:09:01 +0100 Subject: [PATCH 15/19] change roc call result; adding an extra field for the error message pointer When the returned value was smaller than a pointer, there was no space for the error message pointer. --- compiler/gen_llvm/src/llvm/build.rs | 91 +++++++++++------------------ compiler/gen_llvm/src/run_roc.rs | 19 +++--- compiler/test_gen/src/gen_list.rs | 2 +- 3 files changed, 46 insertions(+), 66 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index 3fb3e81adf..f8a16ea1c6 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -3183,8 +3183,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( builder.position_at_end(entry); - let elements = [Layout::Builtin(Builtin::Int64), return_layout]; - let wrapped_layout = Layout::Struct(&elements); + let wrapped_layout = roc_result_layout(env.arena, return_layout); call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call) } else { call_roc_function(env, roc_function, &return_layout, arguments_for_call) @@ -3212,18 +3211,11 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( return_layout: Layout<'a>, c_function_name: &str, ) -> FunctionValue<'ctx> { - let context = env.context; - // a tagged union to indicate to the test loader that a panic occurred. // especially when running 32-bit binaries on a 64-bit machine, there // does not seem to be a smarter solution - let wrapper_return_type = context.struct_type( - &[ - context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), - ], - false, - ); + let wrapper_return_type = + roc_result_type(env, roc_function.get_type().get_return_type().unwrap()); let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); for layout in arguments { @@ -3346,8 +3338,6 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( return_layout: Layout<'a>, c_function_name: &str, ) -> FunctionValue<'ctx> { - let context = env.context; - if env.is_gen_test { return expose_function_to_host_help_c_abi_gen_test( env, @@ -3369,15 +3359,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( ); let wrapper_return_type = if env.is_gen_test { - context - .struct_type( - &[ - context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), - ], - false, - ) - .into() + roc_result_type(env, roc_function.get_type().get_return_type().unwrap()).into() } else { roc_function.get_type().get_return_type().unwrap() }; @@ -3542,11 +3524,7 @@ where let context = env.context; let builder = env.builder; - let call_result_type = context.struct_type( - &[context.i64_type().into(), return_type.as_basic_type_enum()], - false, - ); - + let call_result_type = roc_result_type(env, return_type.as_basic_type_enum()); let result_alloca = builder.build_alloca(call_result_type, "result"); let then_block = context.append_basic_block(parent, "then_block"); @@ -3648,12 +3626,8 @@ where ptr_int }; - let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic); - let return_type = context.struct_type(&[context.i64_type().into(), u8_ptr.into()], false); - // let return_type = call_result_type; - let return_value = { - let v1 = return_type.const_zero(); + let v1 = call_result_type.const_zero(); // flag is non-zero, indicating failure let flag = context.i64_type().const_int(1, false); @@ -3668,17 +3642,7 @@ where v3 }; - // bitcast result alloca so we can store our concrete type { flag, error_msg } in there - let result_alloca_bitcast = builder - .build_bitcast( - result_alloca, - return_type.ptr_type(AddressSpace::Generic), - "result_alloca_bitcast", - ) - .into_pointer_value(); - - // store our return value - builder.build_store(result_alloca_bitcast, return_value); + builder.build_store(result_alloca, return_value); env.builder.build_unconditional_branch(cont_block); } @@ -3701,6 +3665,30 @@ fn make_exception_catcher<'a, 'ctx, 'env>( function_value } +fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>) -> Layout<'a> { + let elements = [ + Layout::Builtin(Builtin::Int64), + Layout::Builtin(Builtin::Usize), + return_layout, + ]; + + Layout::Struct(arena.alloc(elements)) +} + +fn roc_result_type<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + return_type: BasicTypeEnum<'ctx>, +) -> StructType<'ctx> { + env.context.struct_type( + &[ + env.context.i64_type().into(), + env.context.i8_type().ptr_type(AddressSpace::Generic).into(), + return_type, + ], + false, + ) +} + fn make_good_roc_result<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, return_value: BasicValueEnum<'ctx>, @@ -3708,18 +3696,14 @@ fn make_good_roc_result<'a, 'ctx, 'env>( let context = env.context; let builder = env.builder; - let content_type = return_value.get_type(); - let wrapper_return_type = - context.struct_type(&[context.i64_type().into(), content_type], false); - - let v1 = wrapper_return_type.const_zero(); + let v1 = roc_result_type(env, return_value.get_type()).const_zero(); let v2 = builder .build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error") .unwrap(); let v3 = builder - .build_insert_value(v2, return_value, 1, "set_call_result") + .build_insert_value(v2, return_value, 2, "set_call_result") .unwrap(); v3.into_struct_value().into() @@ -3738,13 +3722,8 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( let roc_function_type = roc_function.get_type(); let argument_types = roc_function_type.get_param_types(); - let wrapper_return_type = context.struct_type( - &[ - context.i64_type().into(), - roc_function.get_type().get_return_type().unwrap(), - ], - false, - ); + let wrapper_return_type = + roc_result_type(env, roc_function.get_type().get_return_type().unwrap()); // argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into()); diff --git a/compiler/gen_llvm/src/run_roc.rs b/compiler/gen_llvm/src/run_roc.rs index 884ef41fcc..cb877c6495 100644 --- a/compiler/gen_llvm/src/run_roc.rs +++ b/compiler/gen_llvm/src/run_roc.rs @@ -1,22 +1,23 @@ use std::ffi::CString; +use std::mem::MaybeUninit; use std::os::raw::c_char; -use RocCallResult::*; /// This must have the same size as the repr() of RocCallResult! pub const ROC_CALL_RESULT_DISCRIMINANT_SIZE: usize = std::mem::size_of::(); -#[repr(u64)] -pub enum RocCallResult { - Success(T), - Failure(*mut c_char), +#[repr(C)] +pub struct RocCallResult { + tag: u64, + error_msg: *mut c_char, + value: MaybeUninit, } impl From> for Result { fn from(call_result: RocCallResult) -> Self { - match call_result { - Success(value) => Ok(value), - Failure(failure) => Err({ - let raw = unsafe { CString::from_raw(failure) }; + match call_result.tag { + 0 => Ok(unsafe { call_result.value.assume_init() }), + _ => Err({ + let raw = unsafe { CString::from_raw(call_result.error_msg) }; let result = format!("{:?}", raw); diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 521a96db84..5e0f737e72 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -2341,7 +2341,7 @@ fn list_any() { #[test] #[cfg(any(feature = "gen-llvm"))] -#[ignore] +#[should_panic(expected = r#"Roc failed with message: "UnresolvedTypeVar"#)] fn list_any_empty_with_unknown_element_type() { // Segfaults with invalid memory reference. Running this as a stand-alone // Roc program, generates the following error message: From acb26002c8a5cd0a3a1bc866b9391e94560101e2 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 10 Nov 2021 23:36:16 +0100 Subject: [PATCH 16/19] fix repl --- cli/tests/repl_eval.rs | 13 ------------- compiler/gen_llvm/src/run_roc.rs | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/cli/tests/repl_eval.rs b/cli/tests/repl_eval.rs index 6633a74f8b..f9b0ba8640 100644 --- a/cli/tests/repl_eval.rs +++ b/cli/tests/repl_eval.rs @@ -7,19 +7,6 @@ extern crate indoc; #[cfg(test)] mod repl_eval { use cli_utils::helpers; - use roc_gen_llvm::run_roc::RocCallResult; - - #[test] - fn check_discriminant_size() { - // tells us if the size of the discriminant has changed. Lots of other code - // relies on this size - let value: i64 = 1234; - assert_eq!( - std::mem::size_of_val(&RocCallResult::Success(value)), - roc_gen_llvm::run_roc::ROC_CALL_RESULT_DISCRIMINANT_SIZE - + std::mem::size_of_val(&value) - ) - } const ERROR_MESSAGE_START: char = '─'; diff --git a/compiler/gen_llvm/src/run_roc.rs b/compiler/gen_llvm/src/run_roc.rs index cb877c6495..4428f68fbf 100644 --- a/compiler/gen_llvm/src/run_roc.rs +++ b/compiler/gen_llvm/src/run_roc.rs @@ -87,7 +87,7 @@ macro_rules! run_jit_function_dynamic_type { .ok_or(format!("Unable to JIT compile `{}`", $main_fn_name)) .expect("errored"); - let size = roc_gen_llvm::run_roc::ROC_CALL_RESULT_DISCRIMINANT_SIZE + $bytes; + let size = std::mem::size_of::>() + $bytes; let layout = std::alloc::Layout::array::(size).unwrap(); let result = std::alloc::alloc(layout); main(result); @@ -95,7 +95,7 @@ macro_rules! run_jit_function_dynamic_type { let flag = *result; if flag == 0 { - $transform(result.offset(8) as *const u8) + $transform(result.add(std::mem::size_of::>()) as *const u8) } else { use std::ffi::CString; use std::os::raw::c_char; From 6a694b7772b5f5a7dad364412c614da1ad3c405c Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Wed, 10 Nov 2021 18:47:48 -0800 Subject: [PATCH 17/19] Use collection_trailing_sep_e for packages decl, to allow trailing commas there --- compiler/parse/src/header.rs | 8 ++--- compiler/parse/src/module.rs | 10 ++++-- compiler/parse/src/parser.rs | 1 + compiler/parse/tests/test_parse.rs | 56 ++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/compiler/parse/src/header.rs b/compiler/parse/src/header.rs index b373bd3f59..fb6f50b481 100644 --- a/compiler/parse/src/header.rs +++ b/compiler/parse/src/header.rs @@ -9,13 +9,13 @@ use crate::string_literal; use bumpalo::collections::Vec; use roc_region::all::Loc; -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct PackageName<'a> { pub account: &'a str, pub pkg: &'a str, } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum Version<'a> { Exact(&'a str), Range { @@ -32,7 +32,7 @@ pub enum VersionComparison { DisallowsEqual, } -#[derive(Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum PackageOrPath<'a> { Package(PackageName<'a>, Version<'a>), Path(StrLiteral<'a>), @@ -240,7 +240,7 @@ pub enum TypedIdent<'a> { SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum PackageEntry<'a> { Entry { shorthand: &'a str, diff --git a/compiler/parse/src/module.rs b/compiler/parse/src/module.rs index 72298d6209..b4088b5fdf 100644 --- a/compiler/parse/src/module.rs +++ b/compiler/parse/src/module.rs @@ -586,6 +586,7 @@ struct Packages<'a> { before_packages_keyword: &'a [CommentOrNewline<'a>], after_packages_keyword: &'a [CommentOrNewline<'a>], + final_comments: &'a [CommentOrNewline<'a>], } #[inline(always)] @@ -602,21 +603,24 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> { EPackages::IndentPackages, EPackages::IndentListStart ), - collection_e!( + collection_trailing_sep_e!( word1(b'{', EPackages::ListStart), specialize(EPackages::PackageEntry, loc!(package_entry())), word1(b',', EPackages::ListEnd), word1(b'}', EPackages::ListEnd), min_indent, + EPackages::Open, EPackages::Space, - EPackages::IndentListEnd + EPackages::IndentListEnd, + PackageEntry::SpaceBefore ) ), - |((before_packages_keyword, after_packages_keyword), entries)| { + |((before_packages_keyword, after_packages_keyword), (entries, final_comments))| { Packages { entries, before_packages_keyword, after_packages_keyword, + final_comments, } } ) diff --git a/compiler/parse/src/parser.rs b/compiler/parse/src/parser.rs index 89e4968668..b7e7e3bf74 100644 --- a/compiler/parse/src/parser.rs +++ b/compiler/parse/src/parser.rs @@ -265,6 +265,7 @@ pub enum ETypedIdent<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub enum EPackages<'a> { + Open(Row, Col), Space(BadInputError, Row, Col), Packages(Row, Col), IndentPackages(Row, Col), diff --git a/compiler/parse/tests/test_parse.rs b/compiler/parse/tests/test_parse.rs index 38a2b6ae7a..676863e87d 100644 --- a/compiler/parse/tests/test_parse.rs +++ b/compiler/parse/tests/test_parse.rs @@ -3223,6 +3223,62 @@ mod test_parse { assert_eq!(Ok(expected), actual); } + #[test] + fn full_app_header_trailing_commas() { + use ExposesEntry::Exposed; + use PackageOrPath::Path; + + let newlines = &[Newline]; + let pkg_entry = PackageEntry::Entry { + shorthand: "base", + spaces_after_shorthand: &[], + package_or_path: Located::new(1, 1, 21, 33, Path(PlainLine("./platform"))), + }; + let loc_pkg_entry = Located::new(1, 1, 15, 33, pkg_entry); + let arena = Bump::new(); + let packages = bumpalo::vec![in &arena; loc_pkg_entry]; + let import = ImportsEntry::Package("foo", ModuleName::new("Bar.Baz"), Vec::new_in(&arena)); + let loc_import = Located::new(2, 2, 14, 25, import); + let imports = bumpalo::vec![in &arena; loc_import]; + let provide_entry = Located::new(3, 3, 15, 24, Exposed("quicksort")); + let provides = bumpalo::vec![in &arena; provide_entry]; + let module_name = StrLiteral::PlainLine("quicksort"); + + let header = AppHeader { + before_header: &[], + name: Located::new(0, 0, 4, 15, module_name), + packages, + imports, + provides, + to: Located::new(3, 3, 30, 34, To::ExistingPackage("base")), + after_app_keyword: &[], + before_packages: newlines, + after_packages: &[], + before_imports: newlines, + after_imports: &[], + before_provides: newlines, + after_provides: &[], + before_to: &[], + after_to: &[], + }; + + let expected = roc_parse::ast::Module::App { header }; + + let src = indoc!( + r#" + app "quicksort" + packages { base: "./platform", } + imports [ foo.Bar.Baz ] + provides [ quicksort ] to base + "# + ); + + let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes())) + .map(|tuple| tuple.0); + + assert_eq!(Ok(expected), actual); + } + #[test] fn empty_platform_header() { let pkg_name = PackageName { From 0e9d7d8b7b899905d1bf8c982dd1be372beb8b06 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Wed, 10 Nov 2021 19:46:25 -0800 Subject: [PATCH 18/19] Fix clippy lints due to clones on now-Copy types --- compiler/load/src/file.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 60e8d7a5f2..7cb65d0dbe 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -1734,7 +1734,7 @@ fn update<'a>( let mut shorthands = (*state.arc_shorthands).lock(); for (shorthand, package_or_path) in header.packages.iter() { - shorthands.insert(shorthand, package_or_path.clone()); + shorthands.insert(shorthand, *package_or_path); } if let PkgConfig { @@ -2273,7 +2273,7 @@ fn finish_specialization( let package_or_path = match platform_path { Valid(To::ExistingPackage(shorthand)) => { match (*state.arc_shorthands).lock().get(shorthand) { - Some(p_or_p) => p_or_p.clone(), + Some(p_or_p) => *p_or_p, None => unreachable!(), } } @@ -2978,7 +2978,7 @@ fn send_header<'a>( package_or_path, .. } => { - package_entries.insert(*shorthand, package_or_path.value.clone()); + package_entries.insert(*shorthand, package_or_path.value); } SpaceBefore(inner, _) | SpaceAfter(inner, _) => { parse_entries.push(inner); @@ -3211,7 +3211,7 @@ fn send_header_two<'a>( package_or_path, .. } => { - package_entries.insert(*shorthand, package_or_path.value.clone()); + package_entries.insert(*shorthand, package_or_path.value); } SpaceBefore(inner, _) | SpaceAfter(inner, _) => { parse_entries.push(inner); From 053fbbba0b83d63982dd378e75654bf27eb03225 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Thu, 11 Nov 2021 09:52:11 +0100 Subject: [PATCH 19/19] add unicode TODO --- ast/src/lang/core/str.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ast/src/lang/core/str.rs b/ast/src/lang/core/str.rs index 47177b2e08..0463f77969 100644 --- a/ast/src/lang/core/str.rs +++ b/ast/src/lang/core/str.rs @@ -186,6 +186,7 @@ pub fn update_str_expr( let insert_either = match str_expr { Expr2::SmallStr(arr_string) => { + // TODO make sure this works for unicode "characters" let insert_res = arr_string.try_insert(insert_index as u8, new_char); match insert_res {