@@ -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
461498def 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