From d65881b968f866beb625ee4802a283e3a910cb54 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 12 Jul 2023 19:44:53 +0100 Subject: [PATCH 1/8] gh-105481: expose opcode metadata via the _opcode module --- Include/internal/pycore_opcode_metadata.h | 24 +- Lib/test/test__opcode.py | 64 +++++ Modules/_opcode.c | 89 ++++++ Modules/clinic/_opcode.c.h | 317 +++++++++++++++++++++- Tools/cases_generator/generate_cases.py | 30 +- 5 files changed, 511 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 4a41cd86a4287b..0dd3d649e4db30 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -3,6 +3,8 @@ // Python/bytecodes.c // Do not edit! +#include + #define IS_PSEUDO_INSTR(OP) ( \ ((OP) == LOAD_CLOSURE) || \ @@ -927,6 +929,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { #endif enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC00, INSTR_FMT_IXC000 }; + +#define IS_VALID_OPCODE(OP) \ + (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \ + (_PyOpcode_opcode_metadata[(OP)].valid_entry)) + #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) @@ -935,6 +942,7 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG)) #define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_JUMP_FLAG)) + struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -957,12 +965,16 @@ struct opcode_macro_expansion { #define SAME_OPCODE_METADATA(OP1, OP2) \ (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2)) +#define OPCODE_METADATA_SIZE 512 +#define OPCODE_UOP_NAME_SIZE 512 +#define OPCODE_MACRO_EXPANSION_SIZE 256 + #ifndef NEED_OPCODE_METADATA -extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; -extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; -extern const char * const _PyOpcode_uop_name[512]; +extern const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE]; +extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE]; +extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]; #else // if NEED_OPCODE_METADATA -const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { +const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [NOP] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1180,7 +1192,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CACHE] = { true, INSTR_FMT_IX, 0 }, [RESERVED] = { true, INSTR_FMT_IX, 0 }, }; -const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { +const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] = { [NOP] = { .nuops = 1, .uops = { { NOP, 0, 0 } } }, [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } }, [LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } }, @@ -1294,7 +1306,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; -const char * const _PyOpcode_uop_name[512] = { +const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [300] = "EXIT_TRACE", [301] = "SAVE_IP", [302] = "_POP_JUMP_IF_FALSE", diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 3e084928844d2f..7d9553d9e383a3 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -9,6 +9,70 @@ class OpcodeTests(unittest.TestCase): + def check_bool_function_result(self, func, ops, expected): + for op in ops: + if isinstance(op, str): + op = dis.opmap[op] + with self.subTest(opcode=op, func=func): + self.assertIsInstance(func(op), bool) + self.assertEqual(func(op), expected) + + def test_invalid_opcodes(self): + invalid = [-100, -1, 255, 512, 513, 1000] + self.check_bool_function_result(_opcode.is_valid, invalid, False) + self.check_bool_function_result(_opcode.has_arg, invalid, False) + self.check_bool_function_result(_opcode.has_const, invalid, False) + self.check_bool_function_result(_opcode.has_name, invalid, False) + self.check_bool_function_result(_opcode.has_jump, invalid, False) + + def test_is_valid(self): + names = [ + 'CACHE', + 'POP_TOP', + 'IMPORT_NAME', + 'JUMP', + 'INSTRUMENTED_RETURN_VALUE', + ] + opcodes = [dis.opmap[opname] for opname in names] + self.check_bool_function_result(_opcode.is_valid, opcodes, True) + + def test_has_arg(self): + has_arg = ['SWAP', 'LOAD_FAST', 'INSTRUMENTED_POP_JUMP_IF_TRUE', 'JUMP'] + no_arg = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_arg, has_arg, True) + self.check_bool_function_result(_opcode.has_arg, no_arg, False) + + def test_has_const(self): + has_const = ['LOAD_CONST', 'RETURN_CONST', 'KW_NAMES'] + no_const = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_const, has_const, True) + self.check_bool_function_result(_opcode.has_const, no_const, False) + + def test_has_name(self): + has_name = ['STORE_NAME', 'DELETE_ATTR', 'STORE_GLOBAL', 'IMPORT_FROM', + 'LOAD_FROM_DICT_OR_GLOBALS'] + no_name = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_name, has_name, True) + self.check_bool_function_result(_opcode.has_name, no_name, False) + + def test_has_jump(self): + has_jump = ['FOR_ITER', 'JUMP_FORWARD', 'JUMP', 'POP_JUMP_IF_TRUE', 'SEND'] + no_jump = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_jump, has_jump, True) + self.check_bool_function_result(_opcode.has_jump, no_jump, False) + + # the following test is part of the refactor, it will be removed soon + def test_against_legacy_bool_values(self): + # limiting to ops up to ENTER_EXECUTOR, because everything after that + # is not currently categorized correctly in opcode.py. + for op in range(0, opcode.opmap['ENTER_EXECUTOR']): + with self.subTest(op=op): + if opcode.opname[op] != f'<{op}>': + self.assertEqual(op in dis.hasarg, _opcode.has_arg(op)) + self.assertEqual(op in dis.hasconst, _opcode.has_const(op)) + self.assertEqual(op in dis.hasname, _opcode.has_name(op)) + self.assertEqual(op in dis.hasjrel, _opcode.has_jump(op)) + def test_stack_effect(self): self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 3c0fce48770ac4..f7b11773fe8880 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -1,6 +1,9 @@ #include "Python.h" #include "opcode.h" #include "internal/pycore_code.h" +#define NEED_OPCODE_METADATA +#include "internal/pycore_opcode_metadata.h" +#undef NEED_OPCODE_METADATA /*[clinic input] module _opcode @@ -59,6 +62,87 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg, return effect; } +/*[clinic input] + +_opcode.is_valid -> bool + + opcode: int + +Return True if opcode is valid, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_is_valid_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=b0d918ea1d073f65 input=fe23e0aa194ddae0]*/ +{ + return IS_VALID_OPCODE(opcode); +} + +/*[clinic input] + +_opcode.has_arg -> bool + + opcode: int + +Return True if the opcode uses its oparg, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_arg_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=7a062d3b2dcc0815 input=93d878ba6361db5f]*/ +{ + return IS_VALID_OPCODE(opcode) && OPCODE_HAS_ARG(opcode); +} + +/*[clinic input] + +_opcode.has_const -> bool + + opcode: int + +Return True if the opcode accesses a constant, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_const_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=c646d5027c634120 input=a6999e4cf13f9410]*/ +{ + return IS_VALID_OPCODE(opcode) && OPCODE_HAS_CONST(opcode); +} + +/*[clinic input] + +_opcode.has_name -> bool + + opcode: int + +Return True if the opcode accesses an attribute by name, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_name_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=b49a83555c2fa517 input=448aa5e4bcc947ba]*/ +{ + return IS_VALID_OPCODE(opcode) && OPCODE_HAS_NAME(opcode); +} + +/*[clinic input] + +_opcode.has_jump -> bool + + opcode: int + +Return True if the opcode has a jump target, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_jump_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=e9c583c669f1c46a input=35f711274357a0c3]*/ +{ + return IS_VALID_OPCODE(opcode) && OPCODE_HAS_JUMP(opcode); +} + + /*[clinic input] _opcode.get_specialization_stats @@ -80,6 +164,11 @@ _opcode_get_specialization_stats_impl(PyObject *module) static PyMethodDef opcode_functions[] = { _OPCODE_STACK_EFFECT_METHODDEF + _OPCODE_IS_VALID_METHODDEF + _OPCODE_HAS_ARG_METHODDEF + _OPCODE_HAS_CONST_METHODDEF + _OPCODE_HAS_NAME_METHODDEF + _OPCODE_HAS_JUMP_METHODDEF _OPCODE_GET_SPECIALIZATION_STATS_METHODDEF {NULL, NULL, 0, NULL} }; diff --git a/Modules/clinic/_opcode.c.h b/Modules/clinic/_opcode.c.h index 3bd3ba02387435..3eb050e470c343 100644 --- a/Modules/clinic/_opcode.c.h +++ b/Modules/clinic/_opcode.c.h @@ -86,6 +86,321 @@ _opcode_stack_effect(PyObject *module, PyObject *const *args, Py_ssize_t nargs, return return_value; } +PyDoc_STRVAR(_opcode_is_valid__doc__, +"is_valid($module, /, opcode)\n" +"--\n" +"\n" +"Return True if opcode is valid, False otherwise."); + +#define _OPCODE_IS_VALID_METHODDEF \ + {"is_valid", _PyCFunction_CAST(_opcode_is_valid), METH_FASTCALL|METH_KEYWORDS, _opcode_is_valid__doc__}, + +static int +_opcode_is_valid_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_is_valid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_valid", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_is_valid_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_arg__doc__, +"has_arg($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode uses its oparg, False otherwise."); + +#define _OPCODE_HAS_ARG_METHODDEF \ + {"has_arg", _PyCFunction_CAST(_opcode_has_arg), METH_FASTCALL|METH_KEYWORDS, _opcode_has_arg__doc__}, + +static int +_opcode_has_arg_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_arg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_arg", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_arg_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_const__doc__, +"has_const($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode accesses a constant, False otherwise."); + +#define _OPCODE_HAS_CONST_METHODDEF \ + {"has_const", _PyCFunction_CAST(_opcode_has_const), METH_FASTCALL|METH_KEYWORDS, _opcode_has_const__doc__}, + +static int +_opcode_has_const_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_const(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_const", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_const_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_name__doc__, +"has_name($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode accesses an attribute by name, False otherwise."); + +#define _OPCODE_HAS_NAME_METHODDEF \ + {"has_name", _PyCFunction_CAST(_opcode_has_name), METH_FASTCALL|METH_KEYWORDS, _opcode_has_name__doc__}, + +static int +_opcode_has_name_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_name(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_name", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_name_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_jump__doc__, +"has_jump($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode has a jump target, False otherwise."); + +#define _OPCODE_HAS_JUMP_METHODDEF \ + {"has_jump", _PyCFunction_CAST(_opcode_has_jump), METH_FASTCALL|METH_KEYWORDS, _opcode_has_jump__doc__}, + +static int +_opcode_has_jump_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_jump(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_jump", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_jump_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_opcode_get_specialization_stats__doc__, "get_specialization_stats($module, /)\n" "--\n" @@ -103,4 +418,4 @@ _opcode_get_specialization_stats(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _opcode_get_specialization_stats_impl(module); } -/*[clinic end generated code: output=21e3d53a659c651a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ae2b2ef56d582180 input=a9049054013a1b77]*/ diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a20abcde85b7c7..b6643363fd3656 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1202,6 +1202,8 @@ def write_metadata(self) -> None: self.write_provenance_header() + self.out.emit("\n#include ") + self.write_pseudo_instrs() self.out.emit("") @@ -1212,8 +1214,16 @@ def write_metadata(self) -> None: # Write type definitions self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") + self.out.emit("") + self.out.emit( + "#define IS_VALID_OPCODE(OP) \\\n" + " (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \\\n" + " (_PyOpcode_opcode_metadata[(OP)].valid_entry))") + + self.out.emit("") InstructionFlags.emit_macros(self.out) + self.out.emit("") with self.out.block("struct opcode_metadata", ";"): self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") @@ -1236,13 +1246,20 @@ def write_metadata(self) -> None: self.out.emit("") # Write metadata array declaration + self.out.emit("#define OPCODE_METADATA_SIZE 512") + self.out.emit("#define OPCODE_UOP_NAME_SIZE 512") + self.out.emit("#define OPCODE_MACRO_EXPANSION_SIZE 256") + self.out.emit("") self.out.emit("#ifndef NEED_OPCODE_METADATA") - self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];") - self.out.emit("extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];") - self.out.emit("extern const char * const _PyOpcode_uop_name[512];") + self.out.emit("extern const struct opcode_metadata " + "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE];") + self.out.emit("extern const struct opcode_macro_expansion " + "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE];") + self.out.emit("extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE];") self.out.emit("#else // if NEED_OPCODE_METADATA") - self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {") + self.out.emit("const struct opcode_metadata " + "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {") # Write metadata for each instruction for thing in self.everything: @@ -1263,7 +1280,8 @@ def write_metadata(self) -> None: self.out.emit("};") with self.out.block( - "const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] =", + "const struct opcode_macro_expansion " + "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] =", ";", ): # Write macro expansion for each non-pseudo instruction @@ -1289,7 +1307,7 @@ def write_metadata(self) -> None: case _: typing.assert_never(thing) - with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"): + with self.out.block("const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] =", ";"): self.write_uop_items(lambda name, counter: f"[{counter}] = \"{name}\",") self.out.emit("#endif // NEED_OPCODE_METADATA") From ba367b2ad265e03ca037031bed41a4eace592821 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 12 Jul 2023 21:35:15 +0100 Subject: [PATCH 2/8] compile.c needs metadata, flowgraph doesn't --- Python/compile.c | 2 ++ Python/flowgraph.c | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index d9e38cfdefaf23..52d2818e5d0af5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -36,7 +36,9 @@ #include "pycore_pystate.h" // _Py_GetConfig() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() +#define NEED_OPCODE_METADATA #include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed +#undef NEED_OPCODE_METADATA #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 04f269c5853835..e485ed103147a1 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -7,9 +7,7 @@ #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_opcode_utils.h" -#define NEED_OPCODE_METADATA -#include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed -#undef NEED_OPCODE_METADATA +#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc #undef SUCCESS From b354891fac871d2bc04819abd5ef597af25284bc Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 13 Jul 2023 11:36:18 +0100 Subject: [PATCH 3/8] add PyUnstable_OpcodeMetadata so Modules/ can get metadata --- Include/cpython/compile.h | 1 + Include/internal/pycore_opcode_metadata.h | 12 ++++++------ Modules/_opcode.c | 3 +-- Python/compile.c | 6 ++++++ Tools/cases_generator/generate_cases.py | 6 +++--- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Include/cpython/compile.h b/Include/cpython/compile.h index f5a62a8ec6dd0c..1a3be34907d006 100644 --- a/Include/cpython/compile.h +++ b/Include/cpython/compile.h @@ -67,3 +67,4 @@ typedef struct { #define PY_INVALID_STACK_EFFECT INT_MAX PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump); +PyAPI_FUNC(struct opcode_metadata) PyUnstable_OpcodeMetadata(int opcode); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 0dd3d649e4db30..1c74aec2473333 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -932,16 +932,16 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define IS_VALID_OPCODE(OP) \ (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \ - (_PyOpcode_opcode_metadata[(OP)].valid_entry)) + (PyUnstable_OpcodeMetadata(OP).valid_entry)) #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) #define HAS_JUMP_FLAG (8) -#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_ARG_FLAG)) -#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG)) -#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG)) -#define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_JUMP_FLAG)) +#define OPCODE_HAS_ARG(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_ARG_FLAG)) +#define OPCODE_HAS_CONST(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_CONST_FLAG)) +#define OPCODE_HAS_NAME(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_NAME_FLAG)) +#define OPCODE_HAS_JUMP(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_JUMP_FLAG)) struct opcode_metadata { bool valid_entry; @@ -961,7 +961,7 @@ struct opcode_macro_expansion { #define OPARG_TOP 5 #define OPARG_BOTTOM 6 -#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) +#define OPCODE_METADATA_FMT(OP) (PyUnstable_OpcodeMetadata(OP).instr_format) #define SAME_OPCODE_METADATA(OP1, OP2) \ (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2)) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index f7b11773fe8880..436db66a897892 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -1,9 +1,8 @@ #include "Python.h" +#include "compile.h" #include "opcode.h" #include "internal/pycore_code.h" -#define NEED_OPCODE_METADATA #include "internal/pycore_opcode_metadata.h" -#undef NEED_OPCODE_METADATA /*[clinic input] module _opcode diff --git a/Python/compile.c b/Python/compile.c index 52d2818e5d0af5..d46fe2b2511601 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -866,6 +866,12 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return stack_effect(opcode, oparg, -1); } +struct opcode_metadata +PyUnstable_OpcodeMetadata(int opcode) +{ + return _PyOpcode_opcode_metadata[opcode]; +} + static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index b6643363fd3656..570650baa1669b 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -308,7 +308,7 @@ def emit_macros(cls, out: Formatter): for name, value in flags.bitmask.items(): out.emit( f"#define OPCODE_{name[:-len('_FLAG')]}(OP) " - f"(_PyOpcode_opcode_metadata[(OP)].flags & ({name}))") + f"(PyUnstable_OpcodeMetadata(OP).flags & ({name}))") @dataclasses.dataclass @@ -1218,7 +1218,7 @@ def write_metadata(self) -> None: self.out.emit( "#define IS_VALID_OPCODE(OP) \\\n" " (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \\\n" - " (_PyOpcode_opcode_metadata[(OP)].valid_entry))") + " (PyUnstable_OpcodeMetadata(OP).valid_entry))") self.out.emit("") InstructionFlags.emit_macros(self.out) @@ -1240,7 +1240,7 @@ def write_metadata(self) -> None: self.out.emit("") self.out.emit("#define OPCODE_METADATA_FMT(OP) " - "(_PyOpcode_opcode_metadata[(OP)].instr_format)") + "(PyUnstable_OpcodeMetadata(OP).instr_format)") self.out.emit("#define SAME_OPCODE_METADATA(OP1, OP2) \\") self.out.emit(" (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2))") self.out.emit("") From 8f15de894c7be3a205ff1708c448c24cfb0c52e2 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 13 Jul 2023 16:04:22 +0100 Subject: [PATCH 4/8] add news --- .../next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst b/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst new file mode 100644 index 00000000000000..6d0493d633c29c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst @@ -0,0 +1 @@ +Expose opcode metadat though :mod:`_opcode`. From 63fabee66318a97b684b1809d12d038ecd96f3b0 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 14 Jul 2023 10:10:50 +0100 Subject: [PATCH 5/8] don't expose opcode_metadata --- Include/cpython/compile.h | 7 +++++- Include/internal/pycore_opcode_metadata.h | 12 ++++----- Modules/_opcode.c | 16 +++++++----- Python/compile.c | 30 ++++++++++++++++++++--- Tools/cases_generator/generate_cases.py | 6 ++--- 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Include/cpython/compile.h b/Include/cpython/compile.h index 1a3be34907d006..cd7fd7bd377663 100644 --- a/Include/cpython/compile.h +++ b/Include/cpython/compile.h @@ -67,4 +67,9 @@ typedef struct { #define PY_INVALID_STACK_EFFECT INT_MAX PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump); -PyAPI_FUNC(struct opcode_metadata) PyUnstable_OpcodeMetadata(int opcode); + +PyAPI_FUNC(int) PyUnstable_OpcodeIsValid(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasArg(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasConst(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasName(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasJump(int opcode); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index d0d62a28fd43d8..ece761aa25c729 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -938,16 +938,16 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define IS_VALID_OPCODE(OP) \ (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \ - (PyUnstable_OpcodeMetadata(OP).valid_entry)) + (_PyOpcode_opcode_metadata[OP].valid_entry)) #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) #define HAS_JUMP_FLAG (8) -#define OPCODE_HAS_ARG(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_ARG_FLAG)) -#define OPCODE_HAS_CONST(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_CONST_FLAG)) -#define OPCODE_HAS_NAME(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_NAME_FLAG)) -#define OPCODE_HAS_JUMP(OP) (PyUnstable_OpcodeMetadata(OP).flags & (HAS_JUMP_FLAG)) +#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) +#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) +#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) +#define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_JUMP_FLAG)) struct opcode_metadata { bool valid_entry; @@ -967,7 +967,7 @@ struct opcode_macro_expansion { #define OPARG_TOP 5 #define OPARG_BOTTOM 6 -#define OPCODE_METADATA_FMT(OP) (PyUnstable_OpcodeMetadata(OP).instr_format) +#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[OP].instr_format) #define SAME_OPCODE_METADATA(OP1, OP2) \ (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2)) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 436db66a897892..eb25b41ddb2193 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -74,7 +74,7 @@ static int _opcode_is_valid_impl(PyObject *module, int opcode) /*[clinic end generated code: output=b0d918ea1d073f65 input=fe23e0aa194ddae0]*/ { - return IS_VALID_OPCODE(opcode); + return PyUnstable_OpcodeIsValid(opcode); } /*[clinic input] @@ -90,7 +90,8 @@ static int _opcode_has_arg_impl(PyObject *module, int opcode) /*[clinic end generated code: output=7a062d3b2dcc0815 input=93d878ba6361db5f]*/ { - return IS_VALID_OPCODE(opcode) && OPCODE_HAS_ARG(opcode); + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasArg(opcode); } /*[clinic input] @@ -106,7 +107,8 @@ static int _opcode_has_const_impl(PyObject *module, int opcode) /*[clinic end generated code: output=c646d5027c634120 input=a6999e4cf13f9410]*/ { - return IS_VALID_OPCODE(opcode) && OPCODE_HAS_CONST(opcode); + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasConst(opcode); } /*[clinic input] @@ -122,7 +124,8 @@ static int _opcode_has_name_impl(PyObject *module, int opcode) /*[clinic end generated code: output=b49a83555c2fa517 input=448aa5e4bcc947ba]*/ { - return IS_VALID_OPCODE(opcode) && OPCODE_HAS_NAME(opcode); + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasName(opcode); } /*[clinic input] @@ -138,9 +141,10 @@ static int _opcode_has_jump_impl(PyObject *module, int opcode) /*[clinic end generated code: output=e9c583c669f1c46a input=35f711274357a0c3]*/ { - return IS_VALID_OPCODE(opcode) && OPCODE_HAS_JUMP(opcode); -} + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasJump(opcode); +} /*[clinic input] diff --git a/Python/compile.c b/Python/compile.c index d46fe2b2511601..9e86e06777ffa4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -866,10 +866,34 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return stack_effect(opcode, oparg, -1); } -struct opcode_metadata -PyUnstable_OpcodeMetadata(int opcode) +int +PyUnstable_OpcodeIsValid(int opcode) +{ + return IS_VALID_OPCODE(opcode); +} + +int +PyUnstable_OpcodeHasArg(int opcode) +{ + return OPCODE_HAS_ARG(opcode); +} + +int +PyUnstable_OpcodeHasConst(int opcode) +{ + return OPCODE_HAS_CONST(opcode); +} + +int +PyUnstable_OpcodeHasName(int opcode) +{ + return OPCODE_HAS_NAME(opcode); +} + +int +PyUnstable_OpcodeHasJump(int opcode) { - return _PyOpcode_opcode_metadata[opcode]; + return OPCODE_HAS_JUMP(opcode); } static int diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 570650baa1669b..0d1efd9d5dd92d 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -308,7 +308,7 @@ def emit_macros(cls, out: Formatter): for name, value in flags.bitmask.items(): out.emit( f"#define OPCODE_{name[:-len('_FLAG')]}(OP) " - f"(PyUnstable_OpcodeMetadata(OP).flags & ({name}))") + f"(_PyOpcode_opcode_metadata[OP].flags & ({name}))") @dataclasses.dataclass @@ -1218,7 +1218,7 @@ def write_metadata(self) -> None: self.out.emit( "#define IS_VALID_OPCODE(OP) \\\n" " (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \\\n" - " (PyUnstable_OpcodeMetadata(OP).valid_entry))") + " (_PyOpcode_opcode_metadata[OP].valid_entry))") self.out.emit("") InstructionFlags.emit_macros(self.out) @@ -1240,7 +1240,7 @@ def write_metadata(self) -> None: self.out.emit("") self.out.emit("#define OPCODE_METADATA_FMT(OP) " - "(PyUnstable_OpcodeMetadata(OP).instr_format)") + "(_PyOpcode_opcode_metadata[OP].instr_format)") self.out.emit("#define SAME_OPCODE_METADATA(OP1, OP2) \\") self.out.emit(" (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2))") self.out.emit("") From 517f7b12e00a8d606fb5e60c73288ae54f68797f Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 14 Jul 2023 12:41:01 +0100 Subject: [PATCH 6/8] typos --- .../next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst b/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst index 6d0493d633c29c..bc2ba51d31aa9c 100644 --- a/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst +++ b/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst @@ -1 +1 @@ -Expose opcode metadat though :mod:`_opcode`. +Expose opcode metadata through :mod:`_opcode`. From ca88100fedbd429fbffe28a2fee576df891134c6 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 14 Jul 2023 12:56:27 +0100 Subject: [PATCH 7/8] remove unused #include --- Modules/_opcode.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_opcode.c b/Modules/_opcode.c index eb25b41ddb2193..b3b9873d21a5be 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -2,7 +2,6 @@ #include "compile.h" #include "opcode.h" #include "internal/pycore_code.h" -#include "internal/pycore_opcode_metadata.h" /*[clinic input] module _opcode From c2f33ceb941c3b174a2bd934ce907d2b45afcd30 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 14 Jul 2023 12:59:25 +0100 Subject: [PATCH 8/8] revert unintended change --- Include/internal/pycore_opcode_metadata.h | 4 ++-- Tools/cases_generator/generate_cases.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index aebbbe8b38afb9..8373f56653b1c7 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -946,7 +946,7 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define IS_VALID_OPCODE(OP) \ (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \ - (_PyOpcode_opcode_metadata[OP].valid_entry)) + (_PyOpcode_opcode_metadata[(OP)].valid_entry)) #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) @@ -975,7 +975,7 @@ struct opcode_macro_expansion { #define OPARG_TOP 5 #define OPARG_BOTTOM 6 -#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[OP].instr_format) +#define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) #define SAME_OPCODE_METADATA(OP1, OP2) \ (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2)) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 2afd3a286f849a..6589289121863b 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1208,7 +1208,7 @@ def write_metadata(self) -> None: self.out.emit( "#define IS_VALID_OPCODE(OP) \\\n" " (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \\\n" - " (_PyOpcode_opcode_metadata[OP].valid_entry))") + " (_PyOpcode_opcode_metadata[(OP)].valid_entry))") self.out.emit("") InstructionFlags.emit_macros(self.out) @@ -1230,7 +1230,7 @@ def write_metadata(self) -> None: self.out.emit("") self.out.emit("#define OPCODE_METADATA_FMT(OP) " - "(_PyOpcode_opcode_metadata[OP].instr_format)") + "(_PyOpcode_opcode_metadata[(OP)].instr_format)") self.out.emit("#define SAME_OPCODE_METADATA(OP1, OP2) \\") self.out.emit(" (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2))") self.out.emit("")