Skip to content

Commit

Permalink
pythonGH-111485: Allow arbitrary annotations on instructions and micr…
Browse files Browse the repository at this point in the history
…o-ops. (pythonGH-111697)
  • Loading branch information
markshannon committed Nov 7, 2023
1 parent 13405ec commit 931f443
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 63 deletions.
10 changes: 9 additions & 1 deletion Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions Lib/test/test_generated_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,49 @@ def test_override_op(self):
"""
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()
4 changes: 0 additions & 4 deletions Python/abstract_interp_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 18 additions & 13 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
#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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down
18 changes: 0 additions & 18 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Tools/cases_generator/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,17 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None:
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.",
Expand Down
5 changes: 4 additions & 1 deletion Tools/cases_generator/generate_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,10 @@ def write_macro_expansions(
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.
Expand Down
4 changes: 4 additions & 0 deletions Tools/cases_generator/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -118,6 +120,8 @@ def is_viable_uop(self) -> bool:

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
Expand Down

0 comments on commit 931f443

Please sign in to comment.