Commit 9f118eb6 authored by Stefan Behnel's avatar Stefan Behnel

detect optimisable IndexNodes assignments in ref-count optimisation, but do...

detect optimisable IndexNodes assignments in ref-count optimisation, but do not activate them for now
parent d328d707
...@@ -93,6 +93,7 @@ class Context(object): ...@@ -93,6 +93,7 @@ class Context(object):
from AutoDocTransforms import EmbedSignature from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform
from Optimize import OptimizeBuiltinCalls, ConstantFolding, FinalOptimizePhase from Optimize import OptimizeBuiltinCalls, ConstantFolding, FinalOptimizePhase
from Optimize import DropRefcountingTransform
from Buffer import IntroduceBufferAuxiliaryVars from Buffer import IntroduceBufferAuxiliaryVars
from ModuleNode import check_c_declarations, check_c_declarations_pxd from ModuleNode import check_c_declarations, check_c_declarations_pxd
...@@ -138,6 +139,7 @@ class Context(object): ...@@ -138,6 +139,7 @@ class Context(object):
OptimizeBuiltinCalls(), OptimizeBuiltinCalls(),
IterationTransform(), IterationTransform(),
SwitchTransform(), SwitchTransform(),
DropRefcountingTransform(),
FinalOptimizePhase(self), FinalOptimizePhase(self),
GilCheck(), GilCheck(),
# ClearResultCodes(self), # ClearResultCodes(self),
......
...@@ -528,39 +528,106 @@ class DropRefcountingTransform(Visitor.VisitorTransform): ...@@ -528,39 +528,106 @@ class DropRefcountingTransform(Visitor.VisitorTransform):
visit_Node = Visitor.VisitorTransform.recurse_to_children visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_ParallelAssignmentNode(self, node): def visit_ParallelAssignmentNode(self, node):
left, right, temps = [], [], [] left_names, right_names = [], []
left_indices, right_indices = [], []
temps = []
for stat in node.stats: for stat in node.stats:
if isinstance(stat, Nodes.SingleAssignmentNode): if isinstance(stat, Nodes.SingleAssignmentNode):
lhs = unwrap_node(stat.lhs) if not self._extract_operand(stat.lhs, left_names,
if not isinstance(lhs, ExprNodes.NameNode): left_indices, temps):
return node return node
left.append(lhs) if not self._extract_operand(stat.rhs, right_names,
rhs = unwrap_node(stat.rhs) right_indices, temps):
if isinstance(rhs, ExprNodes.CoerceToTempNode):
temps.append(rhs)
rhs = rhs.arg
if not isinstance(rhs, ExprNodes.NameNode):
return node return node
right.append(rhs) elif isinstance(stat, Nodes.CascadedAssignmentNode):
# FIXME
return node
else: else:
return node return node
for name_node in left + right: if left_names or right_names:
if name_node.entry.is_builtin or name_node.entry.is_pyglobal: # lhs/rhs names must be a non-redundant permutation
lnames = [n.name for n in left_names]
rnames = [n.name for n in right_names]
if set(lnames) != set(rnames):
return node
if len(set(lnames)) != len(right_names):
return node return node
left_names = [n.name for n in left] if left_indices or right_indices:
right_names = [n.name for n in right] # base name and index of index nodes must be a
if set(left_names) != set(right_names): # non-redundant permutation
return node lindices = []
if len(set(left_names)) != len(right): for lhs_node in left_indices:
index_id = self._extract_index_id(lhs_node)
if not index_id:
return node
lindices.append(index_id)
rindices = []
for rhs_node in right_indices:
index_id = self._extract_index_id(rhs_node)
if not index_id:
return node
rindices.append(index_id)
if set(lindices) != set(rindices):
return node
if len(set(lindices)) != len(right_indices):
return node
# really supporting IndexNode requires support in
# __Pyx_GetItemInt(), so let's stop short for now
return node return node
for name_node in left + right + temps: temp_args = [t.arg for t in temps]
name_node.use_managed_ref = False for temp in temps:
temp.use_managed_ref = False
for name_node in left_names + right_names:
if name_node not in temp_args:
name_node.use_managed_ref = False
for index_node in left_indices + right_indices:
index_node.use_managed_ref = False
return node return node
def _extract_operand(self, node, names, indices, temps):
node = unwrap_node(node)
if not node.type.is_pyobject:
return False
if isinstance(node, ExprNodes.CoerceToTempNode):
temps.append(node)
node = node.arg
if isinstance(node, ExprNodes.NameNode):
if node.entry.is_builtin or node.entry.is_pyglobal:
return False
names.append(node)
elif isinstance(node, ExprNodes.IndexNode):
if node.base.type != Builtin.list_type:
return False
if not node.index.type.is_int:
return False
if not isinstance(node.base, ExprNodes.NameNode):
return False
indices.append(node)
else:
return False
return True
def _extract_index_id(self, index_node):
base = index_node.base
index = index_node.index
if isinstance(index, ExprNodes.NameNode):
index_val = index.name
elif isinstance(index, ExprNodes.ConstNode):
# FIXME:
return None
else:
return None
return (base.name, index_val)
class OptimizeBuiltinCalls(Visitor.VisitorTransform): class OptimizeBuiltinCalls(Visitor.VisitorTransform):
"""Optimize some common methods calls and instantiation patterns """Optimize some common methods calls and instantiation patterns
......
__doc__ = u""" __doc__ = u"""
>>> swap(1,2) >>> swap(1,2)
(2, 1) (2, 1)
>>> l = [1,2,3,4]
>>> swap_list_items(l, 1, 2)
>>> l
[1, 3, 2, 4]
>>> swap_list_items(l, 3, 0)
>>> l
[4, 3, 2, 1]
>>> swap_list_items(l, 0, 5)
Traceback (most recent call last):
IndexError: list index out of range
>>> l
[4, 3, 2, 1]
""" """
cimport cython
@cython.test_assert_path_exists(
"//ParallelAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode//CoerceToTempNode/NameNode",
"//ParallelAssignmentNode/SingleAssignmentNode//CoerceToTempNode[@use_managed_ref=False]/NameNode",
)
@cython.test_fail_if_path_exists(
"//ParallelAssignmentNode/SingleAssignmentNode//CoerceToTempNode[@use_managed_ref=True]",
)
def swap(a,b): def swap(a,b):
a,b = b,a a,b = b,a
return a,b return a,b
@cython.test_assert_path_exists(
"//ParallelAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode//CoerceToTempNode/NameNode",
"//ParallelAssignmentNode/SingleAssignmentNode//CoerceToTempNode[@use_managed_ref=True]/NameNode",
)
@cython.test_fail_if_path_exists(
"//ParallelAssignmentNode/SingleAssignmentNode//CoerceToTempNode[@use_managed_ref=False]",
)
def swap_py(a,b):
a,a = b,a
return a,b
@cython.test_assert_path_exists(
# "//ParallelAssignmentNode",
# "//ParallelAssignmentNode/SingleAssignmentNode",
# "//ParallelAssignmentNode/SingleAssignmentNode//IndexNode",
# "//ParallelAssignmentNode/SingleAssignmentNode//IndexNode[@use_managed_ref=False]",
)
@cython.test_fail_if_path_exists(
# "//ParallelAssignmentNode/SingleAssignmentNode//IndexNode[@use_managed_ref=True]",
)
def swap_list_items(list a, int i, int j):
a[i], a[j] = a[j], a[i]
@cython.test_assert_path_exists(
"//ParallelAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode//IndexNode",
"//ParallelAssignmentNode/SingleAssignmentNode//IndexNode[@use_managed_ref=True]",
)
@cython.test_fail_if_path_exists(
"//ParallelAssignmentNode/SingleAssignmentNode//IndexNode[@use_managed_ref=False]",
)
def swap_list_items_py1(list a, int i, int j):
a[i], a[j] = a[j+1], a[i]
@cython.test_assert_path_exists(
"//ParallelAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode",
"//ParallelAssignmentNode/SingleAssignmentNode//IndexNode",
"//ParallelAssignmentNode/SingleAssignmentNode//IndexNode[@use_managed_ref=True]",
)
@cython.test_fail_if_path_exists(
"//ParallelAssignmentNode/SingleAssignmentNode//IndexNode[@use_managed_ref=False]",
)
def swap_list_items_py2(list a, int i, int j):
a[i], a[j] = a[i], a[i]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment