]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-111485: Allow arbitrary annotations on instructions and micro-ops. (GH-111697)
authorMark Shannon <mark@hotpy.org>
Tue, 7 Nov 2023 09:42:39 +0000 (09:42 +0000)
committerGitHub <noreply@github.com>
Tue, 7 Nov 2023 09:42:39 +0000 (09:42 +0000)
Include/internal/pycore_opcode_metadata.h
Lib/test/test_generated_cases.py
Python/abstract_interp_cases.c.h
Python/bytecodes.c
Python/executor_cases.c.h
Tools/cases_generator/analysis.py
Tools/cases_generator/generate_cases.py
Tools/cases_generator/instructions.py
Tools/cases_generator/lexer.py
Tools/cases_generator/parsing.py

index 6d3bda6f1275ea8d8b21f7698a5a9795ad8f5f8b..5cfe8b1d00325a0239bfa630d08d0abbc672793d 100644 (file)
@@ -1771,6 +1771,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } },
     [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } },
     [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } },
+    [TO_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL, 0, 0 } } },
     [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { TO_BOOL_BOOL, 0, 0 } } },
     [TO_BOOL_INT] = { .nuops = 1, .uops = { { TO_BOOL_INT, 0, 0 } } },
     [TO_BOOL_LIST] = { .nuops = 1, .uops = { { TO_BOOL_LIST, 0, 0 } } },
@@ -1785,6 +1786,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } },
     [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } },
     [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } },
+    [BINARY_SUBSCR] = { .nuops = 1, .uops = { { _BINARY_SUBSCR, 0, 0 } } },
     [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } },
     [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } },
     [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } },
@@ -1793,6 +1795,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } },
     [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } },
     [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } },
+    [STORE_SUBSCR] = { .nuops = 1, .uops = { { _STORE_SUBSCR, 0, 0 } } },
     [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } },
     [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } },
     [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } },
@@ -1808,17 +1811,19 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { LOAD_BUILD_CLASS, 0, 0 } } },
     [STORE_NAME] = { .nuops = 1, .uops = { { STORE_NAME, 0, 0 } } },
     [DELETE_NAME] = { .nuops = 1, .uops = { { DELETE_NAME, 0, 0 } } },
-    [UNPACK_SEQUENCE] = { .nuops = 2, .uops = { { _SPECIALIZE_UNPACK_SEQUENCE, 1, 0 }, { _UNPACK_SEQUENCE, 0, 0 } } },
+    [UNPACK_SEQUENCE] = { .nuops = 1, .uops = { { _UNPACK_SEQUENCE, 0, 0 } } },
     [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TWO_TUPLE, 0, 0 } } },
     [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } },
     [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } },
     [UNPACK_EX] = { .nuops = 1, .uops = { { UNPACK_EX, 0, 0 } } },
+    [STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, 0, 0 } } },
     [DELETE_ATTR] = { .nuops = 1, .uops = { { DELETE_ATTR, 0, 0 } } },
     [STORE_GLOBAL] = { .nuops = 1, .uops = { { STORE_GLOBAL, 0, 0 } } },
     [DELETE_GLOBAL] = { .nuops = 1, .uops = { { DELETE_GLOBAL, 0, 0 } } },
     [LOAD_LOCALS] = { .nuops = 1, .uops = { { LOAD_LOCALS, 0, 0 } } },
     [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } },
     [LOAD_NAME] = { .nuops = 1, .uops = { { LOAD_NAME, 0, 0 } } },
+    [LOAD_GLOBAL] = { .nuops = 1, .uops = { { _LOAD_GLOBAL, 0, 0 } } },
     [LOAD_GLOBAL_MODULE] = { .nuops = 2, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _LOAD_GLOBAL_MODULE, 1, 3 } } },
     [LOAD_GLOBAL_BUILTIN] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION, 1, 2 }, { _LOAD_GLOBAL_BUILTINS, 1, 3 } } },
     [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } },
@@ -1842,6 +1847,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [MAP_ADD] = { .nuops = 1, .uops = { { MAP_ADD, 0, 0 } } },
     [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } },
     [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } },
+    [LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, 0, 0 } } },
     [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } },
     [LOAD_ATTR_MODULE] = { .nuops = 2, .uops = { { _CHECK_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, 1, 3 } } },
     [LOAD_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_WITH_HINT, 0, 0 }, { _LOAD_ATTR_WITH_HINT, 1, 3 } } },
@@ -1849,6 +1855,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [LOAD_ATTR_CLASS] = { .nuops = 2, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 } } },
     [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES, 0, 0 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } },
     [STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } },
+    [COMPARE_OP] = { .nuops = 1, .uops = { { _COMPARE_OP, 0, 0 } } },
     [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } },
     [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } },
     [COMPARE_OP_STR] = { .nuops = 1, .uops = { { COMPARE_OP_STR, 0, 0 } } },
@@ -1895,6 +1902,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
     [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { FORMAT_SIMPLE, 0, 0 } } },
     [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { FORMAT_WITH_SPEC, 0, 0 } } },
     [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } },
+    [BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, 0, 0 } } },
     [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } },
 };
 #endif // NEED_OPCODE_METADATA
index ea0c11621a2ca933a708aaef3a92bc1c89b84372..585be642f0427d1a3f58742c8a8f48c6308d5159 100644 (file)
@@ -707,6 +707,49 @@ class TestGeneratedCases(unittest.TestCase):
         """
         self.run_cases_test(input, output)
 
+    def test_annotated_inst(self):
+        input = """
+        guard inst(OP, (--)) {
+            ham();
+        }
+        """
+        output = """
+        TARGET(OP) {
+            frame->instr_ptr = next_instr;
+            next_instr += 1;
+            INSTRUCTION_STATS(OP);
+            ham();
+            DISPATCH();
+        }
+        """
+        self.run_cases_test(input, output)
+
+    def test_annotated_op(self):
+        input = """
+        guard op(OP, (--)) {
+            spam();
+        }
+        macro(M) = OP;
+        """
+        output = """
+        TARGET(M) {
+            frame->instr_ptr = next_instr;
+            next_instr += 1;
+            INSTRUCTION_STATS(M);
+            spam();
+            DISPATCH();
+        }
+        """
+        self.run_cases_test(input, output)
+
+        input = """
+        guard register specializing op(OP, (--)) {
+            spam();
+        }
+        macro(M) = OP;
+        """
+        self.run_cases_test(input, output)
+
 
 if __name__ == "__main__":
     unittest.main()
index c80b5ecbebf1be7ce73c9e13598b6dbbe33b4c31..c6ebea024c3cd219f6087d43c7bc1f30ba98bd38 100644 (file)
             break;
         }
 
-        case _SPECIALIZE_UNPACK_SEQUENCE: {
-            break;
-        }
-
         case _UNPACK_SEQUENCE: {
             STACK_SHRINK(1);
             STACK_GROW(oparg);
index 7c8ee7b976dda10cfa45fd07ad014de355f085d4..8e1d318f195936a4ceef64e996e34c1afcb18d7c 100644 (file)
 #define family(name, ...) static int family_##name
 #define pseudo(name) static int pseudo_##name
 
+/* Annotations */
+#define guard
+#define override
+#define specializing
+
 // Dummy variables for stack effects.
 static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
 static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2;
@@ -312,7 +317,7 @@ dummy_func(
             TO_BOOL_STR,
         };
 
-        op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) {
+        specializing op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -537,7 +542,7 @@ dummy_func(
             BINARY_SUBSCR_TUPLE_INT,
         };
 
-        op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) {
+        specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -689,7 +694,7 @@ dummy_func(
             STORE_SUBSCR_LIST_INT,
         };
 
-        op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) {
+        specializing op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -974,7 +979,7 @@ dummy_func(
             SEND_GEN,
         };
 
-        op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
+        specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1208,7 +1213,7 @@ dummy_func(
             UNPACK_SEQUENCE_LIST,
         };
 
-        op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) {
+        specializing op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) {
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
                 next_instr = this_instr;
@@ -1277,7 +1282,7 @@ dummy_func(
             STORE_ATTR_WITH_HINT,
         };
 
-        op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) {
+        specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1404,7 +1409,7 @@ dummy_func(
             LOAD_GLOBAL_BUILTIN,
         };
 
-        op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) {
+        specializing op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1744,7 +1749,7 @@ dummy_func(
             LOAD_SUPER_ATTR_METHOD,
         };
 
-        op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super, class, unused -- global_super, class, unused)) {
+        specializing op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super, class, unused -- global_super, class, unused)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             int load_method = oparg & 1;
@@ -1860,7 +1865,7 @@ dummy_func(
             LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
         };
 
-        op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
+        specializing op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -2182,7 +2187,7 @@ dummy_func(
             COMPARE_OP_STR,
         };
 
-        op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
+        specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -2506,7 +2511,7 @@ dummy_func(
             FOR_ITER_GEN,
         };
 
-        op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
+        specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -3000,7 +3005,7 @@ dummy_func(
             CALL_ALLOC_AND_ENTER_INIT,
         };
 
-        op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
+        specializing op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -3865,7 +3870,7 @@ dummy_func(
             top = Py_NewRef(bottom);
         }
 
-        op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) {
+        specializing op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) {
             TIER_ONE_ONLY
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
index df7ddf2ded1d195a07f49fb907e0760502352231..d9e9ad133de5089cb1d5b6b59668d428088cf09b 100644 (file)
             break;
         }
 
-        case _SPECIALIZE_UNPACK_SEQUENCE: {
-            PyObject *seq;
-            seq = stack_pointer[-1];
-            uint16_t counter = (uint16_t)next_uop[-1].operand;
-            #if ENABLE_SPECIALIZATION
-            if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
-                next_instr = this_instr;
-                _Py_Specialize_UnpackSequence(seq, next_instr, oparg);
-                DISPATCH_SAME_OPARG();
-            }
-            STAT_INC(UNPACK_SEQUENCE, deferred);
-            DECREMENT_ADAPTIVE_COUNTER(this_instr[1].cache);
-            #endif  /* ENABLE_SPECIALIZATION */
-            (void)seq;
-            (void)counter;
-            break;
-        }
-
         case _UNPACK_SEQUENCE: {
             PyObject *seq;
             seq = stack_pointer[-1];
index bd08e9de481e093aa81c510625c9ca29e238a782..ee93b881d884bf86977c9d53c3706c668b1c59ed 100644 (file)
@@ -139,17 +139,17 @@ class Analyzer:
             match thing:
                 case parsing.InstDef(name=name):
                     macro: parsing.Macro | None = None
-                    if thing.kind == "inst" and not thing.override:
+                    if thing.kind == "inst" and "override" not in thing.annotations:
                         macro = parsing.Macro(name, [parsing.OpName(name)])
                     if name in self.instrs:
-                        if not thing.override:
+                        if "override" not in thing.annotations:
                             raise psr.make_syntax_error(
                                 f"Duplicate definition of '{name}' @ {thing.context} "
                                 f"previous definition @ {self.instrs[name].inst.context}",
                                 thing_first_token,
                             )
                         self.everything[instrs_idx[name]] = thing
-                    if name not in self.instrs and thing.override:
+                    if name not in self.instrs and "override" in thing.annotations:
                         raise psr.make_syntax_error(
                             f"Definition of '{name}' @ {thing.context} is supposed to be "
                             "an override but no previous definition exists.",
index 54bd51885d978588118e051a2d1cf03f34ab8a75..a3313b4929afc4e6d5a1b9a7458ae5c4679d2223 100644 (file)
@@ -651,7 +651,10 @@ class Generator(Analyzer):
         expansions: list[tuple[str, int, int]] = []  # [(name, size, offset), ...]
         for part in parts:
             if isinstance(part, Component):
-                # All component instructions must be viable uops
+                # Skip specializations
+                if "specializing" in part.instr.annotations:
+                    continue
+                # All other component instructions must be viable uops
                 if not part.instr.is_viable_uop():
                     # This note just reminds us about macros that cannot
                     # be expanded to Tier 2 uops. It is not an error.
index f3e4f76697853b69710b0c45823ddd747296f75c..181d8badf7bf22707eb93ffd2747690422c8b5cb 100644 (file)
@@ -46,6 +46,7 @@ class Instruction:
     # Parts of the underlying instruction definition
     inst: parsing.InstDef
     name: str
+    annotations: list[str]
     block: parsing.Block
     block_text: list[str]  # Block.text, less curlies, less PREDICT() calls
     block_line: int  # First line of block in original code
@@ -70,6 +71,7 @@ class Instruction:
     def __init__(self, inst: parsing.InstDef):
         self.inst = inst
         self.name = inst.name
+        self.annotations = inst.annotations
         self.block = inst.block
         self.block_text, self.check_eval_breaker, self.block_line = extract_block_text(
             self.block
@@ -118,6 +120,8 @@ class Instruction:
 
         if self.name == "_EXIT_TRACE":
             return True  # This has 'return frame' but it's okay
+        if self.name == "_SAVE_RETURN_OFFSET":
+            return True  # Adjusts next_instr, but only in tier 1 code
         if self.always_exits:
             dprint(f"Skipping {self.name} because it always exits: {self.always_exits}")
             return False
index a60f6c11a4c4607ec106086a9c05fa300d185b4b..4c5403dc1d1fa8b8a58dcb9eeb2cf92408610c45 100644 (file)
@@ -80,11 +80,12 @@ opmap = {pattern.replace("\\", "") or "\\": op for op, pattern in operators.item
 
 # Macros
 macro = r"# *(ifdef|ifndef|undef|define|error|endif|if|else|include|#)"
-MACRO = "MACRO"
+CMACRO = "CMACRO"
 
 id_re = r"[a-zA-Z_][0-9a-zA-Z_]*"
 IDENTIFIER = "IDENTIFIER"
 
+
 suffix = r"([uU]?[lL]?[lL]?)"
 octal = r"0[0-7]+" + suffix
 hex = r"0[xX][0-9a-fA-F]+"
@@ -173,10 +174,6 @@ INT = "INT"
 kwds.append(INT)
 LONG = "LONG"
 kwds.append(LONG)
-OVERRIDE = "OVERRIDE"
-kwds.append(OVERRIDE)
-REGISTER = "REGISTER"
-kwds.append(REGISTER)
 OFFSETOF = "OFFSETOF"
 kwds.append(OFFSETOF)
 RESTRICT = "RESTRICT"
@@ -207,8 +204,20 @@ VOLATILE = "VOLATILE"
 kwds.append(VOLATILE)
 WHILE = "WHILE"
 kwds.append(WHILE)
+# An instruction in the DSL
+INST = "INST"
+kwds.append(INST)
+# A micro-op in the DSL
+OP = "OP"
+kwds.append(OP)
+# A macro in the DSL
+MACRO = "MACRO"
+kwds.append(MACRO)
 keywords = {name.lower(): name for name in kwds}
 
+ANNOTATION = "ANNOTATION"
+annotations = {"specializing", "guard", "override", "register"}
+
 __all__ = []
 __all__.extend(kwds)
 
@@ -270,6 +279,8 @@ def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[T
         text = m.group(0)
         if text in keywords:
             kind = keywords[text]
+        elif text in annotations:
+            kind = ANNOTATION
         elif letter.match(text):
             kind = IDENTIFIER
         elif text == "...":
@@ -289,7 +300,7 @@ def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[T
         elif text[0] == "'":
             kind = CHARACTER
         elif text[0] == "#":
-            kind = MACRO
+            kind = CMACRO
         elif text[0] == "/" and text[1] in "/*":
             kind = COMMENT
         else:
index 25be5ca3e0da5d319036bca29cc6b9d416e44dc9..49459be68ae5e8f73813040792dc229254db3730 100644 (file)
@@ -105,8 +105,7 @@ UOp = OpName | CacheEffect
 
 @dataclass
 class InstHeader(Node):
-    override: bool
-    register: bool
+    annotations : list[str]
     kind: Literal["inst", "op"]
     name: str
     inputs: list[InputEffect]
@@ -115,8 +114,7 @@ class InstHeader(Node):
 
 @dataclass
 class InstDef(Node):
-    override: bool
-    register: bool
+    annotations : list[str]
     kind: Literal["inst", "op"]
     name: str
     inputs: list[InputEffect]
@@ -146,14 +144,14 @@ class Pseudo(Node):
 class Parser(PLexer):
     @contextual
     def definition(self) -> InstDef | Macro | Pseudo | Family | None:
-        if inst := self.inst_def():
-            return inst
         if macro := self.macro_def():
             return macro
         if family := self.family_def():
             return family
         if pseudo := self.pseudo_def():
             return pseudo
+        if inst := self.inst_def():
+            return inst
         return None
 
     @contextual
@@ -161,8 +159,7 @@ class Parser(PLexer):
         if hdr := self.inst_header():
             if block := self.block():
                 return InstDef(
-                    hdr.override,
-                    hdr.register,
+                    hdr.annotations,
                     hdr.kind,
                     hdr.name,
                     hdr.inputs,
@@ -174,13 +171,15 @@ class Parser(PLexer):
 
     @contextual
     def inst_header(self) -> InstHeader | None:
-        # [override] inst(NAME)
-        #   | [override] [register] inst(NAME, (inputs -- outputs))
-        #   | [override] [register] op(NAME, (inputs -- outputs))
-        # TODO: Make INST a keyword in the lexer.
-        override = bool(self.expect(lx.OVERRIDE))
-        register = bool(self.expect(lx.REGISTER))
-        if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text in ("inst", "op"):
+        # annotation* inst(NAME, (inputs -- outputs))
+        # | annotation* op(NAME, (inputs -- outputs))
+        annotations = []
+        while anno := self.expect(lx.ANNOTATION):
+            annotations.append(anno.text)
+        tkn = self.expect(lx.INST)
+        if not tkn:
+            tkn = self.expect(lx.OP)
+        if tkn:
             kind = cast(Literal["inst", "op"], tkn.text)
             if self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER)):
                 name = tkn.text
@@ -188,7 +187,7 @@ class Parser(PLexer):
                     inp, outp = self.io_effect()
                     if self.expect(lx.RPAREN):
                         if (tkn := self.peek()) and tkn.kind == lx.LBRACE:
-                            return InstHeader(override, register, kind, name, inp, outp)
+                            return InstHeader(annotations, kind, name, inp, outp)
         return None
 
     def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]:
@@ -312,7 +311,7 @@ class Parser(PLexer):
 
     @contextual
     def macro_def(self) -> Macro | None:
-        if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "macro":
+        if tkn := self.expect(lx.MACRO):
             if self.expect(lx.LPAREN):
                 if tkn := self.expect(lx.IDENTIFIER):
                     if self.expect(lx.RPAREN):