forked from M-Labs/artiq
compiler: speedup list processing
This commit is contained in:
parent
f531af510c
commit
0806b67dbf
@ -156,6 +156,67 @@ class ASTSynthesizer:
|
|||||||
return source.Range(self.source_buffer, range_from, range_to,
|
return source.Range(self.source_buffer, range_from, range_to,
|
||||||
expanded_from=self.expanded_from)
|
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):
|
def quote(self, value):
|
||||||
"""Construct an AST fragment equal to `value`."""
|
"""Construct an AST fragment equal to `value`."""
|
||||||
if value is None:
|
if value is None:
|
||||||
@ -217,21 +278,14 @@ class ASTSynthesizer:
|
|||||||
return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc)
|
return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc)
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
begin_loc = self._add("[")
|
begin_loc = self._add("[")
|
||||||
elts = []
|
elts = self.fast_quote_list(value)
|
||||||
for index, elt in enumerate(value):
|
|
||||||
elts.append(self.quote(elt))
|
|
||||||
if index < len(value) - 1:
|
|
||||||
self._add(", ")
|
|
||||||
end_loc = self._add("]")
|
end_loc = self._add("]")
|
||||||
return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(),
|
return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(),
|
||||||
begin_loc=begin_loc, end_loc=end_loc,
|
begin_loc=begin_loc, end_loc=end_loc,
|
||||||
loc=begin_loc.join(end_loc))
|
loc=begin_loc.join(end_loc))
|
||||||
elif isinstance(value, tuple):
|
elif isinstance(value, tuple):
|
||||||
begin_loc = self._add("(")
|
begin_loc = self._add("(")
|
||||||
elts = []
|
elts = self.fast_quote_list(value)
|
||||||
for index, elt in enumerate(value):
|
|
||||||
elts.append(self.quote(elt))
|
|
||||||
self._add(", ")
|
|
||||||
end_loc = self._add(")")
|
end_loc = self._add(")")
|
||||||
return asttyped.TupleT(elts=elts, ctx=None,
|
return asttyped.TupleT(elts=elts, ctx=None,
|
||||||
type=types.TTuple([e.type for e in elts]),
|
type=types.TTuple([e.type for e in elts]),
|
||||||
|
@ -180,6 +180,7 @@ class LLVMIRGenerator:
|
|||||||
self.tbaa_tree,
|
self.tbaa_tree,
|
||||||
ll.Constant(lli64, 1)
|
ll.Constant(lli64, 1)
|
||||||
])
|
])
|
||||||
|
self.quote_fail_msg = None
|
||||||
|
|
||||||
def needs_sret(self, lltyp, may_be_large=True):
|
def needs_sret(self, lltyp, may_be_large=True):
|
||||||
if isinstance(lltyp, ll.VoidType):
|
if isinstance(lltyp, ll.VoidType):
|
||||||
@ -1492,8 +1493,24 @@ class LLVMIRGenerator:
|
|||||||
return llresult
|
return llresult
|
||||||
|
|
||||||
def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name):
|
def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name):
|
||||||
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
fail_msg = "at " + ".".join(path())
|
||||||
for i in range(len(value))]
|
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)),
|
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
|
||||||
list(llelts))
|
list(llelts))
|
||||||
name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name))
|
name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name))
|
||||||
@ -1502,60 +1519,63 @@ class LLVMIRGenerator:
|
|||||||
llglobal.linkage = "private"
|
llglobal.linkage = "private"
|
||||||
return llglobal.bitcast(lleltsary.type.element.as_pointer())
|
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):
|
def _quote(self, value, typ, path):
|
||||||
value_id = id(value)
|
value_id = id(value)
|
||||||
if value_id in self.llobject_map:
|
if value_id in self.llobject_map:
|
||||||
return self.llobject_map[value_id]
|
return self.llobject_map[value_id]
|
||||||
llty = self.llty_of_type(typ)
|
llty = self.llty_of_type(typ)
|
||||||
|
|
||||||
def _quote_attributes():
|
fail_msg = self.quote_fail_msg
|
||||||
llglobal = None
|
if fail_msg == None:
|
||||||
llfields = []
|
self.quote_fail_msg = fail_msg = "at " + ".".join(path())
|
||||||
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
|
|
||||||
|
|
||||||
fail_msg = "at " + ".".join(path())
|
|
||||||
if types.is_constructor(typ) or types.is_instance(typ):
|
if types.is_constructor(typ) or types.is_instance(typ):
|
||||||
if types.is_instance(typ):
|
if types.is_instance(typ):
|
||||||
# Make sure the class functions are quoted, as this has the side effect of
|
# Make sure the class functions are quoted, as this has the side effect of
|
||||||
# initializing the global closures.
|
# initializing the global closures.
|
||||||
self._quote(type(value), typ.constructor,
|
self._quote(type(value), typ.constructor,
|
||||||
lambda: path() + ['__class__'])
|
lambda: path() + ['__class__'])
|
||||||
return _quote_attributes()
|
return self._quote_attributes(value, typ, path, value_id, llty)
|
||||||
elif types.is_module(typ):
|
elif types.is_module(typ):
|
||||||
return _quote_attributes()
|
return self._quote_attributes(value, typ, path, value_id, llty)
|
||||||
elif builtins.is_none(typ):
|
elif builtins.is_none(typ):
|
||||||
assert value is None, fail_msg
|
assert value is None, fail_msg
|
||||||
return ll.Constant.literal_struct([])
|
return ll.Constant.literal_struct([])
|
||||||
|
Loading…
Reference in New Issue
Block a user