Skip to content

Commit 2368f1f

Browse files
committed
[mypyc] feat: remove redundant box/unbox operations
1 parent 116b92b commit 2368f1f

File tree

12 files changed

+206
-161
lines changed

12 files changed

+206
-161
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: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -746,11 +746,9 @@ def test():
746746
r2 :: list
747747
r3, r4 :: native_int
748748
r5, r6, r7 :: bit
749-
r8, r9, r10, r11 :: int
750-
r12 :: object
751-
r13, x, r14 :: int
752-
r15 :: object
753-
r16 :: native_int
749+
r8, r9, r10, r11, x, r12 :: int
750+
r13 :: object
751+
r14 :: native_int
754752
a :: list
755753
L0:
756754
r0 = b'abc'
@@ -777,15 +775,13 @@ L5:
777775
r9 = r10
778776
L6:
779777
r11 = CPyBytes_GetItem(source, r9)
780-
r12 = box(int, r11)
781-
r13 = unbox(int, r12)
782-
x = r13
783-
r14 = f2(x)
784-
r15 = box(int, r14)
785-
CPyList_SetItemUnsafe(r2, r4, r15)
778+
x = r11
779+
r12 = f2(x)
780+
r13 = box(int, r12)
781+
CPyList_SetItemUnsafe(r2, r4, r13)
786782
L7:
787-
r16 = r4 + 1
788-
r4 = r16
783+
r14 = r4 + 1
784+
r4 = r14
789785
goto L1
790786
L8:
791787
a = r2
@@ -810,11 +806,9 @@ def test():
810806
r2 :: list
811807
r3, r4 :: native_int
812808
r5, r6, r7 :: bit
813-
r8, r9, r10, r11 :: int
814-
r12 :: object
815-
r13, x, r14 :: int
816-
r15 :: object
817-
r16 :: native_int
809+
r8, r9, r10, r11, x, r12 :: int
810+
r13 :: object
811+
r14 :: native_int
818812
a :: list
819813
L0:
820814
r0 = b'abc'
@@ -840,15 +834,13 @@ L5:
840834
r9 = r10
841835
L6:
842836
r11 = CPyBytes_GetItem(r0, r9)
843-
r12 = box(int, r11)
844-
r13 = unbox(int, r12)
845-
x = r13
846-
r14 = f2(x)
847-
r15 = box(int, r14)
848-
CPyList_SetItemUnsafe(r2, r4, r15)
837+
x = r11
838+
r12 = f2(x)
839+
r13 = box(int, r12)
840+
CPyList_SetItemUnsafe(r2, r4, r13)
849841
L7:
850-
r16 = r4 + 1
851-
r4 = r16
842+
r14 = r4 + 1
843+
r4 = r14
852844
goto L1
853845
L8:
854846
a = r2
@@ -878,11 +870,9 @@ def test():
878870
r3 :: list
879871
r4, r5 :: native_int
880872
r6, r7, r8 :: bit
881-
r9, r10, r11, r12 :: int
882-
r13 :: object
883-
r14, x, r15 :: int
884-
r16 :: object
885-
r17 :: native_int
873+
r9, r10, r11, r12, x, r13 :: int
874+
r14 :: object
875+
r15 :: native_int
886876
a :: list
887877
L0:
888878
r0 = __main__.source :: static
@@ -913,16 +903,15 @@ L7:
913903
r10 = r11
914904
L8:
915905
r12 = CPyBytes_GetItem(r0, r10)
916-
r13 = box(int, r12)
917-
r14 = unbox(int, r13)
918-
x = r14
919-
r15 = f2(x)
920-
r16 = box(int, r15)
921-
CPyList_SetItemUnsafe(r3, r5, r16)
906+
x = r12
907+
r13 = f2(x)
908+
r14 = box(int, r13)
909+
CPyList_SetItemUnsafe(r3, r5, r14)
922910
L9:
923-
r17 = r5 + 1
924-
r5 = r17
911+
r15 = r5 + 1
912+
r5 = r15
925913
goto L3
926914
L10:
927915
a = r3
928916
return 1
917+

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)