Commit 8c5aa3ef authored by Vitja Makarov's avatar Vitja Makarov

ControlFlowAnalysis: be comaptible with MarkAssignments

parent 2e3a306d
...@@ -26,6 +26,7 @@ cdef class ExitBlock(ControlBlock): ...@@ -26,6 +26,7 @@ cdef class ExitBlock(ControlBlock):
cdef class NameAssignment: cdef class NameAssignment:
cdef public bint is_arg cdef public bint is_arg
cdef public bint is_deletion
cdef public object lhs cdef public object lhs
cdef public object rhs cdef public object rhs
cdef public object entry cdef public object entry
......
...@@ -8,7 +8,7 @@ cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object, ...@@ -8,7 +8,7 @@ cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object,
import Builtin import Builtin
import ExprNodes import ExprNodes
import Nodes import Nodes
from PyrexTypes import py_object_type from PyrexTypes import py_object_type, unspecified_type
from Visitor import TreeVisitor, CythonTransform from Visitor import TreeVisitor, CythonTransform
from Errors import error, warning, InternalError from Errors import error, warning, InternalError
...@@ -24,6 +24,9 @@ class TypedExprNode(ExprNodes.ExprNode): ...@@ -24,6 +24,9 @@ class TypedExprNode(ExprNodes.ExprNode):
object_expr = TypedExprNode(py_object_type, may_be_none=True) object_expr = TypedExprNode(py_object_type, may_be_none=True)
object_expr_not_none = TypedExprNode(py_object_type, may_be_none=False) object_expr_not_none = TypedExprNode(py_object_type, may_be_none=False)
# Fake rhs to silence "unused variable" warning
fake_rhs_expr = TypedExprNode(unspecified_type)
class ControlBlock(object): class ControlBlock(object):
"""Control flow graph node. Sequence of assignments and name references. """Control flow graph node. Sequence of assignments and name references.
...@@ -174,7 +177,7 @@ class ControlFlow(object): ...@@ -174,7 +177,7 @@ class ControlFlow(object):
def mark_deletion(self, node, entry): def mark_deletion(self, node, entry):
if self.block and self.is_tracked(entry): if self.block and self.is_tracked(entry):
assignment = NameAssignment(node, None, entry) assignment = NameDeletion(node, entry)
self.block.stats.append(assignment) self.block.stats.append(assignment)
self.block.gen[entry] = Uninitialized self.block.gen[entry] = Uninitialized
self.entries.add(entry) self.entries.add(entry)
...@@ -293,6 +296,7 @@ class ExceptionDescr(object): ...@@ -293,6 +296,7 @@ class ExceptionDescr(object):
self.finally_enter = finally_enter self.finally_enter = finally_enter
self.finally_exit = finally_exit self.finally_exit = finally_exit
class NameAssignment(object): class NameAssignment(object):
def __init__(self, lhs, rhs, entry): def __init__(self, lhs, rhs, entry):
if lhs.cf_state is None: if lhs.cf_state is None:
...@@ -303,15 +307,24 @@ class NameAssignment(object): ...@@ -303,15 +307,24 @@ class NameAssignment(object):
self.pos = lhs.pos self.pos = lhs.pos
self.refs = set() self.refs = set()
self.is_arg = False self.is_arg = False
self.is_deletion = False
def __repr__(self): def __repr__(self):
return '%s(entry=%r)' % (self.__class__.__name__, self.entry) return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
class Argument(NameAssignment): class Argument(NameAssignment):
def __init__(self, lhs, rhs, entry): def __init__(self, lhs, rhs, entry):
NameAssignment.__init__(self, lhs, rhs, entry) NameAssignment.__init__(self, lhs, rhs, entry)
self.is_arg = True self.is_arg = True
class NameDeletion(NameAssignment):
def __init__(self, lhs, entry):
NameAssignment.__init__(self, lhs, lhs, entry)
self.is_deletion = True
class Uninitialized(object): class Uninitialized(object):
pass pass
...@@ -462,12 +475,13 @@ def check_definitions(flow, compiler_directives): ...@@ -462,12 +475,13 @@ def check_definitions(flow, compiler_directives):
stat.lhs.cf_state.update(state) stat.lhs.cf_state.update(state)
assmt_nodes.add(stat.lhs) assmt_nodes.add(stat.lhs)
i_state = i_state & ~i_assmts.mask i_state = i_state & ~i_assmts.mask
if stat.rhs: if stat.is_deletion:
i_state |= stat.bit
else:
i_state |= i_assmts.bit i_state |= i_assmts.bit
else:
i_state |= stat.bit
assignments.add(stat) assignments.add(stat)
stat.entry.cf_assignments.append(stat) if stat.rhs is not fake_rhs_expr:
stat.entry.cf_assignments.append(stat)
elif isinstance(stat, NameReference): elif isinstance(stat, NameReference):
references[stat.node] = stat.entry references[stat.node] = stat.entry
stat.entry.cf_references.append(stat) stat.entry.cf_references.append(stat)
...@@ -754,7 +768,8 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -754,7 +768,8 @@ class ControlFlowAnalysis(CythonTransform):
entry = self.env.lookup(node.name) entry = self.env.lookup(node.name)
if entry: if entry:
may_be_none = not node.not_none may_be_none = not node.not_none
self.flow.mark_argument(node, TypedExprNode(entry.type, may_be_none), entry) self.flow.mark_argument(
node, TypedExprNode(entry.type, may_be_none), entry)
return node return node
def visit_NameNode(self, node): def visit_NameNode(self, node):
...@@ -838,6 +853,41 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -838,6 +853,41 @@ class ControlFlowAnalysis(CythonTransform):
self.flow.block = None self.flow.block = None
return node return node
def mark_forloop_target(self, node):
# TODO: Remove redundancy with range optimization...
is_special = False
sequence = node.iterator.sequence
if isinstance(sequence, ExprNodes.SimpleCallNode):
function = sequence.function
if sequence.self is None and function.is_name:
if function.name == 'reversed' and len(sequence.args) == 1:
sequence = sequence.args[0]
if isinstance(sequence, ExprNodes.SimpleCallNode):
function = sequence.function
if sequence.self is None and function.is_name:
if function.name in ('range', 'xrange'):
is_special = True
for arg in sequence.args[:2]:
self.mark_assignment(node.target, arg)
if len(sequence.args) > 2:
self.mark_assignment(
node.target,
ExprNodes.binop_node(node.pos,
'+',
sequence.args[0],
sequence.args[2]))
if not is_special:
# A for-loop basically translates to subsequent calls to
# __getitem__(), so using an IndexNode here allows us to
# naturally infer the base type of pointers, C arrays,
# Python strings, etc., while correctly falling back to an
# object type when the base type cannot be handled.
self.mark_assignment(node.target, ExprNodes.IndexNode(
node.pos,
base = sequence,
index = ExprNodes.IntNode(node.pos, value = '0')))
def visit_ForInStatNode(self, node): def visit_ForInStatNode(self, node):
condition_block = self.flow.nextblock() condition_block = self.flow.nextblock()
next_block = self.flow.newblock() next_block = self.flow.newblock()
...@@ -846,7 +896,11 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -846,7 +896,11 @@ class ControlFlowAnalysis(CythonTransform):
self.visit(node.iterator) self.visit(node.iterator)
# Target assignment # Target assignment
self.flow.nextblock() self.flow.nextblock()
self.mark_assignment(node.target)
if isinstance(node, Nodes.ForInStatNode):
self.mark_forloop_target(node)
else: # Parallel
self.mark_assignment(node.target)
# Body block # Body block
if isinstance(node, Nodes.ParallelRangeNode): if isinstance(node, Nodes.ParallelRangeNode):
...@@ -916,12 +970,15 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -916,12 +970,15 @@ class ControlFlowAnalysis(CythonTransform):
self.flow.loops.append(LoopDescr(next_block, condition_block)) self.flow.loops.append(LoopDescr(next_block, condition_block))
self.visit(node.bound1) self.visit(node.bound1)
self.visit(node.bound2) self.visit(node.bound2)
if node.step: if node.step is not None:
self.visit(node.step) self.visit(node.step)
# Target assignment # Target assignment
self.flow.nextblock() self.flow.nextblock()
self.mark_assignment(node.target) self.mark_assignment(node.target, node.bound1)
if node.step is not None:
self.mark_assignment(node.target,
ExprNodes.binop_node(node.pos, '+',
node.bound1, node.step))
# Body block # Body block
self.flow.nextblock() self.flow.nextblock()
self.visit(node.body) self.visit(node.body)
...@@ -1143,6 +1200,6 @@ class ControlFlowAnalysis(CythonTransform): ...@@ -1143,6 +1200,6 @@ class ControlFlowAnalysis(CythonTransform):
def visit_AmpersandNode(self, node): def visit_AmpersandNode(self, node):
if node.operand.is_name: if node.operand.is_name:
# Fake assignment to silence warning # Fake assignment to silence warning
self.mark_assignment(node.operand) self.mark_assignment(node.operand, fake_rhs_expr)
self.visitchildren(node) self.visitchildren(node)
return node return node
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