Skip to content

Commit 2b0d651

Browse files
committed
Intrinsify PyNumber_InPlaceBinOp
1 parent 5bc0893 commit 2b0d651

File tree

3 files changed

+101
-64
lines changed

3 files changed

+101
-64
lines changed

graalpython/com.oracle.graal.python.cext/src/abstract.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ MUST_INLINE static PyObject * do_binop(PyObject *v, PyObject *w, BinOp binop) {
7676
return _jls_PyNumber_BinOp(native_to_java(v), native_to_java(w), (int32_t)binop);
7777
}
7878

79-
UPCALL_ID(PyNumber_InPlaceBinOp);
79+
UPCALL_TYPED_ID(PyNumber_InPlaceBinOp, binop_fun_t);
8080
MUST_INLINE static PyObject * do_inplace_binop(PyObject *v, PyObject *w, BinOp binop) {
81-
return UPCALL_CEXT_O(_jls_PyNumber_InPlaceBinOp, native_to_java(v), native_to_java(w), binop);
81+
return _jls_PyNumber_InPlaceBinOp(native_to_java(v), native_to_java(w), (int32_t)binop);
8282
}
8383

8484
PyObject * PyNumber_Add(PyObject *o1, PyObject *o2) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PythonCextBuiltins.java

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@
228228
import com.oracle.graal.python.nodes.classes.IsSubtypeNodeGen;
229229
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
230230
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
231+
import com.oracle.graal.python.nodes.expression.InplaceArithmetic;
232+
import com.oracle.graal.python.nodes.expression.LookupAndCallInplaceNode;
231233
import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
232234
import com.oracle.graal.python.nodes.function.FunctionRootNode;
233235
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -4131,7 +4133,7 @@ static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressW
41314133
return toSulongNode.execute(result);
41324134
}
41334135

4134-
private static Object extract(PrimitiveNativeWrapper wrapper) {
4136+
static Object extract(PrimitiveNativeWrapper wrapper) {
41354137
if (wrapper.isIntLike()) {
41364138
return wrapper.getLong();
41374139
}
@@ -4183,4 +4185,100 @@ private static BinaryArithmetic getBinaryArithmetic(int op) {
41834185
}
41844186

41854187
}
4188+
4189+
@Builtin(name = "PyNumber_InPlaceBinOp", minNumOfPositionalArgs = 3)
4190+
@GenerateNodeFactory
4191+
abstract static class PyNumberInPlaceBinOp extends PythonTernaryBuiltinNode {
4192+
static int MAX_CACHE_SIZE = InplaceArithmetic.values().length;
4193+
4194+
@Specialization(guards = {"cachedOp == op", "left.isIntLike()", "right.isIntLike()"}, limit = "MAX_CACHE_SIZE")
4195+
static Object doIntLikePrimitiveWrapper(VirtualFrame frame, PrimitiveNativeWrapper left, PrimitiveNativeWrapper right, @SuppressWarnings("unused") int op,
4196+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4197+
@Cached("createCallNode(op)") LookupAndCallInplaceNode callNode,
4198+
@Cached ToNewRefNode toSulongNode,
4199+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4200+
@Cached GetNativeNullNode getNativeNullNode) {
4201+
try {
4202+
return toSulongNode.execute(callNode.execute(frame, left.getLong(), right.getLong()));
4203+
} catch (PException e) {
4204+
transformExceptionToNativeNode.execute(e);
4205+
return toSulongNode.execute(getNativeNullNode.execute());
4206+
}
4207+
}
4208+
4209+
@Specialization(guards = "cachedOp == op", limit = "MAX_CACHE_SIZE", replaces = "doIntLikePrimitiveWrapper")
4210+
static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressWarnings("unused") int op,
4211+
@Cached AsPythonObjectNode leftToJava,
4212+
@Cached AsPythonObjectNode rightToJava,
4213+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4214+
@Cached("createCallNode(op)") LookupAndCallInplaceNode callNode,
4215+
@Cached ToNewRefNode toSulongNode,
4216+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4217+
@Cached GetNativeNullNode getNativeNullNode) {
4218+
// still try to avoid expensive materialization of primitives
4219+
Object result;
4220+
try {
4221+
if (left instanceof PrimitiveNativeWrapper || right instanceof PrimitiveNativeWrapper) {
4222+
Object leftValue;
4223+
Object rightValue;
4224+
if (left instanceof PrimitiveNativeWrapper) {
4225+
leftValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) left);
4226+
} else {
4227+
leftValue = leftToJava.execute(left);
4228+
}
4229+
if (right instanceof PrimitiveNativeWrapper) {
4230+
rightValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) right);
4231+
} else {
4232+
rightValue = rightToJava.execute(right);
4233+
}
4234+
result = callNode.execute(frame, leftValue, rightValue);
4235+
} else {
4236+
result = callNode.execute(frame, leftToJava.execute(left), rightToJava.execute(right));
4237+
}
4238+
} catch (PException e) {
4239+
transformExceptionToNativeNode.execute(e);
4240+
result = getNativeNullNode.execute();
4241+
}
4242+
return toSulongNode.execute(result);
4243+
}
4244+
4245+
/**
4246+
* This needs to stay in sync with {@code abstract.c: enum e_binop}.
4247+
*/
4248+
static LookupAndCallInplaceNode createCallNode(int op) {
4249+
return getInplaceArithmetic(op).create();
4250+
}
4251+
4252+
private static InplaceArithmetic getInplaceArithmetic(int op) {
4253+
switch (op) {
4254+
case 0:
4255+
return InplaceArithmetic.IAdd;
4256+
case 1:
4257+
return InplaceArithmetic.ISub;
4258+
case 2:
4259+
return InplaceArithmetic.IMul;
4260+
case 3:
4261+
return InplaceArithmetic.ITrueDiv;
4262+
case 4:
4263+
return InplaceArithmetic.ILShift;
4264+
case 5:
4265+
return InplaceArithmetic.IRShift;
4266+
case 6:
4267+
return InplaceArithmetic.IOr;
4268+
case 7:
4269+
return InplaceArithmetic.IAnd;
4270+
case 8:
4271+
return InplaceArithmetic.IXor;
4272+
case 9:
4273+
return InplaceArithmetic.IFloorDiv;
4274+
case 10:
4275+
return InplaceArithmetic.IMod;
4276+
case 12:
4277+
return InplaceArithmetic.IMatMul;
4278+
default:
4279+
throw CompilerDirectives.shouldNotReachHere("invalid binary operator");
4280+
}
4281+
}
4282+
4283+
}
41864284
}

graalpython/lib-graalpython/python_cext.py

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -459,67 +459,6 @@ def PyNumber_Check(v):
459459
return _safe_check(v, lambda x: isinstance(int(x), int)) or _safe_check(v, lambda x: isinstance(float(x), float))
460460

461461

462-
def _binop_name(binop):
463-
if binop == 0:
464-
return "+"
465-
elif binop == 1:
466-
return "-"
467-
elif binop == 2:
468-
return "*"
469-
elif binop == 3:
470-
return "/"
471-
elif binop == 4:
472-
return "<<"
473-
elif binop == 5:
474-
return ">>"
475-
elif binop == 6:
476-
return "|"
477-
elif binop == 7:
478-
return "&"
479-
elif binop == 8:
480-
return "^"
481-
elif binop == 9:
482-
return "//"
483-
elif binop == 10:
484-
return "%"
485-
elif binop == 12:
486-
return "@"
487-
488-
489-
@may_raise
490-
def PyNumber_InPlaceBinOp(v, w, binop):
491-
if binop == 0:
492-
v += w
493-
elif binop == 1:
494-
v -= w
495-
elif binop == 2:
496-
v *= w
497-
elif binop == 3:
498-
v /= w
499-
elif binop == 4:
500-
v <<= w
501-
elif binop == 5:
502-
v >>= w
503-
elif binop == 6:
504-
v |= w
505-
elif binop == 7:
506-
v &= w
507-
elif binop == 8:
508-
v ^= w
509-
elif binop == 9:
510-
v //= w
511-
elif binop == 10:
512-
v %= w
513-
elif binop == 12:
514-
v @= w
515-
else:
516-
raise SystemError("unknown in-place binary operator (code=%s)" % binop)
517-
518-
# nothing else required; the operator will automatically fall back if
519-
# no in-place operation is available
520-
return v
521-
522-
523462
@may_raise
524463
def PyNumber_UnaryOp(v, unaryop):
525464
if unaryop == 0:

0 commit comments

Comments
 (0)