gh-104909: Split some more insts into ops (#109943)

These are the most popular specializations of `LOAD_ATTR` and `STORE_ATTR`
that weren't already viable uops:

* Split LOAD_ATTR_METHOD_WITH_VALUES
* Split LOAD_ATTR_METHOD_NO_DICT
* Split LOAD_ATTR_SLOT
* Split STORE_ATTR_SLOT
* Split STORE_ATTR_INSTANCE_VALUE

Also:

* Add `-v` flag to code generator which prints a list of non-viable uops
  (easter-egg: it can print execution counts -- see source)
* Double _Py_UOP_MAX_TRACE_LENGTH to 128



I had dropped one of the DEOPT_IF() calls! :-(
This commit is contained in:
Guido van Rossum 2023-09-27 15:27:44 -07:00 committed by GitHub
parent 45cf5b0c69
commit 5bb6f0fcba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 519 additions and 115 deletions

View file

@ -414,3 +414,61 @@ def check_macro_components(
case _:
assert_never(uop)
return components
def report_non_viable_uops(self, jsonfile: str) -> None:
print("The following ops are not viable uops:")
skips = {
"CACHE",
"RESERVED",
"INTERPRETER_EXIT",
"JUMP_BACKWARD",
"LOAD_FAST_LOAD_FAST",
"LOAD_CONST_LOAD_FAST",
"STORE_FAST_STORE_FAST",
"_BINARY_OP_INPLACE_ADD_UNICODE",
"POP_JUMP_IF_TRUE",
"POP_JUMP_IF_FALSE",
"_ITER_JUMP_LIST",
"_ITER_JUMP_TUPLE",
"_ITER_JUMP_RANGE",
}
try:
# Secret feature: if bmraw.json exists, print and sort by execution count
counts = load_execution_counts(jsonfile)
except FileNotFoundError as err:
counts = {}
non_viable = [
instr
for instr in self.instrs.values()
if instr.name not in skips
and not instr.name.startswith("INSTRUMENTED_")
and not instr.is_viable_uop()
]
non_viable.sort(key=lambda instr: (-counts.get(instr.name, 0), instr.name))
for instr in non_viable:
if instr.name in counts:
scount = f"{counts[instr.name]:,}"
else:
scount = ""
print(f" {scount:>15} {instr.name:<35}", end="")
if instr.name in self.families:
print(" (unspecialized)", end="")
elif instr.family is not None:
print(f" (specialization of {instr.family.name})", end="")
print()
def load_execution_counts(jsonfile: str) -> dict[str, int]:
import json
with open(jsonfile) as f:
jsondata = json.load(f)
# Look for keys like "opcode[LOAD_FAST].execution_count"
prefix = "opcode["
suffix = "].execution_count"
res: dict[str, int] = {}
for key, value in jsondata.items():
if key.startswith(prefix) and key.endswith(suffix):
res[key[len(prefix) : -len(suffix)]] = value
return res

View file

@ -92,6 +92,13 @@
description="Generate the code for the interpreter switch.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
arg_parser.add_argument(
"-v",
"--verbose",
help="Print list of non-viable uops and exit",
action="store_true",
)
arg_parser.add_argument(
"-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT
)
@ -865,6 +872,10 @@ def main() -> None:
a.analyze() # Prints messages and sets a.errors on failure
if a.errors:
sys.exit(f"Found {a.errors} errors")
if args.verbose:
# Load execution counts from bmraw.json, if it exists
a.report_non_viable_uops("bmraw.json")
return
# These raise OSError if output can't be written
a.write_instructions(args.output, args.emit_line_directives)