// mem — flibc's freestanding C-ABI `mem*` providers, ported to Flash from the // hand-written Zig (the first `flibc` library leaf after the `tokenize` and // `readline` cores). // // flibc payloads link without compiler-rt, so the C runtime helpers LLVM emits // for certain loop idioms are not supplied. Once a payload exercises a real // `#memcpy`-backed builder or a bare NUL scan, LLVM's loop-idiom recognizer // lowers it to a `memcpy` / `strlen` call and the link fails on an undefined // symbol. These three byte loops, named exactly `memcpy` / `memset` / `strlen`, // close that loop: the idiom recognizer refuses to rewrite a recognized idiom // into a call to the very function being compiled, so the loops are // self-recursion-safe. // // First port to exercise a many-item pointer's mutability across the family: a // many-item pointer is const-pointee by default in Flash, exactly like a slice // (`[]T`) and a single pointer (`*T`). The copy sources read through bare `[*]u8` // / `[*]u64` and the NUL scan through `[*:0]u8`; the writable destination carries // `mut` (`[*]mut u8` / `[*]mut u64`), the one-word marker the slice and // single-pointer forms already use. The single-item `*anyopaque` / `*mut // anyopaque` distinction is the same: `*T` is a const pointee, `*mut T` a mutable // one. The `///` doc comments are carried through verbatim; the core lowers to // Zig whose token stream matches the reference modulo Flash's canonical layout // (mandatory braces, dropped `//` comments). /// memset(dst, c, n) — fill `n` bytes of `dst` with byte `c`. Byte /// granular; the C ABI returns `dst`. export fn memset(dst [*]mut u8, c i32, n_in u64) [*]mut u8 { var n = n_in var p = dst const byte u8 = #truncate(#as(u32, #bitCast(c))) while n != 0 { p[0] = byte p += 1 n -= 1 } return dst } /// memcpy(dst, src, bytes) — copy `bytes` bytes from `src` to `dst` /// (non-overlapping). Copies 8 bytes at a time when both operands are /// 8-aligned, then drains the tail byte-wise. The C ABI returns `dst`. export fn memcpy(dst *mut anyopaque, src *anyopaque, bytes u64) *mut anyopaque { var d [*]mut u8 = #ptrCast(dst) var s [*]u8 = #ptrCast(src) var n = bytes if #intFromPtr(d) % 8 == 0 && #intFromPtr(s) % 8 == 0 { var d64 [*]mut u64 = #ptrCast(#alignCast(d)) var s64 [*]u64 = #ptrCast(#alignCast(s)) while n >= 8 { d64[0] = s64[0] d64 += 1 s64 += 1 n -= 8 } d = #ptrCast(d64) s = #ptrCast(s64) } while n > 0 { d[0] = s[0] d += 1 s += 1 n -= 1 } return dst } /// strlen(s) — length of the NUL-terminated string at `s`, excluding the /// terminator. The lone scan the idiom recognizer would otherwise route /// to an external `strlen`; defining it here closes the loop. export fn strlen(s [*:0]u8) u64 { var n u64 = 0 while s[n] != 0 { n += 1 } return n }