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
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
Hide 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):
...
@@ -2592,6 +2592,14 @@ class SliceNode(ExprNode):
class
CallNode
(
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
):
def
analyse_as_type_constructor
(
self
,
env
):
type
=
self
.
function
.
analyse_as_type
(
env
)
type
=
self
.
function
.
analyse_as_type
(
env
)
if
type
and
type
.
is_struct_or_union
:
if
type
and
type
.
is_struct_or_union
:
...
@@ -2725,12 +2733,14 @@ class SimpleCallNode(CallNode):
...
@@ -2725,12 +2733,14 @@ class SimpleCallNode(CallNode):
else
:
else
:
self
.
type
=
Builtin
.
builtin_types
[
function
.
entry
.
name
]
self
.
type
=
Builtin
.
builtin_types
[
function
.
entry
.
name
]
self
.
result_ctype
=
py_object_type
self
.
result_ctype
=
py_object_type
self
.
may_return_none
=
False
elif
function
.
is_name
and
function
.
type_entry
:
elif
function
.
is_name
and
function
.
type_entry
:
# We are calling an extension type constructor. As
# We are calling an extension type constructor. As
# long as we do not support __new__(), the result type
# long as we do not support __new__(), the result type
# is clear
# is clear
self
.
type
=
function
.
type_entry
.
type
self
.
type
=
function
.
type_entry
.
type
self
.
result_ctype
=
py_object_type
self
.
result_ctype
=
py_object_type
self
.
may_return_none
=
False
else
:
else
:
self
.
type
=
py_object_type
self
.
type
=
py_object_type
self
.
is_temp
=
1
self
.
is_temp
=
1
...
@@ -2945,6 +2955,12 @@ class PythonCapiFunctionNode(ExprNode):
...
@@ -2945,6 +2955,12 @@ class PythonCapiFunctionNode(ExprNode):
class
PythonCapiCallNode
(
SimpleCallNode
):
class
PythonCapiCallNode
(
SimpleCallNode
):
# Python C-API Function call (only created in transforms)
# 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
,
def
__init__
(
self
,
pos
,
function_name
,
func_type
,
utility_code
=
None
,
py_name
=
None
,
**
kwargs
):
utility_code
=
None
,
py_name
=
None
,
**
kwargs
):
self
.
type
=
func_type
.
return_type
self
.
type
=
func_type
.
return_type
...
@@ -3017,6 +3033,7 @@ class GeneralCallNode(CallNode):
...
@@ -3017,6 +3033,7 @@ class GeneralCallNode(CallNode):
# as we do not support __new__(), the result type is clear
# as we do not support __new__(), the result type is clear
self
.
type
=
function
.
type_entry
.
type
self
.
type
=
function
.
type_entry
.
type
self
.
result_ctype
=
py_object_type
self
.
result_ctype
=
py_object_type
self
.
may_return_none
=
False
else
:
else
:
self
.
type
=
py_object_type
self
.
type
=
py_object_type
self
.
is_temp
=
1
self
.
is_temp
=
1
...
@@ -5611,6 +5628,12 @@ class BoolBinopNode(ExprNode):
...
@@ -5611,6 +5628,12 @@ class BoolBinopNode(ExprNode):
type2
=
self
.
operand2
.
infer_type
(
env
)
type2
=
self
.
operand2
.
infer_type
(
env
)
return
PyrexTypes
.
independent_spanning_type
(
type1
,
type2
)
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
):
def
calculate_constant_result
(
self
):
if
self
.
operator
==
'and'
:
if
self
.
operator
==
'and'
:
self
.
constant_result
=
\
self
.
constant_result
=
\
...
@@ -6397,6 +6420,9 @@ class CastNode(CoercionNode):
...
@@ -6397,6 +6420,9 @@ class CastNode(CoercionNode):
def
__init__
(
self
,
arg
,
new_type
):
def
__init__
(
self
,
arg
,
new_type
):
CoercionNode
.
__init__
(
self
,
arg
)
CoercionNode
.
__init__
(
self
,
arg
)
self
.
type
=
new_type
self
.
type
=
new_type
def
may_be_none
(
self
):
return
self
.
arg
.
may_be_none
()
def
calculate_result_code
(
self
):
def
calculate_result_code
(
self
):
return
self
.
arg
.
result_as
(
self
.
type
)
return
self
.
arg
.
result_as
(
self
.
type
)
...
@@ -6424,6 +6450,11 @@ class PyTypeTestNode(CoercionNode):
...
@@ -6424,6 +6450,11 @@ class PyTypeTestNode(CoercionNode):
def
analyse_types
(
self
,
env
):
def
analyse_types
(
self
,
env
):
pass
pass
def
may_be_none
(
self
):
if
self
.
notnone
:
return
False
return
self
.
arg
.
may_be_none
()
def
result_in_temp
(
self
):
def
result_in_temp
(
self
):
return
self
.
arg
.
result_in_temp
()
return
self
.
arg
.
result_in_temp
()
...
...
Cython/Compiler/Optimize.py
View file @
5dd72bd0
...
@@ -1729,11 +1729,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1729,11 +1729,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"PyObject_GetAttr"
,
self
.
PyObject_GetAttr2_func_type
,
node
.
pos
,
"PyObject_GetAttr"
,
self
.
PyObject_GetAttr2_func_type
,
args
=
pos_args
,
args
=
pos_args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
)
is_temp
=
node
.
is_temp
)
elif
len
(
pos_args
)
==
3
:
elif
len
(
pos_args
)
==
3
:
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_GetAttr3"
,
self
.
PyObject_GetAttr3_func_type
,
node
.
pos
,
"__Pyx_GetAttr3"
,
self
.
PyObject_GetAttr3_func_type
,
args
=
pos_args
,
args
=
pos_args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
is_temp
=
node
.
is_temp
,
utility_code
=
Builtin
.
getattr3_utility_code
)
utility_code
=
Builtin
.
getattr3_utility_code
)
else
:
else
:
...
@@ -1758,6 +1760,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1758,6 +1760,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"PyObject_GetIter"
,
self
.
PyObject_GetIter_func_type
,
node
.
pos
,
"PyObject_GetIter"
,
self
.
PyObject_GetIter_func_type
,
args
=
pos_args
,
args
=
pos_args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
)
is_temp
=
node
.
is_temp
)
elif
len
(
pos_args
)
==
2
:
elif
len
(
pos_args
)
==
2
:
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
...
@@ -1956,6 +1959,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1956,6 +1959,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_Append"
,
self
.
PyObject_Append_func_type
,
node
.
pos
,
"__Pyx_PyObject_Append"
,
self
.
PyObject_Append_func_type
,
args
=
args
,
args
=
args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
is_temp
=
node
.
is_temp
,
utility_code
=
append_utility_code
utility_code
=
append_utility_code
)
)
...
@@ -1979,6 +1983,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1979,6 +1983,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_Pop"
,
self
.
PyObject_Pop_func_type
,
node
.
pos
,
"__Pyx_PyObject_Pop"
,
self
.
PyObject_Pop_func_type
,
args
=
args
,
args
=
args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
is_temp
=
node
.
is_temp
,
utility_code
=
pop_utility_code
utility_code
=
pop_utility_code
)
)
...
@@ -1990,6 +1995,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -1990,6 +1995,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
ExprNodes
.
PythonCapiCallNode
(
return
ExprNodes
.
PythonCapiCallNode
(
node
.
pos
,
"__Pyx_PyObject_PopIndex"
,
self
.
PyObject_PopIndex_func_type
,
node
.
pos
,
"__Pyx_PyObject_PopIndex"
,
self
.
PyObject_PopIndex_func_type
,
args
=
args
,
args
=
args
,
may_return_none
=
True
,
is_temp
=
node
.
is_temp
,
is_temp
=
node
.
is_temp
,
utility_code
=
pop_index_utility_code
utility_code
=
pop_index_utility_code
)
)
...
@@ -2059,6 +2065,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -2059,6 +2065,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
return
self
.
_substitute_method_call
(
return
self
.
_substitute_method_call
(
node
,
"__Pyx_PyDict_GetItemDefault"
,
self
.
Pyx_PyDict_GetItem_func_type
,
node
,
"__Pyx_PyDict_GetItemDefault"
,
self
.
Pyx_PyDict_GetItem_func_type
,
'get'
,
is_unbound_method
,
args
,
'get'
,
is_unbound_method
,
args
,
may_return_none
=
True
,
utility_code
=
dict_getitem_default_utility_code
)
utility_code
=
dict_getitem_default_utility_code
)
...
@@ -2559,7 +2566,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -2559,7 +2566,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
def
_substitute_method_call
(
self
,
node
,
name
,
func_type
,
def
_substitute_method_call
(
self
,
node
,
name
,
func_type
,
attr_name
,
is_unbound_method
,
args
=
(),
attr_name
,
is_unbound_method
,
args
=
(),
utility_code
=
None
):
utility_code
=
None
,
may_return_none
=
ExprNodes
.
PythonCapiCallNode
.
may_return_none
):
args
=
list
(
args
)
args
=
list
(
args
)
if
args
and
not
args
[
0
].
is_literal
:
if
args
and
not
args
[
0
].
is_literal
:
self_arg
=
args
[
0
]
self_arg
=
args
[
0
]
...
@@ -2576,7 +2584,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
...
@@ -2576,7 +2584,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
node
.
pos
,
name
,
func_type
,
node
.
pos
,
name
,
func_type
,
args
=
args
,
args
=
args
,
is_temp
=
node
.
is_temp
,
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
):
def
_inject_int_default_argument
(
self
,
node
,
args
,
arg_index
,
type
,
default_value
):
...
@@ -3000,8 +3009,9 @@ class FinalOptimizePhase(Visitor.CythonTransform):
...
@@ -3000,8 +3009,9 @@ class FinalOptimizePhase(Visitor.CythonTransform):
just before the C code generation phase.
just before the C code generation phase.
The optimizations currently implemented in this class are:
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
- isinstance -> typecheck for cdef types
- eliminate checks for None and/or types that became redundant after tree changes
"""
"""
def
visit_SingleAssignmentNode
(
self
,
node
):
def
visit_SingleAssignmentNode
(
self
,
node
):
"""Avoid redundant initialisation of local variables before their
"""Avoid redundant initialisation of local variables before their
...
@@ -3032,3 +3042,14 @@ class FinalOptimizePhase(Visitor.CythonTransform):
...
@@ -3032,3 +3042,14 @@ class FinalOptimizePhase(Visitor.CythonTransform):
PyTypeObjectPtr
=
PyrexTypes
.
CPtrType
(
utility_scope
.
lookup
(
'PyTypeObject'
).
type
)
PyTypeObjectPtr
=
PyrexTypes
.
CPtrType
(
utility_scope
.
lookup
(
'PyTypeObject'
).
type
)
node
.
args
[
1
]
=
ExprNodes
.
CastNode
(
node
.
args
[
1
],
PyTypeObjectPtr
)
node
.
args
[
1
]
=
ExprNodes
.
CastNode
(
node
.
args
[
1
],
PyTypeObjectPtr
)
return
node
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):
...
@@ -140,6 +140,15 @@ class ResultRefNode(AtomicExprNode):
if
self
.
expression
is
not
None
:
if
self
.
expression
is
not
None
:
return
self
.
expression
.
infer_type
(
env
)
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
):
def
is_simple
(
self
):
return
True
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