On this page

Run self-hosting checks

Run Pipit's compiler under the interpreter and compare its bytecode with native compilation. This checks whether Pipit can run its own compiler. It does not execute the resulting bytecode. These checks run separately from make test and make check.

The tests live in tests/integration/selfhost, a separate module enabled by the integration build tag. They do not add dependencies to the public library.

Run the checks

Run from the repository root:

PIPIT_SELFHOST_ARGS="-report /tmp/pipit-selfhost-report.md" \
  go test -tags integration -count=1 -run '^TestSelfhost$' ./tests/integration/selfhost/

The harness loads internal/compile from source and runs it under Pipit. Each corpus program is compiled both natively and under interpretation, then the packed bytecode is compared byte for byte. The command writes counts, timings, and differences to /tmp/pipit-selfhost-report.md. Inspect that file for the result. The broader make test-integration command updates the committed self-hosting report.

Only the top-level internal/compile package runs interpreted. Its subpackages and Pipit's other packages come natively through sdk/selfhost, whose symbol tables are generated from pipit-symbols-selfhost.yaml with make generate-selfhost-symbols. Packages such as go/ast and go/types come from the standard-library registry.

Select programs and diagnostics

TestSelfhost runs the harness with its defaults. Without -report, it overwrites the committed self-hosting report. Set PIPIT_SELFHOST_ARGS to pass these flags to the harness:

FlagEffect
-corpus DIRthe directory whose */eval.go files are compiled
-compiler DIRthe directory holding the compiler's sources (default internal/compile)
-filter A,Bcompile only the programs whose directory name contains one of the fragments
-limit Ncompile only the first N programs (after -filter)
-vone line per program
-go-dispatch=falserun the interpreted compiler on the assembly dispatcher (see below)
-no-passescompile the compiler itself without optimisation passes
-no-arena-promotioncompile the compiler itself without arena annotations, so every allocation is on the heap
-no-gcnever run the register arena's minor collection while the interpreted compiler runs
-dump DIRsave mismatched bytecode, listings and failure stacks
-trace-lowerings FILElog lowering decisions; also set PIPIT_TRACE_LOWERING=1
-disasm NAMEprint the interpreted compiler's listing of one function, with source lines, and exit
-report FILEthe markdown report path

For example, select programs whose directory names contain 0957 and save diagnostics:

mkdir -p /tmp/selfhost
PIPIT_SELFHOST_ARGS="-filter 0957 -dump /tmp/selfhost -report /tmp/selfhost/report.md" \
  go test -tags integration -count=1 -run '^TestSelfhost$' ./tests/integration/selfhost/

Interpret the result

Inspect the report even when go test passes. TestSelfhost logs bytecode mismatches without failing the test. It fails only when the harness could not run or no report exists at the report path, so a report left by an earlier run still passes. The harness itself returns 0 when every compared program compiles identically; programs that fail natively or do not parse are not compared.

Run additional checks

Run the compiler's own source check and the assembly-dispatch check:

go test -tags integration -count=1 \
  -run '^(TestSelfhostCompilesItself|TestSelfhostAssemblyDispatch)$' \
  ./tests/integration/selfhost/

The first test compares compilation of the compiler itself. The second runs a subset of programs using assembly dispatch. Both are skipped under -short.

To compare two runs of the full corpus:

PIPIT_SELFHOST_DETERMINISM=2 go test -tags integration -count=1 -v \
  -run '^TestSelfhostIsDeterministic$' ./tests/integration/selfhost/

This checks whether each program has the same outcome on both runs. It does not require every program to compile successfully. Use PIPIT_SELFHOST_ARGS to select a smaller set, as shown above. The determinism test writes temporary reports.

To run the full corpus using assembly dispatch:

PIPIT_SELFHOST_ARGS="-go-dispatch=false -report /tmp/pipit-selfhost-assembly.md" \
  go test -tags integration -count=1 -run '^TestSelfhost$' ./tests/integration/selfhost/

Inspect /tmp/pipit-selfhost-assembly.md for mismatches. To investigate memory reuse, add pipit_arena_paranoid to the build tags. This fills released register slabs with a marker value, so accidental reuse returns obviously wrong values.