Skip to content

Commit b87263b

Browse files
authored
gh-106581: Support multiple uops pushing new values (#108895)
Also avoid the need for the awkward .clone() call in the argument to mgr.adjust_inverse() and mgr.adjust().
1 parent 2c4c26c commit b87263b

File tree

2 files changed

+83
-17
lines changed

2 files changed

+83
-17
lines changed

Lib/test/test_generated_cases.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,36 @@ def test_macro_cond_effect(self):
532532
"""
533533
self.run_cases_test(input, output)
534534

535+
def test_macro_push_push(self):
536+
input = """
537+
op(A, (-- val1)) {
538+
val1 = spam();
539+
}
540+
op(B, (-- val2)) {
541+
val2 = spam();
542+
}
543+
macro(M) = A + B;
544+
"""
545+
output = """
546+
TARGET(M) {
547+
PyObject *val1;
548+
PyObject *val2;
549+
// A
550+
{
551+
val1 = spam();
552+
}
553+
// B
554+
{
555+
val2 = spam();
556+
}
557+
STACK_GROW(2);
558+
stack_pointer[-2] = val1;
559+
stack_pointer[-1] = val2;
560+
DISPATCH();
561+
}
562+
"""
563+
self.run_cases_test(input, output)
564+
535565

536566
if __name__ == "__main__":
537567
unittest.main()

Tools/cases_generator/stacking.py

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,19 @@ def adjust_higher(self, eff: StackEffect) -> None:
261261
self.final_offset.higher(eff)
262262

263263
def adjust(self, offset: StackOffset) -> None:
264-
for down in offset.deep:
264+
deep = list(offset.deep)
265+
high = list(offset.high)
266+
for down in deep:
265267
self.adjust_deeper(down)
266-
for up in offset.high:
268+
for up in high:
267269
self.adjust_higher(up)
268270

269271
def adjust_inverse(self, offset: StackOffset) -> None:
270-
for down in offset.deep:
272+
deep = list(offset.deep)
273+
high = list(offset.high)
274+
for down in deep:
271275
self.adjust_higher(down)
272-
for up in offset.high:
276+
for up in high:
273277
self.adjust_deeper(up)
274278

275279
def collect_vars(self) -> dict[str, StackEffect]:
@@ -426,15 +430,26 @@ def write_components(
426430
)
427431

428432
if mgr.instr.name in ("_PUSH_FRAME", "_POP_FRAME"):
429-
# Adjust stack to min_offset (input effects materialized)
433+
# Adjust stack to min_offset.
434+
# This means that all input effects of this instruction
435+
# are materialized, but not its output effects.
436+
# That's as intended, since these two are so special.
430437
out.stack_adjust(mgr.min_offset.deep, mgr.min_offset.high)
431-
# Use clone() since adjust_inverse() mutates final_offset
432-
mgr.adjust_inverse(mgr.final_offset.clone())
438+
# However, for tier 2, pretend the stack is at final offset.
439+
mgr.adjust_inverse(mgr.final_offset)
440+
if tier == TIER_ONE:
441+
# TODO: Check in analyzer that _{PUSH,POP}_FRAME is last.
442+
assert (
443+
mgr is managers[-1]
444+
), f"Expected {mgr.instr.name!r} to be the last uop"
445+
assert_no_pokes(managers)
433446

434447
if mgr.instr.name == "SAVE_CURRENT_IP":
435448
next_instr_is_set = True
436449
if cache_offset:
437450
out.emit(f"next_instr += {cache_offset};")
451+
if tier == TIER_ONE:
452+
assert_no_pokes(managers)
438453

439454
if len(parts) == 1:
440455
mgr.instr.write_body(out, 0, mgr.active_caches, tier)
@@ -443,19 +458,41 @@ def write_components(
443458
mgr.instr.write_body(out, -4, mgr.active_caches, tier)
444459

445460
if mgr is managers[-1] and not next_instr_is_set:
446-
# TODO: Explain why this adjustment is needed.
461+
# Adjust the stack to its final depth, *then* write the
462+
# pokes for all preceding uops.
463+
# Note that for array output effects we may still write
464+
# past the stack top.
447465
out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high)
448-
# Use clone() since adjust_inverse() mutates final_offset
449-
mgr.adjust_inverse(mgr.final_offset.clone())
466+
write_all_pokes(mgr.final_offset, managers, out)
450467

468+
return next_instr_is_set
469+
470+
471+
def assert_no_pokes(managers: list[EffectManager]) -> None:
472+
for mgr in managers:
451473
for poke in mgr.pokes:
452474
if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names:
453-
out.assign(
454-
poke.as_stack_effect(),
455-
poke.effect,
456-
)
475+
assert (
476+
poke.effect.name == UNUSED
477+
), f"Unexpected poke of {poke.effect.name} in {mgr.instr.name!r}"
457478

458-
return next_instr_is_set
479+
480+
def write_all_pokes(
481+
offset: StackOffset, managers: list[EffectManager], out: Formatter
482+
) -> None:
483+
# Emit all remaining pushes (pokes)
484+
for m in managers:
485+
m.adjust_inverse(offset)
486+
write_pokes(m, out)
487+
488+
489+
def write_pokes(mgr: EffectManager, out: Formatter) -> None:
490+
for poke in mgr.pokes:
491+
if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names:
492+
out.assign(
493+
poke.as_stack_effect(),
494+
poke.effect,
495+
)
459496

460497

461498
def write_single_instr_for_abstract_interp(instr: Instruction, out: Formatter) -> None:
@@ -478,8 +515,7 @@ def _write_components_for_abstract_interp(
478515
for mgr in managers:
479516
if mgr is managers[-1]:
480517
out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high)
481-
# Use clone() since adjust_inverse() mutates final_offset
482-
mgr.adjust_inverse(mgr.final_offset.clone())
518+
mgr.adjust_inverse(mgr.final_offset)
483519
# NULL out the output stack effects
484520
for poke in mgr.pokes:
485521
if not poke.effect.size and poke.effect.name not in mgr.instr.unmoved_names:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy