← board

Move / FillChar as compiler intrinsics (future optimization)

Context

Move(const Source; var Dest; Count) and FillChar(var X; Count; Value: Byte) are System primitives FPC makes available without uses and lowers to optimized inline code (often rep movsb/rep stosb or vectorized copies). PXX has neither as a builtin.

Interim (landed 2026-06-24): plain-Pascal Move (overlap-safe / memmove) and FillChar live in lib/rtl/sysutils.pas, resolved via the existing uses SysUtils that every real consumer (and all Synapse units) already has. This is a temporary home — FPC's canonical home is System (bare, no uses). Two things this ticket should eventually deliver:

  1. Proper home / no-uses availability — move them to the auto-pulled compiler/builtin/builtin.pas (the implicit System surface; any uses-bearing program already pulls it, per the tkUses pre-scan in parser.inc), so bare Move/FillChar work with no uses like FPC. Then remove the SysUtils copies.
  2. Optimization (below).

That is correct and unblocks compilation, but a byte-at-a-time Pascal loop is slow for the bulk-copy paths these primitives exist for (MD5/hashing buffers in synacode, string/record blits). FPC-grade code expects them to be cheap.

The ask

Once the plain-Pascal versions are in and proven, make Move and FillChar compiler intrinsics:

Done when

Notes

Progress — 2026-07-02, part 1 (proper home / no-uses) LANDED (v145)

Move and FillChar now live in compiler/builtin/builtin.pas and resolve with NO uses clause: the ident+lparen token pre-scan pulls builtin for bare move(/fillchar( exactly like Str/Val/Copy/Abs (ESP excluded, user routine of the same name shadows). Overlap-safe (memmove) semantics pinned in test/test_move_fillchar_nouses.pas (make test).

The sysutils copies are now shadowed (builtin registers first, identical code); REMOVING them is a Track B follow-up (lib/** ownership) — [[task-remove-sysutils-move-fillchar-copies]]. Part 2 (optimized intrinsic emission, rep movsb/stosb-class) remains this ticket's open scope.

Track B note (2026-07-20)

Surfacing in the Track B ready queue, but the ticket's own header already says Track A and the remaining half (part 2: emitting Move/FillChar as intrinsics instead of calls) is compiler/**. Part 1 landed in v145, and the Track B tail — deleting the shadowed copies from lib/rtl/sysutils.pas — was split out as task-remove-sysutils-move-fillchar-copies and completed 2026-07-04 (it is in done/).

So there is no Track B work left here at all; the lane label is what is stale, not the ticket. Whoever picks this up: it is Track A.

Lane correction (2026-07-20)

Track re-labelled B -> A on 2026-07-20: part 1 landed in v145, the Track B tail (task-remove-sysutils-move-fillchar-copies) completed 2026-07-04, and the only remaining half is intrinsic emission in compiler/**. It was surfacing in the Track B ready queue with nothing a Track B agent could do.