Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8280a0d
wip
matgla Feb 21, 2026
bf6ebcb
added gcctest suite
matgla Feb 22, 2026
f579608
before nested functions implementation
matgla Feb 22, 2026
9e44c00
fix for constant propagation bug when addrtaken
matgla Feb 24, 2026
6df8842
fixed few bugs for structs and optimizations
matgla Feb 25, 2026
07f3505
fixed more bugs, more tests are passing
matgla Feb 27, 2026
ef4ff71
few more fixes
matgla Feb 27, 2026
21fb135
mopre fixes
matgla Feb 27, 2026
f08a71a
more fixes
matgla Feb 28, 2026
c6eef74
more fixes
matgla Feb 28, 2026
6fdd3de
next fix
matgla Feb 28, 2026
c5adc30
wip
matgla Feb 28, 2026
b6ff832
few fixes
matgla Feb 28, 2026
30ca0b1
fixes
matgla Feb 28, 2026
c0eea5f
added builtin clsassify
matgla Feb 28, 2026
ee7d19f
next vla fix
matgla Feb 28, 2026
a469998
Materialization refactoring ongoing
matgla Feb 28, 2026
7d31970
implemented materialization
matgla Mar 3, 2026
a615ce3
all tests are passing
matgla Mar 7, 2026
07564ca
adding more tests
matgla Mar 13, 2026
825a731
wip
matgla Mar 14, 2026
2e936d5
fixes for runner
matgla Mar 14, 2026
6c9f390
wip
matgla Mar 14, 2026
cb37f5b
more fixes
matgla Mar 14, 2026
cdbc6aa
fixed ieee
matgla Mar 14, 2026
d3d4974
fixes
matgla Mar 14, 2026
612ee20
wip
matgla Mar 15, 2026
046e837
wip
matgla Mar 18, 2026
a5cbbbd
more fixes
matgla Mar 19, 2026
f33ecf1
rest fixes
matgla Mar 19, 2026
89195a8
fixed bugs after fixing things for yasos
matgla Mar 21, 2026
ebac649
fix for bugs
matgla Mar 22, 2026
1672815
fetching gcc testsuite
matgla Mar 22, 2026
39a4f06
updated submodule
matgla Mar 22, 2026
dee174d
changed revision
matgla Mar 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# TinyCC ARMv8-M — Copilot Instructions

## Project Overview

Specialized TinyCC fork targeting **ARMv8-M** (Cortex-M33) Thumb-2. IR-based pipeline: C source → preprocessor (`tccpp.c`) → parser (`tccgen.c`) → IR (`tccir.h`, `ir/core.c`) → optimizations (`ir/opt.c`, `ir/licm.c`) → register allocation (`tccls.c`, `ir/live.c`) → Thumb-2 codegen (`arm-thumb-gen.c`) → ELF (`tccelf.c`).

## Build & Test

```bash
./configure && make cross # build armv8m-tcc cross compiler
make test -j16 # primary IR test suite (pytest + QEMU)
make test-asm -j16 # assembly instruction tests
make test-all # IR + GCC torture tests
```

Single-file testing: `cd tests/ir_tests && python run.py -c mytest.c` (add `--dump-ir`, `--cflags="-O1"`, `--gdb` as needed).

## Key Source Files

| File | Role |
|---|---|
| `tccgen.c` | C parser + type system (largest file) |
| `arm-thumb-gen.c` | IR → Thumb-2 backend (~12k lines) |
| `ir/codegen.c` | Central dispatch: routes IR ops to backend handlers |
| `ir/machine_op.h` | `MachineOperand` type (8 kinds: REG, SPILL, IMM, FRAME_ADDR, SYMBOL, PARAM_STACK, CHAIN_REL, NONE) |
| `ir/machine_op.c` | `machine_op_from_ir()` — converts IROperand to MachineOperand |
| `tccls.c` | Linear-scan register allocator |
| `arm-thumb-callsite.c` | AAPCS call-site layout builder |
| `arch/arm_aapcs.c` | ARM procedure call standard |

## Architecture Patterns

### Backend Handler Naming

Backend functions follow a dual naming convention during the ongoing materialization refactor:
- `tcc_gen_machine_<op>_mop(MachineOperand ...)` — **new** MachineOperand-based handlers (preferred)
- `tcc_gen_machine_<op>_op(IROperand ...)` — **legacy** IROperand-based handlers (being removed)

All backend handler declarations live in `tcc.h` (~line 2114+). New code should use `_mop` variants exclusively.

### IR Dispatch (ir/codegen.c)

The codegen uses a single unified two-pass loop (`for (pass = 0; pass < 2; pass++)`):
- **Pass 0 (dry-run)**: discovers scratch register needs, collects branch offsets — `ot()` is a no-op; records per-instruction scratch counts.
- **Inter-pass**: analyzes branch encodings, checks LR usage, runs scratch conflict fixup, emits prologue.
- **Pass 1 (real-run)**: emits actual Thumb-2 machine code using dry-run data for consistency checks.

Both passes share a single `switch (cq->op)` dispatch. Pass-specific behavior (e.g. SWITCH_TABLE sizing, RETURNVOID epilogue jump, INLINE_ASM) uses `if (is_dry_run)` / `if (!is_dry_run)` guards. Adding a new IR op requires adding only one `case`.

### IR Subsystem (`ir/`)

Internal modules included via `ir/ir.h` (which pulls in `tcc.h` first). Naming:
- Static/internal: `ir_<module>_<action>()`
- Public API (in `tccir.h`): `tcc_ir_<action>()`

IR opcodes defined as `TccIrOp` enum in `tccir.h`. Key groups: arithmetic (`ADD`, `SUB`, `MUL`), memory (`LOAD`, `STORE`, `LEA`), control (`JUMP`, `JUMPIF`), function (`FUNCPARAMVAL`, `FUNCCALLVAL`, `RETURNVALUE`), FP (`FADD`, `FSUB`, `CVT_ITOF`).

## Coding Conventions

- `.clang-format`: LLVM-based, 120-col, Allman braces (`BreakBeforeBraces: Allman`)
- Build enforces `-std=c11 -Wunused-function -Werror`
- 2-space indentation inside function bodies; function-level braces on new line, inner braces on same line

## Adding New Functionality

**New IR instruction:** add opcode to `TccIrOp` in `tccir.h` → add lowering in `arm-thumb-gen.c` → add test in `tests/ir_tests/`

**New assembly instruction:** add builder in `arm-thumb-opcodes.c` → token in `thumb-tok.h` → parser in `arm-thumb-asm.c` → test in `tests/thumb/armv8m/`

**New IR test:** create `tests/ir_tests/NN_name.c` + `.expect` file → add entry to `TEST_FILES` in `tests/ir_tests/test_qemu.py`. Avoid adding to `tests/tests2/` (legacy).

## Debug Flags

```bash
make cross CFLAGS+='-DCONFIG_TCC_DEBUG' # enables -dump-ir at runtime
make cross CFLAGS+='-DTCC_LS_DEBUG' # register allocator tracing
make cross CFLAGS+='-DPARSE_DEBUG' # parser debug output
```

Runtime: `./armv8m-tcc -dump-ir -c test.c` or `./armv8m-tcc -vv -c test.c`.

## Test Infrastructure

- IR tests run via QEMU (`qemu-system-arm`, MPS2-AN505 board) with semihosting
- First run requires building newlib: `cd tests/ir_tests/qemu/mps2-an505 && sh ./build_newlib.sh`
- GCC torture tests use submodule: `git submodule update --init --depth 1 tests/gcctestsuite/gcc-testsuite`
- ARM register convention (AAPCS): r0–r3 args/caller-saved, r4–r11 callee-saved, r12+lr caller-saved
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*.lib
*.exp
*.log
vgcore.*
*.bz2
*.zip
.gdb_history
Expand All @@ -27,6 +28,7 @@ config*.h
config*.mak
config.texi
conftest*
!**/conftest.py
c2str
tags
TAGS
Expand Down Expand Up @@ -78,4 +80,8 @@ tests/ir_tests/profile_baselines

lib/fp/soft/test_aeabi_all
lib/fp/soft/test_dmul_host
lib/fp/soft/test_host
lib/fp/soft/test_host
tmp/

.venv
bin/
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
url = https://github.com/c-testsuite/c-testsuite.git
[submodule "tests/ir_tests/qemu/mps2-an505/libs/newlib"]
path = tests/ir_tests/qemu/mps2-an505/libs/newlib
url = https://sourceware.org/git/newlib-cygwin.git
url = https://github.com/RTEMS/sourceware-mirror-newlib-cygwin.git
[submodule "tests/benchmarks/libs/pico-sdk"]
path = tests/benchmarks/libs/pico-sdk
url = https://github.com/raspberrypi/pico-sdk.git
[submodule "tests/benchmarks/mibench"]
path = tests/benchmarks/mibench
url = https://github.com/embecosm/mibench.git
[submodule "tests/gcctestsuite/gcc-testsuite"]
path = tests/gcctestsuite/gcc-testsuite
url = https://github.com/gcc-mirror/gcc.git
19 changes: 15 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,20 +208,31 @@ The project uses multiple testing frameworks:
- Tests are numbered: `01_hello_world.c`, `20_op_add.c`, etc.
- Each `.c` file has a corresponding `.expect` file with expected output

2. **Assembly Tests** (`tests/thumb/armv8m/`): pytest-based assembler tests
2. **GCC Torture Tests** (`tests/gcctestsuite/`): GCC c-torture test suite
- ~2000 compile tests and ~1700 execute tests from GCC
- Git submodule at `tests/gcctestsuite/gcc-testsuite`
- Run via `make test-all` or `pytest tests/gcctestsuite/`

3. **Assembly Tests** (`tests/thumb/armv8m/`): pytest-based assembler tests
- Test individual Thumb-2 instructions
- Compares TCC output against `arm-none-eabi-gcc`

3. **Legacy Tests** (`tests/tests2/`, `tests/pp/`): Makefile-based tests
- C language compliance tests
4. **Legacy Tests** (`tests/tests2/`, `tests/pp/`): Makefile-based tests
- C language compliance tests (curated subset run via IR tests)
- Preprocessor tests

### Running Tests

```bash
# Full test suite (requires ARM cross toolchain, use -j16 for parallel execution)
# Initialize GCC testsuite submodule (one-time)
git submodule update --init --depth 1 tests/gcctestsuite/gcc-testsuite

# Run IR tests (includes curated tests2)
make test -j16

# Run GCC torture tests
make test-all

# Run only IR tests
make test-venv test-prepare
cd tests/ir_tests && pytest -s -n auto
Expand Down
188 changes: 188 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a specialized fork of **TinyCC (Tiny C Compiler)** targeting **ARMv8-M** (Cortex-M33, Cortex-M23). It features a custom IR-based compilation pipeline for embedded ARM Thumb-2 targets.

## Build Commands

```bash
# One-time setup
./configure
git submodule update --init --depth 1 tests/gcctestsuite/gcc-testsuite # optional GCC tests

# Build ARMv8-M cross compiler
make cross

# Build everything including floating point libraries
make cross fp-libs

# Run tests
make test -j16 # IR tests (primary test suite)
make test-asm -j16 # Assembly instruction tests
make test-all # IR + GCC torture tests
make test-gcc-torture-compile # GCC compile-only tests

make clean # Clean build artifacts
```

Output binaries: `armv8m-tcc` (cross compiler), `armv8m-libtcc1.a` (runtime library).

## Running Tests

```bash
# Quick manual test for a single file
cd tests/ir_tests
python run.py -c mytest.c
python run.py -c mytest.c --cflags="-O1"
python run.py -c mytest.c --dump-ir # dump IR
python run.py -c mytest.c --gdb # QEMU GDB debugging

# Run specific pytest IR tests
cd tests/ir_tests && pytest -s -n auto
pytest tests/ir_tests/ -v -k "test_name"

# Run pytest for other suites
pytest tests/gcctestsuite/ -v # GCC torture tests
pytest tests/thumb/armv8m/ -v # assembler tests
```

## Adding Tests

- **IR tests (preferred)**: Create `tests/ir_tests/NN_test_name.c` + add to `TEST_FILES` in `tests/ir_tests/test_qemu.py`. Each `.c` file has a corresponding `.expect` file with expected output.
- **Assembly tests**: Add to `tests/thumb/armv8m/`.
- Avoid adding to `tests/tests2/` (legacy).

## Compilation Pipeline

```
C Source → Preprocessor (tccpp.c)
→ Parser + type checker (tccgen.c)
→ IR generation (tccir.h / ir/core.c)
→ IR optimizations (ir/opt.c, ir/licm.c)
→ Register allocation (tccls.c + ir/live.c)
→ Thumb-2 code gen (arm-thumb-gen.c)
→ ELF output (tccelf.c, tccld.c)
```

## Code Architecture

### Key Source Files

| File | Role |
|------|------|
| `tccgen.c` | C parser, type system, semantic analysis (largest file) |
| `arm-thumb-gen.c` | IR → Thumb-2 code generation backend |
| `tccpp.c` | C preprocessor (macros, includes, conditionals) |
| `tccelf.c` | ELF object file: sections, relocations, symbols |
| `tccls.c` | Liveness analysis + linear scan register allocator |
| `tccld.c` | Linker: symbol resolution, section merging |
| `tccdbg.c` | DWARF/STAB debug info generation |
| `libtcc.c` | Public API for using TCC as a JIT library |
| `arm-thumb-opcodes.c` | Thumb-2 opcode builders |
| `arm-thumb-asm.c` | Inline assembly parser |
| `arch/arm_aapcs.c` | ARM Procedure Call Standard (parameter passing) |

### IR Subsystem (`ir/`)

Internal IR modules — included via `ir/ir.h`, not part of public API. Public IR interface is `tccir.h`.

| File | Role |
|------|------|
| `ir/opt.c` | Main optimizations: constant folding, DCE, etc. |
| `ir/licm.c` | Loop-invariant code motion |
| `ir/core.c` | IR construction and manipulation |
| `ir/live.c` | Liveness analysis for register allocation |
| `ir/mat.c` | Value materialization (reg/memory allocation) |
| `ir/codegen.c` | Central dispatch: unified two-pass loop (dry-run + real-run) routing IR ops to backend `_mop` handlers |
| `ir/vreg.c` | Virtual register management |
| `ir/stack.c` | Stack frame layout |

IR naming conventions:
- Internal functions: `ir_<module>_<action>()` (static)
- Public API (in `tccir.h`): `tcc_ir_<action>()`

### IR Opcodes

Defined in `tccir.h` as `TccIrOp` enum. Key opcode groups:
- Arithmetic: `TCCIR_OP_ADD`, `SUB`, `MUL`, `DIV`
- Memory: `LOAD`, `STORE`, `LEA`, `LOAD_INDEXED`, `STORE_INDEXED`
- Control: `JUMP`, `JUMPIF`, `IJUMP`, `SWITCH_TABLE`
- Functions: `FUNCPARAMVAL`, `FUNCCALLVAL`, `RETURNVALUE`
- FP: `FADD`, `FSUB`, `FMUL`, `CVT_ITOF`, `CVT_FTOI`

### Register Allocation

Two-phase in `tccls.c`:
1. Liveness analysis (`ir/live.c`) — compute live ranges
2. Linear scan — assign physical registers (r0–r12), spill overflow

ARM AAPCS: r0–r3 for first 4 arguments; caller-saved r0–r3, r12, lr; callee-saved r4–r11.

## Coding Conventions

Style defined in `.clang-format`. Function body brace on new line, inner braces on same line:

```c
void function_name(int arg)
{
if (condition) {
do_something();
} else {
do_other();
}
}
```

Build uses `-std=c11 -Wunused-function -Werror`.

## Debug Flags

Pass via `CFLAGS+=` to `make`:

```bash
make CFLAGS+='-DPARSE_DEBUG' # parser debug
make CFLAGS+='-DPP_DEBUG' # preprocessor debug
make CFLAGS+='-DASM_DEBUG' # assembler debug
make CFLAGS+='-DCONFIG_TCC_DEBUG' # enables -dump-ir flag
make CFLAGS+='-DTCC_LS_DEBUG' # register allocator detail
```

At runtime:
```bash
./armv8m-tcc -dump-ir -c test.c # dump IR
./armv8m-tcc -vv -c test.c # verbose output
```

## Extending the Compiler

**New IR instruction:**
1. Add opcode to `TccIrOp` in `tccir.h`
2. Add lowering in `arm-thumb-gen.c`
3. Add test in `tests/ir_tests/`

**New assembly instruction:**
1. Add opcode builder in `arm-thumb-opcodes.c`
2. Add token in `thumb-tok.h`
3. Add parser support in `arm-thumb-asm.c`
4. Add test in `tests/thumb/armv8m/`

## Floating Point Libraries

Located in `lib/fp/`. Build variants:

```bash
cd lib/fp && make FPU=soft # software FP (no FPU)
cd lib/fp && make FPU=vfpv4-sp # Cortex-M4F (single-precision)
cd lib/fp && make FPU=vfpv5-dp # Cortex-M7 (double-precision)
cd lib/fp && make FPU=rp2350 # RP2350 DCP
```

## Test Infrastructure Notes

- IR tests run via QEMU (`qemu-system-arm`) against MPS2-AN505 board model
- The first run builds newlib: `cd tests/ir_tests/qemu/mps2-an505 && sh ./build_newlib.sh`
- GCC torture tests use a git submodule at `tests/gcctestsuite/gcc-testsuite`; tests using `__builtin_*` or `_Complex` are auto-skipped
- Each tests2 test runs at both `-O0` and `-O1`
Loading
Loading