Commit fed7b531 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Buffers: Inplace operators.

parent edffe666
......@@ -1379,7 +1379,7 @@ class IndexNode(ExprNode):
skip_child_analysis = False
buffer_access = False
if self.base.type.is_buffer:
assert isinstance(self.base, NameNode)
assert hasattr(self.base, "entry") # Must be a NameNode-like node
if isinstance(self.index, TupleNode):
indices = self.index.args
else:
......@@ -1394,7 +1394,7 @@ class IndexNode(ExprNode):
if buffer_access:
self.indices = indices
self.index = None
self.index = None # note that original is kept in _index, which is used for cloning
self.type = self.base.type.dtype
self.is_buffer_access = True
self.buffer_type = self.base.entry.type
......@@ -1469,19 +1469,19 @@ class IndexNode(ExprNode):
def generate_subexpr_evaluation_code(self, code):
self.base.generate_evaluation_code(code)
if self.index is not None:
self.index.generate_evaluation_code(code)
else:
if self.indices:
for i in self.indices:
i.generate_evaluation_code(code)
else:
self.index.generate_evaluation_code(code)
def generate_subexpr_disposal_code(self, code):
self.base.generate_disposal_code(code)
if self.index is not None:
self.index.generate_disposal_code(code)
else:
if self.indices:
for i in self.indices:
i.generate_disposal_code(code)
else:
self.index.generate_disposal_code(code)
def generate_result_code(self, code):
if self.is_buffer_access:
......@@ -1525,30 +1525,34 @@ class IndexNode(ExprNode):
value_code,
self.index_unsigned_parameter(),
code.error_goto(self.pos)))
def generate_buffer_assignment_code(self, rhs, code, op=""):
# Used from generate_assignment_code and InPlaceAssignmentNode
ptrexpr = self.buffer_lookup_code(code)
if self.buffer_type.dtype.is_pyobject:
# Must manage refcounts. Decref what is already there
# and incref what we put in.
ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type)
if rhs.is_temp: #TODO: REMOVE
rhs_code = code.funcstate.allocate_temp(rhs.type)
else:
rhs_code = rhs.result_code
code.putln("%s = %s;" % (ptr, ptrexpr))
code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % (
ptr, rhs_code
))
code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
if rhs.is_temp:
code.funcstate.release_temp(rhs_code)
code.funcstate.release_temp(ptr)
else:
# Simple case
code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result_code))
def generate_assignment_code(self, rhs, code):
self.generate_subexpr_evaluation_code(code)
if self.is_buffer_access:
ptrexpr = self.buffer_lookup_code(code)
if self.buffer_type.dtype.is_pyobject:
# Must manage refcounts. Decref what is already there
# and incref what we put in.
ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type)
if rhs.is_temp:
rhs_code = code.funcstate.allocate_temp(rhs.type)
else:
rhs_code = rhs.result_code
code.putln("%s = %s;" % (ptr, ptrexpr))
code.putln("Py_DECREF(*%s); Py_INCREF(%s);" % (
ptr, rhs_code
))
code.putln("*%s = %s;" % (ptr, rhs_code))
if rhs.is_temp:
code.funcstate.release_temp(rhs_code)
code.funcstate.release_temp(ptr)
else:
# Simple case
code.putln("*%s = %s;" % (ptrexpr, rhs.result_code))
self.generate_buffer_assignment_code(rhs, code)
elif self.type.is_pyobject:
self.generate_setitem_code(rhs.py_result(), code)
else:
......@@ -3937,6 +3941,7 @@ class CoercionNode(ExprNode):
def __init__(self, arg):
self.pos = arg.pos
self.arg = arg
self.options = arg.options
if debug_coercion:
print("%s Coercing %s" % (self, self.arg))
......
......@@ -71,10 +71,12 @@ class Node(object):
# pos (string, int, int) Source file position
# is_name boolean Is a NameNode
# is_literal boolean Is a ConstNode
# options dict Compiler directives for this node
is_name = 0
is_literal = 0
temps = None
options = {}
# All descandants should set child_attrs to a list of the attributes
# containing nodes considered "children" in the tree. Each such attribute
......@@ -2517,12 +2519,13 @@ class InPlaceAssignmentNode(AssignmentNode):
def generate_execution_code(self, code):
self.rhs.generate_evaluation_code(code)
self.dup.generate_subexpr_evaluation_code(code)
self.dup.generate_result_code(code)
# self.dup.generate_result_code is run only if it is not buffer access
if self.operator == "**":
extra = ", Py_None"
else:
extra = ""
if self.lhs.type.is_pyobject:
self.dup.generate_result_code(code)
code.putln(
"%s = %s(%s, %s%s); %s" % (
self.result.result_code,
......@@ -2545,7 +2548,12 @@ class InPlaceAssignmentNode(AssignmentNode):
else:
error(self.pos, "No C inplace power operator")
# have to do assignment directly to avoid side-effects
code.putln("%s %s= %s;" % (self.lhs.result_code, c_op, self.rhs.result_code) )
import ExprNodes
if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
self.lhs.generate_buffer_assignment_code(self.rhs, code, c_op)
else:
self.dup.generate_result_code(code)
code.putln("%s %s= %s;" % (self.lhs.result_code, c_op, self.rhs.result_code) )
self.rhs.generate_disposal_code(code)
if self.dup.is_temp:
self.dup.generate_subexpr_disposal_code(code)
......@@ -2555,11 +2563,23 @@ class InPlaceAssignmentNode(AssignmentNode):
self.dup = self.lhs
self.dup.analyse_types(env)
if isinstance(self.lhs, ExprNodes.NameNode):
target_lhs = ExprNodes.NameNode(self.dup.pos, name = self.dup.name, is_temp = self.dup.is_temp, entry = self.dup.entry)
target_lhs = ExprNodes.NameNode(self.dup.pos,
name = self.dup.name,
is_temp = self.dup.is_temp,
entry = self.dup.entry,
options = self.dup.options)
elif isinstance(self.lhs, ExprNodes.AttributeNode):
target_lhs = ExprNodes.AttributeNode(self.dup.pos, obj = ExprNodes.CloneNode(self.lhs.obj), attribute = self.dup.attribute, is_temp = self.dup.is_temp)
target_lhs = ExprNodes.AttributeNode(self.dup.pos,
obj = ExprNodes.CloneNode(self.lhs.obj),
attribute = self.dup.attribute,
is_temp = self.dup.is_temp,
options = self.dup.options)
elif isinstance(self.lhs, ExprNodes.IndexNode):
target_lhs = ExprNodes.IndexNode(self.dup.pos, base = ExprNodes.CloneNode(self.dup.base), index = ExprNodes.CloneNode(self.lhs.index), is_temp = self.dup.is_temp)
target_lhs = ExprNodes.IndexNode(self.dup.pos,
base = ExprNodes.CloneNode(self.dup.base),
index = ExprNodes.CloneNode(self.lhs._index),
is_temp = self.dup.is_temp,
options = self.dup.options)
self.lhs = target_lhs
return self.dup
......
......@@ -596,12 +596,23 @@ TODO
uc[0] = <int>3.14
print uc[0]
cdef char* ch = "asfd"
cdef object[object] objbuf
objbuf[3] = ch
#
# Testing that accessing data using various types of buffer access
# all works.
#
def printbuf_int(object[int] buf, shape):
# Utility func
cdef int i
for i in range(shape[0]):
print buf[i],
print 'END'
@testcase
def printbuf_int_2d(o, shape):
......@@ -654,6 +665,24 @@ def printbuf_float(o, shape):
print "END"
#
# Test assignments
#
@testcase
def inplace_operators(object[int] buf):
"""
>>> buf = IntMockBuffer(None, [2, 2])
>>> inplace_operators(buf)
>>> printbuf_int(buf, (2,))
0 3 END
"""
cdef int j = 0
buf[1] += 1
buf[j] *= 2
buf[0] -= 4
#
# Typedefs
#
......
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