Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-111485: Break up instructions with unused cache entries into component micro-ops #113169

Merged
merged 8 commits into from
Dec 18, 2023

Conversation

markshannon
Copy link
Member

@markshannon markshannon commented Dec 15, 2023

Break up inst into more uops if they contain unused cache entries.

Ideally, micro-ops should not have unused cache entries. This PR implements that for inst declarations.

For example:

inst(TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) {
    DEOPT_IF(!PyBool_Check(value));
    STAT_INC(TO_BOOL, hit);
}

currently converts to:

op(_TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) ...
macro(TO_BOOL_BOOL) = _TO_BOOL_BOOL

With this PR it becomes:

op(_TO_BOOL_BOOL, (value -- value)) ...
macro(TO_BOOL_BOOL) = unused/1, unused/2, _TO_BOOL_BOOL

DISPATCH();
}
"""
self.run_cases_test(input, output)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this test is covering everything that changed in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not, it is just a smoke test.
The real test is that everything continues to work properly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it would be nice if there was a test that adds a /* Skip N cache entries */ comment where it wasn't before this PR, so we could see regressions around that. (I don't care about the singular/plural, but I care about it appearing at all.)

@@ -1444,6 +1463,8 @@
PyObject **args;
PyObject *self;
PyObject *callable;
/* Skip 1 cache entry */
/* Skip 2 cache entries */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it print only that second line?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source is inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused))
So it is skipping 1 entry, then skipping 2 entries.
We could combine them into /* Skip 3 cache entries */ but that would lose the structure, and I don't think it is worth the effort.

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG except I am mystified by the logic for unused in desugar_inst().

@@ -5711,6 +5781,7 @@
static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size");
PyObject *seq;
PyObject **values;
/* Skip 1 cache entry */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In summary, this PR doesn't change the generated cases except by adding some comments.

DISPATCH();
}
"""
self.run_cases_test(input, output)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it would be nice if there was a test that adds a /* Skip N cache entries */ comment where it wasn't before this PR, so we could see regressions around that. (I don't care about the singular/plural, but I care about it appearing at all.)

Comment on lines 350 to 368
op_inputs: list[parser.InputEffect] = []
parts: list[Part] = []
uop_index = -1
for input in inst.inputs:
if isinstance(input, parser.CacheEffect) and input.name == "unused":
parts.append(Skip(input.size))
else:
op_inputs.append(input)
if uop_index < 0:
uop_index = len(parts)
parts.append(Skip(0))
uop = make_uop("_" + inst.name, inst, op_inputs)
uop.implicitly_created = True
uops[inst.name] = uop
add_instruction(name, [uop], instructions)
if uop_index < 0:
parts.append(uop)
else:
parts[uop_index] = uop
add_instruction(name, parts, instructions)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something here feels so clever it needs a comment. and/or an assert We're adding a Skip(0) in L360 and overwriting that in L367. Could we ever add multiple Skip(0) entries? Then we'd be overwriting the first Skip(0) only. Probably my question makes no sense, and a comment would clarify that.

Separately, maybe Skip should have been named Unused? Or even UnusedCacheEffect? Because that's what it represents, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to add Skip(0) due to type constraints. The natural thing to add would be None, but the then we need to add casts, or messy types.

Skip skips over caches entries, so I think the name is better than Unused. We could add Cache though.
A bit out of scope for this PR, though.

@markshannon markshannon merged commit 70d378c into python:main Dec 18, 2023
38 checks passed
ryan-duve pushed a commit to ryan-duve/cpython that referenced this pull request Dec 26, 2023
aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
@markshannon markshannon deleted the unused-to-skips branch August 6, 2024 10:18
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants