Commit e2ad82d7 authored by Charles Blake's avatar Charles Blake

Merge /home/cb/pkg/cy/cython

Conflicts:
	CHANGES.rst
parents 77b4c4ba 68a5d5d7
......@@ -9921,7 +9921,7 @@ class BoolBinopNode(ExprNode):
operator=self.operator,
operand1=operand1, operand2=operand2)
def generate_bool_evaluation_code(self, code, final_result_temp, and_label, or_label, end_label):
def generate_bool_evaluation_code(self, code, final_result_temp, and_label, or_label, end_label, fall_through):
code.mark_pos(self.pos)
outer_labels = (and_label, or_label)
......@@ -9929,19 +9929,20 @@ class BoolBinopNode(ExprNode):
my_label = and_label = code.new_label('next_and')
else:
my_label = or_label = code.new_label('next_or')
self.operand1.generate_bool_evaluation_code(code, final_result_temp, and_label, or_label, end_label)
self.operand1.generate_bool_evaluation_code(
code, final_result_temp, and_label, or_label, end_label, my_label)
and_label, or_label = outer_labels
code.put_label(my_label)
self.operand2.generate_bool_evaluation_code(code, final_result_temp, and_label, or_label, end_label)
self.operand2.generate_bool_evaluation_code(
code, final_result_temp, and_label, or_label, end_label, fall_through)
def generate_evaluation_code(self, code):
self.allocate_temp_result(code)
or_label = and_label = None
end_label = code.new_label('bool_binop_done')
self.generate_bool_evaluation_code(code, self.result(), and_label, or_label, end_label)
if code.label_used(end_label):
self.generate_bool_evaluation_code(code, self.result(), and_label, or_label, end_label, end_label)
code.put_label(end_label)
gil_message = "Truth-testing Python object"
......@@ -10026,7 +10027,7 @@ class BoolBinopResultNode(ExprNode):
test_result = self.arg.result()
return (test_result, self.arg.type.is_pyobject)
def generate_bool_evaluation_code(self, code, final_result_temp, and_label, or_label, end_label):
def generate_bool_evaluation_code(self, code, final_result_temp, and_label, or_label, end_label, fall_through):
code.mark_pos(self.pos)
# x => x
......@@ -10038,31 +10039,43 @@ class BoolBinopResultNode(ExprNode):
self.arg.generate_evaluation_code(code)
if and_label or or_label:
test_result, uses_temp = self.generate_operand_test(code)
if uses_temp and (and_label and or_label):
# cannot become final result => free early
# disposal: uses_temp and (and_label and or_label)
self.arg.generate_disposal_code(code)
sense = '!' if or_label else ''
code.putln("if (%s%s) {" % (sense, test_result))
if uses_temp:
code.funcstate.release_temp(test_result)
if not uses_temp or not (and_label and or_label):
# disposal: (not uses_temp) or {not (and_label and or_label) [if]}
self.arg.generate_disposal_code(code)
if or_label:
if or_label and or_label != fall_through:
# value is false => short-circuit to next 'or'
code.put_goto(or_label)
code.putln("} else {")
if and_label:
# value is true => go to next 'and'
code.put_goto(and_label)
if not or_label:
if or_label:
code.putln("} else {")
if not uses_temp:
# disposal: (not uses_temp) and {(and_label and or_label) [else]}
self.arg.generate_disposal_code(code)
if and_label != fall_through:
code.put_goto(and_label)
if not and_label or not or_label:
# if no next 'and' or 'or', we provide the result
if and_label or or_label:
code.putln("} else {")
self.value.generate_evaluation_code(code)
self.value.make_owned_reference(code)
code.putln("%s = %s;" % (final_result_temp, self.value.result()))
self.value.generate_post_assignment_code(code)
# disposal: {not (and_label and or_label) [else]}
self.arg.generate_disposal_code(code)
self.value.free_temps(code)
if and_label or or_label:
if end_label != fall_through:
code.put_goto(end_label)
if and_label or or_label:
......
......@@ -2276,11 +2276,14 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
if len(pos_args) != 2:
return node
arg, types = pos_args
temp = None
temps = []
if isinstance(types, ExprNodes.TupleNode):
types = types.args
if len(types) == 1 and not types[0].type is Builtin.type_type:
return node # nothing to improve here
if arg.is_attribute or not arg.is_simple():
arg = temp = UtilNodes.ResultRefNode(arg)
arg = UtilNodes.ResultRefNode(arg)
temps.append(arg)
elif types.type is Builtin.type_type:
types = [types]
else:
......@@ -2311,12 +2314,16 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
type_check_function = '__Pyx_TypeCheck'
type_check_args = [arg, test_type_node]
else:
return node
if not test_type_node.is_literal:
test_type_node = UtilNodes.ResultRefNode(test_type_node)
temps.append(test_type_node)
type_check_function = 'PyObject_IsInstance'
type_check_args = [arg, test_type_node]
test_nodes.append(
ExprNodes.PythonCapiCallNode(
test_type_node.pos, type_check_function, self.Py_type_check_func_type,
args = type_check_args,
is_temp = True,
args=type_check_args,
is_temp=True,
))
def join_with_or(a, b, make_binop_node=ExprNodes.binop_node):
......@@ -2326,7 +2333,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
return or_node
test_node = reduce(join_with_or, test_nodes).coerce_to(node.type, env)
if temp is not None:
for temp in temps[::-1]:
test_node = UtilNodes.EvalWithTempExprNode(temp, test_node)
return test_node
......
......@@ -34,3 +34,11 @@ from posix.time cimport *
cimport posix.resource
from posix cimport resource
from posix.resource cimport *
cimport posix.wait
from posix cimport wait
from posix.wait cimport *
cimport posix.mman
from posix cimport mman
from posix.mman cimport *
def foo(obj1, obj2, obj3, obj4, obj5):
def simple_values(obj1, obj2, obj3, obj4):
"""
>>> foo(True, False, 23, 'test', 1)
>>> simple_values(True, False, 23, 'test')
(0.0, 1.0, False, False)
"""
cdef int bool1, bool2
......@@ -22,3 +23,29 @@ def foo(obj1, obj2, obj3, obj4, obj5):
obj4 = obj1 and obj2 and obj3
obj5 = (obj1 + obj2 + obj3) and obj4
return bool3, bool4, obj4, obj5
def non_simple_values(obj1, obj2, obj3, obj4):
"""
>>> non_simple_values(1, 2, 3, 4)
(7, 3, 7, 3, 7, 7, 5, 5)
>>> non_simple_values(0, 0, 3, 4)
(0, 7, 4, 4, 4, 4, 4, 4)
>>> non_simple_values(0, 0, 1, -1)
(0, 0, -1, 0, -1, -1, 0, 0)
>>> non_simple_values(1, -1, 1, -1)
(0, 0, 0, 0, 0, 0, 0, 0)
>>> non_simple_values(1, 2, 1, -1)
(0, 3, 0, 3, 0, 0, 1, 1)
>>> non_simple_values(2, 1, 1, -1)
(0, 3, 1, 3, 0, 0, 1, 1)
"""
and1 = obj1 + obj2 and obj3 + obj4
or1 = obj1 + obj2 or obj3 + obj4
and_or = obj1 + obj2 and obj3 + obj4 or obj1 + obj4
or_and = obj1 + obj2 or obj3 + obj4 and obj1 + obj4
and_or_and = obj1 + obj2 and obj3 + obj4 or obj1 + obj4 and obj2 + obj4
and1_or_and = (and1 or (obj1 + obj4 and obj2 + obj4))
or_and_or = (obj1 + obj2 or obj3 + obj4) and (obj1 + obj4 or obj2 + obj4)
or1_and_or = (or1 and (obj1 + obj4 or obj2 + obj4))
return (and1, or1, and_or, or_and, and_or_and, and1_or_and, or_and_or, or1_and_or)
def non_simple_values(obj1, obj2, obj3, obj4):
"""
>>> non_simple_values(1, 2, 3, 4)
(7, 3, 7, 3, 7, 7, 5, 5)
>>> non_simple_values(0, 0, 3, 4)
(0, 7, 4, 4, 4, 4, 4, 4)
>>> non_simple_values(0, 0, 1, -1)
(0, 0, -1, 0, -1, -1, 0, 0)
>>> non_simple_values(1, -1, 1, -1)
(0, 0, 0, 0, 0, 0, 0, 0)
>>> non_simple_values(1, 2, 1, -1)
(0, 3, 0, 3, 0, 0, 1, 1)
>>> non_simple_values(2, 1, 1, -1)
(0, 3, 1, 3, 0, 0, 1, 1)
"""
and1 = obj1 + obj2 and obj3 + obj4
or1 = obj1 + obj2 or obj3 + obj4
and_or = obj1 + obj2 and obj3 + obj4 or obj1 + obj4
or_and = obj1 + obj2 or obj3 + obj4 and obj1 + obj4
and_or_and = obj1 + obj2 and obj3 + obj4 or obj1 + obj4 and obj2 + obj4
and1_or_and = (and1 or (obj1 + obj4 and obj2 + obj4))
or_and_or = (obj1 + obj2 or obj3 + obj4) and (obj1 + obj4 or obj2 + obj4)
or1_and_or = (or1 and (obj1 + obj4 or obj2 + obj4))
return (and1, or1, and_or, or_and, and_or_and, and1_or_and, or_and_or, or1_and_or)
......@@ -5,6 +5,10 @@ from cpython.bool cimport bool
cdef class A:
pass
a_as_obj = A
@cython.test_assert_path_exists('//SimpleCallNode//SimpleCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode')
......@@ -18,6 +22,7 @@ def test_non_optimised():
assert isinstance(A(), foo)
return True
@cython.test_assert_path_exists('//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode',
'//PythonCapiFunctionNode[@cname = "PyType_Check"]',
......@@ -104,6 +109,7 @@ def test_optimised():
assert isinstance(A(), <type>untyped_type)
return True
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//SimpleCallNode',
'//SimpleCallNode//PythonCapiCallNode',
......@@ -116,10 +122,14 @@ def test_optimised_tuple():
assert isinstance(int(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A))
assert isinstance(list(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, A, a_as_obj))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, type, a_as_obj, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, a_as_obj, tuple, list, dict, set, slice, type, A))
assert isinstance(0, (int, long))
assert not isinstance(u"xyz", (int, long))
return True
def test_custom():
"""
>>> test_custom()
......@@ -134,6 +144,11 @@ cdef class B:
cdef class C:
pass
@cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//SimpleCallNode',
'//SimpleCallNode//PythonCapiCallNode',
'//TupleNode//NameNode')
def test_custom_tuple(obj):
"""
>>> test_custom_tuple(A())
......@@ -145,6 +160,7 @@ def test_custom_tuple(obj):
"""
return isinstance(obj, (A,B))
def test_nested(x):
"""
>>> test_nested(1)
......
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