Skip to content

Commit 0ad18cf

Browse files
committed
Add uop status to opcode metadata
1 parent e2855ca commit 0ad18cf

File tree

4 files changed

+38
-77
lines changed

4 files changed

+38
-77
lines changed

Python/executor_cases.c.h

-38
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,6 @@
2727
break;
2828
}
2929

30-
case LOAD_FAST_LOAD_FAST: {
31-
PyObject *value1;
32-
PyObject *value2;
33-
uint32_t oparg1 = oparg >> 4;
34-
uint32_t oparg2 = oparg & 15;
35-
value1 = GETLOCAL(oparg1);
36-
value2 = GETLOCAL(oparg2);
37-
Py_INCREF(value1);
38-
Py_INCREF(value2);
39-
STACK_GROW(2);
40-
stack_pointer[-1] = value2;
41-
stack_pointer[-2] = value1;
42-
break;
43-
}
44-
4530
case LOAD_CONST: {
4631
PyObject *value;
4732
value = GETITEM(FRAME_CO_CONSTS, oparg);
@@ -58,29 +43,6 @@
5843
break;
5944
}
6045

61-
case STORE_FAST_LOAD_FAST: {
62-
PyObject *value1 = stack_pointer[-1];
63-
PyObject *value2;
64-
uint32_t oparg1 = oparg >> 4;
65-
uint32_t oparg2 = oparg & 15;
66-
SETLOCAL(oparg1, value1);
67-
value2 = GETLOCAL(oparg2);
68-
Py_INCREF(value2);
69-
stack_pointer[-1] = value2;
70-
break;
71-
}
72-
73-
case STORE_FAST_STORE_FAST: {
74-
PyObject *value1 = stack_pointer[-1];
75-
PyObject *value2 = stack_pointer[-2];
76-
uint32_t oparg1 = oparg >> 4;
77-
uint32_t oparg2 = oparg & 15;
78-
SETLOCAL(oparg1, value1);
79-
SETLOCAL(oparg2, value2);
80-
STACK_SHRINK(2);
81-
break;
82-
}
83-
8446
case POP_TOP: {
8547
PyObject *value = stack_pointer[-1];
8648
Py_DECREF(value);

Python/opcode_metadata.h

+27-25
Original file line numberDiff line numberDiff line change
@@ -867,10 +867,12 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT
867867
#define HAS_CONST_FLAG (2)
868868
#define HAS_NAME_FLAG (4)
869869
#define HAS_JUMP_FLAG (8)
870+
#define IS_UOP_FLAG (16)
870871
#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_ARG_FLAG))
871872
#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG))
872873
#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG))
873874
#define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_JUMP_FLAG))
875+
#define OPCODE_IS_UOP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (IS_UOP_FLAG))
874876
struct opcode_metadata {
875877
bool valid_entry;
876878
enum InstructionFormat instr_format;
@@ -885,34 +887,34 @@ struct opcode_metadata {
885887
extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];
886888
#else
887889
const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
888-
[NOP] = { true, INSTR_FMT_IX, 0 },
890+
[NOP] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
889891
[RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
890892
[INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
891893
[LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
892894
[LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
893-
[LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
894-
[LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
895+
[LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
896+
[LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
895897
[LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
896-
[LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG },
897-
[STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
898-
[STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
898+
[LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | IS_UOP_FLAG },
899+
[STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
900+
[STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
899901
[STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
900902
[STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
901-
[POP_TOP] = { true, INSTR_FMT_IX, 0 },
902-
[PUSH_NULL] = { true, INSTR_FMT_IX, 0 },
903-
[END_FOR] = { true, INSTR_FMT_IB, 0 },
903+
[POP_TOP] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
904+
[PUSH_NULL] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
905+
[END_FOR] = { true, INSTR_FMT_IB, IS_UOP_FLAG },
904906
[INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, 0 },
905-
[END_SEND] = { true, INSTR_FMT_IX, 0 },
907+
[END_SEND] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
906908
[INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, 0 },
907909
[UNARY_NEGATIVE] = { true, INSTR_FMT_IX, 0 },
908910
[UNARY_NOT] = { true, INSTR_FMT_IX, 0 },
909911
[UNARY_INVERT] = { true, INSTR_FMT_IX, 0 },
910912
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IBC, 0 },
911913
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IBC, 0 },
912914
[BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IBC, 0 },
913-
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IBC, 0 },
914-
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC, 0 },
915-
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC, 0 },
915+
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IBC, IS_UOP_FLAG },
916+
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC, IS_UOP_FLAG },
917+
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC, IS_UOP_FLAG },
916918
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IBC, 0 },
917919
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB, 0 },
918920
[BINARY_SUBSCR] = { true, INSTR_FMT_IXC, 0 },
@@ -947,7 +949,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
947949
[RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
948950
[END_ASYNC_FOR] = { true, INSTR_FMT_IX, 0 },
949951
[CLEANUP_THROW] = { true, INSTR_FMT_IX, 0 },
950-
[LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX, 0 },
952+
[LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
951953
[LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, 0 },
952954
[STORE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
953955
[DELETE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
@@ -971,8 +973,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
971973
[DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
972974
[LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
973975
[LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
974-
[STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
975-
[COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
976+
[STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
977+
[COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
976978
[BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
977979
[BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
978980
[BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
@@ -1008,7 +1010,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
10081010
[COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
10091011
[COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
10101012
[COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
1011-
[IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
1013+
[IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
10121014
[CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
10131015
[CHECK_EG_MATCH] = { true, INSTR_FMT_IX, 0 },
10141016
[CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, 0 },
@@ -1026,8 +1028,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
10261028
[JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
10271029
[GET_LEN] = { true, INSTR_FMT_IX, 0 },
10281030
[MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
1029-
[MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 },
1030-
[MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 },
1031+
[MATCH_MAPPING] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
1032+
[MATCH_SEQUENCE] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
10311033
[MATCH_KEYS] = { true, INSTR_FMT_IX, 0 },
10321034
[GET_ITER] = { true, INSTR_FMT_IX, 0 },
10331035
[GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, 0 },
@@ -1040,10 +1042,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
10401042
[BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, 0 },
10411043
[BEFORE_WITH] = { true, INSTR_FMT_IX, 0 },
10421044
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX, 0 },
1043-
[SETUP_FINALLY] = { true, INSTR_FMT_IX, 0 },
1044-
[SETUP_CLEANUP] = { true, INSTR_FMT_IX, 0 },
1045-
[SETUP_WITH] = { true, INSTR_FMT_IX, 0 },
1046-
[POP_BLOCK] = { true, INSTR_FMT_IX, 0 },
1045+
[SETUP_FINALLY] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
1046+
[SETUP_CLEANUP] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
1047+
[SETUP_WITH] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
1048+
[POP_BLOCK] = { true, INSTR_FMT_IX, IS_UOP_FLAG },
10471049
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
10481050
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG },
10491051
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG },
@@ -1077,9 +1079,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {
10771079
[CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
10781080
[FORMAT_SIMPLE] = { true, INSTR_FMT_IX, 0 },
10791081
[FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, 0 },
1080-
[COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
1082+
[COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
10811083
[BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG },
1082-
[SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
1084+
[SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_UOP_FLAG },
10831085
[INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, 0 },
10841086
[INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
10851087
[INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },

Python/optimizer.c

+8-13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <stdbool.h>
99
#include <stdint.h>
1010
#include <stddef.h>
11+
#include "opcode_metadata.h"
1112

1213
static bool
1314
has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr)
@@ -352,6 +353,7 @@ uop_execute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **
352353
for (;;) {
353354
int opcode = self->trace[pc].opcode;
354355
int oparg = self->trace[pc].oparg;
356+
// fprintf(stderr, "uop %d, oparg %d\n", opcode, oparg);
355357
pc++;
356358
self->optimizer->instrs_executed++;
357359
switch (opcode) {
@@ -375,7 +377,7 @@ uop_execute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **
375377

376378
default:
377379
{
378-
// fprintf(stderr, "Unknown uop %d, oparg %d\n", opcode, oparg);
380+
fprintf(stderr, "Unknown uop %d, oparg %d\n", opcode, oparg);
379381
Py_FatalError("Unknown uop");
380382
abort(); // Unreachable
381383
for (;;) {}
@@ -394,6 +396,7 @@ translate_bytecode_to_trace(
394396
int max_length)
395397
{
396398
#define ADD_TO_TRACE(OPCODE, OPARG) \
399+
/* fprintf(stderr, "ADD_TO_TRACE(%d, %d)\n", (OPCODE), (OPARG)); */ \
397400
trace[trace_length].opcode = (OPCODE); \
398401
trace[trace_length].oparg = (OPARG); \
399402
trace_length++;
@@ -404,13 +407,6 @@ translate_bytecode_to_trace(
404407
int opcode = instr->op.code;
405408
int oparg = instr->op.arg;
406409
switch (opcode) {
407-
// TODO: Tools/cases_generator should generate these from Python/bytecodes.c,
408-
// or it should generate metadata that can be used to generate these.
409-
case LOAD_FAST:
410-
{
411-
ADD_TO_TRACE(opcode, oparg);
412-
break;
413-
}
414410
case LOAD_FAST_LOAD_FAST:
415411
{
416412
// Reserve space for two uops (+ SETUP + EXIT_TRACE)
@@ -423,13 +419,12 @@ translate_bytecode_to_trace(
423419
ADD_TO_TRACE(LOAD_FAST, oparg2);
424420
break;
425421
}
426-
case LOAD_CONST:
427-
{
428-
ADD_TO_TRACE(opcode, oparg);
429-
break;
430-
}
431422
default:
432423
{
424+
if (OPCODE_IS_UOP(opcode)) {
425+
ADD_TO_TRACE(opcode, oparg);
426+
break;
427+
}
433428
goto done; // Break out of while loop
434429
}
435430
}

Tools/cases_generator/generate_cases.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,14 @@ def assign(self, dst: StackEffect, src: StackEffect):
244244
def cast(self, dst: StackEffect, src: StackEffect) -> str:
245245
return f"({dst.type or 'PyObject *'})" if src.type != dst.type else ""
246246

247-
INSTRUCTION_FLAGS = ['HAS_ARG', 'HAS_CONST', 'HAS_NAME', 'HAS_JUMP']
247+
INSTRUCTION_FLAGS = ['HAS_ARG', 'HAS_CONST', 'HAS_NAME', 'HAS_JUMP', 'IS_UOP']
248248

249249
FORBIDDEN_INSTRUCTIONS = (
250250
"cframe",
251251
"resume_with_error", # Proxy for "goto", which isn't an IDENTIFIER
252252
"kwnames",
253253
"next_instr",
254+
"oparg1", # Proxy for super-instructions like LOAD_FAST_LOAD_FAST
254255
"tstate",
255256
"JUMPBY",
256257
"DEOPT_IF",
@@ -315,6 +316,7 @@ def __init__(self, inst: parser.InstDef):
315316
'HAS_CONST': variable_used(inst, "FRAME_CO_CONSTS"),
316317
'HAS_NAME' : variable_used(inst, "FRAME_CO_NAMES"),
317318
'HAS_JUMP' : variable_used(inst, "JUMPBY"),
319+
'IS_UOP' : self.is_viable_uop(),
318320
}
319321
assert set(flag_data.keys()) == set(INSTRUCTION_FLAGS)
320322
self.flags = 0

0 commit comments

Comments
 (0)