qbepy 2026.2.1__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 (85) hide show
  1. qbepy-2026.2.1/MANIFEST.in +27 -0
  2. qbepy-2026.2.1/PKG-INFO +359 -0
  3. qbepy-2026.2.1/README.md +341 -0
  4. qbepy-2026.2.1/build_ffi.py +96 -0
  5. qbepy-2026.2.1/csrc/qbepy_wrapper.c +411 -0
  6. qbepy-2026.2.1/csrc/qbepy_wrapper.h +80 -0
  7. qbepy-2026.2.1/pyproject.toml +53 -0
  8. qbepy-2026.2.1/setup.cfg +4 -0
  9. qbepy-2026.2.1/setup.py +7 -0
  10. qbepy-2026.2.1/src/qbepy/__init__.py +85 -0
  11. qbepy-2026.2.1/src/qbepy/_ffi.py +66 -0
  12. qbepy-2026.2.1/src/qbepy/compiler.py +164 -0
  13. qbepy-2026.2.1/src/qbepy/errors.py +20 -0
  14. qbepy-2026.2.1/src/qbepy/ir/__init__.py +73 -0
  15. qbepy-2026.2.1/src/qbepy/ir/builder.py +259 -0
  16. qbepy-2026.2.1/src/qbepy/ir/control.py +60 -0
  17. qbepy-2026.2.1/src/qbepy/ir/instructions.py +238 -0
  18. qbepy-2026.2.1/src/qbepy/ir/types.py +84 -0
  19. qbepy-2026.2.1/src/qbepy/ir/values.py +76 -0
  20. qbepy-2026.2.1/src/qbepy.egg-info/PKG-INFO +359 -0
  21. qbepy-2026.2.1/src/qbepy.egg-info/SOURCES.txt +83 -0
  22. qbepy-2026.2.1/src/qbepy.egg-info/dependency_links.txt +1 -0
  23. qbepy-2026.2.1/src/qbepy.egg-info/requires.txt +1 -0
  24. qbepy-2026.2.1/src/qbepy.egg-info/top_level.txt +1 -0
  25. qbepy-2026.2.1/tests/a_unit/__init__.py +0 -0
  26. qbepy-2026.2.1/tests/a_unit/test_builder.py +218 -0
  27. qbepy-2026.2.1/tests/a_unit/test_control.py +84 -0
  28. qbepy-2026.2.1/tests/a_unit/test_instructions.py +207 -0
  29. qbepy-2026.2.1/tests/a_unit/test_types.py +75 -0
  30. qbepy-2026.2.1/tests/a_unit/test_values.py +94 -0
  31. qbepy-2026.2.1/tests/b_integration/__init__.py +0 -0
  32. qbepy-2026.2.1/tests/b_integration/test_compile_module.py +85 -0
  33. qbepy-2026.2.1/tests/b_integration/test_compiler.py +209 -0
  34. qbepy-2026.2.1/tests/c_e2e/__init__.py +0 -0
  35. qbepy-2026.2.1/tests/c_e2e/test_targets.py +202 -0
  36. qbepy-2026.2.1/tests/conftest.py +44 -0
  37. qbepy-2026.2.1/vendor/qbe/LICENSE +19 -0
  38. qbepy-2026.2.1/vendor/qbe/README +18 -0
  39. qbepy-2026.2.1/vendor/qbe/abi.c +25 -0
  40. qbepy-2026.2.1/vendor/qbe/alias.c +222 -0
  41. qbepy-2026.2.1/vendor/qbe/all.h +629 -0
  42. qbepy-2026.2.1/vendor/qbe/amd64/all.h +70 -0
  43. qbepy-2026.2.1/vendor/qbe/amd64/emit.c +726 -0
  44. qbepy-2026.2.1/vendor/qbe/amd64/isel.c +942 -0
  45. qbepy-2026.2.1/vendor/qbe/amd64/sysv.c +721 -0
  46. qbepy-2026.2.1/vendor/qbe/amd64/targ.c +47 -0
  47. qbepy-2026.2.1/vendor/qbe/arm64/abi.c +852 -0
  48. qbepy-2026.2.1/vendor/qbe/arm64/all.h +38 -0
  49. qbepy-2026.2.1/vendor/qbe/arm64/emit.c +679 -0
  50. qbepy-2026.2.1/vendor/qbe/arm64/isel.c +316 -0
  51. qbepy-2026.2.1/vendor/qbe/arm64/targ.c +69 -0
  52. qbepy-2026.2.1/vendor/qbe/cfg.c +567 -0
  53. qbepy-2026.2.1/vendor/qbe/config.h +1 -0
  54. qbepy-2026.2.1/vendor/qbe/copy.c +408 -0
  55. qbepy-2026.2.1/vendor/qbe/emit.c +263 -0
  56. qbepy-2026.2.1/vendor/qbe/fold.c +246 -0
  57. qbepy-2026.2.1/vendor/qbe/gcm.c +460 -0
  58. qbepy-2026.2.1/vendor/qbe/gvn.c +508 -0
  59. qbepy-2026.2.1/vendor/qbe/ifopt.c +121 -0
  60. qbepy-2026.2.1/vendor/qbe/live.c +144 -0
  61. qbepy-2026.2.1/vendor/qbe/load.c +493 -0
  62. qbepy-2026.2.1/vendor/qbe/main.c +210 -0
  63. qbepy-2026.2.1/vendor/qbe/mem.c +488 -0
  64. qbepy-2026.2.1/vendor/qbe/minic/test/collatz.c +33 -0
  65. qbepy-2026.2.1/vendor/qbe/minic/test/euler9.c +26 -0
  66. qbepy-2026.2.1/vendor/qbe/minic/test/knight.c +60 -0
  67. qbepy-2026.2.1/vendor/qbe/minic/test/mandel.c +88 -0
  68. qbepy-2026.2.1/vendor/qbe/minic/test/prime.c +28 -0
  69. qbepy-2026.2.1/vendor/qbe/minic/test/queen.c +70 -0
  70. qbepy-2026.2.1/vendor/qbe/minic/yacc.c +1378 -0
  71. qbepy-2026.2.1/vendor/qbe/ops.h +228 -0
  72. qbepy-2026.2.1/vendor/qbe/parse.c +1442 -0
  73. qbepy-2026.2.1/vendor/qbe/rega.c +696 -0
  74. qbepy-2026.2.1/vendor/qbe/rv64/abi.c +653 -0
  75. qbepy-2026.2.1/vendor/qbe/rv64/all.h +52 -0
  76. qbepy-2026.2.1/vendor/qbe/rv64/emit.c +569 -0
  77. qbepy-2026.2.1/vendor/qbe/rv64/isel.c +255 -0
  78. qbepy-2026.2.1/vendor/qbe/rv64/targ.c +57 -0
  79. qbepy-2026.2.1/vendor/qbe/simpl.c +124 -0
  80. qbepy-2026.2.1/vendor/qbe/spill.c +531 -0
  81. qbepy-2026.2.1/vendor/qbe/ssa.c +433 -0
  82. qbepy-2026.2.1/vendor/qbe/tools/lexh.c +94 -0
  83. qbepy-2026.2.1/vendor/qbe/tools/log2.c +64 -0
  84. qbepy-2026.2.1/vendor/qbe/tools/pmov.c +262 -0
  85. qbepy-2026.2.1/vendor/qbe/util.c +795 -0
@@ -0,0 +1,27 @@
1
+ # Include build script
2
+ include build_ffi.py
3
+ include setup.py
4
+
5
+ # Include C source files
6
+ include csrc/*.c
7
+ include csrc/*.h
8
+
9
+ # Include vendored QBE source
10
+ recursive-include vendor/qbe *.c
11
+ recursive-include vendor/qbe *.h
12
+ include vendor/qbe/LICENSE
13
+ include vendor/qbe/README
14
+ include vendor/qbe/ops.h
15
+ include vendor/qbe/config.h
16
+
17
+ # Include tests
18
+ recursive-include tests *.py
19
+ include tests/conftest.py
20
+
21
+ # Exclude unnecessary files
22
+ global-exclude *.pyc
23
+ global-exclude *.pyo
24
+ global-exclude __pycache__
25
+ global-exclude *.so
26
+ global-exclude *.o
27
+ global-exclude .git*
@@ -0,0 +1,359 @@
1
+ Metadata-Version: 2.4
2
+ Name: qbepy
3
+ Version: 2026.2.1
4
+ Summary: Python bindings for QBE (Quite Bare Engine) compiler backend
5
+ Author-email: Stefane Fermigier <sf@abilian.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://git.sr.ht/~sfermigier/qbepy
8
+ Project-URL: Repository, https://git.sr.ht/~sfermigier/qbepy
9
+ Keywords: compiler,qbe,code-generation,assembly
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Software Development :: Compilers
15
+ Requires-Python: >=3.12
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: cffi>=1.16.0
18
+
19
+ # qbepy
20
+
21
+ Python bindings for [QBE](https://c9x.me/compile/) (Quite Bare Engine), a minimalist compiler backend.
22
+
23
+ QBE is a small, fast compiler backend that takes an SSA-based intermediate language (IL) and produces native machine code for multiple architectures. qbepy provides Python bindings via CFFI, allowing you to compile QBE IL directly from Python without spawning subprocesses.
24
+
25
+ ## Features
26
+
27
+ - **Direct FFI bindings** - No subprocess overhead; QBE is compiled as a Python extension
28
+ - **Multiple targets** - Supports amd64 (System V and Apple ABIs), ARM64, and RISC-V 64
29
+ - **Pythonic IR builder** - Construct QBE IL programmatically with a clean API
30
+ - **Error handling** - QBE errors are raised as Python exceptions
31
+ - **Vendored QBE** - QBE source is included and built automatically during installation
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install qbepy
37
+ # or
38
+ uv add qbepy
39
+ ```
40
+
41
+ Or from source:
42
+
43
+ ```bash
44
+ git clone https://github.com/user/qbepy.git
45
+ cd qbepy
46
+ uv sync
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ### Compiling Raw IL
52
+
53
+ ```python
54
+ import qbepy
55
+
56
+ # QBE IL for a simple add function
57
+ il = """
58
+ export function w $add(w %a, w %b) {
59
+ @start
60
+ %r =w add %a, %b
61
+ ret %r
62
+ }
63
+ """
64
+
65
+ # Compile to assembly
66
+ asm = qbepy.compile_il(il)
67
+ print(asm)
68
+ ```
69
+
70
+ Output (ARM64 Apple):
71
+ ```asm
72
+ .text
73
+ .balign 4
74
+ .globl _add
75
+ _add:
76
+ hint #34
77
+ stp x29, x30, [sp, -16]!
78
+ mov x29, sp
79
+ add w0, w0, w1
80
+ ldp x29, x30, [sp], 16
81
+ ret
82
+ ```
83
+
84
+ ### Using the IR Builder
85
+
86
+ ```python
87
+ import qbepy
88
+ from qbepy import Module, Function, DataDef, W, L
89
+ from qbepy.ir import BinaryOp, Call, Return, Temporary, Global, IntConst
90
+
91
+ # Create a module
92
+ mod = Module()
93
+
94
+ # Add a string constant
95
+ mod.add_data(
96
+ DataDef("greeting")
97
+ .add_string("Hello, World!")
98
+ .add_bytes(0) # null terminator
99
+ )
100
+
101
+ # Create main function
102
+ func = Function("main", W, export=True)
103
+ block = func.add_block("start")
104
+
105
+ # Call puts($greeting)
106
+ r = func.new_temp("r")
107
+ block.instructions.append(
108
+ Call(Global("puts"), [(L, Global("greeting"))], r, W)
109
+ )
110
+ block.terminator = Return(IntConst(0))
111
+
112
+ mod.add_function(func)
113
+
114
+ # Compile to assembly
115
+ asm = qbepy.compile_module(mod)
116
+ print(asm)
117
+ ```
118
+
119
+ ### Specifying a Target
120
+
121
+ ```python
122
+ # Compile for x86-64 System V ABI
123
+ asm = qbepy.compile_il(il, target="amd64_sysv")
124
+
125
+ # Or use the Compiler class
126
+ compiler = qbepy.Compiler(target="arm64")
127
+ asm = compiler.compile(il)
128
+
129
+ # Available targets
130
+ print(qbepy.Compiler.get_available_targets())
131
+ # ['amd64_sysv', 'amd64_apple', 'arm64', 'arm64_apple', 'rv64']
132
+
133
+ # Get default target for current platform
134
+ print(qbepy.Compiler.get_default_target())
135
+ # 'arm64_apple' (on Apple Silicon)
136
+ ```
137
+
138
+ ## API Reference
139
+
140
+ ### Compiler
141
+
142
+ ```python
143
+ from qbepy import Compiler, compile_il, compile_module
144
+
145
+ # Create a compiler instance
146
+ compiler = Compiler(target=None) # None = platform default
147
+
148
+ # Compile IL string to assembly
149
+ asm = compiler.compile(il_string)
150
+
151
+ # Compile a Module object
152
+ asm = compiler.compile_module(module)
153
+
154
+ # Change target
155
+ compiler.set_target("amd64_sysv")
156
+
157
+ # Convenience functions
158
+ asm = compile_il(il_string, target=None)
159
+ asm = compile_module(module, target=None)
160
+ ```
161
+
162
+ ### Types
163
+
164
+ ```python
165
+ from qbepy import W, L, S, D, BaseType, ExtType, AggregateType
166
+
167
+ # Base types
168
+ W # word (32-bit integer)
169
+ L # long (64-bit integer)
170
+ S # single (32-bit float)
171
+ D # double (64-bit float)
172
+
173
+ # Extended types (for memory operations)
174
+ ExtType.BYTE, ExtType.HALF, ExtType.WORD, ExtType.LONG
175
+ ExtType.SINGLE, ExtType.DOUBLE
176
+
177
+ # Aggregate types (structs)
178
+ point = AggregateType("point", [
179
+ (ExtType.WORD, 1), # x: 1 word
180
+ (ExtType.WORD, 1), # y: 1 word
181
+ ])
182
+ ```
183
+
184
+ ### Values
185
+
186
+ ```python
187
+ from qbepy.ir import Temporary, Global, Label, IntConst, FloatConst
188
+
189
+ Temporary("x") # %x - SSA temporary
190
+ Global("main") # $main - global symbol
191
+ Label("loop") # @loop - block label
192
+ IntConst(42) # 42 - integer constant
193
+ FloatConst(3.14) # d_3.14 - double constant
194
+ FloatConst(3.14, is_single=True) # s_3.14 - float constant
195
+ ```
196
+
197
+ ### Instructions
198
+
199
+ ```python
200
+ from qbepy.ir import (
201
+ BinaryOp, # add, sub, mul, div, rem, or, xor, and, sar, shr, shl
202
+ UnaryOp, # neg, copy
203
+ Copy, # copy value
204
+ Load, # load from memory
205
+ Store, # store to memory
206
+ Alloc, # stack allocation
207
+ Call, # function call
208
+ Comparison, # ceqw, cnew, csltw, etc.
209
+ Conversion, # extsw, truncd, stosi, cast, etc.
210
+ Phi, # SSA phi node
211
+ )
212
+
213
+ # Examples
214
+ BinaryOp("add", Temporary("r"), W, Temporary("a"), Temporary("b"))
215
+ Load(Temporary("v"), W, Temporary("ptr"))
216
+ Store("storew", Temporary("v"), Temporary("ptr"))
217
+ Call(Global("printf"), [(L, Global("fmt"))], Temporary("r"), W)
218
+ ```
219
+
220
+ ### Control Flow
221
+
222
+ ```python
223
+ from qbepy.ir import Jump, Branch, Return, Halt
224
+
225
+ Jump(Label("next")) # jmp @next
226
+ Branch(Temporary("c"), Label("t"), Label("f")) # jnz %c, @t, @f
227
+ Return(Temporary("r")) # ret %r
228
+ Return(IntConst(0)) # ret 0
229
+ Return() # ret (void)
230
+ Halt() # hlt (unreachable)
231
+ ```
232
+
233
+ ### Building Modules
234
+
235
+ ```python
236
+ from qbepy import Module, Function, Block, DataDef
237
+
238
+ # Module - container for types, data, and functions
239
+ mod = Module()
240
+ mod.add_type(aggregate_type)
241
+ mod.add_data(data_def)
242
+ mod.add_function(function)
243
+
244
+ # Function
245
+ func = Function("name", return_type, params=[(W, "a"), (L, "b")], export=True)
246
+ block = func.add_block("start")
247
+ temp = func.new_temp("x") # creates unique temporary
248
+
249
+ # Block
250
+ block.instructions.append(instruction)
251
+ block.terminator = Return(value)
252
+
253
+ # DataDef
254
+ data = (DataDef("name", export=True, align=8)
255
+ .add_string("hello")
256
+ .add_bytes(0)
257
+ .add_words(1, 2, 3)
258
+ .add_longs(0x1234567890)
259
+ .add_zero(16))
260
+ ```
261
+
262
+ ## Supported Targets
263
+
264
+ | Target | Description |
265
+ |--------|-------------|
266
+ | `amd64_sysv` | x86-64 with System V ABI (Linux, BSD) |
267
+ | `amd64_apple` | x86-64 with Apple ABI (macOS Intel) |
268
+ | `arm64` | ARM64 with standard ABI (Linux) |
269
+ | `arm64_apple` | ARM64 with Apple ABI (macOS Apple Silicon) |
270
+ | `rv64` | RISC-V 64-bit |
271
+
272
+ ## QBE IL Reference
273
+
274
+ QBE uses a simple SSA-based intermediate language. For the complete specification, see the [QBE IL documentation](https://c9x.me/compile/doc/il.html).
275
+
276
+ ### Basic IL Structure
277
+
278
+ ```
279
+ # Type definitions
280
+ type :point = { w, w }
281
+
282
+ # Data definitions
283
+ data $message = { b "Hello", b 0 }
284
+
285
+ # Function definitions
286
+ export function w $main() {
287
+ @start
288
+ %x =w copy 42
289
+ ret %x
290
+ }
291
+ ```
292
+
293
+ ### IL Basics
294
+
295
+ - Temporaries: `%name` (SSA values)
296
+ - Globals: `$name` (functions and data)
297
+ - Labels: `@name` (basic blocks)
298
+ - Types: `w` (word), `l` (long), `s` (single), `d` (double)
299
+
300
+ ## Error Handling
301
+
302
+ ```python
303
+ from qbepy import CompilationError, compile_il
304
+
305
+ try:
306
+ asm = compile_il("invalid IL code")
307
+ except CompilationError as e:
308
+ print(f"Compilation failed: {e}")
309
+ ```
310
+
311
+ ## Project Structure
312
+
313
+ ```
314
+ qbepy/
315
+ ├── src/qbepy/
316
+ │ ├── __init__.py # Public API exports
317
+ │ ├── _ffi.py # Low-level CFFI bindings
318
+ │ ├── compiler.py # Compiler class
319
+ │ ├── errors.py # Exception types
320
+ │ └── ir/ # IR builder module
321
+ │ ├── types.py # Type definitions
322
+ │ ├── values.py # Value types
323
+ │ ├── instructions.py # Instructions
324
+ │ ├── control.py # Control flow
325
+ │ └── builder.py # Module, Function, Block, DataDef
326
+ ├── csrc/
327
+ │ ├── qbepy_wrapper.c # C wrapper with error handling
328
+ │ └── qbepy_wrapper.h
329
+ ├── vendor/qbe/ # Vendored QBE source
330
+ ├── build_ffi.py # CFFI build script
331
+ └── tests/ # Test suite
332
+ ```
333
+
334
+ ## How It Works
335
+
336
+ qbepy vendors the QBE compiler source and builds it as a Python extension using CFFI. The main challenge is that QBE's error handling uses `exit()`, which would terminate the Python process. qbepy solves this by:
337
+
338
+ 1. Redirecting QBE's `err()` function to a custom handler using preprocessor macros
339
+ 2. Using `setjmp`/`longjmp` to catch errors and return control to Python
340
+ 3. Converting errors to Python exceptions
341
+
342
+ This allows QBE to be used as a library rather than a standalone compiler.
343
+
344
+ ## License
345
+
346
+ qbepy is released under the MIT License.
347
+
348
+ QBE is developed by Quentin Carbonneaux and is also MIT licensed. See [vendor/qbe/LICENSE](vendor/qbe/LICENSE).
349
+
350
+ ## Credits
351
+
352
+ - [QBE](https://c9x.me/compile/) - The compiler backend by Quentin Carbonneaux
353
+ - [CFFI](https://cffi.readthedocs.io/) - C Foreign Function Interface for Python
354
+
355
+ ## See Also
356
+
357
+ - [QBE Documentation](https://c9x.me/compile/doc/il.html) - Complete IL specification
358
+ - [cproc](https://sr.ht/~mcf/cproc/) - A C11 compiler using QBE as backend
359
+ - [Hare](https://harelang.org/) - A systems programming language using QBE
@@ -0,0 +1,341 @@
1
+ # qbepy
2
+
3
+ Python bindings for [QBE](https://c9x.me/compile/) (Quite Bare Engine), a minimalist compiler backend.
4
+
5
+ QBE is a small, fast compiler backend that takes an SSA-based intermediate language (IL) and produces native machine code for multiple architectures. qbepy provides Python bindings via CFFI, allowing you to compile QBE IL directly from Python without spawning subprocesses.
6
+
7
+ ## Features
8
+
9
+ - **Direct FFI bindings** - No subprocess overhead; QBE is compiled as a Python extension
10
+ - **Multiple targets** - Supports amd64 (System V and Apple ABIs), ARM64, and RISC-V 64
11
+ - **Pythonic IR builder** - Construct QBE IL programmatically with a clean API
12
+ - **Error handling** - QBE errors are raised as Python exceptions
13
+ - **Vendored QBE** - QBE source is included and built automatically during installation
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pip install qbepy
19
+ # or
20
+ uv add qbepy
21
+ ```
22
+
23
+ Or from source:
24
+
25
+ ```bash
26
+ git clone https://github.com/user/qbepy.git
27
+ cd qbepy
28
+ uv sync
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ### Compiling Raw IL
34
+
35
+ ```python
36
+ import qbepy
37
+
38
+ # QBE IL for a simple add function
39
+ il = """
40
+ export function w $add(w %a, w %b) {
41
+ @start
42
+ %r =w add %a, %b
43
+ ret %r
44
+ }
45
+ """
46
+
47
+ # Compile to assembly
48
+ asm = qbepy.compile_il(il)
49
+ print(asm)
50
+ ```
51
+
52
+ Output (ARM64 Apple):
53
+ ```asm
54
+ .text
55
+ .balign 4
56
+ .globl _add
57
+ _add:
58
+ hint #34
59
+ stp x29, x30, [sp, -16]!
60
+ mov x29, sp
61
+ add w0, w0, w1
62
+ ldp x29, x30, [sp], 16
63
+ ret
64
+ ```
65
+
66
+ ### Using the IR Builder
67
+
68
+ ```python
69
+ import qbepy
70
+ from qbepy import Module, Function, DataDef, W, L
71
+ from qbepy.ir import BinaryOp, Call, Return, Temporary, Global, IntConst
72
+
73
+ # Create a module
74
+ mod = Module()
75
+
76
+ # Add a string constant
77
+ mod.add_data(
78
+ DataDef("greeting")
79
+ .add_string("Hello, World!")
80
+ .add_bytes(0) # null terminator
81
+ )
82
+
83
+ # Create main function
84
+ func = Function("main", W, export=True)
85
+ block = func.add_block("start")
86
+
87
+ # Call puts($greeting)
88
+ r = func.new_temp("r")
89
+ block.instructions.append(
90
+ Call(Global("puts"), [(L, Global("greeting"))], r, W)
91
+ )
92
+ block.terminator = Return(IntConst(0))
93
+
94
+ mod.add_function(func)
95
+
96
+ # Compile to assembly
97
+ asm = qbepy.compile_module(mod)
98
+ print(asm)
99
+ ```
100
+
101
+ ### Specifying a Target
102
+
103
+ ```python
104
+ # Compile for x86-64 System V ABI
105
+ asm = qbepy.compile_il(il, target="amd64_sysv")
106
+
107
+ # Or use the Compiler class
108
+ compiler = qbepy.Compiler(target="arm64")
109
+ asm = compiler.compile(il)
110
+
111
+ # Available targets
112
+ print(qbepy.Compiler.get_available_targets())
113
+ # ['amd64_sysv', 'amd64_apple', 'arm64', 'arm64_apple', 'rv64']
114
+
115
+ # Get default target for current platform
116
+ print(qbepy.Compiler.get_default_target())
117
+ # 'arm64_apple' (on Apple Silicon)
118
+ ```
119
+
120
+ ## API Reference
121
+
122
+ ### Compiler
123
+
124
+ ```python
125
+ from qbepy import Compiler, compile_il, compile_module
126
+
127
+ # Create a compiler instance
128
+ compiler = Compiler(target=None) # None = platform default
129
+
130
+ # Compile IL string to assembly
131
+ asm = compiler.compile(il_string)
132
+
133
+ # Compile a Module object
134
+ asm = compiler.compile_module(module)
135
+
136
+ # Change target
137
+ compiler.set_target("amd64_sysv")
138
+
139
+ # Convenience functions
140
+ asm = compile_il(il_string, target=None)
141
+ asm = compile_module(module, target=None)
142
+ ```
143
+
144
+ ### Types
145
+
146
+ ```python
147
+ from qbepy import W, L, S, D, BaseType, ExtType, AggregateType
148
+
149
+ # Base types
150
+ W # word (32-bit integer)
151
+ L # long (64-bit integer)
152
+ S # single (32-bit float)
153
+ D # double (64-bit float)
154
+
155
+ # Extended types (for memory operations)
156
+ ExtType.BYTE, ExtType.HALF, ExtType.WORD, ExtType.LONG
157
+ ExtType.SINGLE, ExtType.DOUBLE
158
+
159
+ # Aggregate types (structs)
160
+ point = AggregateType("point", [
161
+ (ExtType.WORD, 1), # x: 1 word
162
+ (ExtType.WORD, 1), # y: 1 word
163
+ ])
164
+ ```
165
+
166
+ ### Values
167
+
168
+ ```python
169
+ from qbepy.ir import Temporary, Global, Label, IntConst, FloatConst
170
+
171
+ Temporary("x") # %x - SSA temporary
172
+ Global("main") # $main - global symbol
173
+ Label("loop") # @loop - block label
174
+ IntConst(42) # 42 - integer constant
175
+ FloatConst(3.14) # d_3.14 - double constant
176
+ FloatConst(3.14, is_single=True) # s_3.14 - float constant
177
+ ```
178
+
179
+ ### Instructions
180
+
181
+ ```python
182
+ from qbepy.ir import (
183
+ BinaryOp, # add, sub, mul, div, rem, or, xor, and, sar, shr, shl
184
+ UnaryOp, # neg, copy
185
+ Copy, # copy value
186
+ Load, # load from memory
187
+ Store, # store to memory
188
+ Alloc, # stack allocation
189
+ Call, # function call
190
+ Comparison, # ceqw, cnew, csltw, etc.
191
+ Conversion, # extsw, truncd, stosi, cast, etc.
192
+ Phi, # SSA phi node
193
+ )
194
+
195
+ # Examples
196
+ BinaryOp("add", Temporary("r"), W, Temporary("a"), Temporary("b"))
197
+ Load(Temporary("v"), W, Temporary("ptr"))
198
+ Store("storew", Temporary("v"), Temporary("ptr"))
199
+ Call(Global("printf"), [(L, Global("fmt"))], Temporary("r"), W)
200
+ ```
201
+
202
+ ### Control Flow
203
+
204
+ ```python
205
+ from qbepy.ir import Jump, Branch, Return, Halt
206
+
207
+ Jump(Label("next")) # jmp @next
208
+ Branch(Temporary("c"), Label("t"), Label("f")) # jnz %c, @t, @f
209
+ Return(Temporary("r")) # ret %r
210
+ Return(IntConst(0)) # ret 0
211
+ Return() # ret (void)
212
+ Halt() # hlt (unreachable)
213
+ ```
214
+
215
+ ### Building Modules
216
+
217
+ ```python
218
+ from qbepy import Module, Function, Block, DataDef
219
+
220
+ # Module - container for types, data, and functions
221
+ mod = Module()
222
+ mod.add_type(aggregate_type)
223
+ mod.add_data(data_def)
224
+ mod.add_function(function)
225
+
226
+ # Function
227
+ func = Function("name", return_type, params=[(W, "a"), (L, "b")], export=True)
228
+ block = func.add_block("start")
229
+ temp = func.new_temp("x") # creates unique temporary
230
+
231
+ # Block
232
+ block.instructions.append(instruction)
233
+ block.terminator = Return(value)
234
+
235
+ # DataDef
236
+ data = (DataDef("name", export=True, align=8)
237
+ .add_string("hello")
238
+ .add_bytes(0)
239
+ .add_words(1, 2, 3)
240
+ .add_longs(0x1234567890)
241
+ .add_zero(16))
242
+ ```
243
+
244
+ ## Supported Targets
245
+
246
+ | Target | Description |
247
+ |--------|-------------|
248
+ | `amd64_sysv` | x86-64 with System V ABI (Linux, BSD) |
249
+ | `amd64_apple` | x86-64 with Apple ABI (macOS Intel) |
250
+ | `arm64` | ARM64 with standard ABI (Linux) |
251
+ | `arm64_apple` | ARM64 with Apple ABI (macOS Apple Silicon) |
252
+ | `rv64` | RISC-V 64-bit |
253
+
254
+ ## QBE IL Reference
255
+
256
+ QBE uses a simple SSA-based intermediate language. For the complete specification, see the [QBE IL documentation](https://c9x.me/compile/doc/il.html).
257
+
258
+ ### Basic IL Structure
259
+
260
+ ```
261
+ # Type definitions
262
+ type :point = { w, w }
263
+
264
+ # Data definitions
265
+ data $message = { b "Hello", b 0 }
266
+
267
+ # Function definitions
268
+ export function w $main() {
269
+ @start
270
+ %x =w copy 42
271
+ ret %x
272
+ }
273
+ ```
274
+
275
+ ### IL Basics
276
+
277
+ - Temporaries: `%name` (SSA values)
278
+ - Globals: `$name` (functions and data)
279
+ - Labels: `@name` (basic blocks)
280
+ - Types: `w` (word), `l` (long), `s` (single), `d` (double)
281
+
282
+ ## Error Handling
283
+
284
+ ```python
285
+ from qbepy import CompilationError, compile_il
286
+
287
+ try:
288
+ asm = compile_il("invalid IL code")
289
+ except CompilationError as e:
290
+ print(f"Compilation failed: {e}")
291
+ ```
292
+
293
+ ## Project Structure
294
+
295
+ ```
296
+ qbepy/
297
+ ├── src/qbepy/
298
+ │ ├── __init__.py # Public API exports
299
+ │ ├── _ffi.py # Low-level CFFI bindings
300
+ │ ├── compiler.py # Compiler class
301
+ │ ├── errors.py # Exception types
302
+ │ └── ir/ # IR builder module
303
+ │ ├── types.py # Type definitions
304
+ │ ├── values.py # Value types
305
+ │ ├── instructions.py # Instructions
306
+ │ ├── control.py # Control flow
307
+ │ └── builder.py # Module, Function, Block, DataDef
308
+ ├── csrc/
309
+ │ ├── qbepy_wrapper.c # C wrapper with error handling
310
+ │ └── qbepy_wrapper.h
311
+ ├── vendor/qbe/ # Vendored QBE source
312
+ ├── build_ffi.py # CFFI build script
313
+ └── tests/ # Test suite
314
+ ```
315
+
316
+ ## How It Works
317
+
318
+ qbepy vendors the QBE compiler source and builds it as a Python extension using CFFI. The main challenge is that QBE's error handling uses `exit()`, which would terminate the Python process. qbepy solves this by:
319
+
320
+ 1. Redirecting QBE's `err()` function to a custom handler using preprocessor macros
321
+ 2. Using `setjmp`/`longjmp` to catch errors and return control to Python
322
+ 3. Converting errors to Python exceptions
323
+
324
+ This allows QBE to be used as a library rather than a standalone compiler.
325
+
326
+ ## License
327
+
328
+ qbepy is released under the MIT License.
329
+
330
+ QBE is developed by Quentin Carbonneaux and is also MIT licensed. See [vendor/qbe/LICENSE](vendor/qbe/LICENSE).
331
+
332
+ ## Credits
333
+
334
+ - [QBE](https://c9x.me/compile/) - The compiler backend by Quentin Carbonneaux
335
+ - [CFFI](https://cffi.readthedocs.io/) - C Foreign Function Interface for Python
336
+
337
+ ## See Also
338
+
339
+ - [QBE Documentation](https://c9x.me/compile/doc/il.html) - Complete IL specification
340
+ - [cproc](https://sr.ht/~mcf/cproc/) - A C11 compiler using QBE as backend
341
+ - [Hare](https://harelang.org/) - A systems programming language using QBE