3
3
Opcodes operate on abstract values (Value) in a register machine. Each
4
4
value has a type (RType). A value can hold various things, such as:
5
5
6
- - local variables (Register)
6
+ - local variables or temporaries (Register)
7
7
- intermediate values of expressions (RegisterOp subclasses)
8
8
- condition flags (true/false)
9
9
- literals (integer literals, True, False, etc.)
10
+
11
+ NOTE: As a convention, we don't create subclasses of concrete Value/Op
12
+ subclasses (e.g. you shouldn't define a subclass of Integer, which
13
+ is a concrete class).
14
+
15
+ If you want to introduce a variant of an existing class, you'd
16
+ typically add an attribute (e.g. a flag) to an existing concrete
17
+ class to enable the new behavior. Sometimes adding a new abstract
18
+ base class is also an option, or just creating a new subclass
19
+ without any inheritance relationship (some duplication of code
20
+ is preferred over introducing complex implementation inheritance).
21
+
22
+ This makes it possible to use isinstance(x, <concrete Value
23
+ subclass>) checks without worrying about potential subclasses.
10
24
"""
11
25
12
26
from __future__ import annotations
13
27
14
28
from abc import abstractmethod
15
29
from collections .abc import Sequence
16
- from typing import TYPE_CHECKING , Final , Generic , NamedTuple , TypeVar , Union
30
+ from typing import TYPE_CHECKING , Final , Generic , NamedTuple , TypeVar , Union , final
17
31
18
32
from mypy_extensions import trait
19
33
47
61
T = TypeVar ("T" )
48
62
49
63
64
+ @final
50
65
class BasicBlock :
51
66
"""IR basic block.
52
67
@@ -142,6 +157,7 @@ def is_void(self) -> bool:
142
157
return isinstance (self .type , RVoid )
143
158
144
159
160
+ @final
145
161
class Register (Value ):
146
162
"""A Register holds a value of a specific type, and it can be read and mutated.
147
163
@@ -168,6 +184,7 @@ def __repr__(self) -> str:
168
184
return f"<Register { self .name !r} at { hex (id (self ))} >"
169
185
170
186
187
+ @final
171
188
class Integer (Value ):
172
189
"""Short integer literal.
173
190
@@ -198,6 +215,7 @@ def numeric_value(self) -> int:
198
215
return self .value
199
216
200
217
218
+ @final
201
219
class Float (Value ):
202
220
"""Float literal.
203
221
@@ -257,13 +275,14 @@ def accept(self, visitor: OpVisitor[T]) -> T:
257
275
258
276
259
277
class BaseAssign (Op ):
260
- """Base class for ops that assign to a register."""
278
+ """Abstract base class for ops that assign to a register."""
261
279
262
280
def __init__ (self , dest : Register , line : int = - 1 ) -> None :
263
281
super ().__init__ (line )
264
282
self .dest = dest
265
283
266
284
285
+ @final
267
286
class Assign (BaseAssign ):
268
287
"""Assign a value to a Register (dest = src)."""
269
288
@@ -286,6 +305,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
286
305
return visitor .visit_assign (self )
287
306
288
307
308
+ @final
289
309
class AssignMulti (BaseAssign ):
290
310
"""Assign multiple values to a Register (dest = src1, src2, ...).
291
311
@@ -320,7 +340,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
320
340
321
341
322
342
class ControlOp (Op ):
323
- """Control flow operation ."""
343
+ """Abstract base class for control flow operations ."""
324
344
325
345
def targets (self ) -> Sequence [BasicBlock ]:
326
346
"""Get all basic block targets of the control operation."""
@@ -331,6 +351,7 @@ def set_target(self, i: int, new: BasicBlock) -> None:
331
351
raise AssertionError (f"Invalid set_target({ self } , { i } )" )
332
352
333
353
354
+ @final
334
355
class Goto (ControlOp ):
335
356
"""Unconditional jump."""
336
357
@@ -360,6 +381,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
360
381
return visitor .visit_goto (self )
361
382
362
383
384
+ @final
363
385
class Branch (ControlOp ):
364
386
"""Branch based on a value.
365
387
@@ -426,6 +448,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
426
448
return visitor .visit_branch (self )
427
449
428
450
451
+ @final
429
452
class Return (ControlOp ):
430
453
"""Return a value from a function."""
431
454
@@ -455,6 +478,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
455
478
return visitor .visit_return (self )
456
479
457
480
481
+ @final
458
482
class Unreachable (ControlOp ):
459
483
"""Mark the end of basic block as unreachable.
460
484
@@ -511,6 +535,7 @@ def can_raise(self) -> bool:
511
535
return self .error_kind != ERR_NEVER
512
536
513
537
538
+ @final
514
539
class IncRef (RegisterOp ):
515
540
"""Increase reference count (inc_ref src)."""
516
541
@@ -531,6 +556,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
531
556
return visitor .visit_inc_ref (self )
532
557
533
558
559
+ @final
534
560
class DecRef (RegisterOp ):
535
561
"""Decrease reference count and free object if zero (dec_ref src).
536
562
@@ -559,6 +585,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
559
585
return visitor .visit_dec_ref (self )
560
586
561
587
588
+ @final
562
589
class Call (RegisterOp ):
563
590
"""Native call f(arg, ...).
564
591
@@ -587,6 +614,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
587
614
return visitor .visit_call (self )
588
615
589
616
617
+ @final
590
618
class MethodCall (RegisterOp ):
591
619
"""Native method call obj.method(arg, ...)"""
592
620
@@ -618,6 +646,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
618
646
return visitor .visit_method_call (self )
619
647
620
648
649
+ @final
621
650
class PrimitiveDescription :
622
651
"""Description of a primitive op.
623
652
@@ -670,6 +699,7 @@ def __repr__(self) -> str:
670
699
return f"<PrimitiveDescription { self .name !r} : { self .arg_types } >"
671
700
672
701
702
+ @final
673
703
class PrimitiveOp (RegisterOp ):
674
704
"""A higher-level primitive operation.
675
705
@@ -707,6 +737,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
707
737
return visitor .visit_primitive_op (self )
708
738
709
739
740
+ @final
710
741
class LoadErrorValue (RegisterOp ):
711
742
"""Load an error value.
712
743
@@ -737,6 +768,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
737
768
return visitor .visit_load_error_value (self )
738
769
739
770
771
+ @final
740
772
class LoadLiteral (RegisterOp ):
741
773
"""Load a Python literal object (dest = 'foo' / b'foo' / ...).
742
774
@@ -772,6 +804,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
772
804
return visitor .visit_load_literal (self )
773
805
774
806
807
+ @final
775
808
class GetAttr (RegisterOp ):
776
809
"""obj.attr (for a native object)"""
777
810
@@ -804,6 +837,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
804
837
return visitor .visit_get_attr (self )
805
838
806
839
840
+ @final
807
841
class SetAttr (RegisterOp ):
808
842
"""obj.attr = src (for a native object)
809
843
@@ -855,6 +889,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
855
889
NAMESPACE_TYPE_VAR : Final = "typevar"
856
890
857
891
892
+ @final
858
893
class LoadStatic (RegisterOp ):
859
894
"""Load a static name (name :: static).
860
895
@@ -895,6 +930,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
895
930
return visitor .visit_load_static (self )
896
931
897
932
933
+ @final
898
934
class InitStatic (RegisterOp ):
899
935
"""static = value :: static
900
936
@@ -927,6 +963,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
927
963
return visitor .visit_init_static (self )
928
964
929
965
966
+ @final
930
967
class TupleSet (RegisterOp ):
931
968
"""dest = (reg, ...) (for fixed-length tuple)"""
932
969
@@ -959,6 +996,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
959
996
return visitor .visit_tuple_set (self )
960
997
961
998
999
+ @final
962
1000
class TupleGet (RegisterOp ):
963
1001
"""Get item of a fixed-length tuple (src[index])."""
964
1002
@@ -983,6 +1021,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
983
1021
return visitor .visit_tuple_get (self )
984
1022
985
1023
1024
+ @final
986
1025
class Cast (RegisterOp ):
987
1026
"""cast(type, src)
988
1027
@@ -1014,6 +1053,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1014
1053
return visitor .visit_cast (self )
1015
1054
1016
1055
1056
+ @final
1017
1057
class Box (RegisterOp ):
1018
1058
"""box(type, src)
1019
1059
@@ -1048,6 +1088,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1048
1088
return visitor .visit_box (self )
1049
1089
1050
1090
1091
+ @final
1051
1092
class Unbox (RegisterOp ):
1052
1093
"""unbox(type, src)
1053
1094
@@ -1074,6 +1115,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1074
1115
return visitor .visit_unbox (self )
1075
1116
1076
1117
1118
+ @final
1077
1119
class RaiseStandardError (RegisterOp ):
1078
1120
"""Raise built-in exception with an optional error string.
1079
1121
@@ -1113,6 +1155,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1113
1155
StealsDescription = Union [bool , list [bool ]]
1114
1156
1115
1157
1158
+ @final
1116
1159
class CallC (RegisterOp ):
1117
1160
"""result = function(arg0, arg1, ...)
1118
1161
@@ -1167,6 +1210,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1167
1210
return visitor .visit_call_c (self )
1168
1211
1169
1212
1213
+ @final
1170
1214
class Truncate (RegisterOp ):
1171
1215
"""result = truncate src from src_type to dst_type
1172
1216
@@ -1197,6 +1241,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1197
1241
return visitor .visit_truncate (self )
1198
1242
1199
1243
1244
+ @final
1200
1245
class Extend (RegisterOp ):
1201
1246
"""result = extend src from src_type to dst_type
1202
1247
@@ -1231,6 +1276,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1231
1276
return visitor .visit_extend (self )
1232
1277
1233
1278
1279
+ @final
1234
1280
class LoadGlobal (RegisterOp ):
1235
1281
"""Load a low-level global variable/pointer.
1236
1282
@@ -1258,6 +1304,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1258
1304
return visitor .visit_load_global (self )
1259
1305
1260
1306
1307
+ @final
1261
1308
class IntOp (RegisterOp ):
1262
1309
"""Binary arithmetic or bitwise op on integer operands (e.g., r1 = r2 + r3).
1263
1310
@@ -1322,6 +1369,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1322
1369
int_op_to_id : Final = {op : op_id for op_id , op in IntOp .op_str .items ()}
1323
1370
1324
1371
1372
+ @final
1325
1373
class ComparisonOp (RegisterOp ):
1326
1374
"""Low-level comparison op for integers and pointers.
1327
1375
@@ -1383,6 +1431,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1383
1431
return visitor .visit_comparison_op (self )
1384
1432
1385
1433
1434
+ @final
1386
1435
class FloatOp (RegisterOp ):
1387
1436
"""Binary float arithmetic op (e.g., r1 = r2 + r3).
1388
1437
@@ -1424,6 +1473,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1424
1473
float_op_to_id : Final = {op : op_id for op_id , op in FloatOp .op_str .items ()}
1425
1474
1426
1475
1476
+ @final
1427
1477
class FloatNeg (RegisterOp ):
1428
1478
"""Float negation op (r1 = -r2)."""
1429
1479
@@ -1444,6 +1494,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1444
1494
return visitor .visit_float_neg (self )
1445
1495
1446
1496
1497
+ @final
1447
1498
class FloatComparisonOp (RegisterOp ):
1448
1499
"""Low-level comparison op for floats."""
1449
1500
@@ -1480,6 +1531,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1480
1531
float_comparison_op_to_id : Final = {op : op_id for op_id , op in FloatComparisonOp .op_str .items ()}
1481
1532
1482
1533
1534
+ @final
1483
1535
class LoadMem (RegisterOp ):
1484
1536
"""Read a memory location: result = *(type *)src.
1485
1537
@@ -1509,6 +1561,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1509
1561
return visitor .visit_load_mem (self )
1510
1562
1511
1563
1564
+ @final
1512
1565
class SetMem (Op ):
1513
1566
"""Write to a memory location: *(type *)dest = src
1514
1567
@@ -1540,6 +1593,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1540
1593
return visitor .visit_set_mem (self )
1541
1594
1542
1595
1596
+ @final
1543
1597
class GetElementPtr (RegisterOp ):
1544
1598
"""Get the address of a struct element.
1545
1599
@@ -1566,6 +1620,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1566
1620
return visitor .visit_get_element_ptr (self )
1567
1621
1568
1622
1623
+ @final
1569
1624
class LoadAddress (RegisterOp ):
1570
1625
"""Get the address of a value: result = (type)&src
1571
1626
@@ -1600,6 +1655,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1600
1655
return visitor .visit_load_address (self )
1601
1656
1602
1657
1658
+ @final
1603
1659
class KeepAlive (RegisterOp ):
1604
1660
"""A no-op operation that ensures source values aren't freed.
1605
1661
@@ -1647,6 +1703,7 @@ def accept(self, visitor: OpVisitor[T]) -> T:
1647
1703
return visitor .visit_keep_alive (self )
1648
1704
1649
1705
1706
+ @final
1650
1707
class Unborrow (RegisterOp ):
1651
1708
"""A no-op op to create a regular reference from a borrowed one.
1652
1709
0 commit comments