]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-105481: reduce repetition in opcode metadata generation code (#107942)
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Mon, 14 Aug 2023 18:36:29 +0000 (19:36 +0100)
committerGitHub <noreply@github.com>
Mon, 14 Aug 2023 18:36:29 +0000 (18:36 +0000)
Include/internal/pycore_opcode_metadata.h
Tools/cases_generator/generate_cases.py

index 9f4437c09e92cbf8fa796dce3f94b6574029fece..c0a2e9d91c4f49e330d1c52ed07334370131c3c5 100644 (file)
 #define _POP_JUMP_IF_TRUE 332
 #define JUMP_TO_TOP 333
 
-#ifndef NEED_OPCODE_METADATA
 extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
-#else
-int
-_PyOpcode_num_popped(int opcode, int oparg, bool jump) {
+#ifdef NEED_OPCODE_METADATA
+int _PyOpcode_num_popped(int opcode, int oparg, bool jump)  {
     switch(opcode) {
         case NOP:
             return 0;
@@ -500,13 +498,11 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
             return -1;
     }
 }
-#endif
+#endif // NEED_OPCODE_METADATA
 
-#ifndef NEED_OPCODE_METADATA
 extern int _PyOpcode_num_pushed(int opcode, int oparg, bool jump);
-#else
-int
-_PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
+#ifdef NEED_OPCODE_METADATA
+int _PyOpcode_num_pushed(int opcode, int oparg, bool jump)  {
     switch(opcode) {
         case NOP:
             return 0;
@@ -946,7 +942,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
             return -1;
     }
 }
-#endif
+#endif // NEED_OPCODE_METADATA
 
 enum InstructionFormat {
     INSTR_FMT_IB,
@@ -1004,11 +1000,8 @@ struct opcode_macro_expansion {
 #define OPCODE_UOP_NAME_SIZE 512
 #define OPCODE_MACRO_EXPANSION_SIZE 256
 
-#ifndef NEED_OPCODE_METADATA
 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
+#ifdef NEED_OPCODE_METADATA
 const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
     [NOP] = { true, INSTR_FMT_IX, 0 },
     [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
@@ -1228,6 +1221,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
     [CACHE] = { true, INSTR_FMT_IX, 0 },
     [RESERVED] = { true, INSTR_FMT_IX, 0 },
 };
+#endif // NEED_OPCODE_METADATA
+
+extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE];
+#ifdef NEED_OPCODE_METADATA
 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 } } },
@@ -1357,6 +1354,10 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } },
     [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } },
 };
+#endif // NEED_OPCODE_METADATA
+
+extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE];
+#ifdef NEED_OPCODE_METADATA
 const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
     [EXIT_TRACE] = "EXIT_TRACE",
     [SAVE_IP] = "SAVE_IP",
index d35a16a80e8d007b7ded5b629f18e0e52b075142..e78b0edff9a0c8952204704d773dfd2e4bc44093 100644 (file)
@@ -4,6 +4,7 @@ Writes the cases to generated_cases.c.h, which is #included in ceval.c.
 """
 
 import argparse
+import contextlib
 import os
 import posixpath
 import sys
@@ -141,6 +142,15 @@ class Generator(Analyzer):
                 typing.assert_never(thing)
         return instr, popped, pushed
 
+    @contextlib.contextmanager
+    def metadata_item(self, signature, open, close):
+        self.out.emit("")
+        self.out.emit(f"extern {signature};")
+        self.out.emit("#ifdef NEED_OPCODE_METADATA")
+        with self.out.block(f"{signature} {open}", close):
+            yield
+        self.out.emit("#endif // NEED_OPCODE_METADATA")
+
     def write_stack_effect_functions(self) -> None:
         popped_data: list[tuple[AnyInstruction, str]] = []
         pushed_data: list[tuple[AnyInstruction, str]] = []
@@ -156,25 +166,16 @@ class Generator(Analyzer):
         def write_function(
             direction: str, data: list[tuple[AnyInstruction, str]]
         ) -> None:
-            self.out.emit("")
-            self.out.emit("#ifndef NEED_OPCODE_METADATA")
-            self.out.emit(
-                f"extern int _PyOpcode_num_{direction}(int opcode, int oparg, bool jump);"
-            )
-            self.out.emit("#else")
-            self.out.emit("int")
-            self.out.emit(
-                f"_PyOpcode_num_{direction}(int opcode, int oparg, bool jump) {{"
-            )
-            self.out.emit("    switch(opcode) {")
-            for instr, effect in data:
-                self.out.emit(f"        case {instr.name}:")
-                self.out.emit(f"            return {effect};")
-            self.out.emit("        default:")
-            self.out.emit("            return -1;")
-            self.out.emit("    }")
-            self.out.emit("}")
-            self.out.emit("#endif")
+
+            with self.metadata_item(
+                f"int _PyOpcode_num_{direction}(int opcode, int oparg, bool jump)", "", ""
+            ):
+                with self.out.block("switch(opcode)"):
+                    for instr, effect in data:
+                        self.out.emit(f"case {instr.name}:")
+                        self.out.emit(f"    return {effect};")
+                    self.out.emit("default:")
+                    self.out.emit("    return -1;")
 
         write_function("popped", popped_data)
         write_function("pushed", pushed_data)
@@ -290,48 +291,33 @@ class Generator(Analyzer):
             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[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(
+            with self.metadata_item(
                 "const struct opcode_metadata "
-                "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {"
-            )
-
-            # Write metadata for each instruction
-            for thing in self.everything:
-                match thing:
-                    case OverriddenInstructionPlaceHolder():
-                        continue
-                    case parsing.InstDef():
-                        if thing.kind != "op":
-                            self.write_metadata_for_inst(self.instrs[thing.name])
-                    case parsing.Macro():
-                        self.write_metadata_for_macro(self.macro_instrs[thing.name])
-                    case parsing.Pseudo():
-                        self.write_metadata_for_pseudo(self.pseudo_instrs[thing.name])
-                    case _:
-                        typing.assert_never(thing)
-
-            # Write end of array
-            self.out.emit("};")
+                "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE]",
+                "=",
+                ";"
+            ):
+                # Write metadata for each instruction
+                for thing in self.everything:
+                    match thing:
+                        case OverriddenInstructionPlaceHolder():
+                            continue
+                        case parsing.InstDef():
+                            if thing.kind != "op":
+                                self.write_metadata_for_inst(self.instrs[thing.name])
+                        case parsing.Macro():
+                            self.write_metadata_for_macro(self.macro_instrs[thing.name])
+                        case parsing.Pseudo():
+                            self.write_metadata_for_pseudo(self.pseudo_instrs[thing.name])
+                        case _:
+                            typing.assert_never(thing)
 
-            with self.out.block(
+            with self.metadata_item(
                 "const struct opcode_macro_expansion "
-                "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] =",
-                ";",
+                "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE]",
+                "=",
+                ";"
             ):
                 # Write macro expansion for each non-pseudo instruction
                 for thing in self.everything:
@@ -360,13 +346,11 @@ class Generator(Analyzer):
                         case _:
                             typing.assert_never(thing)
 
-            with self.out.block(
-                "const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] =", ";"
+            with self.metadata_item(
+                "const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]", "=", ";"
             ):
                 self.write_uop_items(lambda name, counter: f'[{name}] = "{name}",')
 
-            self.out.emit("#endif // NEED_OPCODE_METADATA")
-
         with open(pymetadata_filename, "w") as f:
             # Create formatter
             self.out = Formatter(f, 0, comment="#")
@@ -511,7 +495,7 @@ class Generator(Analyzer):
         if not flag_names:
             flag_names.append("0")
         self.out.emit(
-            f"    [{name}] = {{ true, {INSTR_FMT_PREFIX}{fmt},"
+            f"[{name}] = {{ true, {INSTR_FMT_PREFIX}{fmt},"
             f" {' | '.join(flag_names)} }},"
         )