Skip to content

Commit 812e713

Browse files
committed
Intrinsify PyNumber_BinOp
1 parent e6fe32d commit 812e713

File tree

3 files changed

+113
-32
lines changed

3 files changed

+113
-32
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,10 @@ static PyObject * do_unaryop(PyObject *v, UnaryOp unaryop) {
7070
return UPCALL_CEXT_O(_jls_PyNumber_UnaryOp, native_to_java(v), unaryop);
7171
}
7272

73-
UPCALL_ID(PyNumber_BinOp);
73+
typedef PyObject *(*binop_fun_t)(PyObject *, PyObject *, int32_t);
74+
UPCALL_TYPED_ID(PyNumber_BinOp, binop_fun_t);
7475
MUST_INLINE static PyObject * do_binop(PyObject *v, PyObject *w, BinOp binop) {
75-
return UPCALL_CEXT_O(_jls_PyNumber_BinOp, native_to_java(v), native_to_java(w), binop);
76+
return _jls_PyNumber_BinOp(native_to_java(v), native_to_java(w), (int32_t)binop);
7677
}
7778

7879
UPCALL_ID(PyNumber_InPlaceBinOp);

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

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@
226226
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
227227
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
228228
import com.oracle.graal.python.nodes.classes.IsSubtypeNodeGen;
229+
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
229230
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
230231
import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
231232
import com.oracle.graal.python.nodes.function.FunctionRootNode;
@@ -4073,4 +4074,113 @@ static int doBytes(PBytes bytes,
40734074
return 0;
40744075
}
40754076
}
4077+
4078+
@Builtin(name = "PyNumber_BinOp", minNumOfPositionalArgs = 3)
4079+
@GenerateNodeFactory
4080+
abstract static class PyNumberBinOp extends PythonTernaryBuiltinNode {
4081+
static int MAX_CACHE_SIZE = BinaryArithmetic.values().length;
4082+
4083+
@Specialization(guards = {"cachedOp == op", "left.isIntLike()", "right.isIntLike()"}, limit = "MAX_CACHE_SIZE")
4084+
static Object doIntLikePrimitiveWrapper(VirtualFrame frame, PrimitiveNativeWrapper left, PrimitiveNativeWrapper right, @SuppressWarnings("unused") int op,
4085+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4086+
@Cached("createCallNode(op)") LookupAndCallBinaryNode callNode,
4087+
@Cached ToNewRefNode toSulongNode,
4088+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4089+
@Cached GetNativeNullNode getNativeNullNode) {
4090+
try {
4091+
return toSulongNode.execute(callNode.executeObject(frame, left.getLong(), right.getLong()));
4092+
} catch (PException e) {
4093+
transformExceptionToNativeNode.execute(e);
4094+
return toSulongNode.execute(getNativeNullNode.execute());
4095+
}
4096+
}
4097+
4098+
@Specialization(guards = "cachedOp == op", limit = "MAX_CACHE_SIZE", replaces = "doIntLikePrimitiveWrapper")
4099+
static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressWarnings("unused") int op,
4100+
@Cached AsPythonObjectNode leftToJava,
4101+
@Cached AsPythonObjectNode rightToJava,
4102+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4103+
@Cached("createCallNode(op)") LookupAndCallBinaryNode callNode,
4104+
@Cached ToNewRefNode toSulongNode,
4105+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4106+
@Cached GetNativeNullNode getNativeNullNode) {
4107+
// still try to avoid expensive materialization of primitives
4108+
Object result;
4109+
try {
4110+
if (left instanceof PrimitiveNativeWrapper || right instanceof PrimitiveNativeWrapper) {
4111+
Object leftValue;
4112+
Object rightValue;
4113+
if (left instanceof PrimitiveNativeWrapper) {
4114+
leftValue = extract((PrimitiveNativeWrapper) left);
4115+
} else {
4116+
leftValue = leftToJava.execute(left);
4117+
}
4118+
if (right instanceof PrimitiveNativeWrapper) {
4119+
rightValue = extract((PrimitiveNativeWrapper) right);
4120+
} else {
4121+
rightValue = rightToJava.execute(right);
4122+
}
4123+
result = callNode.executeObject(frame, leftValue, rightValue);
4124+
} else {
4125+
result = callNode.executeObject(frame, leftToJava.execute(left), rightToJava.execute(right));
4126+
}
4127+
} catch (PException e) {
4128+
transformExceptionToNativeNode.execute(e);
4129+
result = getNativeNullNode.execute();
4130+
}
4131+
return toSulongNode.execute(result);
4132+
}
4133+
4134+
private static Object extract(PrimitiveNativeWrapper wrapper) {
4135+
if (wrapper.isIntLike()) {
4136+
return wrapper.getLong();
4137+
}
4138+
if (wrapper.isDouble()) {
4139+
return wrapper.getDouble();
4140+
}
4141+
if (wrapper.isBool()) {
4142+
return wrapper.getBool();
4143+
}
4144+
throw CompilerDirectives.shouldNotReachHere("unexpected wrapper state");
4145+
}
4146+
4147+
/**
4148+
* This needs to stay in sync with {@code abstract.c: enum e_binop}.
4149+
*/
4150+
static LookupAndCallBinaryNode createCallNode(int op) {
4151+
return getBinaryArithmetic(op).create();
4152+
}
4153+
4154+
private static BinaryArithmetic getBinaryArithmetic(int op) {
4155+
switch (op) {
4156+
case 0:
4157+
return BinaryArithmetic.Add;
4158+
case 1:
4159+
return BinaryArithmetic.Sub;
4160+
case 2:
4161+
return BinaryArithmetic.Mul;
4162+
case 3:
4163+
return BinaryArithmetic.TrueDiv;
4164+
case 4:
4165+
return BinaryArithmetic.LShift;
4166+
case 5:
4167+
return BinaryArithmetic.RShift;
4168+
case 6:
4169+
return BinaryArithmetic.Or;
4170+
case 7:
4171+
return BinaryArithmetic.And;
4172+
case 8:
4173+
return BinaryArithmetic.Xor;
4174+
case 9:
4175+
return BinaryArithmetic.FloorDiv;
4176+
case 10:
4177+
return BinaryArithmetic.Mod;
4178+
case 12:
4179+
return BinaryArithmetic.MatMul;
4180+
default:
4181+
throw CompilerDirectives.shouldNotReachHere("invalid binary operator");
4182+
}
4183+
}
4184+
4185+
}
40764186
}

graalpython/lib-graalpython/python_cext.py

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -459,36 +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-
@may_raise
463-
def PyNumber_BinOp(v, w, binop):
464-
if binop == 0:
465-
return v + w
466-
elif binop == 1:
467-
return v - w
468-
elif binop == 2:
469-
return v * w
470-
elif binop == 3:
471-
return v / w
472-
elif binop == 4:
473-
return v << w
474-
elif binop == 5:
475-
return v >> w
476-
elif binop == 6:
477-
return v | w
478-
elif binop == 7:
479-
return v & w
480-
elif binop == 8:
481-
return v ^ w
482-
elif binop == 9:
483-
return v // w
484-
elif binop == 10:
485-
return v % w
486-
elif binop == 12:
487-
return v @ w
488-
else:
489-
raise SystemError("unknown binary operator (code=%s)" % binop)
490-
491-
492462
def _binop_name(binop):
493463
if binop == 0:
494464
return "+"

0 commit comments

Comments
 (0)