def test_compute_liveout_with_attr(self): blocks, as_tree = self.build_arbitrary_blocks( block_links={"A": ["B"], "B": []}, code={ "A": dedent( """\ a = 4 a.b = 2 """ ), "B": dedent( """\ c = a.b """ ), }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[0] cfg_real.gather_initial_info() cfg_real.compute_live_out() expected_live_out = {"A": {"a", "a.b"}, "B": set()} self.assertLiveOutEqual(cfg_real.block_list, expected_live_out)
def test_fill_df_given_7_blocks(self): r""" Note: '|' with no arrows means pointing down H | A <--- DF(A) = A, / \ | DF(B) = G, B E --- DF(C) = F / \ | DF(D) = F C D | DF(E) = A, G \ / | DF(F) = G F | DF(G) = None \ | DF(H) = None G """ blocks = self.build_arbitrary_blocks( block_links={ "H": ["A"], "A": ["B", "E"], "B": ["C", "D"], "C": ["F"], "D": ["F"], "E": ["G", "A"], "F": ["G"], "G": [], }, block_type={ "A": RawBasicBlock, "B": RawBasicBlock, "C": RawBasicBlock, "D": RawBasicBlock, "E": RawBasicBlock, "F": RawBasicBlock, "G": RawBasicBlock, "H": ParentScopeBlock, }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.root = blocks[-1] cfg_real.root.blocks = blocks cfg_real.fill_df() self.assert_df_equal( cfg_real, { "A": ["A"], "B": ["G"], "C": ["F"], "D": ["F"], "E": ["A", "G"], "F": ["G"], "G": [], "H": [] })
def test_delete_node(self): as_tree = AstBuilder().string_build( dedent("""\ z = 2 # 0th block while a < 3: # 1st block if a < 2: # 2nd block z = 2 # 3rd block b = 2 # 4th block c = 3 # 5th block """)) cfg_real = Cfg(as_tree) cfg_real.root = cfg_common.delete_node(cfg_real.root, RawBasicBlock(1, 1))
def test_fill_df_given_6_block_with_loop(self): r""" Note: '|' with no arrows means pointing down A (None) | DF(A) : None B (B) <----- DF(B) : B / \ | DF(C) : F C(F) | | DF(D) : E / | | | Dominance Frontier DF(E) : F D(E) | | | ----> DF(F) : B | / | | E(F) | | \ / | F(B) ---------- """ blocks = self.build_arbitrary_blocks( block_links={ "A": ["B"], "B": ["C", "F"], "C": ["D", "E"], "D": ["E"], "E": ["F"], "F": ["B"] }, block_type={ "A": ParentScopeBlock, "B": RawBasicBlock, "C": RawBasicBlock, "D": RawBasicBlock, "E": RawBasicBlock, "F": RawBasicBlock, }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.root = blocks[0] cfg_real.root.blocks = blocks cfg_real.fill_df() self.assert_df_equal(cfg_real, { "A": [], "B": ["B"], "C": ["F"], "D": ["E"], "E": ["F"], "F": ["B"] })
def test_compute_liveout_given_5_blocks(self): blocks, as_tree = self.build_arbitrary_blocks( block_links={"A": ["B"], "B": ["C", "D"], "C": ["D"], "D": ["E", "B"], "E": []}, code={ "A": dedent( """\ i = 1 """ ), "B": dedent( """\ if i < 0: pass """ ), "C": dedent( """\ s = 0 """ ), "D": dedent( """\ s = s + i i = i + 1 if i < 0: pass """ ), "E": dedent( """\ if s < 3: pass """ ), }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[0] cfg_real.gather_initial_info() cfg_real.compute_live_out() expected_live_out = {"A": {"s", "i"}, "B": {"s", "i"}, "C": {"s", "i"}, "D": {"s", "i"}, "E": set()} self.assertLiveOutEqual(cfg_real.block_list, expected_live_out)
def test_fill_dominate_given_if_else(self): r""" Note: '|' with no arrows means pointing down A Expected Dominator / \ A: [B, C, D] B C ------> B: [] \ / C: [] D D: [] """ blocks = self.build_arbitrary_blocks( block_links={ "A": ["B", "C"], "B": ["D"], "C": ["D"], "D": [] }, block_type={ "A": ParentScopeBlock, "B": RawBasicBlock, "C": RawBasicBlock, "D": RawBasicBlock }, ) cfg_real = Cfg() cfg_real.root = blocks[0] cfg_real.root.blocks = blocks cfg_real.block_list = blocks cfg_real.root.fill_dominates() cfg_real.root.fill_idom() expected_rev_dominator = { "A": {"A"}, "B": {"A", "B"}, "C": {"A", "C"}, "D": {"A", "D"} } expected_idom = {"A": None, "B": "A", "C": "A", "D": "A"} self.assert_dominator_equal(cfg_real, expected_rev_dominator) self.assert_rev_idom_equal(cfg_real, expected_idom)
def test_insert_phi_function_pruned_4_blocks(self): blocks, as_tree = self.build_arbitrary_blocks( block_links={"A": ["B", "C"], "B": ["D"], "C": ["D"], "D": []}, code={ "A": dedent( """\ pass """ ), "B": dedent( """\ var = 3 """ ), "C": dedent( """\ pass """ ), "D": dedent( """\ if var < 3: pass """ ), }, block_type={"A": ParentScopeBlock}, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[0] cfg_real.root.blocks = blocks cfg_real.fill_df() cfg_real.gather_initial_info() cfg_real.compute_live_out() cfg_real.ins_phi_function_all() expected_phi_list = {"A": set(), "B": set(), "C": set(), "D": {"var"}} self.assertPhiListEqual(cfg_real.block_list, expected_phi_list)
def test_3_blocks_with_loops(self): r""" A | B <-- | | | --- C """ blocks, as_tree = self.build_arbitrary_blocks( block_links={ "A": ["B"], "B": ["C", "B"], "C": [], "D": ["A"] }, block_type={"D": ParentScopeBlock}, code={ "A": dedent("""\ b = 2 c = 1 a = 0 """), "B": dedent("""\ b = a + 1 c = c + b a = b * 2 a < c """), "C": dedent("""\ c = c """), "D": "", }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[-1] for blk in cfg_real.block_list[:-1]: blk.scope = cfg_real.block_list[-1] cfg_real.root.ast_node = as_tree cfg_real.root.ssa_code.code_list.append(as_tree) cfg_real.root.blocks = blocks cfg_real.convert_to_ssa() self.assertBlockSsaList( cfg_real.block_list, { "A": dedent("""\ Assign: (b_0,) = 2 Assign: (c_0,) = 1 Assign: (a_0,) = 0 """), "B": dedent("""\ Assign: (a_1,) = Phi(a_0, a_2) Assign: (c_1,) = Phi(c_0, c_2) Assign: (b_1,) = Phi(b_0, b_2) Assign: (b_2,) = BinOp: a_1 + 1 Assign: (c_2,) = BinOp: c_1 + b_2 Assign: (a_2,) = BinOp: b_2 * 2 a_2 < c_2 """), "C": dedent("""\ Assign: (c_3,) = c_2 """), }, )
def test_renaming_given_loop(self): r""" A | B <---- / \ | C D | \ / | E -----| """ blocks, as_tree = self.build_arbitrary_blocks( block_links={ "A": ["B"], "B": ["C", "D"], "C": ["E"], "D": ["E"], "E": ["B"], "F": ["A"] }, block_type={"F": ParentScopeBlock}, code={ "A": dedent("""\ j = 1 k = 1 I = 0 """), "B": dedent("""\ I < 29 """), "C": dedent("""\ j = j + 1 k = k + 1 """), "D": dedent("""\ j = j + 2 k = k + 2 """), "E": dedent("""\ temp = 1 """), "F": "", }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[-1] for blk in cfg_real.block_list[:-1]: blk.scope = cfg_real.block_list[-1] cfg_real.root.ast_node = as_tree cfg_real.root.ssa_code.code_list.append(as_tree) cfg_real.root.blocks = blocks cfg_real.convert_to_ssa() self.assertBlockSsaList( cfg_real.block_list, { "A": dedent("""\ Assign: (j_0,) = 1 Assign: (k_0,) = 1 Assign: (I_0,) = 0 """), "B": dedent("""\ Assign: (temp_0,) = Phi(temp, temp_1) Assign: (k_1,) = Phi(k_0, k_4) Assign: (j_1,) = Phi(j_0, j_4) I_0 < 29 """), "C": dedent("""\ Assign: (j_2,) = BinOp: j_1 + 1 Assign: (k_2,) = BinOp: k_1 + 1 """), "D": dedent("""\ Assign: (j_3,) = BinOp: j_1 + 2 Assign: (k_3,) = BinOp: k_1 + 2 """), "E": dedent("""\ Assign: (k_4,) = Phi(k_2, k_3) Assign: (j_4,) = Phi(j_2, j_3) Assign: (temp_1,) = 1 """), "F": "Module ", }, )
def test_rename_given_custom_4_blocks(self): r""" A / \ B E / \ | C D | \ / | F <---- """ blocks, as_tree = self.build_arbitrary_blocks( block_links={ "A": ["B", "E"], "B": ["C", "D"], "C": ["F"], "D": ["F"], "E": ["G"], "F": ["G"], "G": [] }, block_type={"A": ParentScopeBlock}, code={ "A": dedent("""\ """), "B": dedent("""\ a = 1 #a_0 """), "C": dedent("""\ a = 22 #a_1 """), "D": dedent("""\ a = 33 #a_2 """), "E": dedent("""\ a = 44 #a_4 """), "F": dedent("""\ a = 55 #a_3 """), "G": dedent("""\ a = 66 #a_5 """), }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[0] cfg_real.root.ast_node = as_tree cfg_real.root.ssa_code.code_list.append(as_tree) cfg_real.root.blocks = blocks cfg_real.fill_df() cfg_real.gather_initial_info() cfg_real.compute_live_out() cfg_real.rename_to_ssa() self.assertBlockSsaList( cfg_real.block_list, { "A": dedent("""\ Module """), "B": dedent("""\ Assign: (a_0,) = 1 """), "C": dedent("""\ Assign: (a_1,) = 22 """), "D": dedent("""\ Assign: (a_2,) = 33 """), "E": dedent("""\ Assign: (a_4,) = 44 """), "F": dedent("""\ Assign: (a_3,) = 55 """), "G": dedent("""\ Assign: (a_5,) = 66 """), }, )
def test_insert_phi_function_pruned(self): r""" Note: '|' with no arrows means pointing down A | B <------| / \ | C F | | / \ | | G I | | \ / | | H | \ / | D-----------| | E """ blocks, as_tree = self.build_arbitrary_blocks( block_links={ "A": ["B"], "B": ["C", "F"], "C": ["D"], "D": ["E", "B"], "E": [], "F": ["G", "I"], "G": ["H"], "H": ["D"], "I": ["H"], }, code={ "A": dedent( """\ i = 1 """ ), "B": dedent( """\ a = temp_0 c = temp_1 if a < c: pass """ ), "C": dedent( """\ b = temp_2 c = temp_3 d = temp_4 """ ), "D": dedent( """\ y = a + b z = c + d i = i + 1 if i < 100: pass """ ), "E": "return\n", "F": dedent( """\ a = temp_5 d = temp_6 if a < d: pass """ ), "G": dedent( """\ d = temp """ ), "H": dedent( """\ b = temp """ ), "I": dedent( """\ c = temp """ ), }, block_type={"A": ParentScopeBlock}, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.as_tree = as_tree cfg_real.root = cfg_real.block_list[0] cfg_real.root.blocks = blocks cfg_real.fill_df() cfg_real.gather_initial_info() cfg_real.compute_live_out() cfg_real.ins_phi_function_all() expected_phi_list = { "A": set(), "B": {"i"}, "C": set(), "D": {"a", "b", "c", "d"}, "E": set(), "F": set(), "G": set(), "H": {"c", "d"}, "I": set(), } self.assertPhiListEqual(cfg_real.block_list, expected_phi_list)
def test_fill_dominate_given_while(self): r""" Note: '|' with no arrows means pointing down A | B <----- / \ | A': ['B', 'C', 'D', 'E', 'F'], C | | B': ['C', 'D', 'E', 'F'], / | | | Expected dominator C': ['D', 'E'], D | | | ----> D': [], | / | | E': [], E | | F': []} \ / | F ---------- """ blocks = self.build_arbitrary_blocks( block_links={ "A": ["B"], "B": ["C", "F"], "C": ["D", "E"], "D": ["E"], "E": ["F"], "F": ["B"] }, block_type={ "A": ParentScopeBlock, "B": RawBasicBlock, "C": RawBasicBlock, "D": RawBasicBlock, "E": RawBasicBlock, "F": RawBasicBlock, }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.root = blocks[0] cfg_real.root.blocks = blocks cfg_real.root.fill_dominates() cfg_real.root.fill_idom() expected_rev_dominator = { "A": {"A"}, "B": {"A", "B"}, "C": {"A", "B", "C"}, "D": {"A", "B", "C", "D"}, "E": {"A", "B", "C", "E"}, "F": {"A", "B", "F"}, } expected_idom = { "A": None, "B": "A", "C": "B", "D": "C", "E": "C", "F": "B" } self.assert_dominator_equal(cfg_real, expected_rev_dominator) self.assert_rev_idom_equal(cfg_real, expected_idom)
def test_dominator_tree_given_13_blocks(self): r""" Note: '|' with no arrows means pointing down +---------> R | | | +-----+------------+ | | | | | A <-- B C---------+ | | / \ | | | D --+ E <-+ | G | | | | F / \ | L | | | | J | | | | \ | | | +------ H --+ I ---+--+ | | | | +---------+ | | | | +---------------------- K --+ """ blocks = self.build_arbitrary_blocks( block_links={ "A": ["B", "C", "H"], "B": ["D"], "C": ["B", "D", "F"], "D": ["E"], "E": ["G"], "F": ["G"], "G": ["F", "M"], "H": ["I", "J"], "I": ["L"], "J": ["K", "L"], "K": ["L"], "L": ["M"], "M": ["A", "L"], "N": ["A"], }, block_type={ "A": RawBasicBlock, "B": RawBasicBlock, "C": RawBasicBlock, "D": RawBasicBlock, "E": RawBasicBlock, "F": RawBasicBlock, "G": RawBasicBlock, "H": RawBasicBlock, "I": RawBasicBlock, "J": RawBasicBlock, "K": RawBasicBlock, "L": RawBasicBlock, "M": RawBasicBlock, "N": ParentScopeBlock, }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.root = blocks[-1] cfg_real.root.blocks = blocks cfg_real.root.fill_dominates() cfg_real.root.fill_idom() expected_idom = { "A": ["B", "C", "D", "F", "G", "H", "L", "M"], "B": [], "C": [], "D": ["E"], "E": [], "F": [], "G": [], "H": ["I", "J"], "I": [], "J": ["K"], "K": [], "L": [], "M": [], "N": ["A"], } self.assert_idom_equal(cfg_real, expected_idom)
def test_dominator_tree_given_complex_block(self): r""" Note: '|' with no arrows means pointing down A A | | B <------| B / \ | Dominator Tree / | \ C F | -------> C D F | / \ | | / | \ | G I | E G H I | \ / | | H | \ / | D-----------| | E """ blocks = self.build_arbitrary_blocks( block_links={ "A": ["B"], "B": ["C", "F"], "C": ["D"], "D": ["E", "B"], "E": [], "F": ["G", "I"], "G": ["H"], "H": ["D"], "I": ["H"], }, block_type={ "A": ParentScopeBlock, "B": RawBasicBlock, "C": RawBasicBlock, "D": RawBasicBlock, "E": RawBasicBlock, "F": RawBasicBlock, "G": RawBasicBlock, "H": RawBasicBlock, "I": RawBasicBlock, }, ) cfg_real = Cfg() cfg_real.block_list = blocks cfg_real.root = blocks[0] cfg_real.root.blocks = blocks cfg_real.root.fill_dominates() cfg_real.root.fill_idom() expected_idom = { "A": ["B"], "B": ["C", "D", "F"], "C": [], "D": ["E"], "E": [], "F": ["G", "H", "I"], "G": [], "H": [], "I": [], } self.assert_idom_equal(cfg_real, expected_idom)