diff --git a/crates/compiler/gen_dev/src/generic64/aarch64.rs b/crates/compiler/gen_dev/src/generic64/aarch64.rs index 94ec3af567..8dcf963abb 100644 --- a/crates/compiler/gen_dev/src/generic64/aarch64.rs +++ b/crates/compiler/gen_dev/src/generic64/aarch64.rs @@ -781,6 +781,10 @@ impl Assembler for AArch64Assembler { todo!("registers greater than or equal for AArch64"); } + fn set_if_overflow(_buf: &mut Vec<'_, u8>, _dst: AArch64GeneralReg) { + todo!("set if overflow for AArch64"); + } + #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { ret_reg64(buf, AArch64GeneralReg::LR) diff --git a/crates/compiler/gen_dev/src/generic64/mod.rs b/crates/compiler/gen_dev/src/generic64/mod.rs index afac67e7f5..64c02f28d5 100644 --- a/crates/compiler/gen_dev/src/generic64/mod.rs +++ b/crates/compiler/gen_dev/src/generic64/mod.rs @@ -289,6 +289,8 @@ pub trait Assembler: Sized + Copy { src2: GeneralReg, ); + fn set_if_overflow(buf: &mut Vec<'_, u8>, dst: GeneralReg); + fn ret(buf: &mut Vec<'_, u8>); } @@ -309,6 +311,7 @@ pub struct Backend64Bit< // They are likely to be small enough that it is faster to use a vec and linearly scan it or keep it sorted and binary search. phantom_asm: PhantomData, phantom_cc: PhantomData, + target_info: TargetInfo, env: &'a Env<'a>, interns: &'a mut Interns, helper_proc_gen: CodeGenHelp<'a>, @@ -343,6 +346,7 @@ pub fn new_backend_64bit< Backend64Bit { phantom_asm: PhantomData, phantom_cc: PhantomData, + target_info, env, interns, helper_proc_gen: CodeGenHelp::new(env.arena, target_info, env.module_id), @@ -759,11 +763,63 @@ impl< } } + fn build_num_add_checked( + &mut self, + dst: &Symbol, + src1: &Symbol, + src2: &Symbol, + num_layout: &Layout<'a>, + ) { + use Builtin::Int; + + let buf = &mut self.buf; + + let fields = [*num_layout, Layout::bool()]; + let return_layout = Layout::struct_no_name_order(&fields); + let struct_size = return_layout.stack_size(self.target_info); + + let base_offset = self.storage_manager.claim_stack_area(dst, struct_size); + + match num_layout { + Layout::Builtin(Int(IntWidth::I64 | IntWidth::I32 | IntWidth::I16 | IntWidth::I8)) => { + let dst_reg = self + .storage_manager + .claim_general_reg(buf, &Symbol::DEV_TMP); + + let overflow_reg = self + .storage_manager + .claim_general_reg(buf, &Symbol::DEV_TMP2); + + let src1_reg = self.storage_manager.load_to_general_reg(buf, src1); + let src2_reg = self.storage_manager.load_to_general_reg(buf, src2); + + ASM::add_reg64_reg64_reg64(buf, dst_reg, src1_reg, src2_reg); + ASM::set_if_overflow(buf, overflow_reg); + + ASM::mov_base32_reg64(buf, base_offset, dst_reg); + ASM::mov_base32_reg64(buf, base_offset + 8, overflow_reg); + + self.free_symbol(&Symbol::DEV_TMP); + self.free_symbol(&Symbol::DEV_TMP2); + } + Layout::Builtin(Int(IntWidth::U64 | IntWidth::U32 | IntWidth::U16 | IntWidth::U8)) => { + todo!("addChecked for unsigned integers") + } + Layout::Builtin(Builtin::Float(FloatWidth::F64)) => { + todo!("addChecked for f64") + } + Layout::Builtin(Builtin::Float(FloatWidth::F32)) => { + todo!("addChecked for f32") + } + x => todo!("NumAdd: layout, {:?}", x), + } + } + fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>) { + use Builtin::Int; + match layout { - Layout::Builtin(Builtin::Int( - IntWidth::I64 | IntWidth::I32 | IntWidth::I16 | IntWidth::I8, - )) => { + Layout::Builtin(Int(IntWidth::I64 | IntWidth::I32 | IntWidth::I16 | IntWidth::I8)) => { let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst); let src1_reg = self .storage_manager @@ -773,9 +829,7 @@ impl< .load_to_general_reg(&mut self.buf, src2); ASM::imul_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg); } - Layout::Builtin(Builtin::Int( - IntWidth::U64 | IntWidth::U32 | IntWidth::U16 | IntWidth::U8, - )) => { + Layout::Builtin(Int(IntWidth::U64 | IntWidth::U32 | IntWidth::U16 | IntWidth::U8)) => { let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst); let src1_reg = self .storage_manager diff --git a/crates/compiler/gen_dev/src/generic64/x86_64.rs b/crates/compiler/gen_dev/src/generic64/x86_64.rs index 334a0b82fe..fa76b4391a 100644 --- a/crates/compiler/gen_dev/src/generic64/x86_64.rs +++ b/crates/compiler/gen_dev/src/generic64/x86_64.rs @@ -1318,6 +1318,10 @@ impl Assembler for X86_64Assembler { fn ret(buf: &mut Vec<'_, u8>) { ret(buf); } + + fn set_if_overflow(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg) { + seto_reg64(buf, dst); + } } impl X86_64Assembler { @@ -1965,6 +1969,12 @@ fn setge_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { set_reg64_help(0x9d, buf, reg); } +/// `SETO r/m64` -> Set byte if oveflow flag is set. +#[inline(always)] +fn seto_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { + set_reg64_help(0x90, buf, reg); +} + /// `RET` -> Near return to calling procedure. #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { diff --git a/crates/compiler/gen_dev/src/lib.rs b/crates/compiler/gen_dev/src/lib.rs index ba7c272994..86f13580ee 100644 --- a/crates/compiler/gen_dev/src/lib.rs +++ b/crates/compiler/gen_dev/src/lib.rs @@ -405,6 +405,9 @@ trait Backend<'a> { ); self.build_num_add(sym, &args[0], &args[1], ret_layout) } + LowLevel::NumAddChecked => { + self.build_num_add_checked(sym, &args[0], &args[1], &arg_layouts[0]) + } LowLevel::NumAcos => self.build_fn_call( sym, bitcode::NUM_ACOS[FloatWidth::F64].to_string(), @@ -678,6 +681,13 @@ trait Backend<'a> { self.load_literal_symbols(args); self.build_fn_call(sym, fn_name, args, arg_layouts, ret_layout) } + Symbol::NUM_ADD_CHECKED => { + let layout_id = LayoutIds::default().get(func_sym, ret_layout); + let fn_name = self.symbol_to_string(func_sym, layout_id); + // Now that the arguments are needed, load them if they are literals. + self.load_literal_symbols(args); + self.build_fn_call(sym, fn_name, args, arg_layouts, ret_layout) + } _ => todo!("the function, {:?}", func_sym), } } @@ -699,6 +709,15 @@ trait Backend<'a> { /// build_num_add stores the sum of src1 and src2 into dst. fn build_num_add(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>); + /// build_num_add_checked stores the sum of src1 and src2 into dst. + fn build_num_add_checked( + &mut self, + dst: &Symbol, + src1: &Symbol, + src2: &Symbol, + layout: &Layout<'a>, + ); + /// build_num_mul stores `src1 * src2` into dst. fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>);