qbepy 2026.2.1__cp312-cp312-macosx_14_0_arm64.whl

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.
qbepy/ir/control.py ADDED
@@ -0,0 +1,60 @@
1
+ """QBE control flow instructions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from .values import Label, Value
10
+
11
+
12
+ @dataclass
13
+ class Terminator:
14
+ """Base class for block terminators."""
15
+
16
+ def emit(self) -> str:
17
+ """Emit this terminator as QBE IL."""
18
+ raise NotImplementedError
19
+
20
+
21
+ @dataclass
22
+ class Jump(Terminator):
23
+ """Unconditional jump."""
24
+
25
+ target: Label
26
+
27
+ def emit(self) -> str:
28
+ return f"jmp {self.target}"
29
+
30
+
31
+ @dataclass
32
+ class Branch(Terminator):
33
+ """Conditional branch (jump if non-zero)."""
34
+
35
+ condition: Value
36
+ if_true: Label
37
+ if_false: Label
38
+
39
+ def emit(self) -> str:
40
+ return f"jnz {self.condition}, {self.if_true}, {self.if_false}"
41
+
42
+
43
+ @dataclass
44
+ class Return(Terminator):
45
+ """Function return."""
46
+
47
+ value: Value | None = None
48
+
49
+ def emit(self) -> str:
50
+ if self.value is not None:
51
+ return f"ret {self.value}"
52
+ return "ret"
53
+
54
+
55
+ @dataclass
56
+ class Halt(Terminator):
57
+ """Program halt (unreachable code marker)."""
58
+
59
+ def emit(self) -> str:
60
+ return "hlt"
@@ -0,0 +1,238 @@
1
+ """QBE instruction definitions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import TYPE_CHECKING
7
+
8
+ from .types import BaseType
9
+
10
+ if TYPE_CHECKING:
11
+ from .values import Label, Temporary, Value
12
+
13
+
14
+ @dataclass
15
+ class Instruction:
16
+ """Base class for all instructions."""
17
+
18
+ def emit(self) -> str:
19
+ """Emit this instruction as QBE IL."""
20
+ raise NotImplementedError
21
+
22
+
23
+ @dataclass
24
+ class BinaryOp(Instruction):
25
+ """Binary arithmetic/logic operation.
26
+
27
+ Operations: add, sub, mul, div, rem, udiv, urem,
28
+ and, or, xor, sar, shr, shl
29
+ """
30
+
31
+ op: str
32
+ result: Temporary
33
+ result_type: BaseType
34
+ left: Value
35
+ right: Value
36
+
37
+ def emit(self) -> str:
38
+ return f"{self.result} ={self.result_type.value} {self.op} {self.left}, {self.right}"
39
+
40
+
41
+ @dataclass
42
+ class UnaryOp(Instruction):
43
+ """Unary operation (neg)."""
44
+
45
+ op: str
46
+ result: Temporary
47
+ result_type: BaseType
48
+ operand: Value
49
+
50
+ def emit(self) -> str:
51
+ return f"{self.result} ={self.result_type.value} {self.op} {self.operand}"
52
+
53
+
54
+ @dataclass
55
+ class Copy(Instruction):
56
+ """Copy operation."""
57
+
58
+ result: Temporary
59
+ result_type: BaseType
60
+ value: Value
61
+
62
+ def emit(self) -> str:
63
+ return f"{self.result} ={self.result_type.value} copy {self.value}"
64
+
65
+
66
+ @dataclass
67
+ class Load(Instruction):
68
+ """Memory load operation.
69
+
70
+ Load types: load, loadsb, loadub, loadsh, loaduh, loadsw, loaduw
71
+ """
72
+
73
+ result: Temporary
74
+ result_type: BaseType
75
+ address: Value
76
+ load_type: str = "load"
77
+
78
+ def emit(self) -> str:
79
+ return (
80
+ f"{self.result} ={self.result_type.value} {self.load_type} {self.address}"
81
+ )
82
+
83
+
84
+ @dataclass
85
+ class Store(Instruction):
86
+ """Memory store operation.
87
+
88
+ Store types: storeb, storeh, storew, storel, stores, stored
89
+ """
90
+
91
+ store_type: str
92
+ value: Value
93
+ address: Value
94
+
95
+ def emit(self) -> str:
96
+ return f"{self.store_type} {self.value}, {self.address}"
97
+
98
+
99
+ @dataclass
100
+ class Blit(Instruction):
101
+ """Memory copy (blit) operation."""
102
+
103
+ src: Value
104
+ dst: Value
105
+ size: int
106
+
107
+ def emit(self) -> str:
108
+ return f"blit {self.src}, {self.dst}, {self.size}"
109
+
110
+
111
+ @dataclass
112
+ class Alloc(Instruction):
113
+ """Stack allocation.
114
+
115
+ Alignment can be 4, 8, or 16 bytes.
116
+ """
117
+
118
+ result: Temporary
119
+ size: Value
120
+ align: int = 8
121
+
122
+ def emit(self) -> str:
123
+ alloc_op = f"alloc{self.align}"
124
+ return f"{self.result} =l {alloc_op} {self.size}"
125
+
126
+
127
+ @dataclass
128
+ class Comparison(Instruction):
129
+ """Comparison operation.
130
+
131
+ Integer comparisons: ceqw, cnew, csltw, csgtw, cslew, csgew,
132
+ cultw, cugtw, culew, cugew
133
+ (and 'l' variants for 64-bit)
134
+ Float comparisons: ceqs, cges, cgts, cles, clts, cnes, cos, cuos
135
+ (and 'd' variants for double)
136
+ """
137
+
138
+ op: str
139
+ result: Temporary
140
+ result_type: BaseType
141
+ left: Value
142
+ right: Value
143
+
144
+ def emit(self) -> str:
145
+ return f"{self.result} ={self.result_type.value} {self.op} {self.left}, {self.right}"
146
+
147
+
148
+ @dataclass
149
+ class Conversion(Instruction):
150
+ """Type conversion operation.
151
+
152
+ Operations: extsb, extub, extsh, extuh, extsw, extuw,
153
+ exts, truncd, stosi, stoui, dtosi, dtoui,
154
+ swtof, uwtof, sltof, ultof, cast
155
+ """
156
+
157
+ op: str
158
+ result: Temporary
159
+ result_type: BaseType
160
+ operand: Value
161
+
162
+ def emit(self) -> str:
163
+ return f"{self.result} ={self.result_type.value} {self.op} {self.operand}"
164
+
165
+
166
+ @dataclass
167
+ class Call(Instruction):
168
+ """Function call.
169
+
170
+ Args are tuples of (type, value).
171
+ """
172
+
173
+ target: Value
174
+ args: list[tuple[BaseType | str, Value]]
175
+ result: Temporary | None = None
176
+ result_type: BaseType | str | None = None
177
+ is_variadic: bool = False
178
+
179
+ def emit(self) -> str:
180
+ # Format arguments
181
+ arg_strs = []
182
+ for arg_type, arg_val in self.args:
183
+ if isinstance(arg_type, BaseType):
184
+ type_str = arg_type.value
185
+ else:
186
+ type_str = f":{arg_type}"
187
+ arg_strs.append(f"{type_str} {arg_val}")
188
+
189
+ if self.is_variadic:
190
+ arg_strs.append("...")
191
+
192
+ args_str = ", ".join(arg_strs)
193
+
194
+ if self.result:
195
+ if isinstance(self.result_type, BaseType):
196
+ type_str = self.result_type.value
197
+ else:
198
+ type_str = f":{self.result_type}"
199
+ return f"{self.result} ={type_str} call {self.target}({args_str})"
200
+ return f"call {self.target}({args_str})"
201
+
202
+
203
+ @dataclass
204
+ class Phi(Instruction):
205
+ """Phi instruction for SSA form.
206
+
207
+ Incoming is a list of (Label, Value) pairs.
208
+ """
209
+
210
+ result: Temporary
211
+ result_type: BaseType
212
+ incoming: list[tuple[Label, Value]]
213
+
214
+ def emit(self) -> str:
215
+ pairs = ", ".join(f"{label} {value}" for label, value in self.incoming)
216
+ return f"{self.result} ={self.result_type.value} phi {pairs}"
217
+
218
+
219
+ @dataclass
220
+ class VaStart(Instruction):
221
+ """Initialize variadic argument list."""
222
+
223
+ va_list: Value
224
+
225
+ def emit(self) -> str:
226
+ return f"vastart {self.va_list}"
227
+
228
+
229
+ @dataclass
230
+ class VaArg(Instruction):
231
+ """Fetch next variadic argument."""
232
+
233
+ result: Temporary
234
+ result_type: BaseType
235
+ va_list: Value
236
+
237
+ def emit(self) -> str:
238
+ return f"{self.result} ={self.result_type.value} vaarg {self.va_list}"
qbepy/ir/types.py ADDED
@@ -0,0 +1,84 @@
1
+ """QBE type definitions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from enum import Enum
7
+
8
+
9
+ class BaseType(Enum):
10
+ """Base types for temporaries and function returns."""
11
+
12
+ WORD = "w" # 32-bit integer
13
+ LONG = "l" # 64-bit integer
14
+ SINGLE = "s" # 32-bit float
15
+ DOUBLE = "d" # 64-bit float
16
+
17
+
18
+ class ExtType(Enum):
19
+ """Extended types for data and aggregate fields."""
20
+
21
+ BYTE = "b" # 8-bit
22
+ HALF = "h" # 16-bit halfword
23
+ WORD = "w" # 32-bit word
24
+ LONG = "l" # 64-bit long
25
+ SINGLE = "s" # 32-bit float
26
+ DOUBLE = "d" # 64-bit float
27
+
28
+
29
+ class SubWordType(Enum):
30
+ """Sub-word types for ABI compatibility."""
31
+
32
+ SIGNED_BYTE = "sb"
33
+ UNSIGNED_BYTE = "ub"
34
+ SIGNED_HALF = "sh"
35
+ UNSIGNED_HALF = "uh"
36
+
37
+
38
+ # Convenience aliases
39
+ W = BaseType.WORD
40
+ L = BaseType.LONG
41
+ S = BaseType.SINGLE
42
+ D = BaseType.DOUBLE
43
+
44
+
45
+ @dataclass
46
+ class AggregateType:
47
+ """User-defined aggregate type (struct/union).
48
+
49
+ Example:
50
+ # type :point = { w, w }
51
+ point = AggregateType("point", [(ExtType.WORD, 1), (ExtType.WORD, 1)])
52
+
53
+ # type :vec = align 16 { d 4 }
54
+ vec = AggregateType("vec", [(ExtType.DOUBLE, 4)], align=16)
55
+ """
56
+
57
+ name: str
58
+ fields: list[tuple[ExtType | str, int]] = field(default_factory=list)
59
+ align: int | None = None
60
+ is_opaque: bool = False
61
+ opaque_size: int | None = None
62
+
63
+ def emit(self) -> str:
64
+ """Emit this type definition as QBE IL."""
65
+ align_str = f"align {self.align} " if self.align else ""
66
+
67
+ if self.is_opaque:
68
+ return f"type :{self.name} = {align_str}{{ {self.opaque_size} }}"
69
+
70
+ parts = []
71
+ for field_type, count in self.fields:
72
+ if isinstance(field_type, ExtType):
73
+ type_str = field_type.value
74
+ else:
75
+ # Nested aggregate type reference
76
+ type_str = f":{field_type}"
77
+
78
+ if count > 1:
79
+ parts.append(f"{type_str} {count}")
80
+ else:
81
+ parts.append(type_str)
82
+
83
+ fields_str = ", ".join(parts)
84
+ return f"type :{self.name} = {align_str}{{ {fields_str} }}"
qbepy/ir/values.py ADDED
@@ -0,0 +1,76 @@
1
+ """QBE value types."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class Temporary:
10
+ """Function-scope temporary variable (%name)."""
11
+
12
+ name: str
13
+
14
+ def __str__(self) -> str:
15
+ return f"%{self.name}"
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Global:
20
+ """Global symbol ($name)."""
21
+
22
+ name: str
23
+
24
+ def __str__(self) -> str:
25
+ return f"${self.name}"
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class Label:
30
+ """Block label (@name)."""
31
+
32
+ name: str
33
+
34
+ def __str__(self) -> str:
35
+ return f"@{self.name}"
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class IntConst:
40
+ """Integer constant."""
41
+
42
+ value: int
43
+
44
+ def __str__(self) -> str:
45
+ return str(self.value)
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class FloatConst:
50
+ """Floating-point constant.
51
+
52
+ QBE uses special syntax for floats:
53
+ s_<float> for single precision
54
+ d_<double> for double precision
55
+ """
56
+
57
+ value: float
58
+ is_single: bool = False
59
+
60
+ def __str__(self) -> str:
61
+ prefix = "s_" if self.is_single else "d_"
62
+ return f"{prefix}{self.value}"
63
+
64
+
65
+ @dataclass(frozen=True)
66
+ class TypeRef:
67
+ """Reference to an aggregate type (:typename)."""
68
+
69
+ name: str
70
+
71
+ def __str__(self) -> str:
72
+ return f":{self.name}"
73
+
74
+
75
+ # Type alias for any value that can be used as an operand
76
+ Value = Temporary | Global | IntConst | FloatConst | TypeRef