Skip to content

Commit f977a5c

Browse files
markshannonGlyphack
authored andcommitted
pythonGH-111485: Allow arbitrary annotations on instructions and micro-ops. (pythonGH-111697)
1 parent 024393d commit f977a5c

File tree

10 files changed

+114
-63
lines changed

10 files changed

+114
-63
lines changed

Include/internal/pycore_opcode_metadata.h

+9-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_generated_cases.py

+43
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,49 @@ def test_override_op(self):
707707
"""
708708
self.run_cases_test(input, output)
709709

710+
def test_annotated_inst(self):
711+
input = """
712+
guard inst(OP, (--)) {
713+
ham();
714+
}
715+
"""
716+
output = """
717+
TARGET(OP) {
718+
frame->instr_ptr = next_instr;
719+
next_instr += 1;
720+
INSTRUCTION_STATS(OP);
721+
ham();
722+
DISPATCH();
723+
}
724+
"""
725+
self.run_cases_test(input, output)
726+
727+
def test_annotated_op(self):
728+
input = """
729+
guard op(OP, (--)) {
730+
spam();
731+
}
732+
macro(M) = OP;
733+
"""
734+
output = """
735+
TARGET(M) {
736+
frame->instr_ptr = next_instr;
737+
next_instr += 1;
738+
INSTRUCTION_STATS(M);
739+
spam();
740+
DISPATCH();
741+
}
742+
"""
743+
self.run_cases_test(input, output)
744+
745+
input = """
746+
guard register specializing op(OP, (--)) {
747+
spam();
748+
}
749+
macro(M) = OP;
750+
"""
751+
self.run_cases_test(input, output)
752+
710753

711754
if __name__ == "__main__":
712755
unittest.main()

Python/abstract_interp_cases.c.h

-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

+18-13
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
#define family(name, ...) static int family_##name
5151
#define pseudo(name) static int pseudo_##name
5252

53+
/* Annotations */
54+
#define guard
55+
#define override
56+
#define specializing
57+
5358
// Dummy variables for stack effects.
5459
static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub;
5560
static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2;
@@ -312,7 +317,7 @@ dummy_func(
312317
TO_BOOL_STR,
313318
};
314319

315-
op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) {
320+
specializing op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) {
316321
TIER_ONE_ONLY
317322
#if ENABLE_SPECIALIZATION
318323
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -537,7 +542,7 @@ dummy_func(
537542
BINARY_SUBSCR_TUPLE_INT,
538543
};
539544

540-
op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) {
545+
specializing op(_SPECIALIZE_BINARY_SUBSCR, (counter/1, container, sub -- container, sub)) {
541546
TIER_ONE_ONLY
542547
#if ENABLE_SPECIALIZATION
543548
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -689,7 +694,7 @@ dummy_func(
689694
STORE_SUBSCR_LIST_INT,
690695
};
691696

692-
op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) {
697+
specializing op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) {
693698
TIER_ONE_ONLY
694699
#if ENABLE_SPECIALIZATION
695700
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -974,7 +979,7 @@ dummy_func(
974979
SEND_GEN,
975980
};
976981

977-
op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
982+
specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) {
978983
TIER_ONE_ONLY
979984
#if ENABLE_SPECIALIZATION
980985
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1208,7 +1213,7 @@ dummy_func(
12081213
UNPACK_SEQUENCE_LIST,
12091214
};
12101215

1211-
op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) {
1216+
specializing op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) {
12121217
#if ENABLE_SPECIALIZATION
12131218
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
12141219
next_instr = this_instr;
@@ -1277,7 +1282,7 @@ dummy_func(
12771282
STORE_ATTR_WITH_HINT,
12781283
};
12791284

1280-
op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) {
1285+
specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) {
12811286
TIER_ONE_ONLY
12821287
#if ENABLE_SPECIALIZATION
12831288
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1404,7 +1409,7 @@ dummy_func(
14041409
LOAD_GLOBAL_BUILTIN,
14051410
};
14061411

1407-
op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) {
1412+
specializing op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) {
14081413
TIER_ONE_ONLY
14091414
#if ENABLE_SPECIALIZATION
14101415
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -1744,7 +1749,7 @@ dummy_func(
17441749
LOAD_SUPER_ATTR_METHOD,
17451750
};
17461751

1747-
op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super, class, unused -- global_super, class, unused)) {
1752+
specializing op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super, class, unused -- global_super, class, unused)) {
17481753
TIER_ONE_ONLY
17491754
#if ENABLE_SPECIALIZATION
17501755
int load_method = oparg & 1;
@@ -1860,7 +1865,7 @@ dummy_func(
18601865
LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
18611866
};
18621867

1863-
op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
1868+
specializing op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
18641869
TIER_ONE_ONLY
18651870
#if ENABLE_SPECIALIZATION
18661871
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -2182,7 +2187,7 @@ dummy_func(
21822187
COMPARE_OP_STR,
21832188
};
21842189

2185-
op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
2190+
specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) {
21862191
TIER_ONE_ONLY
21872192
#if ENABLE_SPECIALIZATION
21882193
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -2506,7 +2511,7 @@ dummy_func(
25062511
FOR_ITER_GEN,
25072512
};
25082513

2509-
op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
2514+
specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
25102515
TIER_ONE_ONLY
25112516
#if ENABLE_SPECIALIZATION
25122517
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -3000,7 +3005,7 @@ dummy_func(
30003005
CALL_ALLOC_AND_ENTER_INIT,
30013006
};
30023007

3003-
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])) {
30043009
TIER_ONE_ONLY
30053010
#if ENABLE_SPECIALIZATION
30063011
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
@@ -3865,7 +3870,7 @@ dummy_func(
38653870
top = Py_NewRef(bottom);
38663871
}
38673872

3868-
op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) {
3873+
specializing op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) {
38693874
TIER_ONE_ONLY
38703875
#if ENABLE_SPECIALIZATION
38713876
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {

Python/executor_cases.c.h

-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/analysis.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,17 @@ 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" and "override" not in thing.annotations:
143143
macro = parsing.Macro(name, [parsing.OpName(name)])
144144
if name in self.instrs:
145-
if not thing.override:
145+
if "override" not in thing.annotations:
146146
raise psr.make_syntax_error(
147147
f"Duplicate definition of '{name}' @ {thing.context} "
148148
f"previous definition @ {self.instrs[name].inst.context}",
149149
thing_first_token,
150150
)
151151
self.everything[instrs_idx[name]] = thing
152-
if name not in self.instrs and thing.override:
152+
if name not in self.instrs and "override" in thing.annotations:
153153
raise psr.make_syntax_error(
154154
f"Definition of '{name}' @ {thing.context} is supposed to be "
155155
"an override but no previous definition exists.",

Tools/cases_generator/generate_cases.py

+4-1
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 "specializing" in part.instr.annotations:
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

+4
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+
annotations: list[str]
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.annotations = inst.annotations
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

0 commit comments

Comments
 (0)