Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0b4cb1e

Browse files
[mypyc] Faster min (#10265)
Speeds up `min(x, y)` using a specializer. Co-authored-by: 97littleleaf11 <[email protected]>
1 parent 60f80e0 commit 0b4cb1e

7 files changed

Lines changed: 146 additions & 1 deletion

File tree

mypyc/irbuild/specialize.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,32 @@ def translate_set_from_generator_call(
185185
return None
186186

187187

188+
@specialize_function('builtins.min')
189+
def faster_min(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Optional[Value]:
190+
if expr.arg_kinds == [ARG_POS, ARG_POS]:
191+
x, y = builder.accept(expr.args[0]), builder.accept(expr.args[1])
192+
result = Register(builder.node_type(expr))
193+
comparison = builder.binary_op(y, x, '<', expr.line)
194+
true = BasicBlock()
195+
false = BasicBlock()
196+
next_block = BasicBlock()
197+
198+
builder.add_bool_branch(comparison, true, false)
199+
200+
builder.activate_block(true)
201+
builder.assign(result, builder.coerce(y, result.type, expr.line), expr.line)
202+
builder.goto(next_block)
203+
204+
builder.activate_block(false)
205+
builder.assign(result, builder.coerce(x, result.type, expr.line), expr.line)
206+
builder.goto(next_block)
207+
208+
builder.activate_block(next_block)
209+
210+
return result
211+
return None
212+
213+
188214
@specialize_function('builtins.tuple')
189215
@specialize_function('builtins.frozenset')
190216
@specialize_function('builtins.dict')

mypyc/test-data/fixtures/ir.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ def zip(x: Iterable[T], y: Iterable[S], z: Iterable[V]) -> Iterator[Tuple[T, S,
302302
def eval(e: str) -> Any: ...
303303
def abs(x: float) -> float: ...
304304
def exit() -> None: ...
305+
def min(x: T, y: T) -> T: ...
305306
def repr(o: object) -> str: ...
306307
def ascii(o: object) -> str: ...
307308
def ord(o: object) -> int: ...

mypyc/test-data/irbuild-int.test

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,40 @@ L14:
8080
L15:
8181
L16:
8282
return 12
83+
84+
[case testIntMin]
85+
def f(x: int, y: int) -> int:
86+
return min(x, y)
87+
[out]
88+
def f(x, y):
89+
x, y :: int
90+
r0 :: native_int
91+
r1 :: bit
92+
r2 :: native_int
93+
r3, r4, r5 :: bit
94+
r6 :: bool
95+
r7 :: bit
96+
r8 :: int
97+
L0:
98+
r0 = y & 1
99+
r1 = r0 == 0
100+
r2 = x & 1
101+
r3 = r2 == 0
102+
r4 = r1 & r3
103+
if r4 goto L1 else goto L2 :: bool
104+
L1:
105+
r5 = y < x :: signed
106+
r6 = r5
107+
goto L3
108+
L2:
109+
r7 = CPyTagged_IsLt_(y, x)
110+
r6 = r7
111+
L3:
112+
if r6 goto L4 else goto L5 :: bool
113+
L4:
114+
r8 = y
115+
goto L6
116+
L5:
117+
r8 = x
118+
L6:
119+
return r8

mypyc/test-data/run-dunders.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,3 +757,30 @@ def test_in_place_operator_returns_none() -> None:
757757
o = BadInplaceAdd()
758758
with assertRaises(TypeError, "native.BadInplaceAdd object expected; got None"):
759759
o += 5
760+
761+
[case testDunderMin]
762+
class SomeItem:
763+
def __init__(self, val: int) -> None:
764+
self.val = val
765+
766+
def __lt__(self, x: 'SomeItem') -> bool:
767+
return self.val < x.val
768+
769+
class AnotherItem:
770+
def __init__(self, val: str) -> None:
771+
self.val = val
772+
773+
def __lt__(self, x: 'AnotherItem') -> bool:
774+
return True
775+
776+
def test_dunder_min() -> None:
777+
x = SomeItem(5)
778+
y = SomeItem(10)
779+
z = SomeItem(15)
780+
assert min(x, y).val == 5
781+
assert min(y, z).val == 10
782+
x2 = AnotherItem('xxx')
783+
y2 = AnotherItem('yyy')
784+
z2 = AnotherItem('zzz')
785+
assert min(x2, y2).val == 'yyy'
786+
assert min(y2, x2).val == 'xxx'

mypyc/test-data/run-floats.test

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@ assert str_to_float("44324") == 44324.0
1313
assert str_to_float("23.4") == 23.4
1414
assert str_to_float("-43.44e-4") == -43.44e-4
1515

16-
[case testFloatAbs]
16+
[case testFloatArithmetic]
1717
def test_abs() -> None:
1818
assert abs(0.0) == 0.0
1919
assert abs(-1.234567) == 1.234567
2020
assert abs(44324.732) == 44324.732
2121
assert abs(-23.4) == 23.4
2222
assert abs(-43.44e-4) == 43.44e-4
23+
24+
def test_float_min() -> None:
25+
x: float = 20.0
26+
y: float = 30.0
27+
assert min(x, y) == 20.0
28+
assert min(y, x) == 20.0

mypyc/test-data/run-integers.test

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,44 @@ def test_constant_fold() -> None:
427427
assert n63 == -(1 << 63)
428428
n64 = -(1 << 64) + int()
429429
assert n64 == -(1 << 64)
430+
431+
[case testIntMin]
432+
def test_int_min() -> None:
433+
x: int = 200
434+
y: int = 30
435+
assert min(x, y) == 30
436+
437+
def test_int_min_2() -> None:
438+
x: int = 30
439+
y: int = 200
440+
assert min(x, y) == 30
441+
442+
def test_int_hybrid_min() -> None:
443+
from typing import Any
444+
445+
x: object = 30
446+
y: Any = 20.0
447+
assert min(x, y) == 20.0
448+
449+
u: object = 20
450+
v: float = 30.0
451+
assert min(u, v) == 20
452+
453+
def test_int_incompatible_min() -> None:
454+
x: int = 2
455+
y: str = 'aaa'
456+
try:
457+
print(min(x, y))
458+
except TypeError as e:
459+
assert str(e) == "'<' not supported between instances of 'str' and 'int'"
460+
461+
def test_int_bool_min() -> None:
462+
x: int = 2
463+
y: bool = False
464+
z: bool = True
465+
assert min(x, y) == False
466+
assert min(x, z) == True
467+
468+
u: int = -10
469+
assert min(u, y) == -10
470+
assert min(u, z) == -10

mypyc/test-data/run-strings.test

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ def test_str_to_bool() -> None:
149149
assert is_true(x)
150150
assert not is_false(x)
151151

152+
def test_str_min() -> None:
153+
x: str = 'aaa'
154+
y: str = 'bbb'
155+
z: str = 'aa'
156+
assert min(x, y) == 'aaa'
157+
assert min(x, z) == 'aa'
158+
152159
[case testStringFormattingCStyle]
153160
[typing fixtures/typing-full.pyi]
154161
from typing import Tuple

0 commit comments

Comments
 (0)