def test_dominance_loop_simple(ctx, func, bld): bb_A = func.create_basic_block() bb_B = func.create_basic_block() bld.build_jump(bb_A) bld.position_at_end(bb_A) reg_a_val = bld.build_rload(ctx.reg_a) bld.build_branch(bld.build_eq(reg_a_val, reg_a_val.type.create(0)), bb_A, bb_B) bld.position_at_end(bb_B) bld.build_ret() dom_tree, dom_frontiers = dominance.get_dominance_frontiers(func) rev_dom_tree = tree_to_nodes(dom_tree) assert rev_dom_tree == Node(func.entry, { bb_A: Node(bb_A, { bb_B: Node(bb_B, {}), }), }) assert dom_frontiers == { func.entry: set(), bb_A: {bb_A}, bb_B: set(), }
def test_dominance_single(ctx, func, bld): bld.build_ret() dom_tree, dom_frontiers = dominance.get_dominance_frontiers(func) rev_dom_tree = tree_to_nodes(dom_tree) assert rev_dom_tree == Node(func.entry, {}) assert dom_frontiers == { func.entry: set(), }
def test_dominance_chained_1(ctx, func, bld): bb = func.create_basic_block() bld.build_jump(bb) bld.position_at_end(bb) bld.build_ret() dom_tree, dom_frontiers = dominance.get_dominance_frontiers(func) rev_dom_tree = tree_to_nodes(dom_tree) assert rev_dom_tree == Node(func.entry, { bb: Node(bb, {}), }) assert dom_frontiers == { func.entry: set(), bb: set(), }
def _process(self): self.store_sites = self.get_store_sites(self.function) self.stored_registers = collections.defaultdict(set) # Introduce load instructions at a new entry point and force the # assumption that they are all initialized at this point. This way, # other register loads that are not dominated by a corresponding # register store will inherit these values. Do this even for registers # that are never stored: this makes the data flow even more explicit, # especially with respect to register barriers. old_entry = self.function.entry new_entry = self.function.create_entry_basic_block() self.bld.position_at_end(new_entry) for register, reg_store_sites in self.store_sites.items(): self.def_stacks[register].append(self.bld.build_rload(register)) reg_store_sites.add(new_entry) for ss in reg_store_sites: self.stored_registers[ss].add(register) self.bld.build_jump(old_entry) # Force registers reloading after barrier instructions. for basic_block in self.function: # If some basic block contains a barrier instruction, consider it # as a store site so that its sucessors will have to transmit # new values of registers after it. for insn in basic_block: if self.is_reg_barrier(insn): for register in self.store_sites: self.store_sites[register].add(basic_block) self.stored_registers[basic_block].add(register) break # Enter the regular renaming algorithm... self.dom_tree, dom_frontiers = get_dominance_frontiers(self.function) # For each register, create phi nodes in basic blocks that need some. for register, reg_store_sites in self.store_sites.items(): self.create_phi_nodes(register, reg_store_sites, dom_frontiers) # Now perform the renaming itself. Skip the new entry point: it does # not need renaming (most importantly, it's invalid to rename it). for basic_block in self.dom_tree.get_children(new_entry): self.transform_reg_insns(basic_block)