24
24
GetAttr , LoadStatic , MethodCall , CallC , Truncate , LoadLiteral , AssignMulti ,
25
25
RaiseStandardError , Unreachable , LoadErrorValue ,
26
26
NAMESPACE_TYPE , NAMESPACE_MODULE , NAMESPACE_STATIC , IntOp , GetElementPtr ,
27
- LoadMem , ComparisonOp , LoadAddress , TupleGet , SetMem , KeepAlive , ERR_NEVER , ERR_FALSE
27
+ LoadMem , ComparisonOp , LoadAddress , TupleGet , KeepAlive , ERR_NEVER , ERR_FALSE , SetMem
28
28
)
29
29
from mypyc .ir .rtypes import (
30
30
RType , RUnion , RInstance , RArray , optional_value_type , int_rprimitive , float_rprimitive ,
31
31
bool_rprimitive , list_rprimitive , str_rprimitive , is_none_rprimitive , object_rprimitive ,
32
32
c_pyssize_t_rprimitive , is_short_int_rprimitive , is_tagged , PyVarObject , short_int_rprimitive ,
33
33
is_list_rprimitive , is_tuple_rprimitive , is_dict_rprimitive , is_set_rprimitive , PySetObject ,
34
34
none_rprimitive , RTuple , is_bool_rprimitive , is_str_rprimitive , c_int_rprimitive ,
35
- pointer_rprimitive , PyObject , PyListObject , bit_rprimitive , is_bit_rprimitive ,
36
- object_pointer_rprimitive , c_size_t_rprimitive , dict_rprimitive
35
+ pointer_rprimitive , PyObject , bit_rprimitive , is_bit_rprimitive ,
36
+ object_pointer_rprimitive , c_size_t_rprimitive , dict_rprimitive , PyListObject
37
37
)
38
38
from mypyc .ir .func_ir import FuncDecl , FuncSignature
39
39
from mypyc .ir .class_ir import ClassIR , all_concrete_classes
46
46
binary_ops , unary_ops , ERR_NEG_INT
47
47
)
48
48
from mypyc .primitives .list_ops import (
49
- list_extend_op , new_list_op
49
+ list_extend_op , new_list_op , list_build_op
50
50
)
51
51
from mypyc .primitives .tuple_ops import (
52
52
list_tuple_op , new_tuple_op , new_tuple_with_length_op
78
78
79
79
DictEntry = Tuple [Optional [Value ], Value ]
80
80
81
+ # If the number of items is less than the threshold when initializing
82
+ # a list, we would inline the generate IR using SetMem and expanded
83
+ # for-loop. Otherwise, we would call `list_build_op` for larger lists.
84
+ # TODO: The threshold is a randomly chosen number which needs further
85
+ # study on real-world projects for a better balance.
86
+ LIST_BUILDING_EXPANSION_THRESHOLD = 10
81
87
82
88
# From CPython
83
89
PY_VECTORCALL_ARGUMENTS_OFFSET : Final = 1 << (PLATFORM_SIZE * 8 - 1 )
@@ -669,7 +675,6 @@ def native_args_to_positional(self,
669
675
# coercing everything to the expected type.
670
676
output_args = []
671
677
for lst , arg in zip (formal_to_actual , sig .args ):
672
- output_arg = None
673
678
if arg .kind == ARG_STAR :
674
679
assert star_arg
675
680
output_arg = star_arg
@@ -700,7 +705,7 @@ def gen_method_call(self,
700
705
arg_names : Optional [List [Optional [str ]]] = None ) -> Value :
701
706
"""Generate either a native or Python method call."""
702
707
# If we have *args, then fallback to Python method call.
703
- if ( arg_kinds is not None and any (kind .is_star () for kind in arg_kinds ) ):
708
+ if arg_kinds is not None and any (kind .is_star () for kind in arg_kinds ):
704
709
return self .py_method_call (base , name , arg_values , base .line , arg_kinds , arg_names )
705
710
706
711
# If the base type is one of ours, do a MethodCall
@@ -766,7 +771,7 @@ def none(self) -> Value:
766
771
767
772
def true (self ) -> Value :
768
773
"""Load unboxed True value (type: bool_rprimitive)."""
769
- return Integer (1 , bool_rprimitive )
774
+ return Integer (1 , bool_rprimitive )
770
775
771
776
def false (self ) -> Value :
772
777
"""Load unboxed False value (type: bool_rprimitive)."""
@@ -1008,7 +1013,7 @@ def compare_tuples(self,
1008
1013
return result
1009
1014
length = len (lhs .type .types )
1010
1015
false_assign , true_assign , out = BasicBlock (), BasicBlock (), BasicBlock ()
1011
- check_blocks = [BasicBlock () for i in range (length )]
1016
+ check_blocks = [BasicBlock () for _ in range (length )]
1012
1017
lhs_items = [self .add (TupleGet (lhs , i , line )) for i in range (length )]
1013
1018
rhs_items = [self .add (TupleGet (rhs , i , line )) for i in range (length )]
1014
1019
@@ -1137,8 +1142,15 @@ def new_list_op_with_length(self, length: Value, line: int) -> Value:
1137
1142
return self .call_c (new_list_op , [length ], line )
1138
1143
1139
1144
def new_list_op (self , values : List [Value ], line : int ) -> Value :
1140
- length = Integer (len (values ), c_pyssize_t_rprimitive , line )
1141
- result_list = self .call_c (new_list_op , [length ], line )
1145
+ length : List [Value ] = [Integer (len (values ), c_pyssize_t_rprimitive , line )]
1146
+ if len (values ) >= LIST_BUILDING_EXPANSION_THRESHOLD :
1147
+ return self .call_c (list_build_op , length + values , line )
1148
+
1149
+ # If the length of the list is less than the threshold,
1150
+ # LIST_BUILDING_EXPANSION_THRESHOLD, we directly expand the
1151
+ # for-loop and inline the SetMem operation, which is faster
1152
+ # than list_build_op, however generates more code.
1153
+ result_list = self .call_c (new_list_op , length , line )
1142
1154
if len (values ) == 0 :
1143
1155
return result_list
1144
1156
args = [self .coerce (item , object_rprimitive , line ) for item in values ]
@@ -1174,7 +1186,7 @@ def shortcircuit_helper(self, op: str,
1174
1186
# Having actual Phi nodes would be really nice here!
1175
1187
target = Register (expr_type )
1176
1188
# left_body takes the value of the left side, right_body the right
1177
- left_body , right_body , next = BasicBlock (), BasicBlock (), BasicBlock ()
1189
+ left_body , right_body , next_block = BasicBlock (), BasicBlock (), BasicBlock ()
1178
1190
# true_body is taken if the left is true, false_body if it is false.
1179
1191
# For 'and' the value is the right side if the left is true, and for 'or'
1180
1192
# it is the right side if the left is false.
@@ -1187,15 +1199,15 @@ def shortcircuit_helper(self, op: str,
1187
1199
self .activate_block (left_body )
1188
1200
left_coerced = self .coerce (left_value , expr_type , line )
1189
1201
self .add (Assign (target , left_coerced ))
1190
- self .goto (next )
1202
+ self .goto (next_block )
1191
1203
1192
1204
self .activate_block (right_body )
1193
1205
right_value = right ()
1194
1206
right_coerced = self .coerce (right_value , expr_type , line )
1195
1207
self .add (Assign (target , right_coerced ))
1196
- self .goto (next )
1208
+ self .goto (next_block )
1197
1209
1198
- self .activate_block (next )
1210
+ self .activate_block (next_block )
1199
1211
return target
1200
1212
1201
1213
def add_bool_branch (self , value : Value , true : BasicBlock , false : BasicBlock ) -> None :
0 commit comments