Commit 871739ae authored by Stefan Behnel's avatar Stefan Behnel

Generate C compiler branch hints also for 'raise' statements in nogil and with-gil sections.

parent 7e8f9a3b
......@@ -4893,29 +4893,32 @@ class FinalOptimizePhase(Visitor.EnvTransform, Visitor.NodeRefCleanupMixin):
return node
def _set_ifclause_branch_hint(self, clause, statements_node, inverse=False):
"""Inject a branch hint if the if-clause unconditionally leads to a 'raise' statement.
"""
if not statements_node.is_terminator:
return
if isinstance(statements_node, Nodes.StatListNode):
if not statements_node.stats:
return
statements = statements_node.stats
else:
statements = [statements_node]
# Anything that unconditionally raises exceptions should be considered unlikely.
if isinstance(statements[-1], (Nodes.RaiseStatNode, Nodes.ReraiseStatNode)):
if len(statements) > 1:
# Allow simple statements before the 'raise', but no conditions, loops, etc.
non_branch_nodes = (
Nodes.ExprStatNode,
Nodes.AssignmentNode,
Nodes.DelStatNode,
Nodes.GlobalNode,
Nodes.NonlocalNode,
)
for node in statements[:-1]:
if not isinstance(node, non_branch_nodes):
return
clause.branch_hint = 'likely' if inverse else 'unlikely'
# Allow simple statements, but no conditions, loops, etc.
non_branch_nodes = (
Nodes.ExprStatNode,
Nodes.AssignmentNode,
Nodes.AssertStatNode,
Nodes.DelStatNode,
Nodes.GlobalNode,
Nodes.NonlocalNode,
)
statements = [statements_node]
for next_node_pos, node in enumerate(statements, 1):
if isinstance(node, Nodes.GILStatNode):
statements.insert(next_node_pos, node.body)
continue
if isinstance(node, Nodes.StatListNode):
statements[next_node_pos:next_node_pos] = node.stats
continue
if not isinstance(node, non_branch_nodes):
if next_node_pos == len(statements) and isinstance(node, (Nodes.RaiseStatNode, Nodes.ReraiseStatNode)):
# Anything that unconditionally raises exceptions at the end should be considered unlikely.
clause.branch_hint = 'likely' if inverse else 'unlikely'
break
class ConsolidateOverflowCheck(Visitor.CythonTransform):
......
......@@ -43,3 +43,49 @@ def if_else_raise(x):
return 1
else:
raise TypeError()
@cython.test_assert_path_exists(
"//IfClauseNode",
"//IfClauseNode[@branch_hint = 'unlikely']",
)
def if_raise_else_raise(x):
if x:
raise ValueError()
else:
raise TypeError()
@cython.test_assert_path_exists(
"//IfClauseNode",
"//IfClauseNode[@branch_hint = 'unlikely']",
)
@cython.test_fail_if_path_exists(
"//IfClauseNode[@branch_hint = 'likely']",
"//IfClauseNode[not(@branch_hint)]",
)
def if_elif_raise_else_raise(x):
if x:
raise ValueError()
elif not x:
raise AttributeError()
else:
raise TypeError()
@cython.test_assert_path_exists(
"//IfClauseNode",
"//IfClauseNode[@branch_hint = 'unlikely']",
"//IfClauseNode[@branch_hint = 'unlikely']//GILStatNode",
)
@cython.test_fail_if_path_exists(
"//IfClauseNode[@branch_hint = 'likely']",
"//IfClauseNode[not(@branch_hint)]",
)
cpdef int nogil_if_raise(int x) nogil except -1:
if x:
raise TypeError()
elif not x:
raise ValueError()
else:
x = 2
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