Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

__mulo_limb64

limb64.__mulo_limb64
fn __mulo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool

File

lib/compiler_rt/limb64.zig:959

Code

fn __mulo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
    const limb_cnt = usedLimbCount(bits);

    const out = varLimbs(out_ptr, bits);
    const a = constLimbs(a_ptr, bits);
    const b = constLimbs(b_ptr, bits);

    @memset(out, 0);

    const all_ones = ~@as(u64, 0);
    const a_neg = is_signed and ((limbGet(a, limb_cnt - 1) >> 63) != 0);
    const b_neg = is_signed and ((limbGet(b, limb_cnt - 1) >> 63) != 0);

    var carry: [3]u64 = @splat(0);
    var hi_zero = true;
    var hi_ones = true;
    var hi_borrow: u1 = 0;
    var raw_last: u64 = 0;

    var k: usize = 0;
    while (k < 2 * limb_cnt) : (k += 1) {
        var acc = carry;

        var i: usize = if (k < limb_cnt) 0 else k - (limb_cnt - 1);
        while (i < limb_cnt and i <= k) : (i += 1) {
            const j = k - i;
            if (j >= limb_cnt) continue;

            const p = mulwide(limbGet(a, i), limbGet(b, j));
            add3(&acc, 0, p[0]);
            add3(&acc, 1, p[1]);
        }

        var limb = acc[0];
        if (k < limb_cnt) {
            limbSet(out, k, limb);
            if (k == limb_cnt - 1) raw_last = limb;
        } else {
            if (is_signed) {
                const h = k - limb_cnt;

                const s0 = @subWithOverflow(limb, if (a_neg) limbGet(b, h) else 0);
                const s1 = @subWithOverflow(s0[0], if (b_neg) limbGet(a, h) else 0);
                const s2 = @subWithOverflow(s1[0], hi_borrow);

                limb = s2[0];
                hi_borrow = @intFromBool(s0[1] != 0 or s1[1] != 0 or s2[1] != 0);
            }

            hi_zero = hi_zero and limb == 0;
            hi_ones = hi_ones and limb == all_ones;
        }

        carry = .{ acc[1], acc[2], 0 };
    }

    const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
    if (bits % 64 != 0) {
        limbSet(out, limb_cnt - 1, last);
    }

    fixLastLimb(out_ptr, is_signed, bits);

    if (!is_signed) {
        return !hi_zero or raw_last != last;
    }

    const sign_extend: u64 = if ((last >> 63) == 1) all_ones else 0;
    return (raw_last != last) or if (sign_extend == 0) !hi_zero else !hi_ones;
}