]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-112519: Make it possible to specify instruction flags for pseudo instructions...
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Thu, 30 Nov 2023 11:03:30 +0000 (11:03 +0000)
committerGitHub <noreply@github.com>
Thu, 30 Nov 2023 11:03:30 +0000 (11:03 +0000)
Include/internal/pycore_opcode_metadata.h
Lib/test/test_generated_cases.py
Python/bytecodes.c
Python/flowgraph.c
Tools/cases_generator/analysis.py
Tools/cases_generator/parsing.py

index 4e45725d3934796a1f09973c684fdc36d791b1d0..4ae15e71e8d31820f6ba923ace366bbe1f4100fc 100644 (file)
@@ -1661,7 +1661,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
     [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
-    [JUMP] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG },
+    [JUMP] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [JUMP_NO_INTERRUPT] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG },
     [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG },
     [_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
@@ -1703,9 +1703,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
     [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [BEFORE_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
-    [SETUP_FINALLY] = { true, 0, 0 },
-    [SETUP_CLEANUP] = { true, 0, 0 },
-    [SETUP_WITH] = { true, 0, 0 },
+    [SETUP_FINALLY] = { true, 0, HAS_ARG_FLAG },
+    [SETUP_CLEANUP] = { true, 0, HAS_ARG_FLAG },
+    [SETUP_WITH] = { true, 0, HAS_ARG_FLAG },
     [POP_BLOCK] = { true, 0, 0 },
     [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
     [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
index 98a8fff4268746dd56f2bfde26403ed20ce9ed3d..de96a8764594bae24cce8208814f618a45556492 100644 (file)
@@ -466,6 +466,44 @@ class TestGeneratedCases(unittest.TestCase):
     """
         self.run_cases_test(input, output)
 
+    def test_pseudo_instruction_no_flags(self):
+        input = """
+        pseudo(OP) = {
+            OP1,
+        };
+
+        inst(OP1, (--)) {
+        }
+    """
+        output = """
+        TARGET(OP1) {
+            frame->instr_ptr = next_instr;
+            next_instr += 1;
+            INSTRUCTION_STATS(OP1);
+            DISPATCH();
+        }
+    """
+        self.run_cases_test(input, output)
+
+    def test_pseudo_instruction_with_flags(self):
+        input = """
+        pseudo(OP, (HAS_ARG, HAS_JUMP)) = {
+            OP1,
+        };
+
+        inst(OP1, (--)) {
+        }
+    """
+        output = """
+        TARGET(OP1) {
+            frame->instr_ptr = next_instr;
+            next_instr += 1;
+            INSTRUCTION_STATS(OP1);
+            DISPATCH();
+        }
+    """
+        self.run_cases_test(input, output)
+
     def test_array_input(self):
         input = """
         inst(OP, (below, values[oparg*2], above --)) {
index 2e5f6c8d0d10e2c898541393b644fa17c0b4f9d0..2075c195df3d3835993d3e96aa59c4e84e384443 100644 (file)
@@ -2831,15 +2831,15 @@ dummy_func(
             ERROR_IF(res == NULL, error);
         }
 
-        pseudo(SETUP_FINALLY) = {
+        pseudo(SETUP_FINALLY, (HAS_ARG)) = {
             NOP,
         };
 
-        pseudo(SETUP_CLEANUP) = {
+        pseudo(SETUP_CLEANUP, (HAS_ARG)) = {
             NOP,
         };
 
-        pseudo(SETUP_WITH) = {
+        pseudo(SETUP_WITH, (HAS_ARG)) = {
             NOP,
         };
 
index 87401e14f97f02af7d231d4875870ad50a099cb7..fe632082d5a66c92e3386b65719a169f755b7bd9 100644 (file)
@@ -97,6 +97,7 @@ static const jump_target_label NO_LABEL = {-1};
 static inline int
 is_block_push(cfg_instr *i)
 {
+    assert(OPCODE_HAS_ARG(i->i_opcode) || !IS_BLOCK_PUSH_OPCODE(i->i_opcode));
     return IS_BLOCK_PUSH_OPCODE(i->i_opcode);
 }
 
@@ -2239,7 +2240,6 @@ convert_pseudo_ops(basicblock *entryblock)
         for (int i = 0; i < b->b_iused; i++) {
             cfg_instr *instr = &b->b_instr[i];
             if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
-                assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP));
                 INSTR_SET_OP0(instr, NOP);
             }
             else if (instr->i_opcode == LOAD_CLOSURE) {
index 603b15596f16def1d9ef5334f3a30fd0a83b5307..26d92c13cd82ab1641a62d929e3be5d7a2fd1c15 100644 (file)
@@ -390,9 +390,14 @@ class Analyzer:
             else:
                 targets.append(self.macro_instrs[target_name])
         assert targets
-        ignored_flags = {"HAS_EVAL_BREAK_FLAG", "HAS_DEOPT_FLAG", "HAS_ERROR_FLAG", "HAS_ESCAPES_FLAG"}
+        ignored_flags = {"HAS_EVAL_BREAK_FLAG", "HAS_DEOPT_FLAG", "HAS_ERROR_FLAG",
+                          "HAS_ESCAPES_FLAG"}
         assert len({t.instr_flags.bitmap(ignore=ignored_flags) for t in targets}) == 1
-        return PseudoInstruction(pseudo.name, targets, targets[0].instr_flags)
+
+        flags = InstructionFlags(**{f"{f}_FLAG" : True for f in pseudo.flags})
+        for t in targets:
+            flags.add(t.instr_flags)
+        return PseudoInstruction(pseudo.name, targets, flags)
 
     def analyze_instruction(
         self, instr: Instruction, offset: int
index d36bd52b022ea94c2ea5fbd441c35fb7cd2eabe3..7800adf16794bbaf5c9b5abc06c7f2d6276a1614 100644 (file)
@@ -138,7 +138,8 @@ class Family(Node):
 @dataclass
 class Pseudo(Node):
     name: str
-    targets: list[str]  # opcodes this can be replaced by
+    flags: list[str]   # instr flags to set on the pseudo instruction
+    targets: list[str] # opcodes this can be replaced by
 
 
 class Parser(PLexer):
@@ -374,19 +375,39 @@ class Parser(PLexer):
                                     )
         return None
 
+    def flags(self) -> list[str]:
+        here = self.getpos()
+        if self.expect(lx.LPAREN):
+            if tkn := self.expect(lx.IDENTIFIER):
+                flags = [tkn.text]
+                while self.expect(lx.COMMA):
+                    if tkn := self.expect(lx.IDENTIFIER):
+                        flags.append(tkn.text)
+                    else:
+                        break
+                if not self.expect(lx.RPAREN):
+                    raise self.make_syntax_error("Expected comma or right paren")
+                return flags
+        self.setpos(here)
+        return []
+
     @contextual
     def pseudo_def(self) -> Pseudo | None:
         if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "pseudo":
             size = None
             if self.expect(lx.LPAREN):
                 if tkn := self.expect(lx.IDENTIFIER):
+                    if self.expect(lx.COMMA):
+                        flags = self.flags()
+                    else:
+                        flags = []
                     if self.expect(lx.RPAREN):
                         if self.expect(lx.EQUALS):
                             if not self.expect(lx.LBRACE):
                                 raise self.make_syntax_error("Expected {")
                             if members := self.members():
                                 if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
-                                    return Pseudo(tkn.text, members)
+                                    return Pseudo(tkn.text, flags, members)
         return None
 
     def members(self) -> list[str] | None: