mirror of
https://github.com/python/cpython.git
synced 2025-10-15 03:10:29 +00:00
GH-130415: Use boolean guards to narrow types to values in the JIT (GH-130659)
This commit is contained in:
parent
c6513f7a62
commit
7afa476874
7 changed files with 348 additions and 166 deletions
|
@ -172,6 +172,7 @@ typedef enum _JitSymType {
|
||||||
JIT_SYM_KNOWN_CLASS_TAG = 6,
|
JIT_SYM_KNOWN_CLASS_TAG = 6,
|
||||||
JIT_SYM_KNOWN_VALUE_TAG = 7,
|
JIT_SYM_KNOWN_VALUE_TAG = 7,
|
||||||
JIT_SYM_TUPLE_TAG = 8,
|
JIT_SYM_TUPLE_TAG = 8,
|
||||||
|
JIT_SYM_TRUTHINESS_TAG = 9,
|
||||||
} JitSymType;
|
} JitSymType;
|
||||||
|
|
||||||
typedef struct _jit_opt_known_class {
|
typedef struct _jit_opt_known_class {
|
||||||
|
@ -198,12 +199,19 @@ typedef struct _jit_opt_tuple {
|
||||||
uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];
|
uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];
|
||||||
} JitOptTuple;
|
} JitOptTuple;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tag;
|
||||||
|
bool not;
|
||||||
|
uint16_t value;
|
||||||
|
} JitOptTruthiness;
|
||||||
|
|
||||||
typedef union _jit_opt_symbol {
|
typedef union _jit_opt_symbol {
|
||||||
uint8_t tag;
|
uint8_t tag;
|
||||||
JitOptKnownClass cls;
|
JitOptKnownClass cls;
|
||||||
JitOptKnownValue value;
|
JitOptKnownValue value;
|
||||||
JitOptKnownVersion version;
|
JitOptKnownVersion version;
|
||||||
JitOptTuple tuple;
|
JitOptTuple tuple;
|
||||||
|
JitOptTruthiness truthiness;
|
||||||
} JitOptSymbol;
|
} JitOptSymbol;
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,8 +253,8 @@ typedef struct _JitOptContext {
|
||||||
|
|
||||||
extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);
|
extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);
|
||||||
extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);
|
extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);
|
||||||
extern bool _Py_uop_sym_is_const(JitOptSymbol *sym);
|
extern bool _Py_uop_sym_is_const(JitOptContext *ctx, JitOptSymbol *sym);
|
||||||
extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym);
|
extern PyObject *_Py_uop_sym_get_const(JitOptContext *ctx, JitOptSymbol *sym);
|
||||||
extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);
|
extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);
|
||||||
extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);
|
extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);
|
||||||
extern JitOptSymbol *_Py_uop_sym_new_type(
|
extern JitOptSymbol *_Py_uop_sym_new_type(
|
||||||
|
@ -262,12 +270,13 @@ extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeOb
|
||||||
extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version);
|
extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version);
|
||||||
extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val);
|
extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val);
|
||||||
extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);
|
extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);
|
||||||
extern int _Py_uop_sym_truthiness(JitOptSymbol *sym);
|
extern int _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptSymbol *sym);
|
||||||
extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);
|
extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);
|
||||||
extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);
|
extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);
|
||||||
extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args);
|
extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args);
|
||||||
extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item);
|
extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item);
|
||||||
extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);
|
extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);
|
||||||
|
extern JitOptSymbol *_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptSymbol *value, bool truthy);
|
||||||
|
|
||||||
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
|
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
|
||||||
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
|
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
|
||||||
|
|
|
@ -1437,6 +1437,68 @@ class TestUopsOptimization(unittest.TestCase):
|
||||||
|
|
||||||
crash_addition()
|
crash_addition()
|
||||||
|
|
||||||
|
def test_narrow_type_to_constant_bool_false(self):
|
||||||
|
def f(n):
|
||||||
|
trace = []
|
||||||
|
for i in range(n):
|
||||||
|
# false is always False, but we can only prove that it's a bool:
|
||||||
|
false = i == TIER2_THRESHOLD
|
||||||
|
trace.append("A")
|
||||||
|
if not false: # Kept.
|
||||||
|
trace.append("B")
|
||||||
|
if not false: # Removed!
|
||||||
|
trace.append("C")
|
||||||
|
trace.append("D")
|
||||||
|
if false: # Removed!
|
||||||
|
trace.append("X")
|
||||||
|
trace.append("E")
|
||||||
|
trace.append("F")
|
||||||
|
if false: # Removed!
|
||||||
|
trace.append("X")
|
||||||
|
trace.append("G")
|
||||||
|
return trace
|
||||||
|
|
||||||
|
trace, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
|
||||||
|
self.assertEqual(trace, list("ABCDEFG") * TIER2_THRESHOLD)
|
||||||
|
self.assertIsNotNone(ex)
|
||||||
|
uops = get_opnames(ex)
|
||||||
|
# Only one guard remains:
|
||||||
|
self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 1)
|
||||||
|
self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 0)
|
||||||
|
# But all of the appends we care about are still there:
|
||||||
|
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
|
||||||
|
|
||||||
|
def test_narrow_type_to_constant_bool_true(self):
|
||||||
|
def f(n):
|
||||||
|
trace = []
|
||||||
|
for i in range(n):
|
||||||
|
# true always True, but we can only prove that it's a bool:
|
||||||
|
true = i != TIER2_THRESHOLD
|
||||||
|
trace.append("A")
|
||||||
|
if true: # Kept.
|
||||||
|
trace.append("B")
|
||||||
|
if not true: # Removed!
|
||||||
|
trace.append("X")
|
||||||
|
trace.append("C")
|
||||||
|
if true: # Removed!
|
||||||
|
trace.append("D")
|
||||||
|
trace.append("E")
|
||||||
|
trace.append("F")
|
||||||
|
if not true: # Removed!
|
||||||
|
trace.append("X")
|
||||||
|
trace.append("G")
|
||||||
|
return trace
|
||||||
|
|
||||||
|
trace, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
|
||||||
|
self.assertEqual(trace, list("ABCDEFG") * TIER2_THRESHOLD)
|
||||||
|
self.assertIsNotNone(ex)
|
||||||
|
uops = get_opnames(ex)
|
||||||
|
# Only one guard remains:
|
||||||
|
self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 0)
|
||||||
|
self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 1)
|
||||||
|
# But all of the appends we care about are still there:
|
||||||
|
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
|
||||||
|
|
||||||
|
|
||||||
def global_identity(x):
|
def global_identity(x):
|
||||||
return x
|
return x
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve the experimental JIT's ability to narrow boolean values based on the
|
||||||
|
results of truthiness tests.
|
|
@ -136,26 +136,6 @@ incorrect_keys(_PyUOpInstruction *inst, PyObject *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
check_next_uop(_PyUOpInstruction *buffer, int size, int pc, uint16_t expected)
|
|
||||||
{
|
|
||||||
if (pc + 1 >= size) {
|
|
||||||
DPRINTF(1, "Cannot rewrite %s at pc %d: buffer too small\n",
|
|
||||||
_PyOpcode_uop_name[buffer[pc].opcode], pc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint16_t next_opcode = buffer[pc + 1].opcode;
|
|
||||||
if (next_opcode != expected) {
|
|
||||||
DPRINTF(1,
|
|
||||||
"Cannot rewrite %s at pc %d: unexpected next opcode %s, "
|
|
||||||
"expected %s\n",
|
|
||||||
_PyOpcode_uop_name[buffer[pc].opcode], pc,
|
|
||||||
_PyOpcode_uop_name[next_opcode], _PyOpcode_uop_name[expected]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns 1 if successfully optimized
|
/* Returns 1 if successfully optimized
|
||||||
* 0 if the trace is not suitable for optimization (yet)
|
* 0 if the trace is not suitable for optimization (yet)
|
||||||
* -1 if there was an error. */
|
* -1 if there was an error. */
|
||||||
|
@ -363,6 +343,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
|
||||||
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
|
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
|
||||||
#define sym_tuple_length _Py_uop_sym_tuple_length
|
#define sym_tuple_length _Py_uop_sym_tuple_length
|
||||||
#define sym_is_immortal _Py_uop_sym_is_immortal
|
#define sym_is_immortal _Py_uop_sym_is_immortal
|
||||||
|
#define sym_new_truthiness _Py_uop_sym_new_truthiness
|
||||||
|
|
||||||
static int
|
static int
|
||||||
optimize_to_bool(
|
optimize_to_bool(
|
||||||
|
@ -376,7 +357,7 @@ optimize_to_bool(
|
||||||
*result_ptr = value;
|
*result_ptr = value;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int truthiness = sym_truthiness(value);
|
int truthiness = sym_truthiness(ctx, value);
|
||||||
if (truthiness >= 0) {
|
if (truthiness >= 0) {
|
||||||
PyObject *load = truthiness ? Py_True : Py_False;
|
PyObject *load = truthiness ? Py_True : Py_False;
|
||||||
REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)load);
|
REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)load);
|
||||||
|
|
|
@ -34,6 +34,7 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
|
||||||
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
|
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
|
||||||
#define sym_tuple_length _Py_uop_sym_tuple_length
|
#define sym_tuple_length _Py_uop_sym_tuple_length
|
||||||
#define sym_is_immortal _Py_uop_sym_is_immortal
|
#define sym_is_immortal _Py_uop_sym_is_immortal
|
||||||
|
#define sym_new_truthiness _Py_uop_sym_new_truthiness
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
optimize_to_bool(
|
optimize_to_bool(
|
||||||
|
@ -198,11 +199,11 @@ dummy_func(void) {
|
||||||
// Case C:
|
// Case C:
|
||||||
res = sym_new_type(ctx, &PyFloat_Type);
|
res = sym_new_type(ctx, &PyFloat_Type);
|
||||||
}
|
}
|
||||||
else if (!sym_is_const(right)) {
|
else if (!sym_is_const(ctx, right)) {
|
||||||
// Case A or B... can't know without the sign of the RHS:
|
// Case A or B... can't know without the sign of the RHS:
|
||||||
res = sym_new_unknown(ctx);
|
res = sym_new_unknown(ctx);
|
||||||
}
|
}
|
||||||
else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) {
|
else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, right))) {
|
||||||
// Case B:
|
// Case B:
|
||||||
res = sym_new_type(ctx, &PyFloat_Type);
|
res = sym_new_type(ctx, &PyFloat_Type);
|
||||||
}
|
}
|
||||||
|
@ -223,13 +224,13 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_ADD_INT, (left, right -- res)) {
|
op(_BINARY_OP_ADD_INT, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
||||||
{
|
{
|
||||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left),
|
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(ctx, left),
|
||||||
(PyLongObject *)sym_get_const(right));
|
(PyLongObject *)sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -244,13 +245,13 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) {
|
op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
||||||
{
|
{
|
||||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left),
|
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(ctx, left),
|
||||||
(PyLongObject *)sym_get_const(right));
|
(PyLongObject *)sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -265,13 +266,13 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) {
|
op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
||||||
{
|
{
|
||||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left),
|
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(ctx, left),
|
||||||
(PyLongObject *)sym_get_const(right));
|
(PyLongObject *)sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -286,14 +287,14 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) {
|
op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
||||||
{
|
{
|
||||||
assert(PyFloat_CheckExact(sym_get_const(left)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyFloat_CheckExact(sym_get_const(right)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = PyFloat_FromDouble(
|
PyObject *temp = PyFloat_FromDouble(
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(left)) +
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) +
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(right)));
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -308,14 +309,14 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) {
|
op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
||||||
{
|
{
|
||||||
assert(PyFloat_CheckExact(sym_get_const(left)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyFloat_CheckExact(sym_get_const(right)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = PyFloat_FromDouble(
|
PyObject *temp = PyFloat_FromDouble(
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(left)) -
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) -
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(right)));
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -330,14 +331,14 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) {
|
op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
||||||
{
|
{
|
||||||
assert(PyFloat_CheckExact(sym_get_const(left)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyFloat_CheckExact(sym_get_const(right)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = PyFloat_FromDouble(
|
PyObject *temp = PyFloat_FromDouble(
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(left)) *
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) *
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(right)));
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -352,9 +353,9 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) {
|
op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) {
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
||||||
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
|
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -368,9 +369,9 @@ dummy_func(void) {
|
||||||
|
|
||||||
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) {
|
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) {
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
||||||
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
|
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -391,14 +392,14 @@ dummy_func(void) {
|
||||||
|
|
||||||
op(_TO_BOOL, (value -- res)) {
|
op(_TO_BOOL, (value -- res)) {
|
||||||
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
||||||
res = sym_new_type(ctx, &PyBool_Type);
|
res = sym_new_truthiness(ctx, value, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_TO_BOOL_BOOL, (value -- res)) {
|
op(_TO_BOOL_BOOL, (value -- res)) {
|
||||||
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
||||||
sym_set_type(value, &PyBool_Type);
|
sym_set_type(value, &PyBool_Type);
|
||||||
res = value;
|
res = sym_new_truthiness(ctx, value, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +431,11 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
op(_UNARY_NOT, (value -- res)) {
|
||||||
|
sym_set_type(value, &PyBool_Type);
|
||||||
|
res = sym_new_truthiness(ctx, value, false);
|
||||||
|
}
|
||||||
|
|
||||||
op(_COMPARE_OP, (left, right -- res)) {
|
op(_COMPARE_OP, (left, right -- res)) {
|
||||||
if (oparg & 16) {
|
if (oparg & 16) {
|
||||||
res = sym_new_type(ctx, &PyBool_Type);
|
res = sym_new_type(ctx, &PyBool_Type);
|
||||||
|
@ -521,8 +527,8 @@ dummy_func(void) {
|
||||||
(void)dict_version;
|
(void)dict_version;
|
||||||
(void)index;
|
(void)index;
|
||||||
attr = NULL;
|
attr = NULL;
|
||||||
if (sym_is_const(owner)) {
|
if (sym_is_const(ctx, owner)) {
|
||||||
PyModuleObject *mod = (PyModuleObject *)sym_get_const(owner);
|
PyModuleObject *mod = (PyModuleObject *)sym_get_const(ctx, owner);
|
||||||
if (PyModule_CheckExact(mod)) {
|
if (PyModule_CheckExact(mod)) {
|
||||||
PyObject *dict = mod->md_dict;
|
PyObject *dict = mod->md_dict;
|
||||||
uint64_t watched_mutations = get_mutations(dict);
|
uint64_t watched_mutations = get_mutations(dict);
|
||||||
|
@ -599,19 +605,19 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
|
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
|
||||||
if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) {
|
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
|
||||||
assert(PyFunction_Check(sym_get_const(callable)));
|
assert(PyFunction_Check(sym_get_const(ctx, callable)));
|
||||||
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
|
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
|
||||||
this_instr->operand1 = (uintptr_t)sym_get_const(callable);
|
this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
|
||||||
}
|
}
|
||||||
sym_set_type(callable, &PyFunction_Type);
|
sym_set_type(callable, &PyFunction_Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
|
op(_CHECK_FUNCTION_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
|
||||||
assert(sym_matches_type(callable, &PyFunction_Type));
|
assert(sym_matches_type(callable, &PyFunction_Type));
|
||||||
if (sym_is_const(callable)) {
|
if (sym_is_const(ctx, callable)) {
|
||||||
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
|
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
|
||||||
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(callable);
|
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(ctx, callable);
|
||||||
PyCodeObject *co = (PyCodeObject *)func->func_code;
|
PyCodeObject *co = (PyCodeObject *)func->func_code;
|
||||||
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
|
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
|
||||||
REPLACE_OP(this_instr, _NOP, 0 ,0);
|
REPLACE_OP(this_instr, _NOP, 0 ,0);
|
||||||
|
@ -812,24 +818,26 @@ dummy_func(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_GUARD_IS_TRUE_POP, (flag -- )) {
|
op(_GUARD_IS_TRUE_POP, (flag -- )) {
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
eliminate_pop_guard(this_instr, value != Py_True);
|
eliminate_pop_guard(this_instr, value != Py_True);
|
||||||
}
|
}
|
||||||
|
sym_set_const(flag, Py_True);
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_GUARD_IS_FALSE_POP, (flag -- )) {
|
op(_GUARD_IS_FALSE_POP, (flag -- )) {
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
eliminate_pop_guard(this_instr, value != Py_False);
|
eliminate_pop_guard(this_instr, value != Py_False);
|
||||||
}
|
}
|
||||||
|
sym_set_const(flag, Py_False);
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_GUARD_IS_NONE_POP, (flag -- )) {
|
op(_GUARD_IS_NONE_POP, (flag -- )) {
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
eliminate_pop_guard(this_instr, !Py_IsNone(value));
|
eliminate_pop_guard(this_instr, !Py_IsNone(value));
|
||||||
}
|
}
|
||||||
|
@ -837,11 +845,12 @@ dummy_func(void) {
|
||||||
assert(!sym_matches_type(flag, &_PyNone_Type));
|
assert(!sym_matches_type(flag, &_PyNone_Type));
|
||||||
eliminate_pop_guard(this_instr, true);
|
eliminate_pop_guard(this_instr, true);
|
||||||
}
|
}
|
||||||
|
sym_set_const(flag, Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
op(_GUARD_IS_NOT_NONE_POP, (flag -- )) {
|
op(_GUARD_IS_NOT_NONE_POP, (flag -- )) {
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
eliminate_pop_guard(this_instr, Py_IsNone(value));
|
eliminate_pop_guard(this_instr, Py_IsNone(value));
|
||||||
}
|
}
|
||||||
|
|
114
Python/optimizer_cases.c.h
generated
114
Python/optimizer_cases.c.h
generated
|
@ -140,8 +140,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
case _UNARY_NOT: {
|
case _UNARY_NOT: {
|
||||||
|
JitOptSymbol *value;
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
res = sym_new_not_null(ctx);
|
value = stack_pointer[-1];
|
||||||
|
sym_set_type(value, &PyBool_Type);
|
||||||
|
res = sym_new_truthiness(ctx, value, false);
|
||||||
stack_pointer[-1] = res;
|
stack_pointer[-1] = res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +154,7 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
value = stack_pointer[-1];
|
value = stack_pointer[-1];
|
||||||
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
||||||
res = sym_new_type(ctx, &PyBool_Type);
|
res = sym_new_truthiness(ctx, value, true);
|
||||||
}
|
}
|
||||||
stack_pointer[-1] = res;
|
stack_pointer[-1] = res;
|
||||||
break;
|
break;
|
||||||
|
@ -163,7 +166,7 @@
|
||||||
value = stack_pointer[-1];
|
value = stack_pointer[-1];
|
||||||
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
if (!optimize_to_bool(this_instr, ctx, value, &res)) {
|
||||||
sym_set_type(value, &PyBool_Type);
|
sym_set_type(value, &PyBool_Type);
|
||||||
res = value;
|
res = sym_new_truthiness(ctx, value, true);
|
||||||
}
|
}
|
||||||
stack_pointer[-1] = res;
|
stack_pointer[-1] = res;
|
||||||
break;
|
break;
|
||||||
|
@ -268,15 +271,15 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
||||||
{
|
{
|
||||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
|
||||||
stack_pointer += -2;
|
stack_pointer += -2;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left),
|
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(ctx, left),
|
||||||
(PyLongObject *)sym_get_const(right));
|
(PyLongObject *)sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -303,15 +306,15 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
||||||
{
|
{
|
||||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
|
||||||
stack_pointer += -2;
|
stack_pointer += -2;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left),
|
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(ctx, left),
|
||||||
(PyLongObject *)sym_get_const(right));
|
(PyLongObject *)sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -338,15 +341,15 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type))
|
||||||
{
|
{
|
||||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
assert(PyLong_CheckExact(sym_get_const(ctx, right)));
|
||||||
stack_pointer += -2;
|
stack_pointer += -2;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left),
|
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(ctx, left),
|
||||||
(PyLongObject *)sym_get_const(right));
|
(PyLongObject *)sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -404,14 +407,14 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
||||||
{
|
{
|
||||||
assert(PyFloat_CheckExact(sym_get_const(left)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyFloat_CheckExact(sym_get_const(right)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = PyFloat_FromDouble(
|
PyObject *temp = PyFloat_FromDouble(
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(left)) *
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) *
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(right)));
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -438,14 +441,14 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
||||||
{
|
{
|
||||||
assert(PyFloat_CheckExact(sym_get_const(left)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyFloat_CheckExact(sym_get_const(right)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = PyFloat_FromDouble(
|
PyObject *temp = PyFloat_FromDouble(
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(left)) +
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) +
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(right)));
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -472,14 +475,14 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type))
|
||||||
{
|
{
|
||||||
assert(PyFloat_CheckExact(sym_get_const(left)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, left)));
|
||||||
assert(PyFloat_CheckExact(sym_get_const(right)));
|
assert(PyFloat_CheckExact(sym_get_const(ctx, right)));
|
||||||
PyObject *temp = PyFloat_FromDouble(
|
PyObject *temp = PyFloat_FromDouble(
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(left)) -
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, left)) -
|
||||||
PyFloat_AS_DOUBLE(sym_get_const(right)));
|
PyFloat_AS_DOUBLE(sym_get_const(ctx, right)));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -520,9 +523,9 @@
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
||||||
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
|
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -547,9 +550,9 @@
|
||||||
right = stack_pointer[-1];
|
right = stack_pointer[-1];
|
||||||
left = stack_pointer[-2];
|
left = stack_pointer[-2];
|
||||||
JitOptSymbol *res;
|
JitOptSymbol *res;
|
||||||
if (sym_is_const(left) && sym_is_const(right) &&
|
if (sym_is_const(ctx, left) && sym_is_const(ctx, right) &&
|
||||||
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) {
|
||||||
PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right));
|
PyObject *temp = PyUnicode_Concat(sym_get_const(ctx, left), sym_get_const(ctx, right));
|
||||||
if (temp == NULL) {
|
if (temp == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -1159,8 +1162,8 @@
|
||||||
(void)dict_version;
|
(void)dict_version;
|
||||||
(void)index;
|
(void)index;
|
||||||
attr = NULL;
|
attr = NULL;
|
||||||
if (sym_is_const(owner)) {
|
if (sym_is_const(ctx, owner)) {
|
||||||
PyModuleObject *mod = (PyModuleObject *)sym_get_const(owner);
|
PyModuleObject *mod = (PyModuleObject *)sym_get_const(ctx, owner);
|
||||||
if (PyModule_CheckExact(mod)) {
|
if (PyModule_CheckExact(mod)) {
|
||||||
PyObject *dict = mod->md_dict;
|
PyObject *dict = mod->md_dict;
|
||||||
stack_pointer[-1] = attr;
|
stack_pointer[-1] = attr;
|
||||||
|
@ -1655,10 +1658,10 @@
|
||||||
JitOptSymbol *callable;
|
JitOptSymbol *callable;
|
||||||
callable = stack_pointer[-2 - oparg];
|
callable = stack_pointer[-2 - oparg];
|
||||||
uint32_t func_version = (uint32_t)this_instr->operand0;
|
uint32_t func_version = (uint32_t)this_instr->operand0;
|
||||||
if (sym_is_const(callable) && sym_matches_type(callable, &PyFunction_Type)) {
|
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
|
||||||
assert(PyFunction_Check(sym_get_const(callable)));
|
assert(PyFunction_Check(sym_get_const(ctx, callable)));
|
||||||
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
|
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
|
||||||
this_instr->operand1 = (uintptr_t)sym_get_const(callable);
|
this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
|
||||||
}
|
}
|
||||||
sym_set_type(callable, &PyFunction_Type);
|
sym_set_type(callable, &PyFunction_Type);
|
||||||
break;
|
break;
|
||||||
|
@ -1724,9 +1727,9 @@
|
||||||
self_or_null = stack_pointer[-1 - oparg];
|
self_or_null = stack_pointer[-1 - oparg];
|
||||||
callable = stack_pointer[-2 - oparg];
|
callable = stack_pointer[-2 - oparg];
|
||||||
assert(sym_matches_type(callable, &PyFunction_Type));
|
assert(sym_matches_type(callable, &PyFunction_Type));
|
||||||
if (sym_is_const(callable)) {
|
if (sym_is_const(ctx, callable)) {
|
||||||
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
|
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
|
||||||
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(callable);
|
PyFunctionObject *func = (PyFunctionObject *)sym_get_const(ctx, callable);
|
||||||
PyCodeObject *co = (PyCodeObject *)func->func_code;
|
PyCodeObject *co = (PyCodeObject *)func->func_code;
|
||||||
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
|
if (co->co_argcount == oparg + !sym_is_null(self_or_null)) {
|
||||||
REPLACE_OP(this_instr, _NOP, 0 ,0);
|
REPLACE_OP(this_instr, _NOP, 0 ,0);
|
||||||
|
@ -2160,12 +2163,12 @@
|
||||||
res = sym_new_type(ctx, &PyFloat_Type);
|
res = sym_new_type(ctx, &PyFloat_Type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!sym_is_const(right)) {
|
if (!sym_is_const(ctx, right)) {
|
||||||
// Case A or B... can't know without the sign of the RHS:
|
// Case A or B... can't know without the sign of the RHS:
|
||||||
res = sym_new_unknown(ctx);
|
res = sym_new_unknown(ctx);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (_PyLong_IsNegative((PyLongObject *)sym_get_const(right))) {
|
if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, right))) {
|
||||||
// Case B:
|
// Case B:
|
||||||
res = sym_new_type(ctx, &PyFloat_Type);
|
res = sym_new_type(ctx, &PyFloat_Type);
|
||||||
}
|
}
|
||||||
|
@ -2230,8 +2233,8 @@
|
||||||
case _GUARD_IS_TRUE_POP: {
|
case _GUARD_IS_TRUE_POP: {
|
||||||
JitOptSymbol *flag;
|
JitOptSymbol *flag;
|
||||||
flag = stack_pointer[-1];
|
flag = stack_pointer[-1];
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
|
@ -2239,6 +2242,7 @@
|
||||||
stack_pointer += 1;
|
stack_pointer += 1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
}
|
}
|
||||||
|
sym_set_const(flag, Py_True);
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
break;
|
break;
|
||||||
|
@ -2247,8 +2251,8 @@
|
||||||
case _GUARD_IS_FALSE_POP: {
|
case _GUARD_IS_FALSE_POP: {
|
||||||
JitOptSymbol *flag;
|
JitOptSymbol *flag;
|
||||||
flag = stack_pointer[-1];
|
flag = stack_pointer[-1];
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
|
@ -2256,6 +2260,7 @@
|
||||||
stack_pointer += 1;
|
stack_pointer += 1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
}
|
}
|
||||||
|
sym_set_const(flag, Py_False);
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
break;
|
break;
|
||||||
|
@ -2264,8 +2269,8 @@
|
||||||
case _GUARD_IS_NONE_POP: {
|
case _GUARD_IS_NONE_POP: {
|
||||||
JitOptSymbol *flag;
|
JitOptSymbol *flag;
|
||||||
flag = stack_pointer[-1];
|
flag = stack_pointer[-1];
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
|
@ -2283,14 +2288,15 @@
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
}
|
}
|
||||||
|
sym_set_const(flag, Py_None);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case _GUARD_IS_NOT_NONE_POP: {
|
case _GUARD_IS_NOT_NONE_POP: {
|
||||||
JitOptSymbol *flag;
|
JitOptSymbol *flag;
|
||||||
flag = stack_pointer[-1];
|
flag = stack_pointer[-1];
|
||||||
if (sym_is_const(flag)) {
|
if (sym_is_const(ctx, flag)) {
|
||||||
PyObject *value = sym_get_const(flag);
|
PyObject *value = sym_get_const(ctx, flag);
|
||||||
assert(value != NULL);
|
assert(value != NULL);
|
||||||
stack_pointer += -1;
|
stack_pointer += -1;
|
||||||
assert(WITHIN_STACK_BOUNDS());
|
assert(WITHIN_STACK_BOUNDS());
|
||||||
|
|
|
@ -48,6 +48,12 @@ static JitOptSymbol NO_SPACE_SYMBOL = {
|
||||||
.tag = JIT_SYM_BOTTOM_TAG
|
.tag = JIT_SYM_BOTTOM_TAG
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static JitOptSymbol *
|
||||||
|
allocation_base(JitOptContext *ctx)
|
||||||
|
{
|
||||||
|
return ctx->t_arena.arena;
|
||||||
|
}
|
||||||
|
|
||||||
JitOptSymbol *
|
JitOptSymbol *
|
||||||
out_of_space(JitOptContext *ctx)
|
out_of_space(JitOptContext *ctx)
|
||||||
{
|
{
|
||||||
|
@ -70,6 +76,12 @@ sym_new(JitOptContext *ctx)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void make_const(JitOptSymbol *sym, PyObject *val)
|
||||||
|
{
|
||||||
|
sym->tag = JIT_SYM_KNOWN_VALUE_TAG;
|
||||||
|
sym->value.value = Py_NewRef(val);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
sym_set_bottom(JitOptContext *ctx, JitOptSymbol *sym)
|
sym_set_bottom(JitOptContext *ctx, JitOptSymbol *sym)
|
||||||
{
|
{
|
||||||
|
@ -90,9 +102,21 @@ _Py_uop_sym_is_not_null(JitOptSymbol *sym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
_Py_uop_sym_is_const(JitOptSymbol *sym)
|
_Py_uop_sym_is_const(JitOptContext *ctx, JitOptSymbol *sym)
|
||||||
{
|
{
|
||||||
return sym->tag == JIT_SYM_KNOWN_VALUE_TAG;
|
if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (sym->tag == JIT_SYM_TRUTHINESS_TAG) {
|
||||||
|
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
|
||||||
|
int truthiness = _Py_uop_sym_truthiness(ctx, value);
|
||||||
|
if (truthiness < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
make_const(sym, (truthiness ^ sym->truthiness.not) ? Py_True : Py_False);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -103,11 +127,21 @@ _Py_uop_sym_is_null(JitOptSymbol *sym)
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_Py_uop_sym_get_const(JitOptSymbol *sym)
|
_Py_uop_sym_get_const(JitOptContext *ctx, JitOptSymbol *sym)
|
||||||
{
|
{
|
||||||
if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
|
if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
|
||||||
return sym->value.value;
|
return sym->value.value;
|
||||||
}
|
}
|
||||||
|
if (sym->tag == JIT_SYM_TRUTHINESS_TAG) {
|
||||||
|
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
|
||||||
|
int truthiness = _Py_uop_sym_truthiness(ctx, value);
|
||||||
|
if (truthiness < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *res = (truthiness ^ sym->truthiness.not) ? Py_True : Py_False;
|
||||||
|
make_const(sym, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +187,11 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ)
|
||||||
sym->cls.version = 0;
|
sym->cls.version = 0;
|
||||||
sym->cls.type = typ;
|
sym->cls.type = typ;
|
||||||
return;
|
return;
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
|
if (typ != &PyBool_Type) {
|
||||||
|
sym_set_bottom(ctx, sym);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,16 +232,16 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int
|
||||||
sym->tag = JIT_SYM_TYPE_VERSION_TAG;
|
sym->tag = JIT_SYM_TYPE_VERSION_TAG;
|
||||||
sym->version.version = version;
|
sym->version.version = version;
|
||||||
return true;
|
return true;
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
|
if (version != PyBool_Type.tp_version_tag) {
|
||||||
|
sym_set_bottom(ctx, sym);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void make_const(JitOptSymbol *sym, PyObject *val)
|
|
||||||
{
|
|
||||||
sym->tag = JIT_SYM_KNOWN_VALUE_TAG;
|
|
||||||
sym->value.value = Py_NewRef(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
_Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val)
|
_Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val)
|
||||||
{
|
{
|
||||||
|
@ -240,6 +279,29 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val
|
||||||
case JIT_SYM_UNKNOWN_TAG:
|
case JIT_SYM_UNKNOWN_TAG:
|
||||||
make_const(sym, const_val);
|
make_const(sym, const_val);
|
||||||
return;
|
return;
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
|
if (!PyBool_Check(const_val) ||
|
||||||
|
(_Py_uop_sym_is_const(ctx, sym) &&
|
||||||
|
_Py_uop_sym_get_const(ctx, sym) != const_val))
|
||||||
|
{
|
||||||
|
sym_set_bottom(ctx, sym);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
|
||||||
|
PyTypeObject *type = _Py_uop_sym_get_type(value);
|
||||||
|
if (const_val == (sym->truthiness.not ? Py_False : Py_True)) {
|
||||||
|
// value is truthy. This is only useful for bool:
|
||||||
|
if (type == &PyBool_Type) {
|
||||||
|
_Py_uop_sym_set_const(ctx, value, Py_True);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// value is falsey:
|
||||||
|
else if (type == &PyBool_Type) {
|
||||||
|
_Py_uop_sym_set_const(ctx, value, Py_False);
|
||||||
|
}
|
||||||
|
// TODO: More types (GH-130415)!
|
||||||
|
make_const(sym, const_val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +401,8 @@ _Py_uop_sym_get_type(JitOptSymbol *sym)
|
||||||
return Py_TYPE(sym->value.value);
|
return Py_TYPE(sym->value.value);
|
||||||
case JIT_SYM_TUPLE_TAG:
|
case JIT_SYM_TUPLE_TAG:
|
||||||
return &PyTuple_Type;
|
return &PyTuple_Type;
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
|
return &PyBool_Type;
|
||||||
}
|
}
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -361,6 +425,8 @@ _Py_uop_sym_get_type_version(JitOptSymbol *sym)
|
||||||
return Py_TYPE(sym->value.value)->tp_version_tag;
|
return Py_TYPE(sym->value.value)->tp_version_tag;
|
||||||
case JIT_SYM_TUPLE_TAG:
|
case JIT_SYM_TUPLE_TAG:
|
||||||
return PyTuple_Type.tp_version_tag;
|
return PyTuple_Type.tp_version_tag;
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
|
return PyBool_Type.tp_version_tag;
|
||||||
}
|
}
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -379,6 +445,7 @@ _Py_uop_sym_has_type(JitOptSymbol *sym)
|
||||||
case JIT_SYM_KNOWN_CLASS_TAG:
|
case JIT_SYM_KNOWN_CLASS_TAG:
|
||||||
case JIT_SYM_KNOWN_VALUE_TAG:
|
case JIT_SYM_KNOWN_VALUE_TAG:
|
||||||
case JIT_SYM_TUPLE_TAG:
|
case JIT_SYM_TUPLE_TAG:
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Py_UNREACHABLE();
|
Py_UNREACHABLE();
|
||||||
|
@ -398,7 +465,7 @@ _Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_Py_uop_sym_truthiness(JitOptSymbol *sym)
|
_Py_uop_sym_truthiness(JitOptContext *ctx, JitOptSymbol *sym)
|
||||||
{
|
{
|
||||||
switch(sym->tag) {
|
switch(sym->tag) {
|
||||||
case JIT_SYM_NULL_TAG:
|
case JIT_SYM_NULL_TAG:
|
||||||
|
@ -416,6 +483,16 @@ _Py_uop_sym_truthiness(JitOptSymbol *sym)
|
||||||
break;
|
break;
|
||||||
case JIT_SYM_TUPLE_TAG:
|
case JIT_SYM_TUPLE_TAG:
|
||||||
return sym->tuple.length != 0;
|
return sym->tuple.length != 0;
|
||||||
|
case JIT_SYM_TRUTHINESS_TAG:
|
||||||
|
;
|
||||||
|
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
|
||||||
|
int truthiness = _Py_uop_sym_truthiness(ctx, value);
|
||||||
|
if (truthiness < 0) {
|
||||||
|
return truthiness;
|
||||||
|
}
|
||||||
|
truthiness ^= sym->truthiness.not;
|
||||||
|
make_const(sym, truthiness ? Py_True : Py_False);
|
||||||
|
return truthiness;
|
||||||
}
|
}
|
||||||
PyObject *value = sym->value.value;
|
PyObject *value = sym->value.value;
|
||||||
/* Only handle a few known safe types */
|
/* Only handle a few known safe types */
|
||||||
|
@ -435,12 +512,6 @@ _Py_uop_sym_truthiness(JitOptSymbol *sym)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JitOptSymbol *
|
|
||||||
allocation_base(JitOptContext *ctx)
|
|
||||||
{
|
|
||||||
return ctx->t_arena.arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
JitOptSymbol *
|
JitOptSymbol *
|
||||||
_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args)
|
_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args)
|
||||||
{
|
{
|
||||||
|
@ -503,9 +574,36 @@ _Py_uop_sym_is_immortal(JitOptSymbol *sym)
|
||||||
if (sym->tag == JIT_SYM_KNOWN_CLASS_TAG) {
|
if (sym->tag == JIT_SYM_KNOWN_CLASS_TAG) {
|
||||||
return sym->cls.type == &PyBool_Type;
|
return sym->cls.type == &PyBool_Type;
|
||||||
}
|
}
|
||||||
|
if (sym->tag == JIT_SYM_TRUTHINESS_TAG) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitOptSymbol *
|
||||||
|
_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptSymbol *value, bool truthy)
|
||||||
|
{
|
||||||
|
// It's clearer to invert this in the signature:
|
||||||
|
bool not = !truthy;
|
||||||
|
if (value->tag == JIT_SYM_TRUTHINESS_TAG && value->truthiness.not == not) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
JitOptSymbol *res = sym_new(ctx);
|
||||||
|
if (res == NULL) {
|
||||||
|
return out_of_space(ctx);
|
||||||
|
}
|
||||||
|
int truthiness = _Py_uop_sym_truthiness(ctx, value);
|
||||||
|
if (truthiness < 0) {
|
||||||
|
res->tag = JIT_SYM_TRUTHINESS_TAG;
|
||||||
|
res->truthiness.not = not;
|
||||||
|
res->truthiness.value = (uint16_t)(value - allocation_base(ctx));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
make_const(res, (truthiness ^ not) ? Py_True : Py_False);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// 0 on success, -1 on error.
|
// 0 on success, -1 on error.
|
||||||
_Py_UOpsAbstractFrame *
|
_Py_UOpsAbstractFrame *
|
||||||
_Py_uop_frame_new(
|
_Py_uop_frame_new(
|
||||||
|
@ -570,7 +668,7 @@ _Py_uop_abstractcontext_fini(JitOptContext *ctx)
|
||||||
void
|
void
|
||||||
_Py_uop_abstractcontext_init(JitOptContext *ctx)
|
_Py_uop_abstractcontext_init(JitOptContext *ctx)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(JitOptSymbol) <= 2*sizeof(uint64_t));
|
static_assert(sizeof(JitOptSymbol) <= 2 * sizeof(uint64_t), "JitOptSymbol has grown");
|
||||||
ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE;
|
ctx->limit = ctx->locals_and_stack + MAX_ABSTRACT_INTERP_SIZE;
|
||||||
ctx->n_consumed = ctx->locals_and_stack;
|
ctx->n_consumed = ctx->locals_and_stack;
|
||||||
#ifdef Py_DEBUG // Aids debugging a little. There should never be NULL in the abstract interpreter.
|
#ifdef Py_DEBUG // Aids debugging a little. There should never be NULL in the abstract interpreter.
|
||||||
|
@ -625,6 +723,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
_Py_uop_abstractcontext_init(ctx);
|
_Py_uop_abstractcontext_init(ctx);
|
||||||
PyObject *val_42 = NULL;
|
PyObject *val_42 = NULL;
|
||||||
PyObject *val_43 = NULL;
|
PyObject *val_43 = NULL;
|
||||||
|
PyObject *tuple = NULL;
|
||||||
|
|
||||||
// Use a single 'sym' variable so copy-pasting tests is easier.
|
// Use a single 'sym' variable so copy-pasting tests is easier.
|
||||||
JitOptSymbol *sym = _Py_uop_sym_new_unknown(ctx);
|
JitOptSymbol *sym = _Py_uop_sym_new_unknown(ctx);
|
||||||
|
@ -634,8 +733,8 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "top is NULL");
|
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "top is NULL");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_not_null(sym), "top is not NULL");
|
TEST_PREDICATE(!_Py_uop_sym_is_not_null(sym), "top is not NULL");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "top matches a type");
|
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "top matches a type");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "top is a constant");
|
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, sym), "top is a constant");
|
||||||
TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "top as constant is not NULL");
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == NULL, "top as constant is not NULL");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_bottom(sym), "top is bottom");
|
TEST_PREDICATE(!_Py_uop_sym_is_bottom(sym), "top is bottom");
|
||||||
|
|
||||||
sym = make_bottom(ctx);
|
sym = make_bottom(ctx);
|
||||||
|
@ -645,8 +744,8 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "bottom is NULL is not false");
|
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "bottom is NULL is not false");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_not_null(sym), "bottom is not NULL is not false");
|
TEST_PREDICATE(!_Py_uop_sym_is_not_null(sym), "bottom is not NULL is not false");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "bottom matches a type");
|
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyLong_Type), "bottom matches a type");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "bottom is a constant is not false");
|
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, sym), "bottom is a constant is not false");
|
||||||
TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "bottom as constant is not NULL");
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == NULL, "bottom as constant is not NULL");
|
||||||
TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "bottom isn't bottom");
|
TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "bottom isn't bottom");
|
||||||
|
|
||||||
sym = _Py_uop_sym_new_type(ctx, &PyLong_Type);
|
sym = _Py_uop_sym_new_type(ctx, &PyLong_Type);
|
||||||
|
@ -657,8 +756,8 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int isn't not NULL");
|
TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "int isn't not NULL");
|
||||||
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "int isn't int");
|
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "int isn't int");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "int matches float");
|
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "int matches float");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_const(sym), "int is a constant");
|
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, sym), "int is a constant");
|
||||||
TEST_PREDICATE(_Py_uop_sym_get_const(sym) == NULL, "int as constant is not NULL");
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == NULL, "int as constant is not NULL");
|
||||||
|
|
||||||
_Py_uop_sym_set_type(ctx, sym, &PyLong_Type); // Should be a no-op
|
_Py_uop_sym_set_type(ctx, sym, &PyLong_Type); // Should be a no-op
|
||||||
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(int and int) isn't int");
|
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(int and int) isn't int");
|
||||||
|
@ -679,19 +778,19 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
_Py_uop_sym_set_const(ctx, sym, val_42);
|
_Py_uop_sym_set_const(ctx, sym, val_42);
|
||||||
TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 1, "bool(42) is not True");
|
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 1, "bool(42) is not True");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "42 is NULL");
|
TEST_PREDICATE(!_Py_uop_sym_is_null(sym), "42 is NULL");
|
||||||
TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "42 isn't not NULL");
|
TEST_PREDICATE(_Py_uop_sym_is_not_null(sym), "42 isn't not NULL");
|
||||||
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "42 isn't an int");
|
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "42 isn't an int");
|
||||||
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "42 matches float");
|
TEST_PREDICATE(!_Py_uop_sym_matches_type(sym, &PyFloat_Type), "42 matches float");
|
||||||
TEST_PREDICATE(_Py_uop_sym_is_const(sym), "42 is not a constant");
|
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, sym), "42 is not a constant");
|
||||||
TEST_PREDICATE(_Py_uop_sym_get_const(sym) != NULL, "42 as constant is NULL");
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) != NULL, "42 as constant is NULL");
|
||||||
TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "42 as constant isn't 42");
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == val_42, "42 as constant isn't 42");
|
||||||
TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "42 is not immortal");
|
TEST_PREDICATE(_Py_uop_sym_is_immortal(sym), "42 is not immortal");
|
||||||
|
|
||||||
_Py_uop_sym_set_type(ctx, sym, &PyLong_Type); // Should be a no-op
|
_Py_uop_sym_set_type(ctx, sym, &PyLong_Type); // Should be a no-op
|
||||||
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 42) isn't an int");
|
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyLong_Type), "(42 and 42) isn't an int");
|
||||||
TEST_PREDICATE(_Py_uop_sym_get_const(sym) == val_42, "(42 and 42) as constant isn't 42");
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == val_42, "(42 and 42) as constant isn't 42");
|
||||||
|
|
||||||
_Py_uop_sym_set_type(ctx, sym, &PyFloat_Type); // Should make it bottom
|
_Py_uop_sym_set_type(ctx, sym, &PyFloat_Type); // Should make it bottom
|
||||||
TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom");
|
TEST_PREDICATE(_Py_uop_sym_is_bottom(sym), "(42 and float) isn't bottom");
|
||||||
|
@ -709,11 +808,11 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
|
|
||||||
|
|
||||||
sym = _Py_uop_sym_new_const(ctx, Py_None);
|
sym = _Py_uop_sym_new_const(ctx, Py_None);
|
||||||
TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 0, "bool(None) is not False");
|
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 0, "bool(None) is not False");
|
||||||
sym = _Py_uop_sym_new_const(ctx, Py_False);
|
sym = _Py_uop_sym_new_const(ctx, Py_False);
|
||||||
TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 0, "bool(False) is not False");
|
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 0, "bool(False) is not False");
|
||||||
sym = _Py_uop_sym_new_const(ctx, PyLong_FromLong(0));
|
sym = _Py_uop_sym_new_const(ctx, PyLong_FromLong(0));
|
||||||
TEST_PREDICATE(_Py_uop_sym_truthiness(sym) == 0, "bool(0) is not False");
|
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 0, "bool(0) is not False");
|
||||||
|
|
||||||
JitOptSymbol *i1 = _Py_uop_sym_new_type(ctx, &PyFloat_Type);
|
JitOptSymbol *i1 = _Py_uop_sym_new_type(ctx, &PyFloat_Type);
|
||||||
JitOptSymbol *i2 = _Py_uop_sym_new_const(ctx, val_43);
|
JitOptSymbol *i2 = _Py_uop_sym_new_const(ctx, val_43);
|
||||||
|
@ -724,17 +823,31 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
|
||||||
"tuple item does not match value used to create tuple"
|
"tuple item does not match value used to create tuple"
|
||||||
);
|
);
|
||||||
TEST_PREDICATE(
|
TEST_PREDICATE(
|
||||||
_Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43,
|
_Py_uop_sym_get_const(ctx, _Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43,
|
||||||
"tuple item does not match value used to create tuple"
|
"tuple item does not match value used to create tuple"
|
||||||
);
|
);
|
||||||
PyObject *pair[2] = { val_42, val_43 };
|
PyObject *pair[2] = { val_42, val_43 };
|
||||||
PyObject *tuple = _PyTuple_FromArray(pair, 2);
|
tuple = _PyTuple_FromArray(pair, 2);
|
||||||
sym = _Py_uop_sym_new_const(ctx, tuple);
|
sym = _Py_uop_sym_new_const(ctx, tuple);
|
||||||
TEST_PREDICATE(
|
TEST_PREDICATE(
|
||||||
_Py_uop_sym_get_const(_Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43,
|
_Py_uop_sym_get_const(ctx, _Py_uop_sym_tuple_getitem(ctx, sym, 1)) == val_43,
|
||||||
"tuple item does not match value used to create tuple"
|
"tuple item does not match value used to create tuple"
|
||||||
);
|
);
|
||||||
|
JitOptSymbol *value = _Py_uop_sym_new_type(ctx, &PyBool_Type);
|
||||||
|
sym = _Py_uop_sym_new_truthiness(ctx, value, false);
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyBool_Type), "truthiness is not boolean");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == -1, "truthiness is not unknown");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, sym) == false, "truthiness is constant");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == NULL, "truthiness is not NULL");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, value) == false, "value is constant");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, value) == NULL, "value is not NULL");
|
||||||
|
_Py_uop_sym_set_const(ctx, sym, Py_False);
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_matches_type(sym, &PyBool_Type), "truthiness is not boolean");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, sym) == 0, "truthiness is not True");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, sym) == true, "truthiness is not constant");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, sym) == Py_False, "truthiness is not False");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_is_const(ctx, value) == true, "value is not constant");
|
||||||
|
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, value) == Py_True, "value is not True");
|
||||||
_Py_uop_abstractcontext_fini(ctx);
|
_Py_uop_abstractcontext_fini(ctx);
|
||||||
Py_DECREF(val_42);
|
Py_DECREF(val_42);
|
||||||
Py_DECREF(val_43);
|
Py_DECREF(val_43);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue