Skip to content

Commit 67d0b47

Browse files
committed
[mypyc] feat: remove redundant box/unbox operations
1 parent 9ae3e9a commit 67d0b47

File tree

12 files changed

+217
-171
lines changed

12 files changed

+217
-171
lines changed

mypyc/analysis/dataflow.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,16 @@ def cleanup_cfg(blocks: list[BasicBlock]) -> None:
152152
cfg = get_cfg(blocks)
153153
orig_blocks = blocks.copy()
154154
blocks.clear()
155+
155156
for i, block in enumerate(orig_blocks):
156-
if i == 0 or cfg.pred[block]:
157+
# Keep the block if it's the entry block or has any predecessors
158+
# OR if it is a branch target (i.e., appears in any terminator.targets())
159+
is_branch_target = any(
160+
block is tgt
161+
for b in orig_blocks
162+
for tgt in b.terminator.targets()
163+
)
164+
if i == 0 or cfg.pred[block] or is_branch_target:
157165
blocks.append(block)
158166
else:
159167
changed = True

mypyc/codegen/emitmodule.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
from mypyc.transform.flag_elimination import do_flag_elimination
6868
from mypyc.transform.log_trace import insert_event_trace_logging
6969
from mypyc.transform.lower import lower_ir
70+
from mypyc.transform.redundant_box_elimination import do_box_unbox_elimination
7071
from mypyc.transform.refcount import insert_ref_count_opcodes
7172
from mypyc.transform.spill import insert_spills
7273
from mypyc.transform.uninit import insert_uninit_checks
@@ -227,7 +228,6 @@ def compile_scc_to_ir(
227228
228229
Returns the IR of the modules.
229230
"""
230-
231231
if compiler_options.verbose:
232232
print("Compiling {}".format(", ".join(x.name for x in scc)))
233233

@@ -260,6 +260,7 @@ def compile_scc_to_ir(
260260
# Switch to lower abstraction level IR.
261261
lower_ir(fn, compiler_options)
262262
# Perform optimizations.
263+
do_box_unbox_elimination(fn, compiler_options)
263264
do_copy_propagation(fn, compiler_options)
264265
do_flag_elimination(fn, compiler_options)
265266

mypyc/test-data/irbuild-dict.test

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,8 @@ def union_of_dicts(d):
339339
r12 :: object[1]
340340
r13 :: object_ptr
341341
r14 :: object
342-
r15 :: int
343-
r16 :: object
344-
r17 :: i32
345-
r18, r19, r20 :: bit
342+
r15 :: i32
343+
r16, r17, r18 :: bit
346344
L0:
347345
r0 = PyDict_New()
348346
new = r0
@@ -367,15 +365,13 @@ L2:
367365
r13 = load_address r12
368366
r14 = PyObject_Vectorcall(r11, r13, 1, 0)
369367
keep_alive v
370-
r15 = unbox(int, r14)
371-
r16 = box(int, r15)
372-
r17 = CPyDict_SetItem(new, k, r16)
373-
r18 = r17 >= 0 :: signed
368+
r15 = CPyDict_SetItem(new, k, r14)
369+
r16 = r15 >= 0 :: signed
374370
L3:
375-
r19 = CPyDict_CheckSize(d, r2)
371+
r17 = CPyDict_CheckSize(d, r2)
376372
goto L1
377373
L4:
378-
r20 = CPy_NoErrOccurred()
374+
r18 = CPy_NoErrOccurred()
379375
L5:
380376
return 1
381377
def typeddict(d):

mypyc/test-data/irbuild-lists.test

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -724,13 +724,11 @@ def test():
724724
r0, source :: bytes
725725
r1 :: native_int
726726
r2 :: list
727-
r3 :: native_int
728-
r4, r5, r6 :: bit
729-
r7, r8, r9, r10 :: int
730-
r11 :: object
731-
r12, x, r13 :: int
732-
r14 :: object
733-
r15 :: native_int
727+
r3, r4 :: native_int
728+
r5, r6, r7 :: bit
729+
r8, r9, r10, r11, x, r12 :: int
730+
r13 :: object
731+
r14 :: native_int
734732
a :: list
735733
L0:
736734
r0 = b'abc'
@@ -755,16 +753,14 @@ L5:
755753
r9 = r3 << 1
756754
r8 = r9
757755
L6:
758-
r10 = CPyBytes_GetItem(source, r8)
759-
r11 = box(int, r10)
760-
r12 = unbox(int, r11)
761-
x = r12
762-
r13 = f2(x)
763-
r14 = box(int, r13)
764-
CPyList_SetItemUnsafe(r2, r3, r14)
756+
r11 = CPyBytes_GetItem(source, r9)
757+
x = r11
758+
r12 = f2(x)
759+
r13 = box(int, r12)
760+
CPyList_SetItemUnsafe(r2, r4, r13)
765761
L7:
766-
r15 = r3 + 1
767-
r3 = r15
762+
r14 = r4 + 1
763+
r4 = r14
768764
goto L1
769765
L8:
770766
a = r2
@@ -785,12 +781,11 @@ L0:
785781
return r0
786782
def test():
787783
r0 :: bytes
788-
r1 :: list
789-
r2 :: native_int
790-
r3, r4, r5 :: bit
791-
r6, r7, r8, r9 :: int
792-
r10 :: object
793-
r11, x, r12 :: int
784+
r1 :: native_int
785+
r2 :: list
786+
r3, r4 :: native_int
787+
r5, r6, r7 :: bit
788+
r8, r9, r10, r11, x, r12 :: int
794789
r13 :: object
795790
r14 :: native_int
796791
a :: list
@@ -815,16 +810,14 @@ L5:
815810
r8 = r2 << 1
816811
r7 = r8
817812
L6:
818-
r9 = CPyBytes_GetItem(r0, r7)
819-
r10 = box(int, r9)
820-
r11 = unbox(int, r10)
813+
r11 = CPyBytes_GetItem(r0, r9)
821814
x = r11
822815
r12 = f2(x)
823816
r13 = box(int, r12)
824-
CPyList_SetItemUnsafe(r1, r2, r13)
817+
CPyList_SetItemUnsafe(r2, r4, r13)
825818
L7:
826-
r14 = r2 + 1
827-
r2 = r14
819+
r14 = r4 + 1
820+
r4 = r14
828821
goto L1
829822
L8:
830823
a = r1
@@ -852,13 +845,11 @@ def test():
852845
r1 :: bool
853846
r2 :: native_int
854847
r3 :: list
855-
r4 :: native_int
856-
r5, r6, r7 :: bit
857-
r8, r9, r10, r11 :: int
858-
r12 :: object
859-
r13, x, r14 :: int
860-
r15 :: object
861-
r16 :: native_int
848+
r4, r5 :: native_int
849+
r6, r7, r8 :: bit
850+
r9, r10, r11, r12, x, r13 :: int
851+
r14 :: object
852+
r15 :: native_int
862853
a :: list
863854
L0:
864855
r0 = __main__.source :: static
@@ -887,16 +878,14 @@ L7:
887878
r10 = r4 << 1
888879
r9 = r10
889880
L8:
890-
r11 = CPyBytes_GetItem(r0, r9)
891-
r12 = box(int, r11)
892-
r13 = unbox(int, r12)
893-
x = r13
894-
r14 = f2(x)
895-
r15 = box(int, r14)
896-
CPyList_SetItemUnsafe(r3, r4, r15)
881+
r12 = CPyBytes_GetItem(r0, r10)
882+
x = r12
883+
r13 = f2(x)
884+
r14 = box(int, r13)
885+
CPyList_SetItemUnsafe(r3, r5, r14)
897886
L9:
898-
r16 = r4 + 1
899-
r4 = r16
887+
r15 = r5 + 1
888+
r5 = r15
900889
goto L3
901890
L10:
902891
a = r3

mypyc/test-data/irbuild-set.test

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -649,29 +649,25 @@ def not_precomputed_non_final_name(i):
649649
r0 :: dict
650650
r1 :: str
651651
r2 :: object
652-
r3 :: int
653-
r4 :: set
654-
r5 :: object
655-
r6 :: i32
656-
r7 :: bit
657-
r8 :: object
658-
r9 :: i32
659-
r10 :: bit
660-
r11 :: bool
652+
r3 :: set
653+
r4 :: i32
654+
r5 :: bit
655+
r6 :: object
656+
r7 :: i32
657+
r8 :: bit
658+
r9 :: bool
661659
L0:
662660
r0 = __main__.globals :: static
663661
r1 = 'non_const'
664662
r2 = CPyDict_GetItem(r0, r1)
665-
r3 = unbox(int, r2)
666-
r4 = PySet_New(0)
667-
r5 = box(int, r3)
668-
r6 = PySet_Add(r4, r5)
669-
r7 = r6 >= 0 :: signed
670-
r8 = box(int, i)
671-
r9 = PySet_Contains(r4, r8)
672-
r10 = r9 >= 0 :: signed
673-
r11 = truncate r9: i32 to builtins.bool
674-
return r11
663+
r3 = PySet_New(0)
664+
r4 = PySet_Add(r3, r2)
665+
r5 = r4 >= 0 :: signed
666+
r6 = box(int, i)
667+
r7 = PySet_Contains(r3, r6)
668+
r8 = r7 >= 0 :: signed
669+
r9 = truncate r7: i32 to builtins.bool
670+
return r9
675671
def not_precomputed_nested_set(i):
676672
i :: int
677673
r0 :: set
@@ -769,33 +765,30 @@ def not_precomputed():
769765
r0 :: dict
770766
r1 :: str
771767
r2 :: object
772-
r3 :: int
773-
r4 :: set
774-
r5 :: object
775-
r6 :: i32
776-
r7 :: bit
777-
r8, r9 :: object
778-
r10, not_optimized :: int
779-
r11 :: bit
768+
r3 :: set
769+
r4 :: i32
770+
r5 :: bit
771+
r6, r7 :: object
772+
r8, not_optimized :: int
773+
r9 :: bit
780774
L0:
781775
r0 = __main__.globals :: static
782776
r1 = 'non_const'
783777
r2 = CPyDict_GetItem(r0, r1)
784-
r3 = unbox(int, r2)
785-
r4 = PySet_New(0)
786-
r5 = box(int, r3)
787-
r6 = PySet_Add(r4, r5)
788-
r7 = r6 >= 0 :: signed
789-
r8 = PyObject_GetIter(r4)
778+
r3 = PySet_New(0)
779+
r4 = PySet_Add(r3, r2)
780+
r5 = r4 >= 0 :: signed
781+
r6 = PyObject_GetIter(r3)
790782
L1:
791-
r9 = PyIter_Next(r8)
792-
if is_error(r9) goto L4 else goto L2
783+
r7 = PyIter_Next(r6)
784+
if is_error(r7) goto L4 else goto L2
793785
L2:
794-
r10 = unbox(int, r9)
795-
not_optimized = r10
786+
r8 = unbox(int, r7)
787+
not_optimized = r8
796788
L3:
797789
goto L1
798790
L4:
799-
r11 = CPy_NoErrOccurred()
791+
r9 = CPy_NoErrOccurred()
800792
L5:
801793
return 1
794+

mypyc/test-data/irbuild-singledispatch.test

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,10 @@ def f_obj.__call__(__mypyc_self__, x):
188188
r17 :: ptr
189189
r18 :: object
190190
r19 :: bit
191-
r20 :: int
192-
r21 :: object[1]
193-
r22 :: object_ptr
194-
r23 :: object
195-
r24 :: None
191+
r20 :: object[1]
192+
r21 :: object_ptr
193+
r22 :: object
194+
r23 :: None
196195
L0:
197196
r0 = get_element_ptr x ob_type :: PyObject
198197
r1 = borrow load_mem r0 :: builtins.object*
@@ -225,15 +224,14 @@ L3:
225224
r19 = r18 == r16
226225
if r19 goto L4 else goto L5 :: bool
227226
L4:
228-
r20 = unbox(int, r6)
229227
unreachable
230228
L5:
231-
r21 = [x]
232-
r22 = load_address r21
233-
r23 = PyObject_Vectorcall(r6, r22, 1, 0)
229+
r20 = [x]
230+
r21 = load_address r20
231+
r22 = PyObject_Vectorcall(r6, r21, 1, 0)
234232
keep_alive x
235-
r24 = unbox(None, r23)
236-
return r24
233+
r23 = unbox(None, r22)
234+
return r23
237235
def f_obj.__get__(__mypyc_self__, instance, owner):
238236
__mypyc_self__, instance, owner, r0 :: object
239237
r1 :: bit

mypyc/test-data/irbuild-statements.test

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,7 @@ def f(d):
273273
r6 :: object
274274
r7, key :: int
275275
r8, r9 :: object
276-
r10 :: int
277-
r11, r12 :: bit
276+
r10, r11 :: bit
278277
L0:
279278
r0 = 0
280279
r1 = PyDict_Size(d)
@@ -291,12 +290,11 @@ L2:
291290
key = r7
292291
r8 = box(int, key)
293292
r9 = CPyDict_GetItem(d, r8)
294-
r10 = unbox(int, r9)
295293
L3:
296-
r11 = CPyDict_CheckSize(d, r1)
294+
r10 = CPyDict_CheckSize(d, r1)
297295
goto L1
298296
L4:
299-
r12 = CPy_NoErrOccurred()
297+
r11 = CPy_NoErrOccurred()
300298
L5:
301299
return 1
302300

0 commit comments

Comments
 (0)