Skip to content

Commit

Permalink
Implement boxed constant integers as literals (#12507)
Browse files Browse the repository at this point in the history
This avoids creating a new int object every time
we evaluate an integer literal in a context that
requires a boxed value.

This speeds up this microbenchmark by about 60%:
```
def f() -> None:
    for j in range(1000 * 1000):
        a = []
        for i in range(10):
            a.append(10)
```

In more realistic workloads the impact is hard to
measure and is likely below the noise floor.
  • Loading branch information
JukkaL authored Apr 5, 2022
1 parent ee0638f commit 0e8a03c
Show file tree
Hide file tree
Showing 13 changed files with 130 additions and 124 deletions.
2 changes: 2 additions & 0 deletions mypyc/irbuild/ll_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ def self(self) -> Register:

def box(self, src: Value) -> Value:
if src.type.is_unboxed:
if isinstance(src, Integer) and is_tagged(src.type):
return self.add(LoadLiteral(src.value >> 1, rtype=object_rprimitive))
return self.add(Box(src))
else:
return src
Expand Down
3 changes: 2 additions & 1 deletion mypyc/test-data/exceptions-freq.test
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ def f(x):
r1 :: bit
r2 :: None
L0:
r0 = box(short_int, 2)
r0 = object 1
inc_ref r0
r1 = CPyList_SetItem(x, 0, r0)
if not r1 goto L2 (error at f:3) else goto L1 :: bool
L1:
Expand Down
69 changes: 35 additions & 34 deletions mypyc/test-data/irbuild-basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ L0:
r0 = builtins :: module
r1 = 'print'
r2 = CPyObject_GetAttr(r0, r1)
r3 = box(short_int, 10)
r3 = object 5
r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
return 1

Expand All @@ -738,7 +738,7 @@ L0:
r0 = builtins :: module
r1 = 'print'
r2 = CPyObject_GetAttr(r0, r1)
r3 = box(short_int, 10)
r3 = object 5
r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
return 1

Expand Down Expand Up @@ -810,7 +810,7 @@ def g(y):
L0:
r0 = g(y)
r1 = PyList_New(1)
r2 = box(short_int, 2)
r2 = object 1
r3 = get_element_ptr r1 ob_item :: PyListObject
r4 = load_mem r3 :: ptr*
set_mem r4, r2 :: builtins.object*
Expand Down Expand Up @@ -838,7 +838,7 @@ def g(y):
r7 :: bit
r8, r9 :: object
L0:
r0 = box(short_int, 2)
r0 = object 1
r1 = g(r0)
r2 = PyList_New(1)
r3 = get_element_ptr r2 ob_item :: PyListObject
Expand All @@ -851,7 +851,7 @@ L0:
r7 = CPyList_SetItem(a, 0, r6)
r8 = box(bool, 1)
y = r8
r9 = box(short_int, 6)
r9 = object 3
return r9

[case testCoerceToObject2]
Expand All @@ -869,7 +869,7 @@ def f(a, o):
r2 :: int
r3 :: object
L0:
r0 = box(short_int, 2)
r0 = object 1
a.x = r0; r1 = is_error
r2 = a.n
r3 = box(int, r2)
Expand Down Expand Up @@ -1204,7 +1204,7 @@ L0:
r0 = load_address PyLong_Type
r1 = 'base'
r2 = PyTuple_Pack(1, x)
r3 = box(short_int, 4)
r3 = object 2
r4 = CPyDict_Build(1, r1, r3)
r5 = PyObject_Call(r0, r2, r4)
r6 = unbox(int, r5)
Expand All @@ -1231,7 +1231,7 @@ L0:
r0 = 'insert'
r1 = CPyObject_GetAttr(xs, r0)
r2 = 'x'
r3 = box(short_int, 0)
r3 = object 0
r4 = PyTuple_Pack(1, r3)
r5 = box(int, first)
r6 = CPyDict_Build(1, r2, r5)
Expand All @@ -1242,7 +1242,7 @@ L0:
r11 = 'i'
r12 = PyTuple_Pack(0)
r13 = box(int, second)
r14 = box(short_int, 2)
r14 = object 1
r15 = CPyDict_Build(2, r10, r13, r11, r14)
r16 = PyObject_Call(r9, r12, r15)
return xs
Expand Down Expand Up @@ -1482,7 +1482,7 @@ L1:
L2:
r5 = __main__.globals :: static
r6 = 'x'
r7 = box(short_int, 2)
r7 = object 1
r8 = CPyDict_SetItem(r5, r6, r7)
r9 = r8 >= 0 :: signed
r10 = __main__.globals :: static
Expand Down Expand Up @@ -1516,7 +1516,7 @@ L0:
r0 = m :: module
r1 = 'f'
r2 = CPyObject_GetAttr(r0, r1)
r3 = box(short_int, 2)
r3 = object 1
r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
r5 = cast(str, r4)
return r5
Expand Down Expand Up @@ -1545,7 +1545,7 @@ def main():
r1 :: union[int, str]
r2, x :: int
L0:
r0 = box(short_int, 0)
r0 = object 0
r1 = foo(r0)
r2 = unbox(int, r1)
x = r2
Expand Down Expand Up @@ -1598,7 +1598,7 @@ def main():
r1 :: __main__.A
r2, x :: __main__.B
L0:
r0 = box(short_int, 0)
r0 = object 0
r1 = foo(r0)
r2 = cast(__main__.B, r1)
x = r2
Expand Down Expand Up @@ -1713,7 +1713,7 @@ L0:
r2 = 'f'
r3 = CPyDict_GetItem(r1, r2)
r4 = PyList_New(1)
r5 = box(short_int, 2)
r5 = object 1
r6 = get_element_ptr r4 ob_item :: PyListObject
r7 = load_mem r6 :: ptr*
set_mem r7, r5 :: builtins.object*
Expand Down Expand Up @@ -1757,9 +1757,9 @@ L0:
r0 = 'a'
r1 = 'b'
r2 = 'c'
r3 = box(short_int, 2)
r4 = box(short_int, 4)
r5 = box(short_int, 6)
r3 = object 1
r4 = object 2
r5 = object 3
r6 = CPyDict_Build(3, r0, r3, r1, r4, r2, r5)
r7 = __main__.globals :: static
r8 = 'f'
Expand Down Expand Up @@ -1787,16 +1787,16 @@ def h():
L0:
r0 = 'b'
r1 = 'c'
r2 = box(short_int, 4)
r3 = box(short_int, 6)
r2 = object 2
r3 = object 3
r4 = CPyDict_Build(2, r0, r2, r1, r3)
r5 = __main__.globals :: static
r6 = 'f'
r7 = CPyDict_GetItem(r5, r6)
r8 = PyDict_New()
r9 = CPyDict_UpdateInDisplay(r8, r4)
r10 = r9 >= 0 :: signed
r11 = box(short_int, 2)
r11 = object 1
r12 = PyTuple_Pack(1, r11)
r13 = PyObject_Call(r7, r12, r8)
r14 = unbox(tuple[int, int, int], r13)
Expand Down Expand Up @@ -1913,9 +1913,9 @@ def f():
L0:
r0 = PyList_New(0)
r1 = PyList_New(3)
r2 = box(short_int, 2)
r3 = box(short_int, 4)
r4 = box(short_int, 6)
r2 = object 1
r3 = object 2
r4 = object 3
r5 = get_element_ptr r1 ob_item :: PyListObject
r6 = load_mem r5 :: ptr*
set_mem r6, r2 :: builtins.object*
Expand Down Expand Up @@ -2012,9 +2012,9 @@ def f():
L0:
r0 = PyDict_New()
r1 = PyList_New(3)
r2 = box(short_int, 2)
r3 = box(short_int, 4)
r4 = box(short_int, 6)
r2 = object 1
r3 = object 2
r4 = object 3
r5 = get_element_ptr r1 ob_item :: PyListObject
r6 = load_mem r5 :: ptr*
set_mem r6, r2 :: builtins.object*
Expand Down Expand Up @@ -2429,7 +2429,7 @@ def SubclassedTrait.boxed(self):
self :: __main__.SubclassedTrait
r0 :: object
L0:
r0 = box(short_int, 6)
r0 = object 3
return r0
def DerivingObject.this(self):
self :: __main__.DerivingObject
Expand Down Expand Up @@ -2637,7 +2637,7 @@ L2:
r57 = __main__.globals :: static
r58 = 'Lol'
r59 = CPyDict_GetItem(r57, r58)
r60 = box(short_int, 2)
r60 = object 1
r61 = PyObject_CallFunctionObjArgs(r59, r60, r56, 0)
r62 = cast(tuple, r61)
r63 = __main__.globals :: static
Expand Down Expand Up @@ -2666,9 +2666,9 @@ L2:
r86 = CPyDict_SetItem(r84, r85, r83)
r87 = r86 >= 0 :: signed
r88 = PyList_New(3)
r89 = box(short_int, 2)
r90 = box(short_int, 4)
r91 = box(short_int, 6)
r89 = object 1
r90 = object 2
r91 = object 3
r92 = get_element_ptr r88 ob_item :: PyListObject
r93 = load_mem r92 :: ptr*
set_mem r93, r89 :: builtins.object*
Expand Down Expand Up @@ -3738,9 +3738,9 @@ def range_object():
r10 :: bit
L0:
r0 = load_address PyRange_Type
r1 = box(short_int, 8)
r2 = box(short_int, 24)
r3 = box(short_int, 4)
r1 = object 4
r2 = object 12
r3 = object 2
r4 = PyObject_CallFunctionObjArgs(r0, r1, r2, r3, 0)
r5 = cast(range, r4)
r = r5
Expand Down Expand Up @@ -3784,6 +3784,7 @@ L3:
goto L1
L4:
return 1

[case testLocalRedefinition]
# mypy: allow-redefinition
def f() -> None:
Expand Down
12 changes: 6 additions & 6 deletions mypyc/test-data/irbuild-constant-fold.test
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,13 @@ def unsupported_div():
r4, r5, r6 :: object
r7, y :: float
L0:
r0 = box(short_int, 8)
r1 = box(short_int, 12)
r0 = object 4
r1 = object 6
r2 = PyNumber_TrueDivide(r0, r1)
r3 = cast(float, r2)
x = r3
r4 = box(short_int, 20)
r5 = box(short_int, 10)
r4 = object 10
r5 = object 5
r6 = PyNumber_TrueDivide(r4, r5)
r7 = cast(float, r6)
y = r7
Expand All @@ -160,8 +160,8 @@ def unsupported_pow():
r0, r1, r2 :: object
r3, p :: float
L0:
r0 = box(short_int, 6)
r1 = box(short_int, -2)
r0 = object 3
r1 = object -1
r2 = CPyNumber_Power(r0, r1)
r3 = cast(float, r2)
p = r3
Expand Down
23 changes: 12 additions & 11 deletions mypyc/test-data/irbuild-dict.test
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def f(d):
r0, r1 :: object
r2 :: bool
L0:
r0 = box(short_int, 0)
r0 = object 0
r1 = CPyDict_GetItem(d, r0)
r2 = unbox(bool, r1)
return r2
Expand All @@ -24,7 +24,7 @@ def f(d):
r2 :: int32
r3 :: bit
L0:
r0 = box(short_int, 0)
r0 = object 0
r1 = box(bool, 0)
r2 = CPyDict_SetItem(d, r0, r1)
r3 = r2 >= 0 :: signed
Expand Down Expand Up @@ -66,8 +66,8 @@ def f(x):
r3, d :: dict
L0:
r0 = ''
r1 = box(short_int, 2)
r2 = box(short_int, 4)
r1 = object 1
r2 = object 2
r3 = CPyDict_Build(2, r1, r2, r0, x)
d = r3
return 1
Expand All @@ -87,7 +87,7 @@ def f(d):
r2 :: bit
r3 :: bool
L0:
r0 = box(short_int, 8)
r0 = object 4
r1 = PyDict_Contains(d, r0)
r2 = r1 >= 0 :: signed
r3 = truncate r1: int32 to builtins.bool
Expand All @@ -114,7 +114,7 @@ def f(d):
r2 :: bit
r3, r4 :: bool
L0:
r0 = box(short_int, 8)
r0 = object 4
r1 = PyDict_Contains(d, r0)
r2 = r1 >= 0 :: signed
r3 = truncate r1: int32 to builtins.bool
Expand Down Expand Up @@ -178,7 +178,7 @@ L2:
r8 = cast(str, r7)
k = r8
r9 = CPyDict_GetItem(d, k)
r10 = box(short_int, 2)
r10 = object 1
r11 = PyNumber_InPlaceAdd(r9, r10)
r12 = CPyDict_SetItem(d, k, r11)
r13 = r12 >= 0 :: signed
Expand Down Expand Up @@ -208,11 +208,11 @@ def f(x, y):
r7 :: bit
L0:
r0 = 'z'
r1 = box(short_int, 4)
r1 = object 2
r2 = CPyDict_Build(1, x, r1)
r3 = CPyDict_UpdateInDisplay(r2, y)
r4 = r3 >= 0 :: signed
r5 = box(short_int, 6)
r5 = object 3
r6 = CPyDict_SetItem(r2, r0, r5)
r7 = r6 >= 0 :: signed
return r2
Expand Down Expand Up @@ -423,7 +423,7 @@ L1:
L2:
r2 = 'a'
r3 = PyList_New(1)
r4 = box(short_int, 2)
r4 = object 1
r5 = get_element_ptr r3 ob_item :: PyListObject
r6 = load_mem r5 :: ptr*
set_mem r6, r4 :: builtins.object*
Expand Down Expand Up @@ -451,10 +451,11 @@ L1:
L2:
r2 = 'a'
r3 = 'c'
r4 = box(short_int, 2)
r4 = object 1
r5 = CPyDict_Build(1, r3, r4)
r6 = CPyDict_SetDefault(d, r2, r5)
return r6
L3:
r7 = box(None, 1)
return r7

4 changes: 2 additions & 2 deletions mypyc/test-data/irbuild-generics.test
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def f():
L0:
r0 = C()
c = r0
r1 = box(short_int, 2)
r1 = object 1
c.x = r1; r2 = is_error
r3 = c.x
r4 = unbox(int, r3)
Expand Down Expand Up @@ -118,7 +118,7 @@ L0:
r2 = CPyTagged_Add(y, 2)
r3 = box(int, r2)
r4 = x.set(r3)
r5 = box(short_int, 4)
r5 = object 2
r6 = C(r5)
x = r6
return 1
Expand Down
Loading

0 comments on commit 0e8a03c

Please sign in to comment.