summaryrefslogtreecommitdiffstats
path: root/Tools/cases_generator
diff options
context:
space:
mode:
authorKirill Podoprigora <kirill.bast9@mail.ru>2024-02-23 17:31:57 (GMT)
committerGitHub <noreply@github.com>2024-02-23 17:31:57 (GMT)
commite4561e050148f6dc347e8c7ba30c8125b5fc0e45 (patch)
tree4df655662a8fc71c8e8497b6f3517d72ea22d4b4 /Tools/cases_generator
parent59057ce55a443f35bfd685c688071aebad7b3671 (diff)
downloadcpython-e4561e050148f6dc347e8c7ba30c8125b5fc0e45.zip
cpython-e4561e050148f6dc347e8c7ba30c8125b5fc0e45.tar.gz
cpython-e4561e050148f6dc347e8c7ba30c8125b5fc0e45.tar.bz2
gh-115778: Add `tierN` annotation for instruction definitions (#115815)
This replaces the old `TIER_{ONE,TWO}_ONLY` macros. Note that `specialized` implies `tier1`. Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Diffstat (limited to 'Tools/cases_generator')
-rw-r--r--Tools/cases_generator/analyzer.py15
-rw-r--r--Tools/cases_generator/interpreter_definition.md1
-rw-r--r--Tools/cases_generator/lexer.py2
-rw-r--r--Tools/cases_generator/opcode_metadata_generator.py2
-rw-r--r--Tools/cases_generator/tier2_abstract_generator.py2
-rw-r--r--Tools/cases_generator/tier2_generator.py2
-rw-r--r--Tools/cases_generator/uop_id_generator.py2
-rw-r--r--Tools/cases_generator/uop_metadata_generator.py4
8 files changed, 20 insertions, 10 deletions
diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py
index 49b8b42..b0a15e6 100644
--- a/Tools/cases_generator/analyzer.py
+++ b/Tools/cases_generator/analyzer.py
@@ -17,7 +17,6 @@ class Properties:
needs_this: bool
always_exits: bool
stores_sp: bool
- tier_one_only: bool
uses_co_consts: bool
uses_co_names: bool
uses_locals: bool
@@ -25,6 +24,7 @@ class Properties:
side_exit: bool
pure: bool
passthrough: bool
+ tier: int | None = None
oparg_and_1: bool = False
const_oparg: int = -1
@@ -46,7 +46,6 @@ class Properties:
needs_this=any(p.needs_this for p in properties),
always_exits=any(p.always_exits for p in properties),
stores_sp=any(p.stores_sp for p in properties),
- tier_one_only=any(p.tier_one_only for p in properties),
uses_co_consts=any(p.uses_co_consts for p in properties),
uses_co_names=any(p.uses_co_names for p in properties),
uses_locals=any(p.uses_locals for p in properties),
@@ -68,7 +67,6 @@ SKIP_PROPERTIES = Properties(
needs_this=False,
always_exits=False,
stores_sp=False,
- tier_one_only=False,
uses_co_consts=False,
uses_co_names=False,
uses_locals=False,
@@ -312,6 +310,15 @@ def variable_used(node: parser.InstDef, name: str) -> bool:
token.kind == "IDENTIFIER" and token.text == name for token in node.tokens
)
+def tier_variable(node: parser.InstDef) -> int | None:
+ """Determine whether a tier variable is used in a node."""
+ for token in node.tokens:
+ if token.kind == "ANNOTATION":
+ if token.text == "specializing":
+ return 1
+ if re.fullmatch(r"tier\d", token.text):
+ return int(token.text[-1])
+ return None
def is_infallible(op: parser.InstDef) -> bool:
return not (
@@ -498,7 +505,6 @@ def compute_properties(op: parser.InstDef) -> Properties:
needs_this=variable_used(op, "this_instr"),
always_exits=always_exits(op),
stores_sp=variable_used(op, "SYNC_SP"),
- tier_one_only=variable_used(op, "TIER_ONE_ONLY"),
uses_co_consts=variable_used(op, "FRAME_CO_CONSTS"),
uses_co_names=variable_used(op, "FRAME_CO_NAMES"),
uses_locals=(variable_used(op, "GETLOCAL") or variable_used(op, "SETLOCAL"))
@@ -506,6 +512,7 @@ def compute_properties(op: parser.InstDef) -> Properties:
has_free=has_free,
pure="pure" in op.annotations,
passthrough=passthrough,
+ tier=tier_variable(op),
)
diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md
index 9b57335..889f58f 100644
--- a/Tools/cases_generator/interpreter_definition.md
+++ b/Tools/cases_generator/interpreter_definition.md
@@ -168,6 +168,7 @@ list of annotations and their meanings are as follows:
* `override`. For external use by other interpreter definitions to override the current
instruction definition.
* `pure`. This instruction has no side effects.
+* 'tierN'. This instruction only used by tier N interpreter.
### Special functions/macros
diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py
index 0077921..13aee94 100644
--- a/Tools/cases_generator/lexer.py
+++ b/Tools/cases_generator/lexer.py
@@ -224,6 +224,8 @@ annotations = {
"pure",
"split",
"replicate",
+ "tier1",
+ "tier2",
}
__all__ = []
diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py
index 24fbea6..ab59783 100644
--- a/Tools/cases_generator/opcode_metadata_generator.py
+++ b/Tools/cases_generator/opcode_metadata_generator.py
@@ -284,7 +284,7 @@ def is_viable_expansion(inst: Instruction) -> bool:
continue
if "replaced" in part.annotations:
continue
- if part.properties.tier_one_only or not part.is_viable():
+ if part.properties.tier == 1 or not part.is_viable():
return False
return True
diff --git a/Tools/cases_generator/tier2_abstract_generator.py b/Tools/cases_generator/tier2_abstract_generator.py
index 47a8626..58c3110 100644
--- a/Tools/cases_generator/tier2_abstract_generator.py
+++ b/Tools/cases_generator/tier2_abstract_generator.py
@@ -176,7 +176,7 @@ def generate_abstract_interpreter(
if uop.name in abstract.uops:
override = abstract.uops[uop.name]
validate_uop(override, uop)
- if uop.properties.tier_one_only:
+ if uop.properties.tier == 1:
continue
if uop.replicates:
continue
diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py
index 6fbe5c3..d8eed10 100644
--- a/Tools/cases_generator/tier2_generator.py
+++ b/Tools/cases_generator/tier2_generator.py
@@ -194,7 +194,7 @@ def generate_tier2(
out = CWriter(outfile, 2, lines)
out.emit("\n")
for name, uop in analysis.uops.items():
- if uop.properties.tier_one_only:
+ if uop.properties.tier == 1:
continue
if uop.properties.oparg_and_1:
out.emit(f"/* {uop.name} is split on (oparg & 1) */\n\n")
diff --git a/Tools/cases_generator/uop_id_generator.py b/Tools/cases_generator/uop_id_generator.py
index 907158f..eb5e3f4 100644
--- a/Tools/cases_generator/uop_id_generator.py
+++ b/Tools/cases_generator/uop_id_generator.py
@@ -43,7 +43,7 @@ def generate_uop_ids(
for name, uop in sorted(uops):
if name in PRE_DEFINED:
continue
- if uop.properties.tier_one_only:
+ if uop.properties.tier == 1:
continue
if uop.implicitly_created and not distinct_namespace and not uop.replicated:
out.emit(f"#define {name} {name[1:]}\n")
diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py
index f85f1c6..72eed30 100644
--- a/Tools/cases_generator/uop_metadata_generator.py
+++ b/Tools/cases_generator/uop_metadata_generator.py
@@ -29,7 +29,7 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None:
out.emit("#ifdef NEED_OPCODE_METADATA\n")
out.emit("const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {\n")
for uop in analysis.uops.values():
- if uop.is_viable() and not uop.properties.tier_one_only:
+ if uop.is_viable() and uop.properties.tier != 1:
out.emit(f"[{uop.name}] = {cflags(uop.properties)},\n")
out.emit("};\n\n")
@@ -41,7 +41,7 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None:
out.emit("};\n\n")
out.emit("const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = {\n")
for uop in sorted(analysis.uops.values(), key=lambda t: t.name):
- if uop.is_viable() and not uop.properties.tier_one_only:
+ if uop.is_viable() and uop.properties.tier != 1:
out.emit(f'[{uop.name}] = "{uop.name}",\n')
out.emit("};\n")
out.emit("#endif // NEED_OPCODE_METADATA\n\n")