diff --git a/cilly/src/bin/linker/main.rs b/cilly/src/bin/linker/main.rs index 24e4e83..81b57ae 100644 --- a/cilly/src/bin/linker/main.rs +++ b/cilly/src/bin/linker/main.rs @@ -369,6 +369,7 @@ fn main() { cilly::v2::builtins::casts::insert_casts(&mut final_assembly, &mut overrides); cilly::v2::builtins::insert_heap(&mut final_assembly, &mut overrides); cilly::v2::builtins::generate_int128_ops(&mut final_assembly, &mut overrides, *C_MODE); + cilly::v2::builtins::i128_mul_ovf_check(&mut final_assembly, &mut overrides); if !*C_MODE { cilly::v2::builtins::atomics::generate_all_atomics(&mut final_assembly, &mut overrides); cilly::v2::builtins::instert_threading(&mut final_assembly, &mut overrides); @@ -389,7 +390,8 @@ fn main() { NonZeroU32::new(16), )); - final_assembly.patch_missing_methods(externs, modifies_errno, overrides); + final_assembly.patch_missing_methods(&externs, &modifies_errno, &overrides); + final_assembly.patch_missing_methods(&externs, &modifies_errno, &overrides); add_mandatory_statics(&mut final_assembly); if *DEAD_CODE_ELIMINATION { diff --git a/cilly/src/v2/asm.rs b/cilly/src/v2/asm.rs index 0fe47e4..1615e5a 100644 --- a/cilly/src/v2/asm.rs +++ b/cilly/src/v2/asm.rs @@ -842,18 +842,23 @@ impl Assembly { pub fn patch_missing_methods( &mut self, - externs: FxHashMap<&str, String>, - modifies_errno: FxHashSet<&str>, - override_methods: MissingMethodPatcher, + externs: &FxHashMap<&str, String>, + modifies_errno: &FxHashSet<&str>, + override_methods: &MissingMethodPatcher, ) { let mref_count = self.method_refs.0.len(); let externs: FxHashMap<_, _> = externs .into_iter() - .map(|(fn_name, lib_name)| (self.alloc_string(fn_name), self.alloc_string(lib_name))) + .map(|(fn_name, lib_name)| { + ( + self.alloc_string(fn_name.clone()), + self.alloc_string(lib_name.clone()), + ) + }) .collect(); let preserve_errno: FxHashSet<_> = modifies_errno .into_iter() - .map(|fn_name| self.alloc_string(fn_name)) + .map(|fn_name| self.alloc_string(fn_name.clone())) .collect(); for index in 0..mref_count { // Get the full method refernce diff --git a/cilly/src/v2/builtins/int128/mod.rs b/cilly/src/v2/builtins/int128/mod.rs index 7e0b20b..6453d4a 100644 --- a/cilly/src/v2/builtins/int128/mod.rs +++ b/cilly/src/v2/builtins/int128/mod.rs @@ -2,7 +2,7 @@ use crate::{ v2::{ asm::MissingMethodPatcher, Assembly, BasicBlock, BinOp, CILNode, CILRoot, Int, MethodImpl, }, - Type, + BranchCond, ClassRef, Const, Type, }; pub fn op_direct( @@ -99,3 +99,75 @@ pub fn generate_int128_ops(asm: &mut Assembly, patcher: &mut MissingMethodPatche } } } +pub fn i128_mul_ovf_check(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) { + let name = asm.alloc_string("i128_mul_ovf_check"); + let generator = move |_, asm: &mut Assembly| { + let lhs = asm.alloc_node(CILNode::LdArg(0)); + let rhs = asm.alloc_node(CILNode::LdArg(1)); + let i128_class = ClassRef::int_128(asm); + let get_zero = asm.alloc_string("get_Zero"); + let op_equality = asm.alloc_string("eq_i128"); + let op_mul = asm.alloc_string("mul_i128"); + let op_div = asm.alloc_string("div_i128"); + let i128_classref = asm[i128_class].clone(); + let main_module = *asm.main_module(); + let main_module = asm[main_module].clone(); + let const_zero = i128_classref.static_mref(&[], Type::Int(Int::I128), get_zero, asm); + let const_zero = asm.alloc_node(CILNode::Call(Box::new((const_zero, [].into())))); + let i128_eq = main_module.static_mref( + &[Type::Int(Int::I128), Type::Int(Int::I128)], + Type::Bool, + op_equality, + asm, + ); + let i128_mul = main_module.static_mref( + &[Type::Int(Int::I128), Type::Int(Int::I128)], + Type::Int(Int::I128), + op_mul, + asm, + ); + let i128_div = main_module.static_mref( + &[Type::Int(Int::I128), Type::Int(Int::I128)], + Type::Int(Int::I128), + op_div, + asm, + ); + let rhs_zero = asm.alloc_node(CILNode::Call(Box::new((i128_eq, [rhs, const_zero].into())))); + let jmp_nz = asm.alloc_root(CILRoot::Branch(Box::new(( + 0, + 1, + Some(BranchCond::False(rhs_zero)), + )))); + let ret_false = asm.alloc_node(Const::Bool(false)); + let ret_false = asm.alloc_root(CILRoot::Ret(ret_false)); + let lhs_mul_rhs = asm.alloc_node(CILNode::Call(Box::new((i128_mul, [lhs, rhs].into())))); + let recomputed_rhs = asm.alloc_node(CILNode::Call(Box::new(( + i128_div, + [lhs_mul_rhs, rhs].into(), + )))); + let ovf = asm.alloc_node(CILNode::Call(Box::new(( + i128_eq, + [recomputed_rhs, rhs].into(), + )))); + let ret_ovf = asm.alloc_root(CILRoot::Ret(ovf)); + + MethodImpl::MethodBody { + blocks: vec![ + BasicBlock::new(vec![jmp_nz, ret_false], 0, None), + BasicBlock::new(vec![ret_ovf], 1, None), + ], + locals: vec![], + } + }; + patcher.insert(name, Box::new(generator)); +} +#[test] +fn test() { + let op = BinOp::Eq; + let lhs_type = Int::I128; + panic!( + "{op}_{lhs_type}", + op = op.name(), + lhs_type = lhs_type.name() + ); +} diff --git a/src/binop/checked/mod.rs b/src/binop/checked/mod.rs index cd1bd90..4f60626 100644 --- a/src/binop/checked/mod.rs +++ b/src/binop/checked/mod.rs @@ -3,8 +3,8 @@ use cilly::{ and, call, cil_node::CILNode, cil_root::CILRoot, - conv_i16, conv_i32, conv_i64, conv_i8, conv_isize, conv_u64, conv_usize, gt, gt_un, ldc_i32, - ldc_i64, ldc_u32, ldc_u64, lt, mul, or, + conv_i16, conv_i32, conv_i64, conv_i8, conv_isize, conv_u64, conv_usize, eq, gt, gt_un, + ldc_i32, ldc_i64, ldc_u32, ldc_u64, lt, mul, or, v2::{cilnode::MethodKind, Assembly, ClassRef, FieldDesc, Int, MethodRef}, Type, }; @@ -426,6 +426,20 @@ pub fn mul<'tcx>( ); or!(gt, lt) } + TyKind::Int(IntTy::I128) => { + let op_mul = MethodRef::new( + *ctx.main_module(), + ctx.alloc_string("i128_mul_ovf_check"), + ctx.sig([Type::Int(Int::I128), Type::Int(Int::I128)], Type::Bool), + MethodKind::Static, + vec![].into(), + ); + eq!( + call!(ctx.alloc_methodref(op_mul), [ops_a.clone(), ops_b.clone()]), + CILNode::LdFalse + ) + } + _ => { eprintln!("WARINING: can't checked mul type {ty:?}"); CILNode::LdFalse diff --git a/test/arthm/num_test.rs b/test/arthm/num_test.rs index fede927..5db9393 100644 --- a/test/arthm/num_test.rs +++ b/test/arthm/num_test.rs @@ -40,6 +40,7 @@ pub fn test_variadic_fnptr() { test!(!(p < q)); } fn main() { + isqrt_test(); unsafe { black_box(ldexpf(black_box(434.43), 1232.3434)) }; check_float_nan(); const A: u32 = 0b0101100; @@ -387,3 +388,34 @@ pub fn checked_next_multiple_of(lhs: i8, rhs: i8) -> Option { pub fn add_signed(a: i8, b: i8) -> bool { a.checked_add(b).is_none() } +struct I128W(i64, i64); +fn isqrt_test() { + let val = i128::MAX; + let bytes = val.to_le_bytes(); + for i in bytes { + unsafe { printf(c"i:%u\n".as_ptr(), i as u32) }; + } + test_eq!(bytes[15], 127); + for n in i128::MAX - 127..=i128::MAX { + /* .chain() + .chain((0..i128::MAX.count_ones()).map(|exponent| (1 << exponent) - 1)) + .chain((0..i128::MAX.count_ones()).map(|exponent| 1 << exponent)) */ + let isqrt_n = n.isqrt(); + unsafe { + printf( + c"n:%lld isqrt_n:%lld\n".as_ptr(), + core::mem::transmute::(n), + core::mem::transmute::(isqrt_n), + ) + }; + test!(isqrt_n + .checked_mul(isqrt_n) + .map(|isqrt_n_squared| isqrt_n_squared <= n) + .unwrap_or(false)); + + test!((isqrt_n + 1) + .checked_mul(isqrt_n + 1) + .map(|isqrt_n_plus_1_squared| n < isqrt_n_plus_1_squared) + .unwrap_or(true)); + } +}