Skip to content

Commit addeecb

Browse files
authored
Merge pull request #58 from FractalFir/methodref
Added i128 multiplaction overflow checks
2 parents 9c6545d + 2feab4f commit addeecb

File tree

5 files changed

+134
-9
lines changed

5 files changed

+134
-9
lines changed

cilly/src/bin/linker/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ fn main() {
369369
cilly::v2::builtins::casts::insert_casts(&mut final_assembly, &mut overrides);
370370
cilly::v2::builtins::insert_heap(&mut final_assembly, &mut overrides);
371371
cilly::v2::builtins::generate_int128_ops(&mut final_assembly, &mut overrides, *C_MODE);
372+
cilly::v2::builtins::i128_mul_ovf_check(&mut final_assembly, &mut overrides);
372373
if !*C_MODE {
373374
cilly::v2::builtins::atomics::generate_all_atomics(&mut final_assembly, &mut overrides);
374375
cilly::v2::builtins::instert_threading(&mut final_assembly, &mut overrides);
@@ -389,7 +390,8 @@ fn main() {
389390
NonZeroU32::new(16),
390391
));
391392

392-
final_assembly.patch_missing_methods(externs, modifies_errno, overrides);
393+
final_assembly.patch_missing_methods(&externs, &modifies_errno, &overrides);
394+
final_assembly.patch_missing_methods(&externs, &modifies_errno, &overrides);
393395

394396
add_mandatory_statics(&mut final_assembly);
395397
if *DEAD_CODE_ELIMINATION {

cilly/src/v2/asm.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -842,18 +842,23 @@ impl Assembly {
842842

843843
pub fn patch_missing_methods(
844844
&mut self,
845-
externs: FxHashMap<&str, String>,
846-
modifies_errno: FxHashSet<&str>,
847-
override_methods: MissingMethodPatcher,
845+
externs: &FxHashMap<&str, String>,
846+
modifies_errno: &FxHashSet<&str>,
847+
override_methods: &MissingMethodPatcher,
848848
) {
849849
let mref_count = self.method_refs.0.len();
850850
let externs: FxHashMap<_, _> = externs
851851
.into_iter()
852-
.map(|(fn_name, lib_name)| (self.alloc_string(fn_name), self.alloc_string(lib_name)))
852+
.map(|(fn_name, lib_name)| {
853+
(
854+
self.alloc_string(fn_name.clone()),
855+
self.alloc_string(lib_name.clone()),
856+
)
857+
})
853858
.collect();
854859
let preserve_errno: FxHashSet<_> = modifies_errno
855860
.into_iter()
856-
.map(|fn_name| self.alloc_string(fn_name))
861+
.map(|fn_name| self.alloc_string(fn_name.clone()))
857862
.collect();
858863
for index in 0..mref_count {
859864
// Get the full method refernce

cilly/src/v2/builtins/int128/mod.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
v2::{
33
asm::MissingMethodPatcher, Assembly, BasicBlock, BinOp, CILNode, CILRoot, Int, MethodImpl,
44
},
5-
Type,
5+
BranchCond, ClassRef, Const, Type,
66
};
77

88
pub fn op_direct(
@@ -99,3 +99,75 @@ pub fn generate_int128_ops(asm: &mut Assembly, patcher: &mut MissingMethodPatche
9999
}
100100
}
101101
}
102+
pub fn i128_mul_ovf_check(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
103+
let name = asm.alloc_string("i128_mul_ovf_check");
104+
let generator = move |_, asm: &mut Assembly| {
105+
let lhs = asm.alloc_node(CILNode::LdArg(0));
106+
let rhs = asm.alloc_node(CILNode::LdArg(1));
107+
let i128_class = ClassRef::int_128(asm);
108+
let get_zero = asm.alloc_string("get_Zero");
109+
let op_equality = asm.alloc_string("eq_i128");
110+
let op_mul = asm.alloc_string("mul_i128");
111+
let op_div = asm.alloc_string("div_i128");
112+
let i128_classref = asm[i128_class].clone();
113+
let main_module = *asm.main_module();
114+
let main_module = asm[main_module].clone();
115+
let const_zero = i128_classref.static_mref(&[], Type::Int(Int::I128), get_zero, asm);
116+
let const_zero = asm.alloc_node(CILNode::Call(Box::new((const_zero, [].into()))));
117+
let i128_eq = main_module.static_mref(
118+
&[Type::Int(Int::I128), Type::Int(Int::I128)],
119+
Type::Bool,
120+
op_equality,
121+
asm,
122+
);
123+
let i128_mul = main_module.static_mref(
124+
&[Type::Int(Int::I128), Type::Int(Int::I128)],
125+
Type::Int(Int::I128),
126+
op_mul,
127+
asm,
128+
);
129+
let i128_div = main_module.static_mref(
130+
&[Type::Int(Int::I128), Type::Int(Int::I128)],
131+
Type::Int(Int::I128),
132+
op_div,
133+
asm,
134+
);
135+
let rhs_zero = asm.alloc_node(CILNode::Call(Box::new((i128_eq, [rhs, const_zero].into()))));
136+
let jmp_nz = asm.alloc_root(CILRoot::Branch(Box::new((
137+
0,
138+
1,
139+
Some(BranchCond::False(rhs_zero)),
140+
))));
141+
let ret_false = asm.alloc_node(Const::Bool(false));
142+
let ret_false = asm.alloc_root(CILRoot::Ret(ret_false));
143+
let lhs_mul_rhs = asm.alloc_node(CILNode::Call(Box::new((i128_mul, [lhs, rhs].into()))));
144+
let recomputed_rhs = asm.alloc_node(CILNode::Call(Box::new((
145+
i128_div,
146+
[lhs_mul_rhs, rhs].into(),
147+
))));
148+
let ovf = asm.alloc_node(CILNode::Call(Box::new((
149+
i128_eq,
150+
[recomputed_rhs, rhs].into(),
151+
))));
152+
let ret_ovf = asm.alloc_root(CILRoot::Ret(ovf));
153+
154+
MethodImpl::MethodBody {
155+
blocks: vec![
156+
BasicBlock::new(vec![jmp_nz, ret_false], 0, None),
157+
BasicBlock::new(vec![ret_ovf], 1, None),
158+
],
159+
locals: vec![],
160+
}
161+
};
162+
patcher.insert(name, Box::new(generator));
163+
}
164+
#[test]
165+
fn test() {
166+
let op = BinOp::Eq;
167+
let lhs_type = Int::I128;
168+
panic!(
169+
"{op}_{lhs_type}",
170+
op = op.name(),
171+
lhs_type = lhs_type.name()
172+
);
173+
}

src/binop/checked/mod.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use cilly::{
33
and, call,
44
cil_node::CILNode,
55
cil_root::CILRoot,
6-
conv_i16, conv_i32, conv_i64, conv_i8, conv_isize, conv_u64, conv_usize, gt, gt_un, ldc_i32,
7-
ldc_i64, ldc_u32, ldc_u64, lt, mul, or,
6+
conv_i16, conv_i32, conv_i64, conv_i8, conv_isize, conv_u64, conv_usize, eq, gt, gt_un,
7+
ldc_i32, ldc_i64, ldc_u32, ldc_u64, lt, mul, or,
88
v2::{cilnode::MethodKind, Assembly, ClassRef, FieldDesc, Int, MethodRef},
99
Type,
1010
};
@@ -426,6 +426,20 @@ pub fn mul<'tcx>(
426426
);
427427
or!(gt, lt)
428428
}
429+
TyKind::Int(IntTy::I128) => {
430+
let op_mul = MethodRef::new(
431+
*ctx.main_module(),
432+
ctx.alloc_string("i128_mul_ovf_check"),
433+
ctx.sig([Type::Int(Int::I128), Type::Int(Int::I128)], Type::Bool),
434+
MethodKind::Static,
435+
vec![].into(),
436+
);
437+
eq!(
438+
call!(ctx.alloc_methodref(op_mul), [ops_a.clone(), ops_b.clone()]),
439+
CILNode::LdFalse
440+
)
441+
}
442+
429443
_ => {
430444
eprintln!("WARINING: can't checked mul type {ty:?}");
431445
CILNode::LdFalse

test/arthm/num_test.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub fn test_variadic_fnptr() {
4040
test!(!(p < q));
4141
}
4242
fn main() {
43+
isqrt_test();
4344
unsafe { black_box(ldexpf(black_box(434.43), 1232.3434)) };
4445
check_float_nan();
4546
const A: u32 = 0b0101100;
@@ -387,3 +388,34 @@ pub fn checked_next_multiple_of(lhs: i8, rhs: i8) -> Option<i8> {
387388
pub fn add_signed(a: i8, b: i8) -> bool {
388389
a.checked_add(b).is_none()
389390
}
391+
struct I128W(i64, i64);
392+
fn isqrt_test() {
393+
let val = i128::MAX;
394+
let bytes = val.to_le_bytes();
395+
for i in bytes {
396+
unsafe { printf(c"i:%u\n".as_ptr(), i as u32) };
397+
}
398+
test_eq!(bytes[15], 127);
399+
for n in i128::MAX - 127..=i128::MAX {
400+
/* .chain()
401+
.chain((0..i128::MAX.count_ones()).map(|exponent| (1 << exponent) - 1))
402+
.chain((0..i128::MAX.count_ones()).map(|exponent| 1 << exponent)) */
403+
let isqrt_n = n.isqrt();
404+
unsafe {
405+
printf(
406+
c"n:%lld isqrt_n:%lld\n".as_ptr(),
407+
core::mem::transmute::<i128, I128W>(n),
408+
core::mem::transmute::<i128, I128W>(isqrt_n),
409+
)
410+
};
411+
test!(isqrt_n
412+
.checked_mul(isqrt_n)
413+
.map(|isqrt_n_squared| isqrt_n_squared <= n)
414+
.unwrap_or(false));
415+
416+
test!((isqrt_n + 1)
417+
.checked_mul(isqrt_n + 1)
418+
.map(|isqrt_n_plus_1_squared| n < isqrt_n_plus_1_squared)
419+
.unwrap_or(true));
420+
}
421+
}

0 commit comments

Comments
 (0)