Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5ff1441
[IP] Fixed heap bufer overflow and stack overflows, main problem was …
matgla Jun 26, 2026
05585e3
submodule fix
matgla Jun 26, 2026
5ef1004
gcc-torture: always fetch the pinned commit, never gcc master
matgla Jun 26, 2026
9b4589b
gcc-torture: bump pinned gcc to cbc56384; handle the new tests
matgla Jun 26, 2026
a485fa9
ci: upload debug artifacts when make test fails
matgla Jun 26, 2026
76fa701
fixed bug and added unit tests
matgla Jun 26, 2026
44e3ead
adding new tests
matgla Jun 26, 2026
61233c3
checkpoint before hard-float VFP work
matgla Jun 27, 2026
2be6f5b
bug fixing ongoing
matgla Jun 27, 2026
9a2fdfe
Added a lot of tests that discovered real bugs.
matgla Jun 27, 2026
cffe850
added more fixed for fuzz tests
matgla Jun 30, 2026
35ff198
libs/tinycc: fix packed-bitfield byte store widened to word store
matgla Jun 30, 2026
fe7f1e5
libs/tinycc: knownbits sub-word store slot-overlap fix + test 233
matgla Jun 30, 2026
c7a809a
libs/tinycc: regalloc — keep values off R12 across SWITCH_TABLE dispatch
matgla Jun 30, 2026
f325004
Fixed a lot of compiler bugs, working on metrics server, added a lot of
matgla Jul 3, 2026
5338600
grafana serviec
matgla Jul 3, 2026
5461a9f
changed docker to podman
matgla Jul 3, 2026
0648ee8
fix for docker ompose
matgla Jul 3, 2026
39b5c5e
fixed grafana image
matgla Jul 3, 2026
c0ad730
changed workflow, reduce amount of work on rpi
matgla Jul 3, 2026
7a90f00
fixes for CI
matgla Jul 3, 2026
c09dcf5
removed coverage
matgla Jul 3, 2026
fb6fef2
more tests and fixes
matgla Jul 4, 2026
8e4dc03
more tests
matgla Jul 5, 2026
cb99e17
more tests and fixes
matgla Jul 5, 2026
ade49f9
fix and better workflow
matgla Jul 5, 2026
f8e882d
more fixes
matgla Jul 5, 2026
6442bc2
more CI improvements
matgla Jul 5, 2026
97ab471
more fixes
matgla Jul 5, 2026
6e17641
more generic wchar_t
matgla Jul 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
104 changes: 102 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ on:
branches: [mob]
pull_request:
branches: [mob]
workflow_dispatch:

env:
# Stable synthetic key the metrics job records under (metrics.db keys runs by
# commit_sha+host) -- decoupled from the Pi's actual hostname so dashboard
# rows stay under one stable host even if the runner hostname changes.
METRICS_HOST: armv8m-metrics

jobs:
build-and-test:
Expand All @@ -25,11 +32,104 @@ jobs:
submodules: recursive

- name: Configure
run: ./configure --enable-cross --enable-O2
# --debug enables CONFIG_TCC_DEBUG so the compiler supports -dump-ir;
# without it the frontend types/ tests skip (they need IR dumps).
run: ./configure --enable-cross --enable-O2 --debug

- name: Build and test
shell: bash
env:
# Write a JUnit report from every pytest run (the final ir_tests run
# overwrites it last) so the failure collector knows which tests failed.
PYTEST_ADDOPTS: "--junitxml=/tmp/ci-junit.xml"
run: |
virtualenv .venv
source .venv/bin/activate
make test -j$(nproc)
# `shell: bash` runs with -eo pipefail, so a failing make still fails
# the step even though its output is teed to a log we upload on failure.
make test CI=1 -j$(nproc) 2>&1 | tee /tmp/make-test.log

- name: Golden IR snapshot tests
# Snapshot the per-pass IR against checked-in .expected files. Kept a
# separate step (and a separate `make` target) from `make test`: it
# needs -dump-ir-passes, a debug/diagnostic interface, which the
# --debug build above provides. Runs after `make test` so the cross
# compiler and venv it depends on already exist.
shell: bash
run: |
source .venv/bin/activate
make test-golden-ir

- name: Collect failure artifacts
if: failure()
shell: bash
env:
MAKE_TEST_LOG: /tmp/make-test.log
PYTEST_JUNIT_XML: /tmp/ci-junit.xml
run: |
source .venv/bin/activate 2>/dev/null || true
bash scripts/collect_ci_failure_artifacts.sh "$PWD/ci-failure-artifacts"

- name: Upload failure artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: make-test-failure-artifacts
path: ci-failure-artifacts.tar.gz
retention-days: 14
if-no-files-found: warn

# Metrics: code size (tcc-vs-gcc disasm comparison) + compile time + RP2350
# hardware perf, all on the self-hosted Pi in one job. Merged from the old
# split build-and-measure (cloud codesize) + rp2350-perf (board perf): the
# cross compiler is host-native, so it can't be handed to the aarch64 Pi as
# an artifact anyway -- and the Pi already has the arm-none-eabi toolchain
# the disasm comparison needs, so there's nothing to offload to the cloud.
# One record.py call measures codesize and perf locally against the same
# freshly built tcc, so no scratch-db round-trip / --import-codesize-from.
metrics:
runs-on: [self-hosted, rpi5, pimoroni_pico_plus2]
timeout-minutes: 120
concurrency:
group: metrics-rpi5
cancel-in-progress: false
env:
METRICS_DB: /var/lib/tcc-metrics/metrics.db
PERF_HOST: 127.0.0.1
PERF_IDENTITY: /home/runner/.ssh/id_rp

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
# depth 1 is enough: `make cross` stamps a version string via git
# rev-parse/log -1/diff (no history walk) and record.py runs
# `git show -s HEAD`.
fetch-depth: 1

- name: Build cross compiler
# armv8m-tcc is a *cross* compiler: it targets ARMv8-M but the binary
# itself is host-native, so it must be built on this aarch64 Pi rather
# than shared from an x86_64 runner (an x86_64 build can't exec here --
# the shell would fall back to interpreting it: "Syntax error: )
# unexpected"). --enable-O2/--debug only affect tcc's own binary, not
# the code it emits, so codesize/perf are unaffected by this config.
run: ./configure --enable-cross --enable-O2 --debug && make cross -j$(nproc)

- name: Record codesize + compile time + perf
# --codesize-detail runs the tcc-vs-gcc disasm comparison over the
# corpus (fills codesize_rollup + the per-function codesize_func table
# for Grafana's drill-down); --perf-host runs the RP2350 board
# benchmark. Both land in the real metrics.db under the same run.
# --keep 20 prunes older runs to bound DB growth from --codesize-detail.
run: |
python3 metrics/record.py --db "$METRICS_DB" --rev HEAD --no-correctness \
--codesize-detail --jobs "$(nproc)" \
--host "$METRICS_HOST" --trigger "${{ github.event_name }}" \
--perf-host "$PERF_HOST" --perf-identity "$PERF_IDENTITY" --perf-strict \
--branch mob --keep 20

- name: Gate
if: ${{ vars.METRICS_GATE_ENABLED == 'true' }}
run: python3 metrics/gate.py --db "$METRICS_DB" --rev HEAD --host "$METRICS_HOST" --strict
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ tcc.1
tcc-doc.html
tcc-doc.info

# gcov/lcov coverage artifacts (make coverage-tccgen)
coverage-tccgen/
*.gcda
*.gcno
*.info

win32/doc
win32/examples/libtcc_test.c
win32/libtcc
Expand Down Expand Up @@ -73,6 +79,14 @@ tests/hello
tests/tests2/fred.txt
libtcc.dylib
build/
build_backend/
build_libtcc_api/
build_tccgen/
build_tccopt/
build_tccelf/
build_tccpp/
build_tcctools/
build_tccyaff/
rootfs/
__pycache__/
tests/ir_tests/qemu/mps2-an505/newlib_build/
Expand All @@ -97,8 +111,20 @@ tests/ir_tests/dump_ir.txt
tests/ir_tests/dump.txt
tests/ir_tests/dump_fine.txt
tests/ir_tests/dump_ir_fine.txt
tests/ir_tests/build/
armv8m-tcc.debug
.aider*
.claude
.cache
scripts/.disasm_cache.json
scripts/.disasm_cache.pending.json

# Python test artifacts
__pycache__/
.pytest_cache/
*.pyc
tests/fuzz/results/*
tests/fuzz/fuzz_triage_repros/
tests/fuzz/.sweep_cache/
tests/unit/arm/armv8m/build*

4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{}
{
"cmake.sourceDirectory": "/home/mateusz/repos/tinycc/tests/benchmarks/libs/pico-sdk"
}
51 changes: 51 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# AGENTS.md

Guidance for autonomous coding agents working in this repository (TinyCC fork
targeting ARMv8-M). Read this first, then `CLAUDE.md` for the full project
overview, build commands, and architecture.

## Build & test (always current)

```bash
make cross -j$(nproc) # build armv8m-tcc (rebuild after EVERY edit)
make test -j16 # IR test suite (primary gate)
python3 scripts/diff_olevels.py --seeds 0-5000 --require-qemu # fuzz self-consistency
```

Style: `-std=c11 -Wunused-function -Werror` (treat warnings as build failures).
Function-body brace on its own line; see `.clang-format` and `CLAUDE.md`.

## Debugging an optimizer miscompilation

When a fuzz seed diverges between O-levels (tcc -O0 correct, -O1/-O2 wrong),
follow **`docs/debugging_fuzz_divergences.md`** end-to-end:

1. `scripts/bisect_opt.py --seed N --high=-O1` — QEMU-confirms the culprit
knob(s) and flags the exact IR line where a memory read is misfolded to a
constant, naming the pass group and the gated pass functions.
2. Write a **regression test first** (`tests/ir_tests/NN_fuzz_<cause>.c` +
`.expect`, registered in `tests/ir_tests/test_qemu.py`); confirm it fails
before the fix and passes after.
3. Fix, rebuild, re-run the IR suite + a fuzz sweep; confirm zero *new*
divergences.

Ground truth oracle is `gcc -m32 -funsigned-char` (ARM ABI: unsigned char,
32-bit long). Sweep/triage infrastructure is documented in
`docs/fuzz_triage_guide.md`.

## Conventions for changes

- **Never commit without a regression test** for a bug fix — verbatim or reduced
repro under `tests/ir_tests/`, expected output in a `.expect` file.
- New IR opcode → lowering in `arm-thumb-gen.c` + test. New asm instruction →
builder in `arm-thumb-opcodes.c` + token + parser + test.
- IR internals live in `ir/` (included via `ir/ir.h`); the public IR interface
is `tccir.h`. Internal IR functions are `ir_<module>_<action>()`.
- Don't commit the temporary `TCC_SKIP_SSA*` env-var bisection gates (see the
triage guide); they are investigation-only scaffolding.

## Don't

- Don't disable ASan/leak checks to "fix" a failure; investigate the root cause.
(ASan is ON by default; `./configure --disable-asan` for fast builds only.)
- Don't commit secrets, force-push, or create empty commits.
9 changes: 8 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This is a specialized fork of **TinyCC (Tiny C Compiler)** targeting **ARMv8-M**

```bash
# One-time setup
./configure
./configure # AddressSanitizer is ON by default; ./configure --disable-asan for fast/production builds
make download-gcc-tests # optional: sparse-fetch GCC torture tests (~16 MB, not the full gcc repo)

# Build ARMv8-M cross compiler
Expand Down Expand Up @@ -140,6 +140,13 @@ Build uses `-std=c11 -Wunused-function -Werror`.

## Debug Logging

For debugging **optimizer miscompilations** found by the differential fuzzer
(tcc -O0 correct, -O1/-O2 wrong), see
[`docs/debugging_fuzz_divergences.md`](docs/debugging_fuzz_divergences.md) — the
end-to-end workflow built around `scripts/bisect_opt.py` (QEMU-confirmed culprit
knob + the exact IR line where a memory read is misfolded to a constant).
`docs/fuzz_triage_guide.md` covers the sweep/triage infrastructure.

Unified logging system defined in `log.h`. Each scope is a compile-time switch:

```bash
Expand Down
Loading
Loading