@@ -1968,6 +1968,49 @@ def testfunc(n):
19681968 self .assertNotIn ("_GUARD_NOS_INT" , uops )
19691969 self .assertNotIn ("_GUARD_TOS_INT" , uops )
19701970
1971+ def test_call_len_known_length_small_int (self ):
1972+ def testfunc (n ):
1973+ x = 0
1974+ for _ in range (n ):
1975+ t = (1 , 2 , 3 , 4 , 5 )
1976+ if len (t ) == 5 :
1977+ x += 1
1978+ return x
1979+
1980+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
1981+ self .assertEqual (res , TIER2_THRESHOLD )
1982+ self .assertIsNotNone (ex )
1983+ uops = get_opnames (ex )
1984+ # When the length is < _PY_NSMALLPOSINTS, the len() call is replaced
1985+ # with just an inline load.
1986+ self .assertNotIn ("_CALL_LEN" , uops )
1987+ self .assertNotIn ("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW" , uops )
1988+ self .assertNotIn ("_POP_CALL_LOAD_CONST_INLINE_BORROW" , uops )
1989+ self .assertNotIn ("_POP_TOP_LOAD_CONST_INLINE_BORROW" , uops )
1990+
1991+ def test_call_len_known_length (self ):
1992+ def testfunc (n ):
1993+ class C :
1994+ t = tuple (range (300 ))
1995+
1996+ x = 0
1997+ for _ in range (n ):
1998+ if len (C .t ) == 300 : # comparison + guard removed
1999+ x += 1
2000+ return x
2001+
2002+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
2003+ self .assertEqual (res , TIER2_THRESHOLD )
2004+ self .assertIsNotNone (ex )
2005+ uops = get_opnames (ex )
2006+ # When the length is >= _PY_NSMALLPOSINTS, we cannot replace
2007+ # the len() call with an inline load, but knowing the exact
2008+ # length allows us to optimize more code, such as conditionals
2009+ # in this case
2010+ self .assertIn ("_CALL_LEN" , uops )
2011+ self .assertNotIn ("_COMPARE_OP_INT" , uops )
2012+ self .assertNotIn ("_GUARD_IS_TRUE_POP" , uops )
2013+
19712014 def test_get_len_with_const_tuple (self ):
19722015 def testfunc (n ):
19732016 x = 0.0
0 commit comments