|
226 | 226 | import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
|
227 | 227 | import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
|
228 | 228 | import com.oracle.graal.python.nodes.classes.IsSubtypeNodeGen;
|
| 229 | +import com.oracle.graal.python.nodes.expression.BinaryArithmetic; |
229 | 230 | 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; |
230 | 234 | import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
|
231 | 235 | import com.oracle.graal.python.nodes.function.FunctionRootNode;
|
232 | 236 | import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
|
@@ -4073,4 +4077,279 @@ static int doBytes(PBytes bytes,
|
4073 | 4077 | return 0;
|
4074 | 4078 | }
|
4075 | 4079 | }
|
| 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 | + } |
4076 | 4355 | }
|
0 commit comments