Skip to content

Claude/upgrade ape c library mm z gd - #626

Merged
staalmannen merged 6 commits into
mainfrom
claude/upgrade-ape-c-library-mmZGd
Oct 14, 2026
Merged

staalmannen merged 6 commits into
mainfrom
claude/upgrade-ape-c-library-mmZGd

Conversation

@staalmannen

Copy link
Copy Markdown
Owner

No description provided.

claude and others added 6 commits October 14, 2026 08:48
Six lines in sualign()'s TSTRUCT arm.  The old rule reserved the whole
tfield unit at group start, which is MSVC's; under conformalign the
width now advances per field by ceil((shift+nbits)/8) from the
container's offset, so the next ordinary member sits in what is left of
it at its own alignment -- EDG's offset_after_field non-Microsoft arm
written out, and what gcc, clang and every source-to-source tool's
output assume.  Gated because native 6c links the host's libc.a.

The sharing opens a hazard the old rule could not have: makedot types a
bit-field reference as tfield itself, so every reference is a whole
4-byte access and setting one is a read-modify-write.  With the tail
shared w can stop at o+1, and under #pragma pack on the struct would
end three bytes before the access.  One line covers the container, and
the arithmetic says it is free elsewhere: talign >= 4 whenever a bit
field is present, o is a multiple of 4, w >= o+1, so Asu2 already
rounds past it.

sualign-model.py transcribes the loop and checks it against gcc, since
kencc needs Plan 9 headers and the first build is the VM's.  Its
control is __res_state against the measured acid dump, and it refuses
to print when that fails.  It caught the patch's own comment: the
monotone guard was called load-bearing on the claim that a container is
not restarted between two bit fields, and cc.y's edecor: xdecor arm
resets lastbit and firstbit for every ordinary declarator, so it is.
The guard stays, marked defensive.

structalign-test gains section 9 with the five shapes; section 4's
bit-field probe becomes a check, since the thing that promises it now
exists.  The -9 control count goes 14 -> 21, written down before the
run, and bf_aligned and bf_trailing contribute nothing to it either
way -- which is what makes them the control.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
 half-fix from a whole one

The VM's two are 1b and 2a, predicted by reading and then confirmed on
the host by building the generated C with NUMBER as int: exactly those
two, with the wrapped values -2147483648 and -727379968.  They are the
invariant the file exists to measure, not a regression, and they stay
as failures -- NUMBER is the only integer type a BaCon program has, so
demoting the loudest true thing here would hide it.  The test prints
the diagnosis beside the count now.

My first sizing of the fix was wrong by two orders.  I counted "long"
in the generator -- 232 sites, 175 distinct literals -- and called it
large; the generated C contains none of them and routes every NUMBER
through one #define.  Counting the thing that emits is not counting the
thing emitted.

It is still not one line, and section 6c is why: a FUNCTION's return
type is written as the bare word long rather than as NUMBER, so
widening the define alone is a mixed build -- chicken's C_LLP without
C_SIXTY_FOUR.  Measured in all three configurations on the host: as
generated 0 failures, NUMBER and returns both int 3 (1b, 2a, 6c), and
the half-fix 1 -- 6c alone.  Without it a half-fix and a whole one
print the same thing.  The VM count becomes 3, and the third is newly
measured rather than newly broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
Measured on the host by preprocessing lispbibl.d's first 304 lines with
kencc's predefine set: clisp selects NO architecture at all, where the
same file under gcc's own predefines answers AMD64.  kencc predefines
only __STDC__, _POSIX_SOURCE and the two __APEXP_* markers, and the
port passed no CPU macro -- chicken's C_SIXTY_FOUR for the third time,
an upstream list naming spellings this compiler does not use.

The _PLAN9_SOURCE added to lispbibl.d:124 cannot fix it: that #if also
requires one of i386/__i386__/__x86_64__/__amd64__, so the condition is
false and the edit is inert.  And what it reaches is PC386 -> I80386 ->
pointer_bitsize 32, on a machine with 64-bit pointers, while uintP --
the Lisp object representation -- is derived from exactly that.  An
inert edit that would have been actively wrong had it fired.

The widths themselves are fine: long_bitsize and pointer_bitsize are
separate settings, uintP follows the pointer one, and configure
measures both with the real compiler.  So the gap really is just the
CPU macro, per objtype, and an unknown one now fails loudly rather than
selecting nothing.

Separately, env's arguments are quoted.  = is a syntax character in rc,
legal as a leading assignment or inside quotes and nowhere else, and
env CC=pcc puts bare = signs in arguments.  One grep over every mkfile
in the tree finds no other instance of the unquoted form, which is the
precedent check that would have cleared it had there been one.  Not
measured -- there is no rc on the build host -- so it is the recorded
rule plus the absent precedent rather than a run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
I wrote that no working precedent exists in the tree for an unquoted
key=value argument in an rc recipe.  A sweep of recipe lines only --
as opposed to every tab-indented line, which also catches CFLAGS
continuations and gave 83 hits of noise -- finds one other:
lib/ap/mkfile:63, `mk objtype=$objtype install'.  It sits in
installall:V:, which a normal mk install never reaches, so it is an
untriggered line rather than a demonstrated precedent -- but "none"
was wrong and an almost-true claim reads as having been verified.

The sweep also explains why every -DFOO=1 in the tree is fine and the
edg one was not: those arrive through $CFLAGS, and mk exports its
variables into rc's environment, so rc expands them after parsing and
the = never reaches the parser as text.  A literal one typed into a
recipe does.

One command on the VM settles both lines either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
@staalmannen
staalmannen merged commit 5699c93 into main Oct 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants