Skip to content

Commit fde5f18

Browse files
committed
Allow arbitrary annotations on instructions and micro-ops. Use one to declare specializing micro-ops
1 parent d49aba5 commit fde5f18

File tree

10 files changed

+74
-80
lines changed

10 files changed

+74
-80
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_generated_cases.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -666,12 +666,9 @@ def test_macro_push_push(self):
666666
"""
667667
self.run_cases_test(input, output)
668668

669-
def test_override_inst(self):
669+
def test_annotated_inst(self):
670670
input = """
671-
inst(OP, (--)) {
672-
spam();
673-
}
674-
override inst(OP, (--)) {
671+
annotation inst(OP, (--)) {
675672
ham();
676673
}
677674
"""
@@ -686,22 +683,19 @@ def test_override_inst(self):
686683
"""
687684
self.run_cases_test(input, output)
688685

689-
def test_override_op(self):
686+
def test_annotated_op(self):
690687
input = """
691-
op(OP, (--)) {
688+
annotation op(OP, (--)) {
692689
spam();
693690
}
694691
macro(M) = OP;
695-
override op(OP, (--)) {
696-
ham();
697-
}
698692
"""
699693
output = """
700694
TARGET(M) {
701695
frame->instr_ptr = next_instr;
702696
next_instr += 1;
703697
INSTRUCTION_STATS(M);
704-
ham();
698+
spam();
705699
DISPATCH();
706700
}
707701
"""

Python/abstract_interp_cases.c.h

Lines changed: 0 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
#define family(name, ...) static int family_##name
5151
#define pseudo(name) static int pseudo_##name
5252

53+
/* Annotations */
54+
#define guard
55+
#define specializing
56+
5357
// Dummy variables for stack effects.
5458
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
5559
static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2;
@@ -312,7 +316,7 @@ dummy_func(
312316
TO_BOOL_STR,
313317
};
314318

315-
op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) {
319+
specializing op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) {
316320
TIER_ONE_ONLY
317321
#if ENABLE_SPECIALIZATION
318322
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -537,7 +541,7 @@ dummy_func(
537541
BINARY_SUBSCR_TUPLE_INT,
538542
};
539543

540-
op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) {
544+
specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) {
541545
TIER_ONE_ONLY
542546
#if ENABLE_SPECIALIZATION
543547
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -689,7 +693,7 @@ dummy_func(
689693
STORE_SUBSCR_LIST_INT,
690694
};
691695

692-
op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) {
696+
specializing op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) {
693697
TIER_ONE_ONLY
694698
#if ENABLE_SPECIALIZATION
695699
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -974,7 +978,7 @@ dummy_func(
974978
SEND_GEN,
975979
};
976980

977-
op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
981+
specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
978982
TIER_ONE_ONLY
979983
#if ENABLE_SPECIALIZATION
980984
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1208,7 +1212,7 @@ dummy_func(
12081212
UNPACK_SEQUENCE_LIST,
12091213
};
12101214

1211-
op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) {
1215+
specializing op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) {
12121216
#if ENABLE_SPECIALIZATION
12131217
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
12141218
next_instr = this_instr;
@@ -1277,7 +1281,7 @@ dummy_func(
12771281
STORE_ATTR_WITH_HINT,
12781282
};
12791283

1280-
op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) {
1284+
specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) {
12811285
TIER_ONE_ONLY
12821286
#if ENABLE_SPECIALIZATION
12831287
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1404,7 +1408,7 @@ dummy_func(
14041408
LOAD_GLOBAL_BUILTIN,
14051409
};
14061410

1407-
op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) {
1411+
specializing op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) {
14081412
TIER_ONE_ONLY
14091413
#if ENABLE_SPECIALIZATION
14101414
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1744,7 +1748,7 @@ dummy_func(
17441748
LOAD_SUPER_ATTR_METHOD,
17451749
};
17461750

1747-
op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super, class, unused -- global_super, class, unused)) {
1751+
specializing op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super, class, unused -- global_super, class, unused)) {
17481752
TIER_ONE_ONLY
17491753
#if ENABLE_SPECIALIZATION
17501754
int load_method = oparg & 1;
@@ -1860,7 +1864,7 @@ dummy_func(
18601864
LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
18611865
};
18621866

1863-
op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
1867+
specializing op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
18641868
TIER_ONE_ONLY
18651869
#if ENABLE_SPECIALIZATION
18661870
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -2182,7 +2186,7 @@ dummy_func(
21822186
COMPARE_OP_STR,
21832187
};
21842188

2185-
op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
2189+
specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
21862190
TIER_ONE_ONLY
21872191
#if ENABLE_SPECIALIZATION
21882192
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -2506,7 +2510,7 @@ dummy_func(
25062510
FOR_ITER_GEN,
25072511
};
25082512

2509-
op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
2513+
specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
25102514
TIER_ONE_ONLY
25112515
#if ENABLE_SPECIALIZATION
25122516
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -3001,7 +3005,7 @@ dummy_func(
30013005
CALL_ALLOC_AND_ENTER_INIT,
30023006
};
30033007

3004-
op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
3008+
specializing op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
30053009
TIER_ONE_ONLY
30063010
#if ENABLE_SPECIALIZATION
30073011
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -3866,7 +3870,7 @@ dummy_func(
38663870
top = Py_NewRef(bottom);
38673871
}
38683872

3869-
op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) {
3873+
specializing op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) {
38703874
TIER_ONE_ONLY
38713875
#if ENABLE_SPECIALIZATION
38723876
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {

Python/executor_cases.c.h

Lines changed: 0 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/analysis.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,20 +139,12 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None:
139139
match thing:
140140
case parsing.InstDef(name=name):
141141
macro: parsing.Macro | None = None
142-
if thing.kind == "inst" and not thing.override:
142+
if thing.kind == "inst":
143143
macro = parsing.Macro(name, [parsing.OpName(name)])
144144
if name in self.instrs:
145-
if not thing.override:
146-
raise psr.make_syntax_error(
147-
f"Duplicate definition of '{name}' @ {thing.context} "
148-
f"previous definition @ {self.instrs[name].inst.context}",
149-
thing_first_token,
150-
)
151-
self.everything[instrs_idx[name]] = thing
152-
if name not in self.instrs and thing.override:
153145
raise psr.make_syntax_error(
154-
f"Definition of '{name}' @ {thing.context} is supposed to be "
155-
"an override but no previous definition exists.",
146+
f"Duplicate definition of '{name}' @ {thing.context} "
147+
f"previous definition @ {self.instrs[name].inst.context}",
156148
thing_first_token,
157149
)
158150
self.instrs[name] = Instruction(thing)

Tools/cases_generator/generate_cases.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,10 @@ def write_macro_expansions(
651651
expansions: list[tuple[str, int, int]] = [] # [(name, size, offset), ...]
652652
for part in parts:
653653
if isinstance(part, Component):
654-
# All component instructions must be viable uops
654+
# Skip specializations
655+
if part.instr.annotation == "specializing":
656+
continue
657+
# All other component instructions must be viable uops
655658
if not part.instr.is_viable_uop():
656659
# This note just reminds us about macros that cannot
657660
# be expanded to Tier 2 uops. It is not an error.

Tools/cases_generator/instructions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Instruction:
4646
# Parts of the underlying instruction definition
4747
inst: parsing.InstDef
4848
name: str
49+
annotation: str | None
4950
block: parsing.Block
5051
block_text: list[str] # Block.text, less curlies, less PREDICT() calls
5152
block_line: int # First line of block in original code
@@ -70,6 +71,7 @@ class Instruction:
7071
def __init__(self, inst: parsing.InstDef):
7172
self.inst = inst
7273
self.name = inst.name
74+
self.annotation = inst.annotation
7375
self.block = inst.block
7476
self.block_text, self.check_eval_breaker, self.block_line = extract_block_text(
7577
self.block
@@ -118,6 +120,8 @@ def is_viable_uop(self) -> bool:
118120

119121
if self.name == "_EXIT_TRACE":
120122
return True # This has 'return frame' but it's okay
123+
if self.name == "_SAVE_RETURN_OFFSET":
124+
return True # Adjusts next_instr, but only in tier 1 code
121125
if self.always_exits:
122126
dprint(f"Skipping {self.name} because it always exits: {self.always_exits}")
123127
return False

Tools/cases_generator/lexer.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,12 @@ def choice(*opts: str) -> str:
8080

8181
# Macros
8282
macro = r"# *(ifdef|ifndef|undef|define|error|endif|if|else|include|#)"
83-
MACRO = "MACRO"
83+
CMACRO = "CMACRO"
8484

8585
id_re = r"[a-zA-Z_][0-9a-zA-Z_]*"
8686
IDENTIFIER = "IDENTIFIER"
8787

88+
8889
suffix = r"([uU]?[lL]?[lL]?)"
8990
octal = r"0[0-7]+" + suffix
9091
hex = r"0[xX][0-9a-fA-F]+"
@@ -173,8 +174,6 @@ def choice(*opts: str) -> str:
173174
kwds.append(INT)
174175
LONG = "LONG"
175176
kwds.append(LONG)
176-
OVERRIDE = "OVERRIDE"
177-
kwds.append(OVERRIDE)
178177
REGISTER = "REGISTER"
179178
kwds.append(REGISTER)
180179
OFFSETOF = "OFFSETOF"
@@ -207,8 +206,20 @@ def choice(*opts: str) -> str:
207206
kwds.append(VOLATILE)
208207
WHILE = "WHILE"
209208
kwds.append(WHILE)
209+
#An instruction in the DSL
210+
INST = "INST"
211+
kwds.append(INST)
212+
#A micro-op in the DSL
213+
OP = "OP"
214+
kwds.append(OP)
215+
#A macro in the DSL
216+
MACRO = "MACRO"
217+
kwds.append(MACRO)
210218
keywords = {name.lower(): name for name in kwds}
211219

220+
ANNOTATION = "ANNOTATION"
221+
annotations = {"specializing", "guard"}
222+
212223
__all__ = []
213224
__all__.extend(kwds)
214225

@@ -270,6 +281,8 @@ def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[T
270281
text = m.group(0)
271282
if text in keywords:
272283
kind = keywords[text]
284+
elif text in annotations:
285+
kind = ANNOTATION
273286
elif letter.match(text):
274287
kind = IDENTIFIER
275288
elif text == "...":
@@ -289,7 +302,7 @@ def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[T
289302
elif text[0] == "'":
290303
kind = CHARACTER
291304
elif text[0] == "#":
292-
kind = MACRO
305+
kind = CMACRO
293306
elif text[0] == "/" and text[1] in "/*":
294307
kind = COMMENT
295308
else:

0 commit comments

Comments
 (0)