xm-darwin: force 32-bit HOST_WIDE_INT to match Linux i386 reference#35
Merged
Xeeynamo merged 4 commits intoMay 13, 2026
Merged
Conversation
The macOS build of cc1 produces non-bit-identical machine code vs the
Linux i386 reference build for the same C input. Root cause: machmode.h
derives HOST_WIDE_INT from `long`, which is 64-bit on darwin LP64 and
32-bit on i386-host Linux (where the reference is built with -m32):
#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
#define HOST_WIDE_INT long /* 64-bit on darwin */
#else
#define HOST_WIDE_INT int /* 32-bit on i386 */
#endif
cc1's internal integer-constant arithmetic (constant folding, RTL
constants, shifts, sign-extension) all operate on HOST_WIDE_INT. With
64-bit width, intermediate values keep precision the source never asked
for, propagating into different code generation in non-trivial ways.
Override HOST_WIDE_INT to 32-bit in xm-darwin.h. cc1 itself remains a
64-bit Mach-O binary; only target-constant width is constrained, mirroring
the i386-host Linux build. Host pointer/size_t semantics are unaffected.
Add a regression test (tests/host_wide_int.c) that compiles a function
returning `1u << 31` and greps for `# 0x80000000$` in the output. cc1
prints constants at HOST_WIDE_INT width, so a 64-bit-host build emits
`# 0xffffffff80000000` (sign-extended); the test catches the divergence
without needing to compare bit-exact machine code. Wired into all three
macos.sh build scripts and the corresponding Linux Dockerfiles for
parity.
Concrete validation: rood-reverse (https://github.com/ser-pounce/rood-reverse)
goes from 8 PRG mismatches in `make check` to all-match with this patch.
The size of the codegen drift before the fix was substantial — e.g.
MENU8.PRG/88.o was 44 bytes shorter than the Linux reference, which
cascaded into VMA shifts across multiple downstream sections.
Xeeynamo
reviewed
May 13, 2026
Collaborator
Xeeynamo
left a comment
There was a problem hiding this comment.
Looks good so far. I only ask to remove the comment that have been added. A git blame on file and line is enough to go back to the PR and find the intention of a change.
Co-authored-by: Luciano Ciccariello <Xeeynamo@users.noreply.github.com>
Co-authored-by: Luciano Ciccariello <Xeeynamo@users.noreply.github.com>
Xeeynamo
approved these changes
May 13, 2026
This was referenced May 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The macOS-native cc1 binaries (added in #34) produce non-bit-identical machine code vs the Linux i386 reference build for the same C input. Concrete repro: when used as the cc1 binary for rood-reverse (a PSX decompilation), 8 of the project's PRGs fail `make check`. Same C source, same maspsx/binutils chain, same preprocessor — only the cc1 binary differs.
For example, MENU8.PRG/88.o is 44 bytes shorter when compiled by the macOS cc1 vs the Linux cc1, and that drift cascades across sections downstream.
Root cause
`machmode.h:49-55` derives `HOST_WIDE_INT` from `long`:
```c
#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
#define HOST_WIDE_INT long
#else
#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
#define HOST_WIDE_INT int
#endif
```
cc1's internal integer-constant arithmetic (constant folding, RTL constants, shifts, sign-extension) all operate on `HOST_WIDE_INT`. With 64-bit width, intermediate values keep precision the source never asked for, propagating into different code generation in non-trivial ways.
Fix
Override `HOST_WIDE_INT` to 32-bit in `patches/xm-darwin.h`. cc1 itself remains a 64-bit Mach-O binary; only target-constant width is constrained. Host pointer / `size_t` semantics are unaffected.
Test
Adds `tests/host_wide_int.c` — compiles `return 1u << 31;` and greps for `# 0x80000000$` in the output. cc1 prints constants at `HOST_WIDE_INT` width:
The grep catches the divergence without needing bit-exact .o comparisons. Wired into all three `*-macos.sh` scripts and the corresponding Linux Dockerfiles for parity.
Validation
With this patch applied: