Skip to content

Commit 0c81ce1

Browse files
authored
GH-115819: Eliminate Boolean guards when value is known (GH-116355)
1 parent c91bdf8 commit 0c81ce1

File tree

6 files changed

+102
-2
lines changed

6 files changed

+102
-2
lines changed

Include/internal/pycore_optimizer.h

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ extern _Py_UopsSymbol *_Py_uop_sym_new_type(
9090
_Py_UOpsContext *ctx, PyTypeObject *typ);
9191
extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val);
9292
extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx);
93+
extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym);
9394
extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ);
9495
extern bool _Py_uop_sym_set_null(_Py_UopsSymbol *sym);
9596
extern bool _Py_uop_sym_set_non_null(_Py_UopsSymbol *sym);

Lib/test/test_capi/test_opt.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ def testfunc(a):
331331
ex = get_first_executor(testfunc)
332332
self.assertIsNotNone(ex)
333333
uops = get_opnames(ex)
334-
self.assertIn("_GUARD_IS_NOT_NONE_POP", uops)
334+
self.assertNotIn("_GUARD_IS_NONE_POP", uops)
335+
self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops)
335336

336337
def test_pop_jump_if_not_none(self):
337338
def testfunc(a):
@@ -347,7 +348,8 @@ def testfunc(a):
347348
ex = get_first_executor(testfunc)
348349
self.assertIsNotNone(ex)
349350
uops = get_opnames(ex)
350-
self.assertIn("_GUARD_IS_NONE_POP", uops)
351+
self.assertNotIn("_GUARD_IS_NONE_POP", uops)
352+
self.assertNotIn("_GUARD_IS_NOT_NONE_POP", uops)
351353

352354
def test_pop_jump_if_true(self):
353355
def testfunc(n):

Python/optimizer_analysis.c

+11
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
292292
#define sym_is_null _Py_uop_sym_is_null
293293
#define sym_new_const _Py_uop_sym_new_const
294294
#define sym_new_null _Py_uop_sym_new_null
295+
#define sym_has_type _Py_uop_sym_has_type
295296
#define sym_matches_type _Py_uop_sym_matches_type
296297
#define sym_set_null _Py_uop_sym_set_null
297298
#define sym_set_non_null _Py_uop_sym_set_non_null
@@ -324,6 +325,16 @@ optimize_to_bool(
324325
return 0;
325326
}
326327

328+
static void
329+
eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
330+
{
331+
REPLACE_OP(this_instr, _POP_TOP, 0, 0);
332+
if (exit) {
333+
REPLACE_OP((this_instr+1), _EXIT_TRACE, 0, 0);
334+
this_instr[1].target = this_instr->target;
335+
}
336+
}
337+
327338
/* 1 for success, 0 for not ready, cannot error at the moment. */
328339
static int
329340
optimize_uops(

Python/optimizer_bytecodes.c

+41
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
2121
#define sym_new_const _Py_uop_sym_new_const
2222
#define sym_new_null _Py_uop_sym_new_null
2323
#define sym_matches_type _Py_uop_sym_matches_type
24+
#define sym_has_type _Py_uop_sym_has_type
2425
#define sym_set_null _Py_uop_sym_set_null
2526
#define sym_set_non_null _Py_uop_sym_set_non_null
2627
#define sym_set_type _Py_uop_sym_set_type
@@ -36,6 +37,8 @@ optimize_to_bool(
3637
_Py_UopsSymbol *value,
3738
_Py_UopsSymbol **result_ptr);
3839

40+
extern void
41+
eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
3942

4043
static int
4144
dummy_func(void) {
@@ -557,7 +560,45 @@ dummy_func(void) {
557560
(void)iter;
558561
}
559562

563+
op(_GUARD_IS_TRUE_POP, (flag -- )) {
564+
if (sym_is_const(flag)) {
565+
PyObject *value = sym_get_const(flag);
566+
assert(value != NULL);
567+
eliminate_pop_guard(this_instr, value != Py_True);
568+
}
569+
}
570+
571+
op(_GUARD_IS_FALSE_POP, (flag -- )) {
572+
if (sym_is_const(flag)) {
573+
PyObject *value = sym_get_const(flag);
574+
assert(value != NULL);
575+
eliminate_pop_guard(this_instr, value != Py_False);
576+
}
577+
}
578+
579+
op(_GUARD_IS_NONE_POP, (flag -- )) {
580+
if (sym_is_const(flag)) {
581+
PyObject *value = sym_get_const(flag);
582+
assert(value != NULL);
583+
eliminate_pop_guard(this_instr, !Py_IsNone(value));
584+
}
585+
else if (sym_has_type(flag)) {
586+
assert(!sym_matches_type(flag, &_PyNone_Type));
587+
eliminate_pop_guard(this_instr, true);
588+
}
589+
}
560590

591+
op(_GUARD_IS_NOT_NONE_POP, (flag -- )) {
592+
if (sym_is_const(flag)) {
593+
PyObject *value = sym_get_const(flag);
594+
assert(value != NULL);
595+
eliminate_pop_guard(this_instr, Py_IsNone(value));
596+
}
597+
else if (sym_has_type(flag)) {
598+
assert(!sym_matches_type(flag, &_PyNone_Type));
599+
eliminate_pop_guard(this_instr, false);
600+
}
601+
}
561602

562603

563604
// END BYTECODES //

Python/optimizer_cases.c.h

+36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_symbols.c

+9
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,15 @@ _Py_uop_sym_new_null(_Py_UOpsContext *ctx)
231231
return null_sym;
232232
}
233233

234+
bool
235+
_Py_uop_sym_has_type(_Py_UopsSymbol *sym)
236+
{
237+
if (_Py_uop_sym_is_bottom(sym)) {
238+
return false;
239+
}
240+
return sym->typ != NULL;
241+
}
242+
234243
bool
235244
_Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ)
236245
{

0 commit comments

Comments
 (0)