cymphony 0.14.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cymphony-0.14.3/MANIFEST.in +7 -0
- cymphony-0.14.3/Makefile +41 -0
- cymphony-0.14.3/PKG-INFO +6 -0
- cymphony-0.14.3/README.md +356 -0
- cymphony-0.14.3/cymphony.egg-info/PKG-INFO +6 -0
- cymphony-0.14.3/cymphony.egg-info/SOURCES.txt +75 -0
- cymphony-0.14.3/cymphony.egg-info/dependency_links.txt +1 -0
- cymphony-0.14.3/cymphony.egg-info/entry_points.txt +3 -0
- cymphony-0.14.3/cymphony.egg-info/requires.txt +1 -0
- cymphony-0.14.3/cymphony.egg-info/top_level.txt +1 -0
- cymphony-0.14.3/docs/architecture.md +187 -0
- cymphony-0.14.3/docs/c-language-support.md +234 -0
- cymphony-0.14.3/docs/design.md +120 -0
- cymphony-0.14.3/docs/isa.txt +495 -0
- cymphony-0.14.3/docs/optimization-todos.md +290 -0
- cymphony-0.14.3/docs/validation.md +23 -0
- cymphony-0.14.3/examples/arena_allocator.c +60 -0
- cymphony-0.14.3/examples/bigprime.c +630 -0
- cymphony-0.14.3/examples/constant_folding.c +6 -0
- cymphony-0.14.3/examples/demo.c +17 -0
- cymphony-0.14.3/examples/dynamic_sensor_report.c +207 -0
- cymphony-0.14.3/examples/insertion_sort.c +29 -0
- cymphony-0.14.3/examples/interprocedural_constant_folding.c +12 -0
- cymphony-0.14.3/examples/pi.c +537 -0
- cymphony-0.14.3/examples/primes.c +26 -0
- cymphony-0.14.3/examples/towers_of_hanoi.c +47 -0
- cymphony-0.14.3/pyproject.toml +35 -0
- cymphony-0.14.3/setup.cfg +4 -0
- cymphony-0.14.3/setup.py +15 -0
- cymphony-0.14.3/symphony/__init__.py +13 -0
- cymphony-0.14.3/symphony/__main__.py +3 -0
- cymphony-0.14.3/symphony/backend.py +3 -0
- cymphony-0.14.3/symphony/cli.py +199 -0
- cymphony-0.14.3/symphony/compiler.py +52 -0
- cymphony-0.14.3/symphony/emulator/__init__.py +6 -0
- cymphony-0.14.3/symphony/emulator/machine.py +230 -0
- cymphony-0.14.3/symphony/emulator/native.py +33 -0
- cymphony-0.14.3/symphony/emulator/native_emulator.c +697 -0
- cymphony-0.14.3/symphony/frontend.py +3 -0
- cymphony-0.14.3/symphony/frontends/__init__.py +1 -0
- cymphony-0.14.3/symphony/frontends/c/__init__.py +7 -0
- cymphony-0.14.3/symphony/frontends/c/compiler.py +177 -0
- cymphony-0.14.3/symphony/frontends/c/frontend.py +1079 -0
- cymphony-0.14.3/symphony/frontends/c/parser.py +34 -0
- cymphony-0.14.3/symphony/frontends/c/preprocessor.py +334 -0
- cymphony-0.14.3/symphony/frontends/protocol.py +21 -0
- cymphony-0.14.3/symphony/intrinsics.py +3 -0
- cymphony-0.14.3/symphony/ir.py +3 -0
- cymphony-0.14.3/symphony/isa.py +3 -0
- cymphony-0.14.3/symphony/middle/__init__.py +5 -0
- cymphony-0.14.3/symphony/middle/analysis/__init__.py +5 -0
- cymphony-0.14.3/symphony/middle/analysis/cfg.py +115 -0
- cymphony-0.14.3/symphony/middle/ir.py +447 -0
- cymphony-0.14.3/symphony/middle/model.py +194 -0
- cymphony-0.14.3/symphony/middle/passes/__init__.py +6 -0
- cymphony-0.14.3/symphony/middle/passes/manager.py +32 -0
- cymphony-0.14.3/symphony/middle/passes/pipeline.py +1486 -0
- cymphony-0.14.3/symphony/model.py +3 -0
- cymphony-0.14.3/symphony/optimize.py +5 -0
- cymphony-0.14.3/symphony/optimizer/__init__.py +12 -0
- cymphony-0.14.3/symphony/optimizer/cfg.py +3 -0
- cymphony-0.14.3/symphony/optimizer/pipeline.py +3 -0
- cymphony-0.14.3/symphony/project.py +245 -0
- cymphony-0.14.3/symphony/runtime/__init__.py +6 -0
- cymphony-0.14.3/symphony/runtime/helpers.py +211 -0
- cymphony-0.14.3/symphony/runtime/intrinsics.py +133 -0
- cymphony-0.14.3/symphony/targets/__init__.py +1 -0
- cymphony-0.14.3/symphony/targets/symphony/__init__.py +7 -0
- cymphony-0.14.3/symphony/targets/symphony/abi.py +75 -0
- cymphony-0.14.3/symphony/targets/symphony/assembler.py +177 -0
- cymphony-0.14.3/symphony/targets/symphony/backend.py +1120 -0
- cymphony-0.14.3/symphony/targets/symphony/config.py +57 -0
- cymphony-0.14.3/symphony/targets/symphony/isa.py +190 -0
- cymphony-0.14.3/symphony/targets/symphony/legalize.py +32 -0
- cymphony-0.14.3/symphony/targets/symphony/registers.py +59 -0
- cymphony-0.14.3/tests/test_compiler.py +1231 -0
- cymphony-0.14.3/tests/test_integration.py +260 -0
cymphony-0.14.3/Makefile
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
PYTHON ?= python
|
|
2
|
+
DIST_DIR ?= dist
|
|
3
|
+
WHEEL_DIR ?= $(DIST_DIR)/wheels
|
|
4
|
+
|
|
5
|
+
.PHONY: native install test selfhost selfhost-test wheel ci-wheels sdist dist clean
|
|
6
|
+
|
|
7
|
+
native:
|
|
8
|
+
$(PYTHON) setup.py build_ext --inplace
|
|
9
|
+
|
|
10
|
+
install:
|
|
11
|
+
$(PYTHON) -m pip install -e .
|
|
12
|
+
|
|
13
|
+
test: native
|
|
14
|
+
SYMPHONY_TEST_ISA=dynphony $(PYTHON) -m unittest discover -s tests -v
|
|
15
|
+
SYMPHONY_TEST_ISA=symphony $(PYTHON) -m unittest discover -s tests -v
|
|
16
|
+
SYMPHONY_TEST_ISA=dynphony $(PYTHON) -m unittest discover -s selfhost/tests -v
|
|
17
|
+
SYMPHONY_TEST_ISA=symphony $(PYTHON) -m unittest discover -s selfhost/tests -v
|
|
18
|
+
|
|
19
|
+
selfhost: native
|
|
20
|
+
$(MAKE) -C selfhost stages
|
|
21
|
+
|
|
22
|
+
selfhost-test:
|
|
23
|
+
$(MAKE) -C selfhost test
|
|
24
|
+
|
|
25
|
+
wheel:
|
|
26
|
+
mkdir -p $(WHEEL_DIR)
|
|
27
|
+
$(PYTHON) -m pip wheel --no-deps --no-build-isolation --wheel-dir $(WHEEL_DIR) .
|
|
28
|
+
|
|
29
|
+
ci-wheels:
|
|
30
|
+
mkdir -p $(WHEEL_DIR)
|
|
31
|
+
$(PYTHON) -m cibuildwheel --output-dir $(WHEEL_DIR)
|
|
32
|
+
|
|
33
|
+
sdist:
|
|
34
|
+
$(PYTHON) setup.py sdist --dist-dir $(DIST_DIR)
|
|
35
|
+
|
|
36
|
+
dist: wheel sdist
|
|
37
|
+
|
|
38
|
+
clean:
|
|
39
|
+
rm -rf build $(DIST_DIR)
|
|
40
|
+
find symphony -name '_native*.so' -delete
|
|
41
|
+
find symphony -name '_native*.pyd' -delete
|
cymphony-0.14.3/PKG-INFO
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# Symphony C compiler
|
|
2
|
+
|
|
3
|
+
A runnable Python compiler for a useful C subset, with first-class Symphony and
|
|
4
|
+
Dynphony targets. It emits flat, big-endian binaries directly; no separate
|
|
5
|
+
assembler or linker is needed.
|
|
6
|
+
|
|
7
|
+
The implementation separates syntax parsing, semantic analysis, typed syntax, IR lowering, optimization, instruction selection, and binary layout. It includes a reference emulator and automated execution/encoding tests.
|
|
8
|
+
|
|
9
|
+
A second compiler, written in the C subset it compiles, lives in
|
|
10
|
+
[`selfhost/`](selfhost/README.md). It reads projects from persistent storage,
|
|
11
|
+
emits Symphony or Dynphony images, and rebuilds itself byte-for-byte. Use
|
|
12
|
+
`make selfhost-test` for its complete
|
|
13
|
+
compile-the-compiler/compile-a-program/run-the-program test.
|
|
14
|
+
|
|
15
|
+
## Run it
|
|
16
|
+
|
|
17
|
+
Requires Python 3.10+ and `pycparser`. From this project's directory:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
python -m pip install -e .
|
|
21
|
+
scc examples/demo.c -o demo.bin --run
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Compile and link a project from multiple translation units, with project headers
|
|
25
|
+
and command-line macros:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
scc src/main.c src/parser.c src/backend.c \
|
|
29
|
+
-I include -D DEBUG=1 -o compiler.bin
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Each source file is preprocessed and type-checked in its own translation-unit
|
|
33
|
+
scope. External functions and objects are resolved across the project, while
|
|
34
|
+
file-scope `static` definitions remain private. The linked program is optimized
|
|
35
|
+
as one unit before the final flat image is laid out.
|
|
36
|
+
|
|
37
|
+
Expected output includes `main returned 146`. Installing the package provides
|
|
38
|
+
two first-class commands:
|
|
39
|
+
|
|
40
|
+
- `scc` targets Symphony by default.
|
|
41
|
+
- `dcc` targets Dynphony by default.
|
|
42
|
+
|
|
43
|
+
Both accept `--target symphony` or `--target dynphony` explicitly. If
|
|
44
|
+
`pycparser` is already installed, `python -m symphony` behaves like `scc`.
|
|
45
|
+
|
|
46
|
+
For long emulator runs, display live host-side instruction throughput and raise
|
|
47
|
+
the safety limit as needed:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
scc examples/pi.c -o pi.bin --run \
|
|
51
|
+
--hz-meter --max-steps 100000000
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The meter's Hz value is decoded instructions executed per real second,
|
|
55
|
+
not a simulated hardware clock frequency.
|
|
56
|
+
|
|
57
|
+
Build and select the optional native C emulator with:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
make native
|
|
61
|
+
scc examples/pi.c -o pi.bin --run --hz-meter --engine native
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`--engine auto` is the default and prefers the native extension when installed;
|
|
65
|
+
`--engine python` always selects the portable reference emulator. Build local
|
|
66
|
+
wheels with `make wheel`, an sdist with `make sdist`, or both with `make dist`.
|
|
67
|
+
`make ci-wheels` invokes cibuildwheel for the current platform.
|
|
68
|
+
|
|
69
|
+
Symphony's fixed four-byte instruction encoding is the default. The native
|
|
70
|
+
build contains separately compiled Dynphony and Symphony
|
|
71
|
+
cores; target selection happens before execution and adds no ISA-mode branch to
|
|
72
|
+
either instruction loop.
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
scc examples/demo.c -o demo.symphony.bin --run --engine auto
|
|
76
|
+
|
|
77
|
+
dcc examples/demo.c -o demo.dynphony.bin --run --engine auto
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Tags matching `v*` trigger `.github/workflows/release.yml`. The workflow checks
|
|
81
|
+
that the tag matches `pyproject.toml`, runs the test suite, builds and smoke-tests
|
|
82
|
+
CPython 3.10–3.15 wheels for mainstream Linux x86_64/arm64, macOS Intel/Apple
|
|
83
|
+
Silicon, and Windows AMD64/ARM64 targets, builds an sdist, and attaches every
|
|
84
|
+
distribution to a GitHub Release.
|
|
85
|
+
Create a release with, for example, `git tag v0.14.0 && git push origin v0.14.0`.
|
|
86
|
+
|
|
87
|
+
Generate a position-independent image and execute it at another address:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
scc examples/demo.c -o demo.pic.bin \
|
|
91
|
+
--pic --run --run-address 0x12345 \
|
|
92
|
+
--emit-ir demo.ir --map demo.map.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Compile for a fixed nonzero address, with configurable memory sizes:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
scc examples/demo.c -o demo.bin \
|
|
99
|
+
--load-address 0x10000 --ram-size 0x100000 \
|
|
100
|
+
--persistent-size 0x10000
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The raw file begins with the first instruction; it is **not padded to the load address**. Load the file's first byte at the selected address and begin execution there. PIC images can instead run at any address where the image fits contiguously and leaves enough room for the stack. `--run-address` only controls emulator placement. JSON maps contain absolute symbols for fixed-address images and image-relative offsets for PIC images.
|
|
104
|
+
|
|
105
|
+
Run the compiler and self-host test suites against both ISAs:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
make test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
To run one suite for one ISA, set `SYMPHONY_TEST_ISA` (default `symphony`):
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
SYMPHONY_TEST_ISA=dynphony python -m unittest discover -s tests -v
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Supported language
|
|
118
|
+
|
|
119
|
+
The complete support matrix, known limitations, and Symphony-family built-ins
|
|
120
|
+
are documented in [docs/c-language-support.md](docs/c-language-support.md).
|
|
121
|
+
|
|
122
|
+
- Plain `char` is unsigned; explicit signed/unsigned `char`, `short`, `int`, and `long` are supported.
|
|
123
|
+
- Pointers, pointers to pointers, function pointers, explicit integer/pointer casts, and `void` functions/pointers.
|
|
124
|
+
- Local variables and lexical scopes; file-scope globals, `static` globals/functions, static locals, external declarations resolved across linked translation units, and file/block-scope typedefs.
|
|
125
|
+
- Named and anonymous structures, self-referential structure pointers, natural member layout, `.`/`->`, nested structure/array members, and brace initialization for structure objects.
|
|
126
|
+
- Enumerations with implicit or integer-constant enumerator values.
|
|
127
|
+
- `const` objects and pointers with qualifier-preserving conversions and modification diagnostics.
|
|
128
|
+
- Decimal/octal/hex integer literals, character literals, ordinary single-byte strings, and comments.
|
|
129
|
+
- Arithmetic `+ - * / %`, bitwise operations, shifts, comparisons, logical operators, prefix/postfix increment/decrement, assignment and compound assignment.
|
|
130
|
+
- Short-circuit `&&`/`||`, conditional `?:`, comma expressions, and unevaluated `sizeof`.
|
|
131
|
+
- Conditional 96×40 ASCII text-screen support through literal-format `printf`,
|
|
132
|
+
`screen_framebuffer`, and `screen_cursor`.
|
|
133
|
+
- `if`/`else`, `while`, `for`, `do`/`while`, `break`, `continue`.
|
|
134
|
+
- Functions, direct/indirect calls, recursion, and returns. The first seven scalar arguments use registers; later scalar arguments are passed on the stack.
|
|
135
|
+
- Fixed-size and multidimensional arrays, inferred outer array bounds, brace/string initializers, array indexing/decay, pointer scaling/difference, dereference, and address-of.
|
|
136
|
+
- Zero-filled globals, partially initialized arrays, integer constant initializers, and symbolic pointer initializers such as `int *p = &a[2]`.
|
|
137
|
+
- Software multiplication and signed/unsigned division/remainder. Division is bounded to 32 iterations, including for large unsigned divisors.
|
|
138
|
+
- Freestanding library declarations through `stdio.h`, `stdlib.h`, and
|
|
139
|
+
`string.h`, plus Symphony device extensions through `symphony.h`.
|
|
140
|
+
|
|
141
|
+
Entry must be `int main(void)` or `int main()`. An empty parameter list is treated as exactly zero parameters. Falling off `main` returns zero. Other non-void functions also get a deterministic zero fallthrough, although callers must not rely on this for portable C.
|
|
142
|
+
|
|
143
|
+
## Machine and ABI
|
|
144
|
+
|
|
145
|
+
| Property | Value |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Registers / byte addresses | 32 bits |
|
|
148
|
+
| Instruction encoding | Symphony: fixed 4 bytes; Dynphony: variable width |
|
|
149
|
+
| Instruction immediates | 16 bits, unsigned |
|
|
150
|
+
| Byte order | Big-endian |
|
|
151
|
+
| Loads | 8/16/32 bits; narrow loads zero-extend |
|
|
152
|
+
| Unaligned memory access | Allowed |
|
|
153
|
+
| `char` / `short` / `int` / `long` | 1 / 2 / 4 / 4 bytes |
|
|
154
|
+
| Pointers | 4 bytes |
|
|
155
|
+
| Object alignment | Natural, capped at 4 bytes |
|
|
156
|
+
| Arguments | first seven in `r1`–`r7`, later arguments on stack |
|
|
157
|
+
| Results | `flags`, `r1`–`r7`; scalar C results use `r1` |
|
|
158
|
+
| Caller-saved | `r1`–`r7`, `flags` |
|
|
159
|
+
| Callee-saved | `r8`–`r12` |
|
|
160
|
+
| Link register | `r13` |
|
|
161
|
+
| Stack | `sp = 0` at startup, downward, 4-byte aligned |
|
|
162
|
+
| RAM | Unified; addresses wrap modulo configured power-of-two size |
|
|
163
|
+
| Default RAM / load address | 16 MiB / 0 |
|
|
164
|
+
| Termination | Infinite jump loop; main's result remains in `r1` |
|
|
165
|
+
|
|
166
|
+
Calls place the continuation address in `r13`; leaf functions return with a
|
|
167
|
+
single `jmp r13`. A function that still contains a non-tail call after the
|
|
168
|
+
whole-program optimization fixed point saves its incoming `r13` once and
|
|
169
|
+
restores it before returning. `r11` is the frame pointer when a function needs
|
|
170
|
+
a stack frame. In PIC mode startup obtains the image base in `r12` using
|
|
171
|
+
`counter` at image offset zero and generated functions preserve it; fixed-address
|
|
172
|
+
builds make `r12` available to the allocator. The `_start` IR root initializes
|
|
173
|
+
`sp` when reachable code can use the stack; the optimizer removes that operation
|
|
174
|
+
from fully stack-free images.
|
|
175
|
+
|
|
176
|
+
Fallible ABI functions return zero in `flags` on success and an odd status code
|
|
177
|
+
on error, allowing `je` to branch directly to an error path. Other functions may
|
|
178
|
+
clobber `flags`. The ABI permits multiple word results in `r1`–`r7`; the current
|
|
179
|
+
C language subset produces one scalar result in `r1`.
|
|
180
|
+
|
|
181
|
+
Large constants and all label addresses use fixed-width materialization, avoiding a 64 KiB code/address limit. PIC addresses add the runtime base. Startup initializes pointer-valued globals from symbol offsets on every entry; it never repeatedly adds a base to previously rebased values. Other mutable globals are not reset on reentry unless the image is reloaded.
|
|
182
|
+
|
|
183
|
+
RAM size participates in layout diagnostics and emulator configuration. Persistent size is validated and recorded in the map. It does not partition main RAM into persistent and volatile regions.
|
|
184
|
+
|
|
185
|
+
## Symphony device functions
|
|
186
|
+
|
|
187
|
+
Include `<symphony.h>` to declare the target-specific API. Each call emits the
|
|
188
|
+
matching target instruction without ordinary function-call overhead:
|
|
189
|
+
|
|
190
|
+
```c
|
|
191
|
+
#include <symphony.h>
|
|
192
|
+
|
|
193
|
+
unsigned int input(void); /* in */
|
|
194
|
+
void output(unsigned int value); /* out */
|
|
195
|
+
unsigned int keyboard(void); /* keyboard */
|
|
196
|
+
void screen(unsigned int setting, unsigned int value);
|
|
197
|
+
unsigned int time(void); /* low 32 bits */
|
|
198
|
+
unsigned int time_low(void); /* low 32 bits */
|
|
199
|
+
unsigned int time_high(void); /* high 32 bits */
|
|
200
|
+
unsigned int persistent_load(unsigned int address);
|
|
201
|
+
void persistent_store(unsigned int address, unsigned int value);
|
|
202
|
+
void jump(unsigned int address); /* does not return */
|
|
203
|
+
char *screen_framebuffer(void); /* 96x40 ASCII cells */
|
|
204
|
+
void screen_cursor(unsigned int x, unsigned int y);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
For example:
|
|
208
|
+
|
|
209
|
+
```c
|
|
210
|
+
int main(void) {
|
|
211
|
+
unsigned int value = input();
|
|
212
|
+
output(value + keyboard());
|
|
213
|
+
screen(2, value);
|
|
214
|
+
persistent_store(0, value);
|
|
215
|
+
return time();
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`input()` and `keyboard()` return zero in the reference emulator when their
|
|
220
|
+
queues are empty. `output()` appends to `machine.outputs`, and `screen()` appends
|
|
221
|
+
`(setting, value)` to `machine.screen_updates`. Set `persistent_size` on the
|
|
222
|
+
compiler target to record and validate the hardware size; pass the same size to
|
|
223
|
+
`Machine` for emulation. The CLI does this automatically when `--run` is used.
|
|
224
|
+
Device addresses retain the hardware's wrapping behavior. These names are
|
|
225
|
+
reserved and cannot be used for user-defined functions.
|
|
226
|
+
|
|
227
|
+
## Limitations
|
|
228
|
+
|
|
229
|
+
This is a C subset compiler, not a conforming full C implementation. Unsupported constructs produce diagnostics where encountered:
|
|
230
|
+
|
|
231
|
+
- The built-in preprocessor supports includes, object/function macros,
|
|
232
|
+
conditional compilation, `#undef`, `#pragma once`, and `#error`. Macro
|
|
233
|
+
stringification, token pasting, variadic macros, and a hosted standard library
|
|
234
|
+
remain unsupported. Minimal freestanding `stdbool.h`, `stddef.h`, `stdint.h`,
|
|
235
|
+
`stdio.h`, `stdlib.h`, and `string.h` headers are provided, along with the
|
|
236
|
+
target-specific `symphony.h`.
|
|
237
|
+
- Multiple source translation units link directly into one optimized flat image.
|
|
238
|
+
Serializable object files, archives, dynamic linking, and incremental linking
|
|
239
|
+
are not yet implemented.
|
|
240
|
+
- No 64-bit `long long`, floating point, unions, bit-fields, or variadic functions.
|
|
241
|
+
- No `volatile` or `restrict`, local `extern`, designated initializers, `switch`, `goto`, or inline assembly.
|
|
242
|
+
- No aggregate arguments/returns or old-style function definitions.
|
|
243
|
+
- Structure assignment is not implemented. Aggregate initializers require nested braces; brace elision and designated initialization are not implemented. Non-VLA array bounds must be compile-time constants. Multiple tentative global definitions are rejected rather than merged.
|
|
244
|
+
- Decimal literals above `2147483647` need an explicit `U` suffix because unsuffixed decimal values would require an unsupported 64-bit C type. Write the minimum signed integer as `(-2147483647 - 1)` or cast `0x80000000u`.
|
|
245
|
+
- Strings use ordinary single-byte characters and escapes; no wide/Unicode literal types. String literals reside in writable unified memory, but modifying one is still C undefined behavior.
|
|
246
|
+
- The optimizer promotes non-escaping scalar locals, propagates copies and constants, folds scalar expressions, simplifies control flow, rematerializes constants and addresses, selects immediate ALU forms, removes unused pure values and functions, strength-reduces power-of-two arithmetic, and includes only reachable arithmetic helpers.
|
|
247
|
+
- The compiler checks static image fit and a single largest frame, but cannot guarantee stack capacity across recursion or nested calls. Stack collision and out-of-bounds accesses are not trapped by generated code.
|
|
248
|
+
|
|
249
|
+
Signed overflow, invalid shifts, invalid pointer operations, and division by zero remain C undefined behavior. The compiler does not exploit signed-overflow UB for optimization. Software division by zero deterministically returns zero; signed minimum divided by minus one wraps in the helper. Those are implementation behaviors, not portable guarantees.
|
|
250
|
+
|
|
251
|
+
## Current optimization scope
|
|
252
|
+
|
|
253
|
+
The optimizer currently applies safe local and whole-program reductions:
|
|
254
|
+
|
|
255
|
+
- Small integer constants use one immediate instruction; small negative constants use immediate subtraction from `zr`.
|
|
256
|
+
- Constants, global addresses, and local addresses are regenerated at their uses instead of occupying stack slots.
|
|
257
|
+
- ALU operations and comparisons use immediate forms when the operand fits 16 bits.
|
|
258
|
+
- Multiplication by a positive power of two becomes a left shift. Unsigned division and remainder by powers of two become a right shift and mask.
|
|
259
|
+
- Unused pure IR values are removed. Calls and memory/control-flow operations are retained.
|
|
260
|
+
- Non-escaping scalar locals become IR values. Copies and constants propagate within basic blocks; constant arithmetic, comparisons, casts, and branches are folded.
|
|
261
|
+
- Comparisons used only by a branch remain in flags and branch directly, without constructing, spilling, and retesting a Boolean value.
|
|
262
|
+
- Instructions after an unconditional transfer are removed through the next block boundary. Jumps are threaded through forwarding blocks, jumps to any immediately following label are removed, and conditional branches use the following block as fallthrough.
|
|
263
|
+
- Startup is represented by the `_start` IR root. Functions and software arithmetic helpers unreachable from it, calls, function pointers, or static relocations are omitted.
|
|
264
|
+
- Functions without locals, parameters, or live computed stack values omit the `r11` frame-pointer save/restore.
|
|
265
|
+
- Read-only parameters whose addresses are never taken become ordinary IR values. A local register allocator keeps straight-line leaf expressions in `r1`–`r7`, preferring their incoming argument registers. For example, `int add(int a, int b) { return a + b; }` begins with `add r1, r1, r2` and needs no frame.
|
|
266
|
+
- Functions with control flow assign frequently used values to `r8`–`r10` and,
|
|
267
|
+
for fixed-address images, `r12`. Each function saves and restores only the
|
|
268
|
+
callee-saved registers it actually uses, so those values survive calls and
|
|
269
|
+
loop backedges. PIC images reserve `r12` instead.
|
|
270
|
+
- Values that die at a call can use `r3`–`r6` without save/restore traffic. Call arguments are placed as a parallel assignment, including register-cycle breaking and a safe mixed-source fallback.
|
|
271
|
+
- A global Tier 1 fixed point alternates local/CFG simplification with call-graph reachability. Non-recursive functions with exactly one surviving direct call site are relocated into that site and their standalone body is deleted. This naturally absorbs `main` into `_start` when possible.
|
|
272
|
+
- Known-symbol calls use explicit direct-call IR, while function-pointer calls remain indirect. This gives reachability, inlining, and tail-call analysis the callee symbol directly.
|
|
273
|
+
- Explicit CFG construction records predecessors and successors, selects one-target conditional branches with an implicit fallthrough edge inside the fixed point, removes unreachable blocks after branch folding, and deletes unused labels. Straight-line intrinsic functions use the leaf allocator, so input parameters can remain in their incoming registers.
|
|
274
|
+
- Safe tail calls restore the current frame and jump directly to the callee. Functions with addressable local objects stay on the ordinary call path because a callee may receive a pointer into that frame.
|
|
275
|
+
- After final layout, all symbolic fixed-address branches and direct calls relax to their shortest legal immediate or register-target encoding. Shrinking is repeated until instruction sizes and label addresses are stable, with no unreachable padding retained.
|
|
276
|
+
- Termination repeats one jump instruction. Fixed low-address images use `jmp immediate`; PIC and high-address images materialize the target once outside the loop and repeat `jmp r7`.
|
|
277
|
+
|
|
278
|
+
The next substantial opportunities are dead-global elimination, immutable-global load folding, bounded compile-time evaluation, loop analysis, paired division/remainder, common-subexpression elimination, and control-flow-aware stack-slot reuse. Stack-slot reuse must use control-flow liveness rather than textual instruction intervals because loop backedges make the latter incorrect. The dependency-ordered checklist is in [docs/optimization-todos.md](docs/optimization-todos.md).
|
|
279
|
+
|
|
280
|
+
## Comparing against GCC
|
|
281
|
+
|
|
282
|
+
`gcc-backend/` is a bootstrap GCC machine-description target used purely to
|
|
283
|
+
benchmark dyncc's codegen/optimizer output against real GCC (`-Os`/`-O2`) on
|
|
284
|
+
the same example programs, by hijacking GCC's `moxie` target and
|
|
285
|
+
hand-assembling its output into real Symphony machine code. It is not part
|
|
286
|
+
of dyncc's own build. See [gcc-backend/README.md](gcc-backend/README.md)
|
|
287
|
+
for how to build the cross-compiler, assemble its output, and run a fair
|
|
288
|
+
comparison.
|
|
289
|
+
|
|
290
|
+
## Project structure
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
symphony/
|
|
294
|
+
frontends/
|
|
295
|
+
protocol.py source-language frontend contract
|
|
296
|
+
c/ C parsing, semantics, and common-IR lowering
|
|
297
|
+
middle/
|
|
298
|
+
model.py shared types, symbols, typed nodes, and static objects
|
|
299
|
+
ir.py canonical language-neutral IR
|
|
300
|
+
analysis/ CFG and reusable middle-end analyses
|
|
301
|
+
passes/ fixed-point manager and optimization passes
|
|
302
|
+
targets/symphony/
|
|
303
|
+
registers.py architectural register names
|
|
304
|
+
abi.py C calling-convention roles
|
|
305
|
+
isa.py instruction names and byte encoders
|
|
306
|
+
config.py target options and image metadata
|
|
307
|
+
assembler.py symbols, relocations, and final relaxation
|
|
308
|
+
backend.py instruction selection, registers, and stack frames
|
|
309
|
+
runtime/ device declarations and selectively linked helpers
|
|
310
|
+
emulator/ reference machine, device model, and native cores
|
|
311
|
+
compiler.py frontend-independent pipeline orchestrator
|
|
312
|
+
project.py DCP1/DCC1 persistent project and control records
|
|
313
|
+
cli.py scc/dcc: raw binary, IR dump, JSON map, optional execution
|
|
314
|
+
selfhost/ self-hosting compiler written in C
|
|
315
|
+
examples/ example C programs
|
|
316
|
+
tests/ compiler, integration, and encoding tests
|
|
317
|
+
docs/ language reference, design notes, and Dynphony ISA text
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Thin root-level compatibility modules preserve imports such as `symphony.isa`
|
|
321
|
+
and `symphony.frontend`.
|
|
322
|
+
|
|
323
|
+
`examples/towers_of_hanoi.c` is a recursive controller for the Turing Complete
|
|
324
|
+
magnet puzzle. It reads the highest disk number, source, destination, and spare
|
|
325
|
+
locations from the first four inputs and emits the magnet-control sequence.
|
|
326
|
+
|
|
327
|
+
`examples/constant_folding.c` demonstrates whole-entry constant collapse. Its
|
|
328
|
+
three locals and `a + b * c` expression compile to `mov r1, 1466` followed by
|
|
329
|
+
the halt jump; no multiplication helper or standalone `main` remains.
|
|
330
|
+
|
|
331
|
+
`examples/interprocedural_constant_folding.c` computes the same value through a
|
|
332
|
+
sole-called `foo(int)`. Function relocation exposes its argument and locals to
|
|
333
|
+
the global fixed point, producing the identical 8-byte result.
|
|
334
|
+
|
|
335
|
+
`examples/arena_allocator.c` remains an example of a specialized bump allocator.
|
|
336
|
+
Ordinary programs can instead call the bundled `malloc`/`free` and `mem*`
|
|
337
|
+
functions directly without headers.
|
|
338
|
+
|
|
339
|
+
`examples/dynamic_sensor_report.c` is a complete input-driven example using the
|
|
340
|
+
new runtime. It grows a heap-backed sample vector, sorts with VLA workspace,
|
|
341
|
+
deduplicates overlapping storage, builds a heap-backed histogram and statistical
|
|
342
|
+
report, emits the results, and releases every allocation.
|
|
343
|
+
|
|
344
|
+
The API exposes each pipeline stage:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
from symphony import Target, compile_source
|
|
348
|
+
|
|
349
|
+
result = compile_source("int main(void) { return 6 * 7; }", target=Target(pic=True))
|
|
350
|
+
raw_bytes = result.image.binary
|
|
351
|
+
print(result.ir.dump())
|
|
352
|
+
print(result.image.metadata())
|
|
353
|
+
# result.parsed: pycparser AST; result.typed: independent typed AST
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
The emulator verifies generated binaries, and encoding tests compare with the supplied ISA text. Its flags model implements the specified signed/unsigned branch relations without assuming a hardware flag bit layout. **Execution on the actual Turing Complete circuit has not been verified.** See [docs/design.md](docs/design.md) for extension points and validation details.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
Makefile
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
cymphony.egg-info/PKG-INFO
|
|
7
|
+
cymphony.egg-info/SOURCES.txt
|
|
8
|
+
cymphony.egg-info/dependency_links.txt
|
|
9
|
+
cymphony.egg-info/entry_points.txt
|
|
10
|
+
cymphony.egg-info/requires.txt
|
|
11
|
+
cymphony.egg-info/top_level.txt
|
|
12
|
+
docs/architecture.md
|
|
13
|
+
docs/c-language-support.md
|
|
14
|
+
docs/design.md
|
|
15
|
+
docs/isa.txt
|
|
16
|
+
docs/optimization-todos.md
|
|
17
|
+
docs/validation.md
|
|
18
|
+
examples/arena_allocator.c
|
|
19
|
+
examples/bigprime.c
|
|
20
|
+
examples/constant_folding.c
|
|
21
|
+
examples/demo.c
|
|
22
|
+
examples/dynamic_sensor_report.c
|
|
23
|
+
examples/insertion_sort.c
|
|
24
|
+
examples/interprocedural_constant_folding.c
|
|
25
|
+
examples/pi.c
|
|
26
|
+
examples/primes.c
|
|
27
|
+
examples/towers_of_hanoi.c
|
|
28
|
+
symphony/__init__.py
|
|
29
|
+
symphony/__main__.py
|
|
30
|
+
symphony/backend.py
|
|
31
|
+
symphony/cli.py
|
|
32
|
+
symphony/compiler.py
|
|
33
|
+
symphony/frontend.py
|
|
34
|
+
symphony/intrinsics.py
|
|
35
|
+
symphony/ir.py
|
|
36
|
+
symphony/isa.py
|
|
37
|
+
symphony/model.py
|
|
38
|
+
symphony/optimize.py
|
|
39
|
+
symphony/project.py
|
|
40
|
+
symphony/emulator/__init__.py
|
|
41
|
+
symphony/emulator/machine.py
|
|
42
|
+
symphony/emulator/native.py
|
|
43
|
+
symphony/emulator/native_emulator.c
|
|
44
|
+
symphony/frontends/__init__.py
|
|
45
|
+
symphony/frontends/protocol.py
|
|
46
|
+
symphony/frontends/c/__init__.py
|
|
47
|
+
symphony/frontends/c/compiler.py
|
|
48
|
+
symphony/frontends/c/frontend.py
|
|
49
|
+
symphony/frontends/c/parser.py
|
|
50
|
+
symphony/frontends/c/preprocessor.py
|
|
51
|
+
symphony/middle/__init__.py
|
|
52
|
+
symphony/middle/ir.py
|
|
53
|
+
symphony/middle/model.py
|
|
54
|
+
symphony/middle/analysis/__init__.py
|
|
55
|
+
symphony/middle/analysis/cfg.py
|
|
56
|
+
symphony/middle/passes/__init__.py
|
|
57
|
+
symphony/middle/passes/manager.py
|
|
58
|
+
symphony/middle/passes/pipeline.py
|
|
59
|
+
symphony/optimizer/__init__.py
|
|
60
|
+
symphony/optimizer/cfg.py
|
|
61
|
+
symphony/optimizer/pipeline.py
|
|
62
|
+
symphony/runtime/__init__.py
|
|
63
|
+
symphony/runtime/helpers.py
|
|
64
|
+
symphony/runtime/intrinsics.py
|
|
65
|
+
symphony/targets/__init__.py
|
|
66
|
+
symphony/targets/symphony/__init__.py
|
|
67
|
+
symphony/targets/symphony/abi.py
|
|
68
|
+
symphony/targets/symphony/assembler.py
|
|
69
|
+
symphony/targets/symphony/backend.py
|
|
70
|
+
symphony/targets/symphony/config.py
|
|
71
|
+
symphony/targets/symphony/isa.py
|
|
72
|
+
symphony/targets/symphony/legalize.py
|
|
73
|
+
symphony/targets/symphony/registers.py
|
|
74
|
+
tests/test_compiler.py
|
|
75
|
+
tests/test_integration.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pycparser<3,>=2.21
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
symphony
|