@@ -1953,6 +1953,61 @@ def testfunc(n):
19531953 self .assertNotIn ("_GUARD_NOS_INT" , uops )
19541954 self .assertNotIn ("_GUARD_TOS_INT" , uops )
19551955
1956+ def test_call_len_known_length_small_int (self ):
1957+ def testfunc (n ):
1958+ x = 0
1959+ for _ in range (n ):
1960+ a = (1 , 2 , 3 , 4 , 5 )
1961+ if len (a ) == 5 :
1962+ x += 1
1963+ return x
1964+
1965+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
1966+ self .assertEqual (res , TIER2_THRESHOLD )
1967+ self .assertIsNotNone (ex )
1968+ uops = get_opnames (ex )
1969+ # When the length is < _PY_NSMALLPOSINTS, the len() call is replaced
1970+ # with just an inline load.
1971+ self .assertNotIn ("_CALL_LEN" , uops )
1972+ self .assertNotIn ("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW" , uops )
1973+ self .assertNotIn ("_POP_CALL_LOAD_CONST_INLINE_BORROW" , uops )
1974+ self .assertNotIn ("_POP_TOP_LOAD_CONST_INLINE_BORROW" , uops )
1975+
1976+ def test_call_len_known_length (self ):
1977+ def testfunc (n ):
1978+ x = 0
1979+ for _ in range (n ):
1980+ a = (1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1981+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1982+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1983+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1984+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1985+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1986+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1987+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1988+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1989+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1990+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1991+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1992+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1993+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
1994+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 )
1995+ if len (a ) == 300 : # comparison + guard removed
1996+ x += 1
1997+ return x
1998+
1999+ res , ex = self ._run_with_optimizer (testfunc , TIER2_THRESHOLD )
2000+ self .assertEqual (res , TIER2_THRESHOLD )
2001+ self .assertIsNotNone (ex )
2002+ uops = get_opnames (ex )
2003+ # When the length is >= _PY_NSMALLPOSINTS, we cannot replace
2004+ # the len() call with an inline load, but knowing the exact
2005+ # length allows us to optimize more code, such as conditionals
2006+ # in this case
2007+ self .assertIn ("_CALL_LEN" , uops )
2008+ self .assertNotIn ("_COMPARE_OP_INT" , uops )
2009+ self .assertNotIn ("_GUARD_IS_TRUE_POP" , uops )
2010+
19562011 def test_get_len_with_const_tuple (self ):
19572012 def testfunc (n ):
19582013 x = 0.0
0 commit comments