diff --git a/compiler/gen_dev/src/generic64/aarch64.rs b/compiler/gen_dev/src/generic64/aarch64.rs index 890995c726..6363ce14b5 100644 --- a/compiler/gen_dev/src/generic64/aarch64.rs +++ b/compiler/gen_dev/src/generic64/aarch64.rs @@ -510,6 +510,15 @@ impl Assembler for AArch64Assembler { unimplemented!("registers less than not implemented yet for AArch64"); } + #[inline(always)] + fn is_zero_reg64_reg64( + _buf: &mut Vec<'_, u8>, + _dst: AArch64GeneralReg, + _src: AArch64GeneralReg, + ) { + unimplemented!("registers is zero not implemented yet for AArch64"); + } + #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { ret_reg64(buf, AArch64GeneralReg::LR) diff --git a/compiler/gen_dev/src/generic64/mod.rs b/compiler/gen_dev/src/generic64/mod.rs index 354c545ebc..70431216ca 100644 --- a/compiler/gen_dev/src/generic64/mod.rs +++ b/compiler/gen_dev/src/generic64/mod.rs @@ -186,6 +186,8 @@ pub trait Assembler { src2: GeneralReg, ); + fn is_zero_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg); + fn ret(buf: &mut Vec<'_, u8>); } @@ -500,12 +502,7 @@ impl< // move return value to dst. match ret_layout { - Layout::Builtin(Builtin::Int1) => { - let dst_reg = self.claim_general_reg(dst)?; - ASM::mov_reg64_reg64(&mut self.buf, dst_reg, CC::GENERAL_RETURN_REGS[0]); - Ok(()) - } - Layout::Builtin(Builtin::Int64) => { + Layout::Builtin(Builtin::Int64 | Builtin::Int1) => { let dst_reg = self.claim_general_reg(dst)?; ASM::mov_reg64_reg64(&mut self.buf, dst_reg, CC::GENERAL_RETURN_REGS[0]); Ok(()) @@ -899,6 +896,23 @@ impl< } } + fn build_num_is_zero( + &mut self, + dst: &Symbol, + src: &Symbol, + arg_layout: &Layout<'a>, + ) -> Result<(), String> { + match arg_layout { + Layout::Builtin(Builtin::Int64) => { + let dst_reg = self.claim_general_reg(dst)?; + let src_reg = self.load_to_general_reg(src)?; + ASM::is_zero_reg64_reg64(&mut self.buf, dst_reg, src_reg); + Ok(()) + } + x => Err(format!("NumIsZero: layout, {:?}, not implemented yet", x)), + } + } + fn create_struct( &mut self, sym: &Symbol, diff --git a/compiler/gen_dev/src/generic64/x86_64.rs b/compiler/gen_dev/src/generic64/x86_64.rs index 8e542c1c15..a1fcb8b5e5 100644 --- a/compiler/gen_dev/src/generic64/x86_64.rs +++ b/compiler/gen_dev/src/generic64/x86_64.rs @@ -1118,6 +1118,12 @@ impl Assembler for X86_64Assembler { setl_reg64(buf, dst); } + #[inline(always)] + fn is_zero_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) { + test_reg64_reg64(buf, src, src); + sete_reg64(buf, dst); + } + #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { ret(buf); diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 0aff496a0c..a776bc9704 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -5,7 +5,7 @@ use bumpalo::{collections::Vec, Bump}; use roc_builtins::bitcode::{self, FloatWidth, IntWidth}; use roc_collections::all::{MutMap, MutSet}; -use roc_module::ident::TagName; +use roc_module::ident::{ModuleName, TagName}; use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, Symbol}; use roc_mono::ir::{ @@ -236,13 +236,24 @@ where arg_layouts, ret_layout, ) - } else { + } else if func_sym + .module_string(&self.env().interns) + .starts_with(ModuleName::APP) + { let fn_name = LayoutIds::default() .get(*func_sym, layout) .to_symbol_string(*func_sym, &self.env().interns); // Now that the arguments are needed, load them if they are literals. self.load_literal_symbols(arguments)?; self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout) + } else { + self.build_run_low_level_dev( + sym, + *func_sym, + arguments, + arg_layouts, + ret_layout, + ) } } @@ -460,6 +471,37 @@ where } } + // build dev backend-only low-level + fn build_run_low_level_dev( + &mut self, + sym: &Symbol, + func_sym: Symbol, + args: &'a [Symbol], + arg_layouts: &[Layout<'a>], + ret_layout: &Layout<'a>, + ) -> Result<(), String> { + self.load_literal_symbols(args)?; + match func_sym { + Symbol::NUM_IS_ZERO => { + debug_assert_eq!( + 1, + args.len(), + "NumIsZero: expected to have exactly one argument" + ); + debug_assert_eq!( + Layout::Builtin(Builtin::Int1), + *ret_layout, + "NumIsZero: expected to have return layout of type I1" + ); + self.build_num_is_zero(sym, &args[0], &arg_layouts[0]) + } + _ => Err(format!( + "the function, {:?}, is not yet implemented", + func_sym + )), + } + } + /// build_fn_call creates a call site for a function. /// This includes dealing with things like saving regs and propagating the returned value. fn build_fn_call( @@ -541,6 +583,14 @@ where arg_layout: &Layout<'a>, ) -> Result<(), String>; + /// build_num_is_zero stores the result of `src == 0` into dst. + fn build_num_is_zero( + &mut self, + dst: &Symbol, + src: &Symbol, + arg_layout: &Layout<'a>, + ) -> Result<(), String>; + /// literal_map gets the map from symbol to literal, used for lazy loading and literal folding. fn literal_map(&mut self) -> &mut MutMap>;