Supporting cython.operator in C
The following code cimport cython.operator cdef long foo(long x, long y): return cython.operator.comma(x, y) gives AttributeError: 'CBinopNode' object has no attribute 'analyse_c_operation' Is there any fundamental reason why such operators are only implemented for C++ and not pure C? What would be needed to support such operators in C? Jeroen.
I can't think of any fundamental reason these couldn't be implemented in C, but there's really no need to do so as they can't be overridden in C. On Tue, May 31, 2016 at 3:28 AM, Jeroen Demeyer <jdemeyer@cage.ugent.be> wrote:
The following code
cimport cython.operator cdef long foo(long x, long y): return cython.operator.comma(x, y)
gives AttributeError: 'CBinopNode' object has no attribute 'analyse_c_operation'
Is there any fundamental reason why such operators are only implemented for C++ and not pure C? What would be needed to support such operators in C?
Jeroen. _______________________________________________ cython-devel mailing list cython-devel@python.org https://mail.python.org/mailman/listinfo/cython-devel
On 2016-05-31 20:35, Robert Bradshaw wrote:
I can't think of any fundamental reason these couldn't be implemented in C, but there's really no need to do so as they can't be overridden in C.
Well, for the comma operator there might be no reason. However, it would be nice if one could generate arbitrary code of the form (x) (operator) (y) for any C/C++ values x and y and any operator. Two particular cases I encountered where this would be useful: 1. "x = y" where x is something that Cython does not consider an lvalue. 2. "x || y" because Cython's "x or y" generates complicated code which isn't optimized as well as "x || y". Jeroen.
On Wed, Jun 1, 2016 at 1:56 PM, Jeroen Demeyer <jdemeyer@cage.ugent.be> wrote:
On 2016-05-31 20:35, Robert Bradshaw wrote:
I can't think of any fundamental reason these couldn't be implemented in C, but there's really no need to do so as they can't be overridden in C.
Well, for the comma operator there might be no reason. However, it would be nice if one could generate arbitrary code of the form
(x) (operator) (y)
for any C/C++ values x and y and any operator. Two particular cases I encountered where this would be useful:
1. "x = y" where x is something that Cython does not consider an lvalue.
Cython doesn't support operator= even for C++, nor provide an operator.X definition for it. (These are only provided for operators that don't have a Python equivalent.) Are there cases in C where one has an lvalue but Cython can't tell? (I suppose foo(x) if foo is a macro--is that the only case?) You can always define your own macro #define ASSIGN(a, b) (a = b). Redefining what a valid lvalue is in the language (and syntax) is a whole can of worms I'd rather avoid getting into...
2. "x || y" because Cython's "x or y" generates complicated code which isn't optimized as well as "x || y".
I just tried using gcc -O3 and the resulting assembly is identical. Granted, "x or y" does have a different meaning in Python (and Cython), returning the first of x or y that is True rather than a boolean. To get the C behavior, write <bint>(x or y). I think this is automatically done when it's used as a condition. The "more complicated" code is necessary to get the correct short-circuiting behavior, in particular when the right hand side is not expressible as a pure C expression (e.g. requires intermediates). - Robert
On 2016-06-02 05:43, Robert Bradshaw wrote:
2. "x || y" because Cython's "x or y" generates complicated code which isn't optimized as well as "x || y".
I just tried using gcc -O3 and the resulting assembly is identical.
Well, that would depend on what x and y are. A very concrete example: "if isinstance(x, (int,long))", which is parsed as "if PyInt_Check(x) or PyLong_Check(x)" is slightly slower than "if PyInt_Check(x) || PyLong_Check(x)".
On Thu, Jun 2, 2016 at 12:57 AM, Jeroen Demeyer <jdemeyer@cage.ugent.be> wrote:
On 2016-06-02 05:43, Robert Bradshaw wrote:
2. "x || y" because Cython's "x or y" generates complicated code which isn't optimized as well as "x || y".
I just tried using gcc -O3 and the resulting assembly is identical.
Well, that would depend on what x and y are.
A very concrete example:
"if isinstance(x, (int,long))", which is parsed as "if PyInt_Check(x) or PyLong_Check(x)" is slightly slower than "if PyInt_Check(x) || PyLong_Check(x)".
That is very surprising. How much slower? If this is the case, we should be trying to fix Cython's code generation rather than adding extra operators like || that one needs to know to use. I wonder if this is due to gcc's expectations about the likelyhood of truth values of the subexpressions in a logical or vs. an if... For both assign and or, the problem boils down to the fact that subexpressions in Python do not necessarily map to subexpressions in C. If operator.assign(a, b) is simply syntactic sugar for "a = b" and operator.logical_or syntactic sugar for "a or b" then there is no advantage to providing them as attributes of operator. On the other hand, if one wants to just "drop in" the C operators "=" and "||" then consider a[i].x = foo() if b or a[i].x: ... This would translate to [statements extracting a[i].x into tmp1] tmp1 = foo(); [statements extracting a[i].x into tmp2 with side effects] if (b || tmp2) { ... } The trouble is, in both cases one needs to come up with a *C expression* representing a[i].x (and for assignment it must be an lvalue) and add extra logic forbidding this to be assigned to a temporary. This is not always (or even often?) possible, especially when a is an arbitrary Python object. Saying these operators are only allowed when it's possible, and having extra logic to not store any intermediates in temporaries in that case, makes the language inconsistent. - Robert
On 2016-06-02 21:12, Robert Bradshaw wrote:
"if isinstance(x, (int,long))", which is parsed as "if PyInt_Check(x) or PyLong_Check(x)" is slightly slower than "if PyInt_Check(x) || PyLong_Check(x)".
That is very surprising. How much slower?
With GCC 4.9.3, roughly 4% for a simple loop like for x in L: if isinstance(x, (int, long)): return True
I wonder if this is due to gcc's expectations about the likelyhood of truth values of the subexpressions in a logical or vs. an if...
I doubt it. It's just the optimizer which optimizes arithmetic better than if/goto.
On Thu, Jun 2, 2016 at 1:06 PM, Jeroen Demeyer <jdemeyer@cage.ugent.be> wrote:
On 2016-06-02 21:12, Robert Bradshaw wrote:
"if isinstance(x, (int,long))", which is parsed as "if PyInt_Check(x) or PyLong_Check(x)" is slightly slower than "if PyInt_Check(x) || PyLong_Check(x)".
That is very surprising. How much slower?
With GCC 4.9.3, roughly 4% for a simple loop like
for x in L: if isinstance(x, (int, long)): return True
I wonder if this is due to gcc's expectations about the likelyhood of truth values of the subexpressions in a logical or vs. an if...
I doubt it. It's just the optimizer which optimizes arithmetic better than if/goto.
I'm able to replicate the 4% slowdown in that example. However, if I replace L with a list of ints (rather than a list of non-ints) and change the return to an integer increment the isinstance version goes to 4% faster than the || version, so I'd call this microbenchmark a wash.
participants (2)
-
Jeroen Demeyer -
Robert Bradshaw