compiler: speedup list processing

pull/1710/head
pca006132 2021-07-02 13:54:54 +08:00 committed by Sébastien Bourdeauducq
parent f531af510c
commit 0806b67dbf
2 changed files with 125 additions and 51 deletions

View File

@ -156,6 +156,67 @@ class ASTSynthesizer:
return source.Range(self.source_buffer, range_from, range_to,
expanded_from=self.expanded_from)
def fast_quote_list(self, value):
elts = [None] * len(value)
is_T = False
if len(value) > 0:
v = value[0]
is_T = True
if isinstance(v, int):
T = int
elif isinstance(v, float):
T = float
elif isinstance(v, numpy.int32):
T = numpy.int32
elif isinstance(v, numpy.int64):
T = numpy.int64
else:
is_T = False
if is_T:
for v in value:
if not isinstance(v, T):
is_T = False
break
if is_T:
is_int = T != float
if T == int:
typ = builtins.TInt()
elif T == float:
typ = builtins.TFloat()
elif T == numpy.int32:
typ = builtins.TInt32()
elif T == numpy.int64:
typ = builtins.TInt64()
else:
assert False
text = [repr(elt) for elt in value]
start = len(self.source)
self.source += ", ".join(text)
if is_int:
for i, (v, t) in enumerate(zip(value, text)):
l = len(t)
elts[i] = asttyped.NumT(
n=int(v), ctx=None, type=typ,
loc=source.Range(
self.source_buffer, start, start + l,
expanded_from=self.expanded_from))
start += l + 2
else:
for i, (v, t) in enumerate(zip(value, text)):
l = len(t)
elts[i] = asttyped.NumT(
n=v, ctx=None, type=typ,
loc=source.Range(
self.source_buffer, start, start + l,
expanded_from=self.expanded_from))
start += l + 2
else:
for index, elt in enumerate(value):
elts[index] = self.quote(elt)
if index < len(value) - 1:
self._add(", ")
return elts
def quote(self, value):
"""Construct an AST fragment equal to `value`."""
if value is None:
@ -217,21 +278,14 @@ class ASTSynthesizer:
return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc)
elif isinstance(value, list):
begin_loc = self._add("[")
elts = []
for index, elt in enumerate(value):
elts.append(self.quote(elt))
if index < len(value) - 1:
self._add(", ")
elts = self.fast_quote_list(value)
end_loc = self._add("]")
return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(),
begin_loc=begin_loc, end_loc=end_loc,
loc=begin_loc.join(end_loc))
elif isinstance(value, tuple):
begin_loc = self._add("(")
elts = []
for index, elt in enumerate(value):
elts.append(self.quote(elt))
self._add(", ")
elts = self.fast_quote_list(value)
end_loc = self._add(")")
return asttyped.TupleT(elts=elts, ctx=None,
type=types.TTuple([e.type for e in elts]),

View File

@ -180,6 +180,7 @@ class LLVMIRGenerator:
self.tbaa_tree,
ll.Constant(lli64, 1)
])
self.quote_fail_msg = None
def needs_sret(self, lltyp, may_be_large=True):
if isinstance(lltyp, ll.VoidType):
@ -1492,8 +1493,24 @@ class LLVMIRGenerator:
return llresult
def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name):
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
for i in range(len(value))]
fail_msg = "at " + ".".join(path())
if len(value) > 0:
if builtins.is_int(elt_type):
int_typ = (int, numpy.int32, numpy.int64)
for v in value:
assert isinstance(v, int_typ), fail_msg
llty = self.llty_of_type(elt_type)
llelts = [ll.Constant(llty, int(v)) for v in value]
elif builtins.is_float(elt_type):
for v in value:
assert isinstance(v, float), fail_msg
llty = self.llty_of_type(elt_type)
llelts = [ll.Constant(llty, v) for v in value]
else:
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
for i in range(len(value))]
else:
assert False, fail_msg
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
list(llelts))
name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name))
@ -1502,60 +1519,63 @@ class LLVMIRGenerator:
llglobal.linkage = "private"
return llglobal.bitcast(lleltsary.type.element.as_pointer())
def _quote_attributes(self, value, typ, path, value_id, llty):
llglobal = None
llfields = []
emit_as_constant = True
for attr in typ.attributes:
if attr == "__objectid__":
objectid = self.embedding_map.store_object(value)
llfields.append(ll.Constant(lli32, objectid))
assert llglobal is None
if types.is_constructor(typ):
llglobal = self.get_class(typ)
else:
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
name="O.{}".format(objectid))
self.llobject_map[value_id] = llglobal
else:
attrvalue = getattr(value, attr)
is_class_function = (types.is_constructor(typ) and
types.is_function(typ.attributes[attr]) and
not types.is_external_function(typ.attributes[attr]))
if is_class_function:
attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue)
if not (types.is_instance(typ) and attr in typ.constant_attributes):
emit_as_constant = False
llattrvalue = self._quote(attrvalue, typ.attributes[attr],
lambda: path() + [attr])
llfields.append(llattrvalue)
if is_class_function:
llclosureptr = self.get_global_closure_ptr(typ, attr)
llclosureptr.initializer = llattrvalue
llglobal.global_constant = emit_as_constant
llglobal.initializer = ll.Constant(llty.pointee, llfields)
llglobal.linkage = "private"
return llglobal
def _quote(self, value, typ, path):
value_id = id(value)
if value_id in self.llobject_map:
return self.llobject_map[value_id]
llty = self.llty_of_type(typ)
def _quote_attributes():
llglobal = None
llfields = []
emit_as_constant = True
for attr in typ.attributes:
if attr == "__objectid__":
objectid = self.embedding_map.store_object(value)
llfields.append(ll.Constant(lli32, objectid))
fail_msg = self.quote_fail_msg
if fail_msg == None:
self.quote_fail_msg = fail_msg = "at " + ".".join(path())
assert llglobal is None
if types.is_constructor(typ):
llglobal = self.get_class(typ)
else:
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
name="O.{}".format(objectid))
self.llobject_map[value_id] = llglobal
else:
attrvalue = getattr(value, attr)
is_class_function = (types.is_constructor(typ) and
types.is_function(typ.attributes[attr]) and
not types.is_external_function(typ.attributes[attr]))
if is_class_function:
attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue)
if not (types.is_instance(typ) and attr in typ.constant_attributes):
emit_as_constant = False
llattrvalue = self._quote(attrvalue, typ.attributes[attr],
lambda: path() + [attr])
llfields.append(llattrvalue)
if is_class_function:
llclosureptr = self.get_global_closure_ptr(typ, attr)
llclosureptr.initializer = llattrvalue
llglobal.global_constant = emit_as_constant
llglobal.initializer = ll.Constant(llty.pointee, llfields)
llglobal.linkage = "private"
return llglobal
fail_msg = "at " + ".".join(path())
if types.is_constructor(typ) or types.is_instance(typ):
if types.is_instance(typ):
# Make sure the class functions are quoted, as this has the side effect of
# initializing the global closures.
self._quote(type(value), typ.constructor,
lambda: path() + ['__class__'])
return _quote_attributes()
return self._quote_attributes(value, typ, path, value_id, llty)
elif types.is_module(typ):
return _quote_attributes()
return self._quote_attributes(value, typ, path, value_id, llty)
elif builtins.is_none(typ):
assert value is None, fail_msg
return ll.Constant.literal_struct([])