Skip to content

Commit e9dc1d3

Browse files
committed
[GR-22172] Intrinsify arithmetic operation dispatch helpers.
PullRequest: graalpython/1696
2 parents bc2f304 + 7f30594 commit e9dc1d3

File tree

5 files changed

+290
-110
lines changed

5 files changed

+290
-110
lines changed

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,21 @@ int PyNumber_Check(PyObject *o) {
6565
return 0;
6666
}
6767

68-
UPCALL_ID(PyNumber_UnaryOp);
68+
typedef PyObject *(*unaryop_fun_t)(PyObject *, int32_t);
69+
UPCALL_TYPED_ID(PyNumber_UnaryOp, unaryop_fun_t);
6970
static PyObject * do_unaryop(PyObject *v, UnaryOp unaryop) {
70-
return UPCALL_CEXT_O(_jls_PyNumber_UnaryOp, native_to_java(v), unaryop);
71+
return _jls_PyNumber_UnaryOp(native_to_java(v), (int32_t)unaryop);
7172
}
7273

73-
UPCALL_ID(PyNumber_BinOp);
74+
typedef PyObject *(*binop_fun_t)(PyObject *, PyObject *, int32_t);
75+
UPCALL_TYPED_ID(PyNumber_BinOp, binop_fun_t);
7476
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);
77+
return _jls_PyNumber_BinOp(native_to_java(v), native_to_java(w), (int32_t)binop);
7678
}
7779

78-
UPCALL_ID(PyNumber_InPlaceBinOp);
80+
UPCALL_TYPED_ID(PyNumber_InPlaceBinOp, binop_fun_t);
7981
MUST_INLINE static PyObject * do_inplace_binop(PyObject *v, PyObject *w, BinOp binop) {
80-
return UPCALL_CEXT_O(_jls_PyNumber_InPlaceBinOp, native_to_java(v), native_to_java(w), binop);
82+
return _jls_PyNumber_InPlaceBinOp(native_to_java(v), native_to_java(w), (int32_t)binop);
8183
}
8284

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

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

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@
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;
231+
import com.oracle.graal.python.nodes.expression.InplaceArithmetic;
232+
import com.oracle.graal.python.nodes.expression.LookupAndCallInplaceNode;
233+
import com.oracle.graal.python.nodes.expression.UnaryArithmetic;
230234
import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
231235
import com.oracle.graal.python.nodes.function.FunctionRootNode;
232236
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -4073,4 +4077,279 @@ static int doBytes(PBytes bytes,
40734077
return 0;
40744078
}
40754079
}
4080+
4081+
// directly called without landing function
4082+
@Builtin(name = "PyNumber_UnaryOp", minNumOfPositionalArgs = 2)
4083+
@GenerateNodeFactory
4084+
abstract static class PyNumberUnaryOp extends PythonBinaryBuiltinNode {
4085+
static int MAX_CACHE_SIZE = UnaryArithmetic.values().length;
4086+
4087+
@Specialization(guards = {"cachedOp == op", "left.isIntLike()"}, limit = "MAX_CACHE_SIZE")
4088+
static Object doIntLikePrimitiveWrapper(VirtualFrame frame, PrimitiveNativeWrapper left, @SuppressWarnings("unused") int op,
4089+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4090+
@Cached("createCallNode(op)") LookupAndCallUnaryNode callNode,
4091+
@Cached ToNewRefNode toSulongNode,
4092+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4093+
@Cached GetNativeNullNode getNativeNullNode) {
4094+
try {
4095+
return toSulongNode.execute(callNode.executeObject(frame, left.getLong()));
4096+
} catch (PException e) {
4097+
transformExceptionToNativeNode.execute(e);
4098+
return toSulongNode.execute(getNativeNullNode.execute());
4099+
}
4100+
}
4101+
4102+
@Specialization(guards = "cachedOp == op", limit = "MAX_CACHE_SIZE", replaces = "doIntLikePrimitiveWrapper")
4103+
static Object doObject(VirtualFrame frame, Object left, @SuppressWarnings("unused") int op,
4104+
@Cached AsPythonObjectNode leftToJava,
4105+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4106+
@Cached("createCallNode(op)") LookupAndCallUnaryNode callNode,
4107+
@Cached ToNewRefNode toSulongNode,
4108+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4109+
@Cached GetNativeNullNode getNativeNullNode) {
4110+
// still try to avoid expensive materialization of primitives
4111+
Object result;
4112+
try {
4113+
Object leftValue;
4114+
if (left instanceof PrimitiveNativeWrapper) {
4115+
leftValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) left);
4116+
} else {
4117+
leftValue = leftToJava.execute(left);
4118+
}
4119+
result = callNode.executeObject(frame, leftValue);
4120+
} catch (PException e) {
4121+
transformExceptionToNativeNode.execute(e);
4122+
result = getNativeNullNode.execute();
4123+
}
4124+
return toSulongNode.execute(result);
4125+
}
4126+
4127+
/**
4128+
* This needs to stay in sync with {@code abstract.c: enum e_unaryop}.
4129+
*/
4130+
static LookupAndCallUnaryNode createCallNode(int op) {
4131+
UnaryArithmetic unaryArithmetic;
4132+
switch (op) {
4133+
case 0:
4134+
unaryArithmetic = UnaryArithmetic.Pos;
4135+
break;
4136+
case 1:
4137+
unaryArithmetic = UnaryArithmetic.Neg;
4138+
break;
4139+
case 2:
4140+
unaryArithmetic = UnaryArithmetic.Invert;
4141+
break;
4142+
default:
4143+
throw CompilerDirectives.shouldNotReachHere("invalid unary operator");
4144+
}
4145+
return unaryArithmetic.create();
4146+
}
4147+
}
4148+
4149+
// directly called without landing function
4150+
@Builtin(name = "PyNumber_BinOp", minNumOfPositionalArgs = 3)
4151+
@GenerateNodeFactory
4152+
abstract static class PyNumberBinOp extends PythonTernaryBuiltinNode {
4153+
static int MAX_CACHE_SIZE = BinaryArithmetic.values().length;
4154+
4155+
@Specialization(guards = {"cachedOp == op", "left.isIntLike()", "right.isIntLike()"}, limit = "MAX_CACHE_SIZE")
4156+
static Object doIntLikePrimitiveWrapper(VirtualFrame frame, PrimitiveNativeWrapper left, PrimitiveNativeWrapper right, @SuppressWarnings("unused") int op,
4157+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4158+
@Cached("createCallNode(op)") LookupAndCallBinaryNode callNode,
4159+
@Cached ToNewRefNode toSulongNode,
4160+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4161+
@Cached GetNativeNullNode getNativeNullNode) {
4162+
try {
4163+
return toSulongNode.execute(callNode.executeObject(frame, left.getLong(), right.getLong()));
4164+
} catch (PException e) {
4165+
transformExceptionToNativeNode.execute(e);
4166+
return toSulongNode.execute(getNativeNullNode.execute());
4167+
}
4168+
}
4169+
4170+
@Specialization(guards = "cachedOp == op", limit = "MAX_CACHE_SIZE", replaces = "doIntLikePrimitiveWrapper")
4171+
static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressWarnings("unused") int op,
4172+
@Cached AsPythonObjectNode leftToJava,
4173+
@Cached AsPythonObjectNode rightToJava,
4174+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4175+
@Cached("createCallNode(op)") LookupAndCallBinaryNode callNode,
4176+
@Cached ToNewRefNode toSulongNode,
4177+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4178+
@Cached GetNativeNullNode getNativeNullNode) {
4179+
// still try to avoid expensive materialization of primitives
4180+
Object result;
4181+
try {
4182+
if (left instanceof PrimitiveNativeWrapper || right instanceof PrimitiveNativeWrapper) {
4183+
Object leftValue;
4184+
Object rightValue;
4185+
if (left instanceof PrimitiveNativeWrapper) {
4186+
leftValue = extract((PrimitiveNativeWrapper) left);
4187+
} else {
4188+
leftValue = leftToJava.execute(left);
4189+
}
4190+
if (right instanceof PrimitiveNativeWrapper) {
4191+
rightValue = extract((PrimitiveNativeWrapper) right);
4192+
} else {
4193+
rightValue = rightToJava.execute(right);
4194+
}
4195+
result = callNode.executeObject(frame, leftValue, rightValue);
4196+
} else {
4197+
result = callNode.executeObject(frame, leftToJava.execute(left), rightToJava.execute(right));
4198+
}
4199+
} catch (PException e) {
4200+
transformExceptionToNativeNode.execute(e);
4201+
result = getNativeNullNode.execute();
4202+
}
4203+
return toSulongNode.execute(result);
4204+
}
4205+
4206+
static Object extract(PrimitiveNativeWrapper wrapper) {
4207+
if (wrapper.isIntLike()) {
4208+
return wrapper.getLong();
4209+
}
4210+
if (wrapper.isDouble()) {
4211+
return wrapper.getDouble();
4212+
}
4213+
if (wrapper.isBool()) {
4214+
return wrapper.getBool();
4215+
}
4216+
throw CompilerDirectives.shouldNotReachHere("unexpected wrapper state");
4217+
}
4218+
4219+
/**
4220+
* This needs to stay in sync with {@code abstract.c: enum e_binop}.
4221+
*/
4222+
static LookupAndCallBinaryNode createCallNode(int op) {
4223+
return getBinaryArithmetic(op).create();
4224+
}
4225+
4226+
private static BinaryArithmetic getBinaryArithmetic(int op) {
4227+
switch (op) {
4228+
case 0:
4229+
return BinaryArithmetic.Add;
4230+
case 1:
4231+
return BinaryArithmetic.Sub;
4232+
case 2:
4233+
return BinaryArithmetic.Mul;
4234+
case 3:
4235+
return BinaryArithmetic.TrueDiv;
4236+
case 4:
4237+
return BinaryArithmetic.LShift;
4238+
case 5:
4239+
return BinaryArithmetic.RShift;
4240+
case 6:
4241+
return BinaryArithmetic.Or;
4242+
case 7:
4243+
return BinaryArithmetic.And;
4244+
case 8:
4245+
return BinaryArithmetic.Xor;
4246+
case 9:
4247+
return BinaryArithmetic.FloorDiv;
4248+
case 10:
4249+
return BinaryArithmetic.Mod;
4250+
case 12:
4251+
return BinaryArithmetic.MatMul;
4252+
default:
4253+
throw CompilerDirectives.shouldNotReachHere("invalid binary operator");
4254+
}
4255+
}
4256+
4257+
}
4258+
4259+
// directly called without landing function
4260+
@Builtin(name = "PyNumber_InPlaceBinOp", minNumOfPositionalArgs = 3)
4261+
@GenerateNodeFactory
4262+
abstract static class PyNumberInPlaceBinOp extends PythonTernaryBuiltinNode {
4263+
static int MAX_CACHE_SIZE = InplaceArithmetic.values().length;
4264+
4265+
@Specialization(guards = {"cachedOp == op", "left.isIntLike()", "right.isIntLike()"}, limit = "MAX_CACHE_SIZE")
4266+
static Object doIntLikePrimitiveWrapper(VirtualFrame frame, PrimitiveNativeWrapper left, PrimitiveNativeWrapper right, @SuppressWarnings("unused") int op,
4267+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4268+
@Cached("createCallNode(op)") LookupAndCallInplaceNode callNode,
4269+
@Cached ToNewRefNode toSulongNode,
4270+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4271+
@Cached GetNativeNullNode getNativeNullNode) {
4272+
try {
4273+
return toSulongNode.execute(callNode.execute(frame, left.getLong(), right.getLong()));
4274+
} catch (PException e) {
4275+
transformExceptionToNativeNode.execute(e);
4276+
return toSulongNode.execute(getNativeNullNode.execute());
4277+
}
4278+
}
4279+
4280+
@Specialization(guards = "cachedOp == op", limit = "MAX_CACHE_SIZE", replaces = "doIntLikePrimitiveWrapper")
4281+
static Object doObject(VirtualFrame frame, Object left, Object right, @SuppressWarnings("unused") int op,
4282+
@Cached AsPythonObjectNode leftToJava,
4283+
@Cached AsPythonObjectNode rightToJava,
4284+
@Cached("op") @SuppressWarnings("unused") int cachedOp,
4285+
@Cached("createCallNode(op)") LookupAndCallInplaceNode callNode,
4286+
@Cached ToNewRefNode toSulongNode,
4287+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4288+
@Cached GetNativeNullNode getNativeNullNode) {
4289+
// still try to avoid expensive materialization of primitives
4290+
Object result;
4291+
try {
4292+
if (left instanceof PrimitiveNativeWrapper || right instanceof PrimitiveNativeWrapper) {
4293+
Object leftValue;
4294+
Object rightValue;
4295+
if (left instanceof PrimitiveNativeWrapper) {
4296+
leftValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) left);
4297+
} else {
4298+
leftValue = leftToJava.execute(left);
4299+
}
4300+
if (right instanceof PrimitiveNativeWrapper) {
4301+
rightValue = PyNumberBinOp.extract((PrimitiveNativeWrapper) right);
4302+
} else {
4303+
rightValue = rightToJava.execute(right);
4304+
}
4305+
result = callNode.execute(frame, leftValue, rightValue);
4306+
} else {
4307+
result = callNode.execute(frame, leftToJava.execute(left), rightToJava.execute(right));
4308+
}
4309+
} catch (PException e) {
4310+
transformExceptionToNativeNode.execute(e);
4311+
result = getNativeNullNode.execute();
4312+
}
4313+
return toSulongNode.execute(result);
4314+
}
4315+
4316+
/**
4317+
* This needs to stay in sync with {@code abstract.c: enum e_binop}.
4318+
*/
4319+
static LookupAndCallInplaceNode createCallNode(int op) {
4320+
return getInplaceArithmetic(op).create();
4321+
}
4322+
4323+
private static InplaceArithmetic getInplaceArithmetic(int op) {
4324+
switch (op) {
4325+
case 0:
4326+
return InplaceArithmetic.IAdd;
4327+
case 1:
4328+
return InplaceArithmetic.ISub;
4329+
case 2:
4330+
return InplaceArithmetic.IMul;
4331+
case 3:
4332+
return InplaceArithmetic.ITrueDiv;
4333+
case 4:
4334+
return InplaceArithmetic.ILShift;
4335+
case 5:
4336+
return InplaceArithmetic.IRShift;
4337+
case 6:
4338+
return InplaceArithmetic.IOr;
4339+
case 7:
4340+
return InplaceArithmetic.IAnd;
4341+
case 8:
4342+
return InplaceArithmetic.IXor;
4343+
case 9:
4344+
return InplaceArithmetic.IFloorDiv;
4345+
case 10:
4346+
return InplaceArithmetic.IMod;
4347+
case 12:
4348+
return InplaceArithmetic.IMatMul;
4349+
default:
4350+
throw CompilerDirectives.shouldNotReachHere("invalid binary operator");
4351+
}
4352+
}
4353+
4354+
}
40764355
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2900,7 +2900,7 @@ protected static boolean isInt(Object times) {
29002900

29012901
private static int toIndex(VirtualFrame frame, Object times, PRaiseNode raiseNode, PythonObjectLibrary lib) {
29022902
if (lib.canBeIndex(times)) {
2903-
return lib.asSizeWithState(times, PArguments.getThreadState(frame));
2903+
return lib.asSizeWithFrame(times, PythonBuiltinClassType.OverflowError, frame);
29042904
}
29052905
throw raiseNode.raise(TypeError, ERROR_MSG, times);
29062906
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallUnaryNode.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ public abstract static class NoAttributeHandler extends PNodeWithContext {
9999

100100
public abstract Object executeObject(VirtualFrame frame, int receiver);
101101

102+
public abstract Object executeObject(VirtualFrame frame, long receiver);
103+
102104
public abstract Object executeObject(VirtualFrame frame, double receiver);
103105

104106
public static LookupAndCallUnaryNode create(String name) {

0 commit comments

Comments
 (0)