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.

crc32

Crc32c.crc32
fn crc32(crc: u32, input: []const u8) u32

File

lib/std/hash/crc/Crc32c.zig:144

Code

fn crc32(crc: u32, input: []const u8) u32 {
    var crc0: u64 = ~crc;

    // Compute the CRC for up to seven leading bytes to bring the
    // `next` pointer to an eight-byte boundary.
    var next = input;
    while (next.len > 0 and @intFromPtr(next.ptr) & 7 != 0) {
        asm volatile ("crc32b %[out], %[in]"
            : [in] "+r" (crc0),
            : [out] "rm" (next[0]),
        );
        next = next[1..];
    }

    // Compute the CRC on sets of LONG * 3 bytes, executing three independent
    // CRC instructions, each on LONG bytes. This is an optimization for
    // targets where the CRC instruction has a throughput of one CRC per
    // cycle, but a latency of three cycles.
    while (next.len >= LONG * 3) {
        var crc1: u64 = 0;
        var crc2: u64 = 0;

        const start = next.len;
        while (true) {
            // Safe @alignCast(), since we've aligned the pointer to 8 bytes before this loop.
            const long: [*]const u64 = @ptrCast(@alignCast(next));
            asm volatile (
                \\crc32q %[out0], %[in0]
                \\crc32q %[out1], %[in1]
                \\crc32q %[out2], %[in2]
                : [in0] "+r" (crc0),
                  [in1] "+r" (crc1),
                  [in2] "+r" (crc2),
                : [out0] "rm" (long[0 * LONG / 8]),
                  [out1] "rm" (long[1 * LONG / 8]),
                  [out2] "rm" (long[2 * LONG / 8]),
            );
            next = next[8..];
            if (next.len <= start - LONG) break;
        }

        crc0 = shift(&long_lookup_table, @truncate(crc0)) ^ crc1;
        crc0 = shift(&long_lookup_table, @truncate(crc0)) ^ crc2;
        next = next[LONG * 2 ..];
    }

    // Same thing as above, but for smaller chunks of SHORT bytes.
    while (next.len >= SHORT * 3) {
        var crc1: u64 = 0;
        var crc2: u64 = 0;

        const start = next.len;
        while (true) {
            const long: [*]const u64 = @ptrCast(@alignCast(next));
            asm volatile (
                \\crc32q %[out0], %[in0]
                \\crc32q %[out1], %[in1]
                \\crc32q %[out2], %[in2]
                : [in0] "+r" (crc0),
                  [in1] "+r" (crc1),
                  [in2] "+r" (crc2),
                : [out0] "rm" (long[0 * SHORT / 8]),
                  [out1] "rm" (long[1 * SHORT / 8]),
                  [out2] "rm" (long[2 * SHORT / 8]),
            );
            next = next[8..];
            if (next.len <= start - SHORT) break;
        }

        crc0 = shift(&short_lookup_table, @truncate(crc0)) ^ crc1;
        crc0 = shift(&short_lookup_table, @truncate(crc0)) ^ crc2;
        next = next[SHORT * 2 ..];
    }

    // Compute via 8-byte chunks, until we're left with less than 8 bytes.
    while (next.len >= 8) {
        const long: [*]const u64 = @ptrCast(@alignCast(next));
        asm volatile ("crc32q %[out], %[in]"
            : [in] "+r" (crc0),
            : [out] "rm" (long[0]),
        );
        next = next[8..];
    }

    // Finish the last bytes with just single instructions.
    while (next.len > 0) {
        asm volatile ("crc32b %[out], %[in]"
            : [in] "+r" (crc0),
            : [out] "rm" (next[0]),
        );
        next = next[1..];
    }

    return @truncate(~crc0);
}