예제 #1
0
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(),
    }
예제 #2
0
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(),
    }
예제 #3
0
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(),
    }
예제 #4
0
    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)