|
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;
|
230 | 231 | import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
|
231 | 232 | import com.oracle.graal.python.nodes.function.FunctionRootNode;
|
@@ -4073,4 +4074,113 @@ static int doBytes(PBytes bytes,
|
4073 | 4074 | return 0;
|
4074 | 4075 | }
|
4075 | 4076 | }
|
| 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 | + } |
4076 | 4186 | }
|
0 commit comments