-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-106581: Support multiple uops pushing new values #108895
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -261,15 +261,19 @@ def adjust_higher(self, eff: StackEffect) -> None: | |
self.final_offset.higher(eff) | ||
|
||
def adjust(self, offset: StackOffset) -> None: | ||
for down in offset.deep: | ||
deep = list(offset.deep) | ||
high = list(offset.high) | ||
for down in deep: | ||
self.adjust_deeper(down) | ||
for up in offset.high: | ||
for up in high: | ||
self.adjust_higher(up) | ||
|
||
def adjust_inverse(self, offset: StackOffset) -> None: | ||
for down in offset.deep: | ||
deep = list(offset.deep) | ||
high = list(offset.high) | ||
for down in deep: | ||
self.adjust_higher(down) | ||
for up in offset.high: | ||
for up in high: | ||
self.adjust_deeper(up) | ||
|
||
def collect_vars(self) -> dict[str, StackEffect]: | ||
|
@@ -426,15 +430,26 @@ def write_components( | |
) | ||
|
||
if mgr.instr.name in ("_PUSH_FRAME", "_POP_FRAME"): | ||
# Adjust stack to min_offset (input effects materialized) | ||
# Adjust stack to min_offset. | ||
# This means that all input effects of this instruction | ||
# are materialized, but not its output effects. | ||
# That's as intended, since these two are so special. | ||
out.stack_adjust(mgr.min_offset.deep, mgr.min_offset.high) | ||
# Use clone() since adjust_inverse() mutates final_offset | ||
mgr.adjust_inverse(mgr.final_offset.clone()) | ||
# However, for tier 2, pretend the stack is at final offset. | ||
mgr.adjust_inverse(mgr.final_offset) | ||
if tier == TIER_ONE: | ||
# TODO: Check in analyzer that _{PUSH,POP}_FRAME is last. | ||
assert ( | ||
mgr is managers[-1] | ||
), f"Expected {mgr.instr.name!r} to be the last uop" | ||
assert_no_pokes(managers) | ||
|
||
if mgr.instr.name == "SAVE_CURRENT_IP": | ||
next_instr_is_set = True | ||
if cache_offset: | ||
out.emit(f"next_instr += {cache_offset};") | ||
if tier == TIER_ONE: | ||
assert_no_pokes(managers) | ||
Comment on lines
+445
to
+452
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are pokes bad for these? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because I don't want to think about what to do with loose pokes in macros containing If and when we need to support that case, this assert will remind us (or at least me :-) that some additional effort is needed here. (Kind of like how the |
||
|
||
if len(parts) == 1: | ||
mgr.instr.write_body(out, 0, mgr.active_caches, tier) | ||
|
@@ -443,19 +458,41 @@ def write_components( | |
mgr.instr.write_body(out, -4, mgr.active_caches, tier) | ||
|
||
if mgr is managers[-1] and not next_instr_is_set: | ||
# TODO: Explain why this adjustment is needed. | ||
# Adjust the stack to its final depth, *then* write the | ||
# pokes for all preceding uops. | ||
# Note that for array output effects we may still write | ||
# past the stack top. | ||
Comment on lines
+463
to
+464
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems surprising to me. When could this happen? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E.g. in |
||
out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high) | ||
# Use clone() since adjust_inverse() mutates final_offset | ||
mgr.adjust_inverse(mgr.final_offset.clone()) | ||
write_all_pokes(mgr.final_offset, managers, out) | ||
|
||
return next_instr_is_set | ||
|
||
|
||
def assert_no_pokes(managers: list[EffectManager]) -> None: | ||
for mgr in managers: | ||
for poke in mgr.pokes: | ||
if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names: | ||
out.assign( | ||
poke.as_stack_effect(), | ||
poke.effect, | ||
) | ||
assert ( | ||
poke.effect.name == UNUSED | ||
), f"Unexpected poke of {poke.effect.name} in {mgr.instr.name!r}" | ||
|
||
return next_instr_is_set | ||
|
||
def write_all_pokes( | ||
offset: StackOffset, managers: list[EffectManager], out: Formatter | ||
) -> None: | ||
# Emit all remaining pushes (pokes) | ||
for m in managers: | ||
m.adjust_inverse(offset) | ||
write_pokes(m, out) | ||
|
||
|
||
def write_pokes(mgr: EffectManager, out: Formatter) -> None: | ||
for poke in mgr.pokes: | ||
if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names: | ||
out.assign( | ||
poke.as_stack_effect(), | ||
poke.effect, | ||
) | ||
|
||
|
||
def write_single_instr_for_abstract_interp(instr: Instruction, out: Formatter) -> None: | ||
|
@@ -478,8 +515,7 @@ def _write_components_for_abstract_interp( | |
for mgr in managers: | ||
if mgr is managers[-1]: | ||
out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high) | ||
# Use clone() since adjust_inverse() mutates final_offset | ||
mgr.adjust_inverse(mgr.final_offset.clone()) | ||
mgr.adjust_inverse(mgr.final_offset) | ||
# NULL out the output stack effects | ||
for poke in mgr.pokes: | ||
if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, why? I assume it has something to do with the comment you removed below (
# Use clone() since adjust_inverse() mutates final_offset
), but I'm not sure I understand.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. That
.clone()
call was needed becauseadjust_higher()
andadjust_deeper()
changeself.final_offset
(in place), and the argument here may beself.final_offset
. (And ditto formin_offset
.) So previously my "fix" for this was to pass in a clone of the argument. The new fix avoids the need to clone in the caller but effectively clones thedeep
andhigh
lists of the argument.