package runtime @(default_calling_convention="none") foreign { @(link_name="llvm.cttz.i8") _ctz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 --- @(link_name="llvm.cttz.i16") _ctz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 --- @(link_name="llvm.cttz.i32") _ctz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 --- @(link_name="llvm.cttz.i64") _ctz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 --- } _ctz :: proc{ _ctz_u8, _ctz_u16, _ctz_u32, _ctz_u64, }; @(default_calling_convention="none") foreign { @(link_name="llvm.ctlz.i8") _clz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 --- @(link_name="llvm.ctlz.i16") _clz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 --- @(link_name="llvm.ctlz.i32") _clz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 --- @(link_name="llvm.ctlz.i64") _clz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 --- } _clz :: proc{ _clz_u8, _clz_u16, _clz_u32, _clz_u64, }; udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { n := transmute([2]u64)a; d := transmute([2]u64)b; q, r: [2]u64 = ---, ---; sr: u32 = 0; low :: ODIN_ENDIAN == "big" ? 1 : 0; high :: 1 - low; U64_BITS :: 8*size_of(u64); U128_BITS :: 8*size_of(u128); // Special Cases if n[high] == 0 { if d[high] == 0 { if rem != nil { res := n[low] % d[low]; rem^ = u128(res); } return u128(n[low] / d[low]); } if rem != nil { rem^ = u128(n[low]); } return 0; } if d[low] == 0 { if d[high] == 0 { if rem != nil { rem^ = u128(n[high] % d[low]); } return u128(n[high] / d[low]); } if n[low] == 0 { if rem != nil { r[high] = n[high] % d[high]; r[low] = 0; rem^ = transmute(u128)r; } return u128(n[high] / d[high]); } if d[high] & (d[high]-1) == 0 { if rem != nil { r[low] = n[low]; r[high] = n[high] & (d[high] - 1); rem^ = transmute(u128)r; } return u128(n[high] >> _ctz(d[high])); } sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high]))); if sr > U64_BITS - 2 { if rem != nil { rem^ = a; } return 0; } sr += 1; q[low] = 0; q[high] = n[low] << u64(U64_BITS - sr); r[high] = n[high] >> sr; r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr); } else { if d[high] == 0 { if d[low] & (d[low] - 1) == 0 { if rem != nil { rem^ = u128(n[low] & (d[low] - 1)); } if d[low] == 1 { return a; } sr = u32(_ctz(d[low])); q[high] = n[high] >> sr; q[low] = (n[high] << (U64_BITS-sr)) | (n[low] >> sr); return transmute(u128)q; } sr = 1 + U64_BITS + u32(_clz(d[low])) - u32(_clz(n[high])); switch { case sr == U64_BITS: q[low] = 0; q[high] = n[low]; r[high] = 0; r[low] = n[high]; case sr < U64_BITS: q[low] = 0; q[high] = n[low] << (U64_BITS - sr); r[high] = n[high] >> sr; r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr); case: q[low] = n[low] << (U128_BITS - sr); q[high] = (n[high] << (U128_BITS - sr)) | (n[low] >> (sr - U64_BITS)); r[high] = 0; r[low] = n[high] >> (sr - U64_BITS); } } else { sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high]))); if sr > U64_BITS - 1 { if rem != nil { rem^ = a; } return 0; } sr += 1; q[low] = 0; if sr == U64_BITS { q[high] = n[low]; r[high] = 0; r[low] = n[high]; } else { r[high] = n[high] >> sr; r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr); q[high] = n[low] << (U64_BITS - sr); } } } carry: u32 = 0; r_all: u128 = ---; for ; sr > 0; sr -= 1 { r[high] = (r[high] << 1) | (r[low] >> (U64_BITS - 1)); r[low] = (r[low] << 1) | (q[high] >> (U64_BITS - 1)); q[high] = (q[high] << 1) | (q[low] >> (U64_BITS - 1)); q[low] = (q[low] << 1) | u64(carry); r_all = transmute(u128)r; s := i128(b - r_all - 1) >> (U128_BITS - 1); carry = u32(s & 1); r_all -= b & transmute(u128)s; r = transmute([2]u64)r_all; } q_all := ((transmute(u128)q) << 1) | u128(carry); if rem != nil { rem^ = r_all; } return q_all; }