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.
Files changed (77) hide show
  1. cymphony-0.14.3/MANIFEST.in +7 -0
  2. cymphony-0.14.3/Makefile +41 -0
  3. cymphony-0.14.3/PKG-INFO +6 -0
  4. cymphony-0.14.3/README.md +356 -0
  5. cymphony-0.14.3/cymphony.egg-info/PKG-INFO +6 -0
  6. cymphony-0.14.3/cymphony.egg-info/SOURCES.txt +75 -0
  7. cymphony-0.14.3/cymphony.egg-info/dependency_links.txt +1 -0
  8. cymphony-0.14.3/cymphony.egg-info/entry_points.txt +3 -0
  9. cymphony-0.14.3/cymphony.egg-info/requires.txt +1 -0
  10. cymphony-0.14.3/cymphony.egg-info/top_level.txt +1 -0
  11. cymphony-0.14.3/docs/architecture.md +187 -0
  12. cymphony-0.14.3/docs/c-language-support.md +234 -0
  13. cymphony-0.14.3/docs/design.md +120 -0
  14. cymphony-0.14.3/docs/isa.txt +495 -0
  15. cymphony-0.14.3/docs/optimization-todos.md +290 -0
  16. cymphony-0.14.3/docs/validation.md +23 -0
  17. cymphony-0.14.3/examples/arena_allocator.c +60 -0
  18. cymphony-0.14.3/examples/bigprime.c +630 -0
  19. cymphony-0.14.3/examples/constant_folding.c +6 -0
  20. cymphony-0.14.3/examples/demo.c +17 -0
  21. cymphony-0.14.3/examples/dynamic_sensor_report.c +207 -0
  22. cymphony-0.14.3/examples/insertion_sort.c +29 -0
  23. cymphony-0.14.3/examples/interprocedural_constant_folding.c +12 -0
  24. cymphony-0.14.3/examples/pi.c +537 -0
  25. cymphony-0.14.3/examples/primes.c +26 -0
  26. cymphony-0.14.3/examples/towers_of_hanoi.c +47 -0
  27. cymphony-0.14.3/pyproject.toml +35 -0
  28. cymphony-0.14.3/setup.cfg +4 -0
  29. cymphony-0.14.3/setup.py +15 -0
  30. cymphony-0.14.3/symphony/__init__.py +13 -0
  31. cymphony-0.14.3/symphony/__main__.py +3 -0
  32. cymphony-0.14.3/symphony/backend.py +3 -0
  33. cymphony-0.14.3/symphony/cli.py +199 -0
  34. cymphony-0.14.3/symphony/compiler.py +52 -0
  35. cymphony-0.14.3/symphony/emulator/__init__.py +6 -0
  36. cymphony-0.14.3/symphony/emulator/machine.py +230 -0
  37. cymphony-0.14.3/symphony/emulator/native.py +33 -0
  38. cymphony-0.14.3/symphony/emulator/native_emulator.c +697 -0
  39. cymphony-0.14.3/symphony/frontend.py +3 -0
  40. cymphony-0.14.3/symphony/frontends/__init__.py +1 -0
  41. cymphony-0.14.3/symphony/frontends/c/__init__.py +7 -0
  42. cymphony-0.14.3/symphony/frontends/c/compiler.py +177 -0
  43. cymphony-0.14.3/symphony/frontends/c/frontend.py +1079 -0
  44. cymphony-0.14.3/symphony/frontends/c/parser.py +34 -0
  45. cymphony-0.14.3/symphony/frontends/c/preprocessor.py +334 -0
  46. cymphony-0.14.3/symphony/frontends/protocol.py +21 -0
  47. cymphony-0.14.3/symphony/intrinsics.py +3 -0
  48. cymphony-0.14.3/symphony/ir.py +3 -0
  49. cymphony-0.14.3/symphony/isa.py +3 -0
  50. cymphony-0.14.3/symphony/middle/__init__.py +5 -0
  51. cymphony-0.14.3/symphony/middle/analysis/__init__.py +5 -0
  52. cymphony-0.14.3/symphony/middle/analysis/cfg.py +115 -0
  53. cymphony-0.14.3/symphony/middle/ir.py +447 -0
  54. cymphony-0.14.3/symphony/middle/model.py +194 -0
  55. cymphony-0.14.3/symphony/middle/passes/__init__.py +6 -0
  56. cymphony-0.14.3/symphony/middle/passes/manager.py +32 -0
  57. cymphony-0.14.3/symphony/middle/passes/pipeline.py +1486 -0
  58. cymphony-0.14.3/symphony/model.py +3 -0
  59. cymphony-0.14.3/symphony/optimize.py +5 -0
  60. cymphony-0.14.3/symphony/optimizer/__init__.py +12 -0
  61. cymphony-0.14.3/symphony/optimizer/cfg.py +3 -0
  62. cymphony-0.14.3/symphony/optimizer/pipeline.py +3 -0
  63. cymphony-0.14.3/symphony/project.py +245 -0
  64. cymphony-0.14.3/symphony/runtime/__init__.py +6 -0
  65. cymphony-0.14.3/symphony/runtime/helpers.py +211 -0
  66. cymphony-0.14.3/symphony/runtime/intrinsics.py +133 -0
  67. cymphony-0.14.3/symphony/targets/__init__.py +1 -0
  68. cymphony-0.14.3/symphony/targets/symphony/__init__.py +7 -0
  69. cymphony-0.14.3/symphony/targets/symphony/abi.py +75 -0
  70. cymphony-0.14.3/symphony/targets/symphony/assembler.py +177 -0
  71. cymphony-0.14.3/symphony/targets/symphony/backend.py +1120 -0
  72. cymphony-0.14.3/symphony/targets/symphony/config.py +57 -0
  73. cymphony-0.14.3/symphony/targets/symphony/isa.py +190 -0
  74. cymphony-0.14.3/symphony/targets/symphony/legalize.py +32 -0
  75. cymphony-0.14.3/symphony/targets/symphony/registers.py +59 -0
  76. cymphony-0.14.3/tests/test_compiler.py +1231 -0
  77. cymphony-0.14.3/tests/test_integration.py +260 -0
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include Makefile
3
+ include setup.py
4
+ recursive-include docs *.md *.txt
5
+ recursive-include symphony *.c
6
+ recursive-include examples *.c
7
+ recursive-include tests *.py
@@ -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
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: cymphony
3
+ Version: 0.14.3
4
+ Summary: A small typed C compiler targeting the Symphony and Dynphony ISAs
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: pycparser<3,>=2.21
@@ -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,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: cymphony
3
+ Version: 0.14.3
4
+ Summary: A small typed C compiler targeting the Symphony and Dynphony ISAs
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: pycparser<3,>=2.21
@@ -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,3 @@
1
+ [console_scripts]
2
+ dcc = symphony.cli:dcc
3
+ scc = symphony.cli:scc
@@ -0,0 +1 @@
1
+ pycparser<3,>=2.21
@@ -0,0 +1 @@
1
+ symphony