mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-132732: Automatically constant evaluate pure operations (GH-132733)
This adds a "macro" to the optimizer DSL called "REPLACE_OPCODE_IF_EVALUATES_PURE", which allows automatically constant evaluating a bytecode body if certain inputs have no side effects upon evaluations (such as ints, strings, and floats). Co-authored-by: Tomas R. <tomas.roun8@gmail.com>
This commit is contained in:
parent
c45f4f3ebe
commit
695ab61351
10 changed files with 706 additions and 122 deletions
|
@ -850,7 +850,7 @@ dummy_func(
|
|||
DEOPT_IF(!res);
|
||||
}
|
||||
|
||||
pure op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) {
|
||||
op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) {
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5);
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "pycore_function.h"
|
||||
#include "pycore_uop_ids.h"
|
||||
#include "pycore_range.h"
|
||||
#include "pycore_unicodeobject.h"
|
||||
#include "pycore_ceval.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -321,7 +323,10 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
|
|||
/* Shortened forms for convenience, used in optimizer_bytecodes.c */
|
||||
#define sym_is_not_null _Py_uop_sym_is_not_null
|
||||
#define sym_is_const _Py_uop_sym_is_const
|
||||
#define sym_is_safe_const _Py_uop_sym_is_safe_const
|
||||
#define sym_get_const _Py_uop_sym_get_const
|
||||
#define sym_new_const_steal _Py_uop_sym_new_const_steal
|
||||
#define sym_get_const_as_stackref _Py_uop_sym_get_const_as_stackref
|
||||
#define sym_new_unknown _Py_uop_sym_new_unknown
|
||||
#define sym_new_not_null _Py_uop_sym_new_not_null
|
||||
#define sym_new_type _Py_uop_sym_new_type
|
||||
|
@ -350,6 +355,8 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
|
|||
#define sym_new_compact_int _Py_uop_sym_new_compact_int
|
||||
#define sym_new_truthiness _Py_uop_sym_new_truthiness
|
||||
|
||||
#define JUMP_TO_LABEL(label) goto label;
|
||||
|
||||
static int
|
||||
optimize_to_bool(
|
||||
_PyUOpInstruction *this_instr,
|
||||
|
|
|
@ -181,6 +181,7 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_BINARY_OP, (lhs, rhs -- res)) {
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(lhs, rhs);
|
||||
bool lhs_int = sym_matches_type(lhs, &PyLong_Type);
|
||||
bool rhs_int = sym_matches_type(rhs, &PyLong_Type);
|
||||
bool lhs_float = sym_matches_type(lhs, &PyFloat_Type);
|
||||
|
@ -235,35 +236,23 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_BINARY_OP_ADD_INT, (left, right -- res)) {
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_compact_int(ctx);
|
||||
}
|
||||
|
||||
op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) {
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_compact_int(ctx);
|
||||
}
|
||||
|
||||
op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) {
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_compact_int(ctx);
|
||||
}
|
||||
|
||||
op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) {
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyFloat_FromDouble(
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) +
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
Py_DECREF(temp);
|
||||
// TODO gh-115506:
|
||||
// replace opcode with constant propagated one and update tests!
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
}
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
// TODO (gh-134584): Refactor this to use another uop
|
||||
if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) {
|
||||
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
|
||||
|
@ -271,23 +260,8 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) {
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyFloat_FromDouble(
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) -
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
Py_DECREF(temp);
|
||||
// TODO gh-115506:
|
||||
// replace opcode with constant propagated one and update tests!
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
}
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
// TODO (gh-134584): Refactor this to use another uop
|
||||
if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) {
|
||||
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
|
||||
|
@ -295,23 +269,8 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) {
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyFloat_FromDouble(
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) *
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
Py_DECREF(temp);
|
||||
// TODO gh-115506:
|
||||
// replace opcode with constant propagated one and update tests!
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
}
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
// TODO (gh-134584): Refactor this to use another uop
|
||||
if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) {
|
||||
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
|
||||
|
@ -319,19 +278,8 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) {
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyUnicode_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyUnicode_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyUnicode_Type);
|
||||
}
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right);
|
||||
res = sym_new_type(ctx, &PyUnicode_Type);
|
||||
}
|
||||
|
||||
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) {
|
||||
|
@ -443,6 +391,7 @@ dummy_func(void) {
|
|||
}
|
||||
|
||||
op(_UNARY_NOT, (value -- res)) {
|
||||
REPLACE_OPCODE_IF_EVALUATES_PURE(value);
|
||||
sym_set_type(value, &PyBool_Type);
|
||||
res = sym_new_truthiness(ctx, value, false);
|
||||
}
|
||||
|
|
304
Python/optimizer_cases.c.h
generated
304
Python/optimizer_cases.c.h
generated
|
@ -206,6 +206,21 @@
|
|||
JitOptRef value;
|
||||
JitOptRef res;
|
||||
value = stack_pointer[-1];
|
||||
if (
|
||||
sym_is_safe_const(ctx, value)
|
||||
) {
|
||||
JitOptRef value_sym = value;
|
||||
_PyStackRef value = sym_get_const_as_stackref(ctx, value_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
assert(PyStackRef_BoolCheck(value));
|
||||
res_stackref = PyStackRef_IsFalse(value)
|
||||
? PyStackRef_True : PyStackRef_False;
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-1] = res;
|
||||
break;
|
||||
}
|
||||
sym_set_type(value, &PyBool_Type);
|
||||
res = sym_new_truthiness(ctx, value, false);
|
||||
stack_pointer[-1] = res;
|
||||
|
@ -391,7 +406,41 @@
|
|||
}
|
||||
|
||||
case _BINARY_OP_MULTIPLY_INT: {
|
||||
JitOptRef right;
|
||||
JitOptRef left;
|
||||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyLong_CheckExact(left_o));
|
||||
assert(PyLong_CheckExact(right_o));
|
||||
assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
res_stackref = _PyCompactLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o);
|
||||
if (PyStackRef_IsNull(res_stackref )) {
|
||||
ctx->done = true;
|
||||
break;
|
||||
}
|
||||
PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
|
||||
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
res = sym_new_compact_int(ctx);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
|
@ -400,7 +449,41 @@
|
|||
}
|
||||
|
||||
case _BINARY_OP_ADD_INT: {
|
||||
JitOptRef right;
|
||||
JitOptRef left;
|
||||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyLong_CheckExact(left_o));
|
||||
assert(PyLong_CheckExact(right_o));
|
||||
assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
res_stackref = _PyCompactLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
|
||||
if (PyStackRef_IsNull(res_stackref )) {
|
||||
ctx->done = true;
|
||||
break;
|
||||
}
|
||||
PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
|
||||
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
res = sym_new_compact_int(ctx);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
|
@ -409,7 +492,41 @@
|
|||
}
|
||||
|
||||
case _BINARY_OP_SUBTRACT_INT: {
|
||||
JitOptRef right;
|
||||
JitOptRef left;
|
||||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyLong_CheckExact(left_o));
|
||||
assert(PyLong_CheckExact(right_o));
|
||||
assert(_PyLong_BothAreCompact((PyLongObject *)left_o, (PyLongObject *)right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
res_stackref = _PyCompactLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o);
|
||||
if (PyStackRef_IsNull(res_stackref )) {
|
||||
ctx->done = true;
|
||||
break;
|
||||
}
|
||||
PyStackRef_CLOSE_SPECIALIZED(right, _PyLong_ExactDealloc);
|
||||
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
res = sym_new_compact_int(ctx);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
|
@ -443,29 +560,42 @@
|
|||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyFloat_FromDouble(
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) *
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||
if (temp == NULL) {
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyFloat_CheckExact(left_o));
|
||||
assert(PyFloat_CheckExact(right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
double dres =
|
||||
((PyFloatObject *)left_o)->ob_fval *
|
||||
((PyFloatObject *)right_o)->ob_fval;
|
||||
res_stackref = _PyFloat_FromDouble_ConsumeInputs(left, right, dres);
|
||||
if (PyStackRef_IsNull(res_stackref )) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
stack_pointer += -1;
|
||||
break;
|
||||
}
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) {
|
||||
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
|
||||
}
|
||||
stack_pointer[-1] = res;
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -475,29 +605,42 @@
|
|||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyFloat_FromDouble(
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) +
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||
if (temp == NULL) {
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyFloat_CheckExact(left_o));
|
||||
assert(PyFloat_CheckExact(right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
double dres =
|
||||
((PyFloatObject *)left_o)->ob_fval +
|
||||
((PyFloatObject *)right_o)->ob_fval;
|
||||
res_stackref = _PyFloat_FromDouble_ConsumeInputs(left, right, dres);
|
||||
if (PyStackRef_IsNull(res_stackref )) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
stack_pointer += -1;
|
||||
break;
|
||||
}
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) {
|
||||
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
|
||||
}
|
||||
stack_pointer[-1] = res;
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -507,29 +650,42 @@
|
|||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyFloat_FromDouble(
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) -
|
||||
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||
if (temp == NULL) {
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyFloat_CheckExact(left_o));
|
||||
assert(PyFloat_CheckExact(right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
double dres =
|
||||
((PyFloatObject *)left_o)->ob_fval -
|
||||
((PyFloatObject *)right_o)->ob_fval;
|
||||
res_stackref = _PyFloat_FromDouble_ConsumeInputs(left, right, dres);
|
||||
if (PyStackRef_IsNull(res_stackref )) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
stack_pointer += -1;
|
||||
break;
|
||||
}
|
||||
res = sym_new_type(ctx, &PyFloat_Type);
|
||||
if (PyJitRef_IsBorrowed(left) && PyJitRef_IsBorrowed(right)) {
|
||||
REPLACE_OP(this_instr, op_without_decref_inputs[opcode], oparg, 0);
|
||||
}
|
||||
stack_pointer[-1] = res;
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -566,24 +722,39 @@
|
|||
JitOptRef res;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
|
||||
assert(PyUnicode_CheckExact(sym_get_const(ctx, left)));
|
||||
assert(PyUnicode_CheckExact(sym_get_const(ctx, right)));
|
||||
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
|
||||
if (temp == NULL) {
|
||||
if (
|
||||
sym_is_safe_const(ctx, left) &&
|
||||
sym_is_safe_const(ctx, right)
|
||||
) {
|
||||
JitOptRef left_sym = left;
|
||||
JitOptRef right_sym = right;
|
||||
_PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
|
||||
_PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
assert(PyUnicode_CheckExact(left_o));
|
||||
assert(PyUnicode_CheckExact(right_o));
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
PyObject *res_o = PyUnicode_Concat(left_o, right_o);
|
||||
PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc);
|
||||
PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc);
|
||||
if (res_o == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
res_stackref = PyStackRef_FromPyObjectSteal(res_o);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
res = sym_new_type(ctx, &PyUnicode_Type);
|
||||
stack_pointer += -1;
|
||||
}
|
||||
stack_pointer[-1] = res;
|
||||
res = sym_new_type(ctx, &PyUnicode_Type);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2539,6 +2710,31 @@
|
|||
JitOptRef res;
|
||||
rhs = stack_pointer[-1];
|
||||
lhs = stack_pointer[-2];
|
||||
if (
|
||||
sym_is_safe_const(ctx, lhs) &&
|
||||
sym_is_safe_const(ctx, rhs)
|
||||
) {
|
||||
JitOptRef lhs_sym = lhs;
|
||||
JitOptRef rhs_sym = rhs;
|
||||
_PyStackRef lhs = sym_get_const_as_stackref(ctx, lhs_sym);
|
||||
_PyStackRef rhs = sym_get_const_as_stackref(ctx, rhs_sym);
|
||||
_PyStackRef res_stackref;
|
||||
/* Start of uop copied from bytecodes for constant evaluation */
|
||||
PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs);
|
||||
PyObject *rhs_o = PyStackRef_AsPyObjectBorrow(rhs);
|
||||
assert(_PyEval_BinaryOps[oparg]);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o);
|
||||
if (res_o == NULL) {
|
||||
JUMP_TO_LABEL(error);
|
||||
}
|
||||
res_stackref = PyStackRef_FromPyObjectSteal(res_o);
|
||||
/* End of uop copied from bytecodes for constant evaluation */
|
||||
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
|
||||
break;
|
||||
}
|
||||
bool lhs_int = sym_matches_type(lhs, &PyLong_Type);
|
||||
bool rhs_int = sym_matches_type(rhs, &PyLong_Type);
|
||||
bool lhs_float = sym_matches_type(lhs, &PyFloat_Type);
|
||||
|
|
|
@ -185,6 +185,35 @@ _Py_uop_sym_get_const(JitOptContext *ctx, JitOptRef ref)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
_PyStackRef
|
||||
_Py_uop_sym_get_const_as_stackref(JitOptContext *ctx, JitOptRef sym)
|
||||
{
|
||||
PyObject *const_val = _Py_uop_sym_get_const(ctx, sym);
|
||||
if (const_val == NULL) {
|
||||
return PyStackRef_NULL;
|
||||
}
|
||||
return PyStackRef_FromPyObjectBorrow(const_val);
|
||||
}
|
||||
|
||||
/*
|
||||
Indicates whether the constant is safe to constant evaluate
|
||||
(without side effects).
|
||||
*/
|
||||
bool
|
||||
_Py_uop_sym_is_safe_const(JitOptContext *ctx, JitOptRef sym)
|
||||
{
|
||||
PyObject *const_val = _Py_uop_sym_get_const(ctx, sym);
|
||||
if (const_val == NULL) {
|
||||
return false;
|
||||
}
|
||||
PyTypeObject *typ = Py_TYPE(const_val);
|
||||
return (typ == &PyLong_Type) ||
|
||||
(typ == &PyUnicode_Type) ||
|
||||
(typ == &PyFloat_Type) ||
|
||||
(typ == &PyTuple_Type) ||
|
||||
(typ == &PyBool_Type);
|
||||
}
|
||||
|
||||
void
|
||||
_Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
|
||||
{
|
||||
|
@ -467,6 +496,16 @@ _Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val)
|
|||
return ref;
|
||||
}
|
||||
|
||||
JitOptRef
|
||||
_Py_uop_sym_new_const_steal(JitOptContext *ctx, PyObject *const_val)
|
||||
{
|
||||
assert(const_val != NULL);
|
||||
JitOptRef res = _Py_uop_sym_new_const(ctx, const_val);
|
||||
// Decref once because sym_new_const increfs it.
|
||||
Py_DECREF(const_val);
|
||||
return res;
|
||||
}
|
||||
|
||||
JitOptRef
|
||||
_Py_uop_sym_new_null(JitOptContext *ctx)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue