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
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cython
Commits
5dd72bd0
Commit
5dd72bd0
authored
Aug 09, 2010
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more None check elimination
parent
339700e7
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
64 additions
and
3 deletions
+64
-3
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+31
-0
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+24
-3
Cython/Compiler/UtilNodes.py
Cython/Compiler/UtilNodes.py
+9
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
5dd72bd0
...
...
@@ -2592,6 +2592,14 @@ class SliceNode(ExprNode):
class
CallNode
(
ExprNode
):
# allow overriding the default 'may_be_none' behaviour
may_return_none
=
None
def
may_be_none
(
self
):
if
self
.
may_return_none
is
not
None
:
return
self
.
may_return_none
return
ExprNode
.
may_be_none
(
self
)
def
analyse_as_type_constructor
(
self
,
env
):
type
=
self
.
function
.
analyse_as_type
(
env
)
if
type
and
type
.
is_struct_or_union
:
...
...
@@ -2725,12 +2733,14 @@ class SimpleCallNode(CallNode):
else
:
self
.
type
=
Builtin
.
builtin_types
[
function
.
entry
.
name
]
self
.
result_ctype
=
py_object_type
self
.
may_return_none
=
False
elif
function
.
is_name
and
function
.
type_entry
:
# We are calling an extension type constructor. As
# long as we do not support __new__(), the result type
# is clear
self
.
type
=
function
.
type_entry
.
type
self
.
result_ctype
=
py_object_type
self
.
may_return_none
=
False
else
:
self
.
type
=
py_object_type
self
.
is_temp
=
1
...
...
@@ -2945,6 +2955,12 @@ class PythonCapiFunctionNode(ExprNode):
class
PythonCapiCallNode
(
SimpleCallNode
):
# Python C-API Function call (only created in transforms)
# By default, we assume that the call never returns None, as this
# is true for most C-API functions in CPython. If this does not
# apply to a call, set the following to True (or None to inherit
# the default behaviour).
may_return_none
=
False
def
__init__
(
self
,
pos
,
function_name
,
func_type
,
utility_code
=
None
,
py_name
=
None
,
**
kwargs
):
self
.
type
=
func_type
.
return_type
...
...
@@ -3017,6 +3033,7 @@ class GeneralCallNode(CallNode):
# as we do not support __new__(), the result type is clear
self
.
type
=
function
.
type_entry
.
type
self
.
result_ctype
=
py_object_type
self
.
may_return_none
=
False
else
:
self
.
type
=
py_object_type
self
.
is_temp
=
1
...
...
@@ -5611,6 +5628,12 @@ class BoolBinopNode(ExprNode):
type2
=
self
.
operand2
.
infer_type
(
env
)
return
PyrexTypes
.
independent_spanning_type
(
type1
,
type2
)
def
may_be_none
(
self
):
if
self
.
operator
==
'or'
:
return
self
.
operand2
.
may_be_none
()
else
:
return
self
.
operand1
.
may_be_none
()
or
self
.
operand2
.
may_be_none
()
def
calculate_constant_result
(
self
):
if
self
.
operator
==
'and'
:
self
.
constant_result
=
\
...
...
@@ -6398,6 +6421,9 @@ class CastNode(CoercionNode):
CoercionNode
.
__init__
(
self
,
arg
)
self
.
type
=
new_type
def
may_be_none
(
self
):
return
self
.
arg
.
may_be_none
()
def
calculate_result_code
(
self
):
return
self
.
arg
.
result_as
(
self
.
type
)
...
...
@@ -6425,6 +6451,11 @@ class PyTypeTestNode(CoercionNode):
def
analyse_types
(
self
,
env
):
pass
def
may_be_none
(
self
):
if
self
.
notnone
:
return
False
return
self
.
arg
.
may_be_none
()
def
result_in_temp
(
self
):
return
self
.
arg
.
result_in_temp
()
...
...
Cython/Compiler/Optimize.py
View file @
5dd72bd0
...
...
@@ -1729,11 +1729,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"PyObject_GetAttr"
,
self
.
PyObject_GetAttr2_func_type
,
args
=
pos_args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
)
elif
len
(
pos_args
)
==
3
:
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_GetAttr3"
,
self
.
PyObject_GetAttr3_func_type
,
args
=
pos_args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
utility_code
=
Builtin
.
getattr3_utility_code
)
else
:
...
...
@@ -1758,6 +1760,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"PyObject_GetIter"
,
self
.
PyObject_GetIter_func_type
,
args
=
pos_args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
)
elif
len
(
pos_args
)
==
2
:
return
ExprNodes
.
PythonCapiCallNode
(
...
...
@@ -1956,6 +1959,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_Append"
,
self
.
PyObject_Append_func_type
,
args
=
args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
utility_code
=
append_utility_code
)
...
...
@@ -1979,6 +1983,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_Pop"
,
self
.
PyObject_Pop_func_type
,
args
=
args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
utility_code
=
pop_utility_code
)
...
...
@@ -1990,6 +1995,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_PopIndex"
,
self
.
PyObject_PopIndex_func_type
,
args
=
args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
utility_code
=
pop_index_utility_code
)
...
...
@@ -2059,6 +2065,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
self
.
_substitute_method_call
(
node
,
"__Pyx_PyDict_GetItemDefault"
,
self
.
Pyx_PyDict_GetItem_func_type
,
'get'
,
is_unbound_method
,
args
,
may_return_none
=
True
,
utility_code
=
dict_getitem_default_utility_code
)
...
...
@@ -2559,7 +2566,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
def
_substitute_method_call
(
self
,
node
,
name
,
func_type
,
attr_name
,
is_unbound_method
,
args
=
(),
utility_code
=
None
):
utility_code
=
None
,
may_return_none
=
ExprNodes
.
PythonCapiCallNode
.
may_return_none
):
args
=
list
(
args
)
if
args
and
not
args
[
0
].
is_literal
:
self_arg
=
args
[
0
]
...
...
@@ -2576,7 +2584,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
node
.
pos
,
name
,
func_type
,
args
=
args
,
is_temp
=
node
.
is_temp
,
utility_code
=
utility_code
utility_code
=
utility_code
,
may_return_none
=
may_return_none
,
)
def
_inject_int_default_argument
(
self
,
node
,
args
,
arg_index
,
type
,
default_value
):
...
...
@@ -3000,8 +3009,9 @@ class FinalOptimizePhase(Visitor.CythonTransform):
just before the C code generation phase.
The optimizations currently implemented in this class are:
-
E
liminate None assignment and refcounting for first assignment.
-
e
liminate None assignment and refcounting for first assignment.
- isinstance -> typecheck for cdef types
- eliminate checks for None and/or types that became redundant after tree changes
"""
def
visit_SingleAssignmentNode
(
self
,
node
):
"""Avoid redundant initialisation of local variables before their
...
...
@@ -3032,3 +3042,14 @@ class FinalOptimizePhase(Visitor.CythonTransform):
PyTypeObjectPtr
=
PyrexTypes
.
CPtrType
(
utility_scope
.
lookup
(
'PyTypeObject'
).
type
)
node
.
args
[
1
]
=
ExprNodes
.
CastNode
(
node
.
args
[
1
],
PyTypeObjectPtr
)
return
node
def
visit_PyTypeTestNode
(
self
,
node
):
"""Remove tests for alternatively allowed None values from
type tests when we know that the argument cannot be None
anyway.
"""
self
.
visitchildren
(
node
)
if
not
node
.
notnone
:
if
not
node
.
arg
.
may_be_none
():
node
.
notnone
=
True
return
node
Cython/Compiler/UtilNodes.py
View file @
5dd72bd0
...
...
@@ -140,6 +140,15 @@ class ResultRefNode(AtomicExprNode):
if
self
.
expression
is
not
None
:
return
self
.
expression
.
infer_type
(
env
)
def
_DISABLED_may_be_none
(
self
):
# not sure if this is safe - the expression may not be the
# only value that gets assigned
if
self
.
expression
is
not
None
:
return
self
.
expression
.
may_be_none
()
if
self
.
type
is
not
None
:
return
self
.
type
.
is_pyobject
return
True
# play safe
def
is_simple
(
self
):
return
True
...
...
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