Skip to content

Commit eba715e

Browse files
committed
Add new predicate symbol and IS_OP constant narrowing
1 parent e30a46b commit eba715e

6 files changed

Lines changed: 121 additions & 2 deletions

File tree

Include/internal/pycore_optimizer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value,
191191
extern bool _Py_uop_sym_is_compact_int(JitOptRef sym);
192192
extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx);
193193
extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym);
194+
extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef subject_ref, JitOptRef constant_ref, JitOptPredicateKind kind, bool invert);
195+
extern bool _Py_uop_sym_is_known_singleton(JitOptContext *ctx, JitOptRef sym);
196+
extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true);
194197

195198
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
196199
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);

Include/internal/pycore_optimizer_types.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ typedef enum _JitSymType {
3939
JIT_SYM_TUPLE_TAG = 8,
4040
JIT_SYM_TRUTHINESS_TAG = 9,
4141
JIT_SYM_COMPACT_INT = 10,
42+
JIT_SYM_PREDICATE_TAG = 11,
4243
} JitSymType;
4344

4445
typedef struct _jit_opt_known_class {
@@ -71,6 +72,19 @@ typedef struct {
7172
uint16_t value;
7273
} JitOptTruthiness;
7374

75+
typedef enum {
76+
JIT_PRED_IS,
77+
// JIT_PRED_EQ,
78+
} JitOptPredicateKind;
79+
80+
typedef struct {
81+
uint8_t tag;
82+
uint8_t kind;
83+
bool invert;
84+
uint16_t subject;
85+
uint16_t constant;
86+
} JitOptPredicate;
87+
7488
typedef struct {
7589
uint8_t tag;
7690
} JitOptCompactInt;
@@ -83,6 +97,7 @@ typedef union _jit_opt_symbol {
8397
JitOptTuple tuple;
8498
JitOptTruthiness truthiness;
8599
JitOptCompactInt compact;
100+
JitOptPredicate predicate;
86101
} JitOptSymbol;
87102

88103
// This mimics the _PyStackRef API

Python/optimizer_analysis.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ incorrect_keys(PyObject *obj, uint32_t version)
186186
#define sym_is_compact_int _Py_uop_sym_is_compact_int
187187
#define sym_new_compact_int _Py_uop_sym_new_compact_int
188188
#define sym_new_truthiness _Py_uop_sym_new_truthiness
189+
#define sym_new_predicate _Py_uop_sym_new_predicate
190+
#define sym_is_known_singleton _Py_uop_sym_is_known_singleton
191+
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing
189192

190193
#define JUMP_TO_LABEL(label) goto label;
191194

Python/optimizer_bytecodes.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
3838
#define sym_new_compact_int _Py_uop_sym_new_compact_int
3939
#define sym_is_compact_int _Py_uop_sym_is_compact_int
4040
#define sym_new_truthiness _Py_uop_sym_new_truthiness
41+
#define sym_new_predicate _Py_uop_sym_new_predicate
42+
#define sym_is_known_singleton _Py_uop_sym_is_known_singleton
43+
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing
4144

4245
extern int
4346
optimize_to_bool(
@@ -533,7 +536,16 @@ dummy_func(void) {
533536
}
534537

535538
op(_IS_OP, (left, right -- b, l, r)) {
536-
b = sym_new_type(ctx, &PyBool_Type);
539+
bool invert = (oparg != 0);
540+
if (sym_is_known_singleton(ctx, left)) {
541+
b = sym_new_predicate(ctx, right, left, JIT_PRED_IS ,invert);
542+
}
543+
else if (sym_is_known_singleton(ctx, right)) {
544+
b = sym_new_predicate(ctx, left, right, JIT_PRED_IS, invert);
545+
}
546+
else {
547+
b = sym_new_type(ctx, &PyBool_Type);
548+
}
537549
l = left;
538550
r = right;
539551
}
@@ -1142,6 +1154,7 @@ dummy_func(void) {
11421154
assert(value != NULL);
11431155
eliminate_pop_guard(this_instr, value != Py_True);
11441156
}
1157+
sym_apply_predicate_narrowing(ctx, flag, true);
11451158
sym_set_const(flag, Py_True);
11461159
}
11471160

@@ -1187,6 +1200,7 @@ dummy_func(void) {
11871200
assert(value != NULL);
11881201
eliminate_pop_guard(this_instr, value != Py_False);
11891202
}
1203+
sym_apply_predicate_narrowing(ctx, flag, false);
11901204
sym_set_const(flag, Py_False);
11911205
}
11921206

Python/optimizer_cases.c.h

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_symbols.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
258258
sym->cls.version = 0;
259259
sym->cls.type = typ;
260260
return;
261+
case JIT_SYM_PREDICATE_TAG:
261262
case JIT_SYM_TRUTHINESS_TAG:
262263
if (typ != &PyBool_Type) {
263264
sym_set_bottom(ctx, sym);
@@ -319,6 +320,7 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
319320
sym->tag = JIT_SYM_TYPE_VERSION_TAG;
320321
sym->version.version = version;
321322
return true;
323+
case JIT_SYM_PREDICATE_TAG:
322324
case JIT_SYM_TRUTHINESS_TAG:
323325
if (version != PyBool_Type.tp_version_tag) {
324326
sym_set_bottom(ctx, sym);
@@ -385,6 +387,16 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val)
385387
case JIT_SYM_UNKNOWN_TAG:
386388
make_const(sym, const_val);
387389
return;
390+
case JIT_SYM_PREDICATE_TAG:
391+
if (!PyBool_Check(const_val) ||
392+
(_Py_uop_sym_is_const(ctx, ref) &&
393+
_Py_uop_sym_get_const(ctx, ref) != const_val))
394+
{
395+
sym_set_bottom(ctx, sym);
396+
return;
397+
}
398+
make_const(sym, const_val);
399+
return;
388400
case JIT_SYM_TRUTHINESS_TAG:
389401
if (!PyBool_Check(const_val) ||
390402
(_Py_uop_sym_is_const(ctx, ref) &&
@@ -538,6 +550,7 @@ _Py_uop_sym_get_type(JitOptRef ref)
538550
return _PyType_LookupByVersion(sym->version.version);
539551
case JIT_SYM_TUPLE_TAG:
540552
return &PyTuple_Type;
553+
case JIT_SYM_PREDICATE_TAG:
541554
case JIT_SYM_TRUTHINESS_TAG:
542555
return &PyBool_Type;
543556
case JIT_SYM_COMPACT_INT:
@@ -566,6 +579,7 @@ _Py_uop_sym_get_type_version(JitOptRef ref)
566579
return Py_TYPE(sym->value.value)->tp_version_tag;
567580
case JIT_SYM_TUPLE_TAG:
568581
return PyTuple_Type.tp_version_tag;
582+
case JIT_SYM_PREDICATE_TAG:
569583
case JIT_SYM_TRUTHINESS_TAG:
570584
return PyBool_Type.tp_version_tag;
571585
case JIT_SYM_COMPACT_INT:
@@ -759,6 +773,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
759773
}
760774
return;
761775
case JIT_SYM_TUPLE_TAG:
776+
case JIT_SYM_PREDICATE_TAG:
762777
case JIT_SYM_TRUTHINESS_TAG:
763778
sym_set_bottom(ctx, sym);
764779
return;
@@ -772,6 +787,64 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
772787
}
773788
}
774789

790+
JitOptRef
791+
_Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef subject_ref, JitOptRef constant_ref, JitOptPredicateKind kind, bool invert)
792+
{
793+
assert(_Py_uop_sym_is_const(ctx, constant_ref));
794+
795+
JitOptSymbol *subject = PyJitRef_Unwrap(subject_ref);
796+
JitOptSymbol *constant = PyJitRef_Unwrap(constant_ref);
797+
798+
JitOptSymbol *res = sym_new(ctx);
799+
if (res == NULL) {
800+
return out_of_space_ref(ctx);
801+
}
802+
803+
res->tag = JIT_SYM_PREDICATE_TAG;
804+
res->predicate.invert = invert;
805+
res->predicate.kind = kind;
806+
res->predicate.subject = (uint16_t)(subject - allocation_base(ctx));
807+
res->predicate.constant = (uint16_t)(constant - allocation_base(ctx));
808+
809+
return PyJitRef_Wrap(res);
810+
}
811+
812+
bool
813+
_Py_uop_sym_is_known_singleton(JitOptContext *ctx, JitOptRef ref)
814+
{
815+
if (_Py_uop_sym_is_safe_const(ctx, ref)) {
816+
PyObject *value = _Py_uop_sym_get_const(ctx, ref);
817+
return value == Py_None || value == Py_True || value == Py_False;
818+
}
819+
return false;
820+
}
821+
822+
void
823+
_Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef ref, bool branch_is_true)
824+
{
825+
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
826+
if (sym->tag != JIT_SYM_PREDICATE_TAG) {
827+
return;
828+
}
829+
830+
JitOptPredicate pred = sym->predicate;
831+
bool narrow = (branch_is_true && !pred.invert) || (!branch_is_true && pred.invert);
832+
if (!narrow) {
833+
return;
834+
}
835+
836+
if (pred.kind == JIT_PRED_IS) {
837+
JitOptRef subject_ref = PyJitRef_Wrap(allocation_base(ctx) + pred.subject);
838+
JitOptRef constant_ref = PyJitRef_Wrap(allocation_base(ctx) + pred.constant);
839+
PyObject *const_val = _Py_uop_sym_get_const(ctx, constant_ref);
840+
if (const_val == NULL) {
841+
return;
842+
}
843+
_Py_uop_sym_set_const(ctx, subject_ref, const_val);
844+
assert(_Py_uop_sym_is_safe_const(ctx, subject_ref));
845+
}
846+
}
847+
775848
JitOptRef
776849
_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef ref, bool truthy)
777850
{

0 commit comments

Comments
 (0)