Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7afa476

Browse filesBrowse files
authored
GH-130415: Use boolean guards to narrow types to values in the JIT (GH-130659)
1 parent c6513f7 commit 7afa476
Copy full SHA for 7afa476

File tree

7 files changed

+348
-166
lines changed
Filter options

7 files changed

+348
-166
lines changed

‎Include/internal/pycore_optimizer.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_optimizer.h
+12-3Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ typedef enum _JitSymType {
172172
JIT_SYM_KNOWN_CLASS_TAG = 6,
173173
JIT_SYM_KNOWN_VALUE_TAG = 7,
174174
JIT_SYM_TUPLE_TAG = 8,
175+
JIT_SYM_TRUTHINESS_TAG = 9,
175176
} JitSymType;
176177

177178
typedef struct _jit_opt_known_class {
@@ -198,12 +199,19 @@ typedef struct _jit_opt_tuple {
198199
uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];
199200
} JitOptTuple;
200201

202+
typedef struct {
203+
uint8_t tag;
204+
bool not;
205+
uint16_t value;
206+
} JitOptTruthiness;
207+
201208
typedef union _jit_opt_symbol {
202209
uint8_t tag;
203210
JitOptKnownClass cls;
204211
JitOptKnownValue value;
205212
JitOptKnownVersion version;
206213
JitOptTuple tuple;
214+
JitOptTruthiness truthiness;
207215
} JitOptSymbol;
208216

209217

@@ -245,8 +253,8 @@ typedef struct _JitOptContext {
245253

246254
extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);
247255
extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);
248-
extern bool _Py_uop_sym_is_const(JitOptSymbol *sym);
249-
extern PyObject *_Py_uop_sym_get_const(JitOptSymbol *sym);
256+
extern bool _Py_uop_sym_is_const(JitOptContext *ctx, JitOptSymbol *sym);
257+
extern PyObject *_Py_uop_sym_get_const(JitOptContext *ctx, JitOptSymbol *sym);
250258
extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);
251259
extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);
252260
extern JitOptSymbol *_Py_uop_sym_new_type(
@@ -262,12 +270,13 @@ extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeOb
262270
extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version);
263271
extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val);
264272
extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);
265-
extern int _Py_uop_sym_truthiness(JitOptSymbol *sym);
273+
extern int _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptSymbol *sym);
266274
extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);
267275
extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);
268276
extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args);
269277
extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item);
270278
extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);
279+
extern JitOptSymbol *_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptSymbol *value, bool truthy);
271280

272281
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
273282
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);

‎Lib/test/test_capi/test_opt.py

Copy file name to clipboardExpand all lines: Lib/test/test_capi/test_opt.py
+62Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,68 @@ def crash_addition():
14371437

14381438
crash_addition()
14391439

1440+
def test_narrow_type_to_constant_bool_false(self):
1441+
def f(n):
1442+
trace = []
1443+
for i in range(n):
1444+
# false is always False, but we can only prove that it's a bool:
1445+
false = i == TIER2_THRESHOLD
1446+
trace.append("A")
1447+
if not false: # Kept.
1448+
trace.append("B")
1449+
if not false: # Removed!
1450+
trace.append("C")
1451+
trace.append("D")
1452+
if false: # Removed!
1453+
trace.append("X")
1454+
trace.append("E")
1455+
trace.append("F")
1456+
if false: # Removed!
1457+
trace.append("X")
1458+
trace.append("G")
1459+
return trace
1460+
1461+
trace, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
1462+
self.assertEqual(trace, list("ABCDEFG") * TIER2_THRESHOLD)
1463+
self.assertIsNotNone(ex)
1464+
uops = get_opnames(ex)
1465+
# Only one guard remains:
1466+
self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 1)
1467+
self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 0)
1468+
# But all of the appends we care about are still there:
1469+
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
1470+
1471+
def test_narrow_type_to_constant_bool_true(self):
1472+
def f(n):
1473+
trace = []
1474+
for i in range(n):
1475+
# true always True, but we can only prove that it's a bool:
1476+
true = i != TIER2_THRESHOLD
1477+
trace.append("A")
1478+
if true: # Kept.
1479+
trace.append("B")
1480+
if not true: # Removed!
1481+
trace.append("X")
1482+
trace.append("C")
1483+
if true: # Removed!
1484+
trace.append("D")
1485+
trace.append("E")
1486+
trace.append("F")
1487+
if not true: # Removed!
1488+
trace.append("X")
1489+
trace.append("G")
1490+
return trace
1491+
1492+
trace, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
1493+
self.assertEqual(trace, list("ABCDEFG") * TIER2_THRESHOLD)
1494+
self.assertIsNotNone(ex)
1495+
uops = get_opnames(ex)
1496+
# Only one guard remains:
1497+
self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 0)
1498+
self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 1)
1499+
# But all of the appends we care about are still there:
1500+
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
1501+
14401502

14411503
def global_identity(x):
14421504
return x
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve the experimental JIT's ability to narrow boolean values based on the
2+
results of truthiness tests.

‎Python/optimizer_analysis.c

Copy file name to clipboardExpand all lines: Python/optimizer_analysis.c
+2-21Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -136,26 +136,6 @@ incorrect_keys(_PyUOpInstruction *inst, PyObject *obj)
136136
return 0;
137137
}
138138

139-
static int
140-
check_next_uop(_PyUOpInstruction *buffer, int size, int pc, uint16_t expected)
141-
{
142-
if (pc + 1 >= size) {
143-
DPRINTF(1, "Cannot rewrite %s at pc %d: buffer too small\n",
144-
_PyOpcode_uop_name[buffer[pc].opcode], pc);
145-
return 0;
146-
}
147-
uint16_t next_opcode = buffer[pc + 1].opcode;
148-
if (next_opcode != expected) {
149-
DPRINTF(1,
150-
"Cannot rewrite %s at pc %d: unexpected next opcode %s, "
151-
"expected %s\n",
152-
_PyOpcode_uop_name[buffer[pc].opcode], pc,
153-
_PyOpcode_uop_name[next_opcode], _PyOpcode_uop_name[expected]);
154-
return 0;
155-
}
156-
return 1;
157-
}
158-
159139
/* Returns 1 if successfully optimized
160140
* 0 if the trace is not suitable for optimization (yet)
161141
* -1 if there was an error. */
@@ -363,6 +343,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
363343
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
364344
#define sym_tuple_length _Py_uop_sym_tuple_length
365345
#define sym_is_immortal _Py_uop_sym_is_immortal
346+
#define sym_new_truthiness _Py_uop_sym_new_truthiness
366347

367348
static int
368349
optimize_to_bool(
@@ -376,7 +357,7 @@ optimize_to_bool(
376357
*result_ptr = value;
377358
return 1;
378359
}
379-
int truthiness = sym_truthiness(value);
360+
int truthiness = sym_truthiness(ctx, value);
380361
if (truthiness >= 0) {
381362
PyObject *load = truthiness ? Py_True : Py_False;
382363
REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)load);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.