diff --git a/artiq/compiler/transforms/interleaver.py b/artiq/compiler/transforms/interleaver.py index ea2097ad2..f737d839c 100644 --- a/artiq/compiler/transforms/interleaver.py +++ b/artiq/compiler/transforms/interleaver.py @@ -45,55 +45,57 @@ class Interleaver: postdom_tree = None for insn in func.instructions(): - if isinstance(insn, ir.Parallel): - # Lazily compute dominators. - if postdom_tree is None: - postdom_tree = domination.PostDominatorTree(func) + if not isinstance(insn, ir.Parallel): + continue - interleave_until = postdom_tree.immediate_dominator(insn.basic_block) - assert (interleave_until is not None) # no nonlocal flow in `with parallel` + # Lazily compute dominators. + if postdom_tree is None: + postdom_tree = domination.PostDominatorTree(func) - target_block = insn.basic_block - target_time = 0 - source_blocks = insn.basic_block.successors() - source_times = [0 for _ in source_blocks] + interleave_until = postdom_tree.immediate_dominator(insn.basic_block) + assert (interleave_until is not None) # no nonlocal flow in `with parallel` - while len(source_blocks) > 0: - def iodelay_of_block(block): - terminator = block.terminator() - if isinstance(terminator, ir.Delay): - # We should be able to fold everything without free variables. - assert iodelay.is_const(terminator.expr) - return terminator.expr.value - else: - return 0 + target_block = insn.basic_block + target_time = 0 + source_blocks = insn.basic_block.successors() + source_times = [0 for _ in source_blocks] - def time_after_block(pair): - index, block = pair - return source_times[index] + iodelay_of_block(block) - - index, source_block = min(enumerate(source_blocks), key=time_after_block) - source_block_delay = iodelay_of_block(source_block) - - target_terminator = target_block.terminator() - if isinstance(target_terminator, (ir.Delay, ir.Branch)): - target_terminator.set_target(source_block) - elif isinstance(target_terminator, ir.Parallel): - target_terminator.replace_with(ir.Branch(source_block)) + while len(source_blocks) > 0: + def iodelay_of_block(block): + terminator = block.terminator() + if isinstance(terminator, ir.Delay): + # We should be able to fold everything without free variables. + assert iodelay.is_const(terminator.expr) + return terminator.expr.value else: - assert False + return 0 - new_source_block = postdom_tree.immediate_dominator(source_block) - assert (new_source_block is not None) - assert delay_free_subgraph(source_block, new_source_block) + def time_after_block(pair): + index, block = pair + return source_times[index] + iodelay_of_block(block) - target_block = source_block - target_time += source_block_delay + index, source_block = min(enumerate(source_blocks), key=time_after_block) + source_block_delay = iodelay_of_block(source_block) - if new_source_block == interleave_until: - # We're finished with this branch. - del source_blocks[index] - del source_times[index] - else: - source_blocks[index] = new_source_block - source_times[index] = target_time + target_terminator = target_block.terminator() + if isinstance(target_terminator, (ir.Delay, ir.Branch)): + target_terminator.set_target(source_block) + elif isinstance(target_terminator, ir.Parallel): + target_terminator.replace_with(ir.Branch(source_block)) + else: + assert False + + target_block = source_block + target_time += source_block_delay + + new_source_block = postdom_tree.immediate_dominator(source_block) + assert (new_source_block is not None) + assert delay_free_subgraph(source_block, new_source_block) + + if new_source_block == interleave_until: + # We're finished with this branch. + del source_blocks[index] + del source_times[index] + else: + source_blocks[index] = new_source_block + source_times[index] = target_time