Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
a9072286
Commit
a9072286
authored
Sep 27, 2011
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avoid unnecessary None checks based on control flow analysis (ticket #743)
parent
8ddf15a3
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
119 additions
and
10 deletions
+119
-10
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+10
-0
Cython/Compiler/FlowControl.py
Cython/Compiler/FlowControl.py
+16
-8
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+9
-0
tests/run/cf_none.pyx
tests/run/cf_none.pyx
+84
-0
tests/run/list.pyx
tests/run/list.pyx
+0
-2
No files found.
Cython/Compiler/ExprNodes.py
View file @
a9072286
...
@@ -1481,6 +1481,16 @@ class NameNode(AtomicExprNode):
...
@@ -1481,6 +1481,16 @@ class NameNode(AtomicExprNode):
# If it's not a C variable, it'll be in a temp.
# If it's not a C variable, it'll be in a temp.
return
1
return
1
def
may_be_none
(
self
):
if
self
.
cf_state
:
# evaluate control flow state to see if there were any
# potential None values assigned to the node so far
for
assignment
in
self
.
cf_state
:
if
assignment
.
rhs
.
may_be_none
():
return
True
return
False
return
super
(
NameNode
,
self
).
may_be_none
()
def
nonlocally_immutable
(
self
):
def
nonlocally_immutable
(
self
):
if
ExprNode
.
nonlocally_immutable
(
self
):
if
ExprNode
.
nonlocally_immutable
(
self
):
return
True
return
True
...
...
Cython/Compiler/FlowControl.py
View file @
a9072286
...
@@ -14,11 +14,16 @@ from Visitor import TreeVisitor, CythonTransform
...
@@ -14,11 +14,16 @@ from Visitor import TreeVisitor, CythonTransform
from
Errors
import
error
,
warning
,
CompileError
,
InternalError
from
Errors
import
error
,
warning
,
CompileError
,
InternalError
class
TypedExprNode
(
ExprNodes
.
ExprNode
):
class
TypedExprNode
(
ExprNodes
.
ExprNode
):
# Used for declaring assignments of a specified type w
h
ithout a known entry.
# Used for declaring assignments of a specified type without a known entry.
def
__init__
(
self
,
type
):
def
__init__
(
self
,
type
,
may_be_none
=
None
):
self
.
type
=
type
self
.
type
=
type
self
.
_may_be_none
=
may_be_none
object_expr
=
TypedExprNode
(
py_object_type
)
def
may_be_none
(
self
):
return
self
.
_may_be_none
!=
False
object_expr
=
TypedExprNode
(
py_object_type
,
may_be_none
=
True
)
object_expr_not_none
=
TypedExprNode
(
py_object_type
,
may_be_none
=
False
)
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.
...
@@ -588,11 +593,13 @@ class CreateControlFlowGraph(CythonTransform):
...
@@ -588,11 +593,13 @@ class CreateControlFlowGraph(CythonTransform):
if
node
.
star_arg
:
if
node
.
star_arg
:
self
.
flow
.
mark_argument
(
node
.
star_arg
,
self
.
flow
.
mark_argument
(
node
.
star_arg
,
TypedExprNode
(
Builtin
.
tuple_type
),
TypedExprNode
(
Builtin
.
tuple_type
,
may_be_none
=
False
),
node
.
star_arg
.
entry
)
node
.
star_arg
.
entry
)
if
node
.
starstar_arg
:
if
node
.
starstar_arg
:
self
.
flow
.
mark_argument
(
node
.
starstar_arg
,
self
.
flow
.
mark_argument
(
node
.
starstar_arg
,
TypedExprNode
(
Builtin
.
dict_type
),
TypedExprNode
(
Builtin
.
dict_type
,
may_be_none
=
False
),
node
.
starstar_arg
.
entry
)
node
.
starstar_arg
.
entry
)
self
.
visitchildren
(
node
)
self
.
visitchildren
(
node
)
# Workaround for generators
# Workaround for generators
...
@@ -621,7 +628,7 @@ class CreateControlFlowGraph(CythonTransform):
...
@@ -621,7 +628,7 @@ class CreateControlFlowGraph(CythonTransform):
if
entry
.
is_anonymous
:
if
entry
.
is_anonymous
:
entry
=
self
.
env
.
lookup
(
node
.
name
)
entry
=
self
.
env
.
lookup
(
node
.
name
)
if
entry
:
if
entry
:
self
.
flow
.
mark_assignment
(
node
,
object_expr
,
entry
)
self
.
flow
.
mark_assignment
(
node
,
object_expr
_not_none
,
entry
)
return
self
.
visit_FuncDefNode
(
node
)
return
self
.
visit_FuncDefNode
(
node
)
def
visit_GeneratorBodyDefNode
(
self
,
node
):
def
visit_GeneratorBodyDefNode
(
self
,
node
):
...
@@ -717,7 +724,8 @@ class CreateControlFlowGraph(CythonTransform):
...
@@ -717,7 +724,8 @@ class CreateControlFlowGraph(CythonTransform):
def
visit_CArgDeclNode
(
self
,
node
):
def
visit_CArgDeclNode
(
self
,
node
):
entry
=
self
.
env
.
lookup
(
node
.
name
)
entry
=
self
.
env
.
lookup
(
node
.
name
)
if
entry
:
if
entry
:
self
.
flow
.
mark_argument
(
node
,
TypedExprNode
(
entry
.
type
),
entry
)
may_be_none
=
not
node
.
not_none
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
):
...
@@ -1091,7 +1099,7 @@ class CreateControlFlowGraph(CythonTransform):
...
@@ -1091,7 +1099,7 @@ class CreateControlFlowGraph(CythonTransform):
def
visit_PyClassDefNode
(
self
,
node
):
def
visit_PyClassDefNode
(
self
,
node
):
self
.
flow
.
mark_assignment
(
node
.
target
,
self
.
flow
.
mark_assignment
(
node
.
target
,
object_expr
,
self
.
env
.
lookup
(
node
.
name
))
object_expr
_not_none
,
self
.
env
.
lookup
(
node
.
name
))
# TODO: add negative attribute list to "visitchildren"?
# TODO: add negative attribute list to "visitchildren"?
self
.
visitchildren
(
node
,
attrs
=
[
'dict'
,
'metaclass'
,
self
.
visitchildren
(
node
,
attrs
=
[
'dict'
,
'metaclass'
,
'mkw'
,
'bases'
,
'classobj'
])
'mkw'
,
'bases'
,
'classobj'
])
...
...
Cython/Compiler/Optimize.py
View file @
a9072286
...
@@ -3530,3 +3530,12 @@ class FinalOptimizePhase(Visitor.CythonTransform):
...
@@ -3530,3 +3530,12 @@ class FinalOptimizePhase(Visitor.CythonTransform):
if
not
node
.
arg
.
may_be_none
():
if
not
node
.
arg
.
may_be_none
():
node
.
notnone
=
True
node
.
notnone
=
True
return
node
return
node
def
visit_NoneCheckNode
(
self
,
node
):
"""Remove None checks from expressions that definitely do not
carry a None value.
"""
self
.
visitchildren
(
node
)
if
not
node
.
arg
.
may_be_none
():
return
node
.
arg
return
node
tests/run/cf_none.pyx
0 → 100644
View file @
a9072286
cimport
cython
@
cython
.
test_fail_if_path_exists
(
'//NoneCheckNode'
)
def
none_checks
(
a
):
"""
>>> none_checks(1)
22
>>> none_checks(None)
True
"""
c
=
None
d
=
{
11
:
22
}
if
a
is
c
:
return
True
else
:
return
d
.
get
(
11
)
@
cython
.
test_assert_path_exists
(
'//NoneCheckNode'
)
def
dict_arg
(
dict
a
):
"""
>>> dict_arg({})
>>> dict_arg({1:2})
2
"""
return
a
.
get
(
1
)
@
cython
.
test_fail_if_path_exists
(
'//NoneCheckNode'
)
def
dict_arg_not_none
(
dict
a
not
None
):
"""
>>> dict_arg_not_none({})
>>> dict_arg_not_none({1:2})
2
"""
return
a
.
get
(
1
)
@
cython
.
test_assert_path_exists
(
'//NoneCheckNode'
)
def
reassignment
(
dict
d
):
"""
>>> reassignment({})
(None, 2)
>>> reassignment({1:3})
(3, 2)
"""
a
=
d
.
get
(
1
)
d
=
{
1
:
2
}
b
=
d
.
get
(
1
)
return
a
,
b
@
cython
.
test_fail_if_path_exists
(
'//NoneCheckNode'
)
def
conditional
(
a
):
"""
>>> conditional(True)
2
>>> conditional(False)
3
"""
if
a
:
d
=
{
1
:
2
}
else
:
d
=
{
1
:
3
}
return
d
.
get
(
1
)
@
cython
.
test_assert_path_exists
(
'//NoneCheckNode'
)
def
conditional_arg
(
a
,
dict
d
):
"""
>>> conditional_arg(True, {1:2})
>>> conditional_arg(False, {1:2})
2
"""
if
a
:
d
=
{}
return
d
.
get
(
1
)
@
cython
.
test_fail_if_path_exists
(
'//NoneCheckNode'
)
def
conditional_not_none
(
a
,
dict
d
not
None
):
"""
>>> conditional_not_none(True, {1:2})
>>> conditional_not_none(False, {1:2})
2
"""
if
a
:
d
=
{}
return
d
.
get
(
1
)
tests/run/list.pyx
View file @
a9072286
...
@@ -57,7 +57,6 @@ def test_list_sort_reversed():
...
@@ -57,7 +57,6 @@ def test_list_sort_reversed():
l1
.
sort
(
reversed
=
True
)
l1
.
sort
(
reversed
=
True
)
return
l1
return
l1
@
cython
.
test_assert_path_exists
(
"//SimpleCallNode//NoneCheckNode"
)
def
test_list_reverse
():
def
test_list_reverse
():
"""
"""
>>> test_list_reverse()
>>> test_list_reverse()
...
@@ -68,7 +67,6 @@ def test_list_reverse():
...
@@ -68,7 +67,6 @@ def test_list_reverse():
l1
.
reverse
()
l1
.
reverse
()
return
l1
return
l1
@
cython
.
test_assert_path_exists
(
"//SimpleCallNode//NoneCheckNode"
)
def
test_list_append
():
def
test_list_append
():
"""
"""
>>> test_list_append()
>>> test_list_append()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment