def format(self): # Yes... when serializing a whole function, this is computed once per # basic block instead of once for the function... But do we care? from decompil.analysis.predecessors import get_predecessors preds = get_predecessors(self.function, allow_incomplete=True)[self] indentation = (Text, ' ') result = self.format_label() + [(Punctuation, ':'), (Text, '\n')] if preds: result.extend([ indentation, (Comment, '; Predecessors: {}'.format(', '.join( sorted(pred.name for pred in preds)))), (Text, '\n'), ]) current_origin = None for insn in self.instructions: if insn.origin != current_origin: current_origin = insn.origin result.extend([ indentation, (Comment, '; {}'.format(current_origin)), (Text, '\n'), ]) result.append(indentation) result.extend(insn.format()) result.append((Text, '\n')) return result
def format(self): # Yes... when serializing a whole function, this is computed once per # basic block instead of once for the function... But do we care? from decompil.analysis.predecessors import get_predecessors preds = get_predecessors(self.function, allow_incomplete=True)[self] indentation = (Text, ' ') result = self.format_label() + [ (Punctuation, ':'), (Text, '\n') ] if preds: result.extend([ indentation, (Comment, '; Predecessors: {}'.format(', '.join(sorted( pred.name for pred in preds )))), (Text, '\n'), ]) current_origin = None for insn in self.instructions: if insn.origin != current_origin: current_origin = insn.origin result.extend([ indentation, (Comment, '; {}'.format(current_origin)), (Text, '\n'), ]) result.append(indentation) result.extend(insn.format()) result.append((Text, '\n')) return result
def __init__(self, function): self.function = function self.predecessors = get_predecessors(function) self.bld = builder.Builder() # Mapping: register -> set of all basic blocks that store a value in # this register. self.store_sites = None # Reverse mapping for it (i.e. basic block -> set of all registers # affected by this basic block). self.stored_registers = None # Mapping: register -> stack of values to use when loading the register # (at some specific point, take the top). Initialized in _process and # really used in transform_reg_insns. self.def_stacks = collections.defaultdict(list) self.dom_tree = None
def get_dominator_tree(func): """Return the dominance tree for basic blocks in func. This tree is a dictionnary that maps basic blocks to their parent (their immediate dominator). """ # Implementation is based on Modern Compiler Implementation, Andew W. # Appel, Chapter 19 Static Single-Assignment Form, algorithms 19.9 and # 19.10 (naive versions). predecessors = get_predecessors(func) dfs_tree, dfs_numbers = get_dfs_spanning_tree(func) # Mapping: basic block -> its immediate dominator. Once completely built, # we can build the dominator tree from it. imm_dominators = {} # Mapping: basic block -> semidominator semidominators = {} # Mapping: basic_block -> ??? TODO ancestors = {} # Mapping: basic_block -> ??? TODO buckets = collections.defaultdict(set) # Mapping: basic_block -> ??? TODO same_dominators = {} def ancestor_with_lowest_semi_no(basic_block): result = basic_block while result not in ancestors: bb_semi = semidominators.get(basic_block, None) result_semi = semidominators.get(result, None) if (dfs_numbers.get(bb_semi, 0) < dfs_numbers.get(result_semi, 0)): result = basic_block result = ancestors[result] return result basic_blocks_dfs_order = list( sorted((dfs_number, basic_block) for basic_block, dfs_number in dfs_numbers.items())) for i, basic_block in reversed(basic_blocks_dfs_order): if i == 0: imm_dominators[basic_block] = None continue parent = dfs_tree.get_parent(basic_block) # Compute the semi-dominator for basic_block. semi_candidate = parent semi_candidate_number = dfs_numbers[semi_candidate] for pred in predecessors[basic_block]: s = (pred if dfs_numbers[pred] <= i else semidominators.get( ancestor_with_lowest_semi_no(pred), None)) s_no = dfs_numbers[s] if s_no < semi_candidate_number: semi_candidate, semi_candidate_number = s, s_no semidominators[basic_block] = semi_candidate buckets[semi_candidate].add(basic_block) ancestors[basic_block] = parent for bb in buckets[parent]: y = ancestor_with_lowest_semi_no(bb) if semidominators[y] == semidominators[bb]: imm_dominators[bb] = parent else: same_dominators[bb] = y buckets[parent] = set() for i, basic_block in basic_blocks_dfs_order[1:]: try: same_dom = same_dominators[basic_block] except KeyError: pass else: imm_dominators[basic_block] = imm_dominators[same_dom] return parent_links_to_tree(imm_dominators)
def __init__(self, function): self.function = function self.predecessors = get_predecessors(function)
def get_dominator_tree(func): """Return the dominance tree for basic blocks in func. This tree is a dictionnary that maps basic blocks to their parent (their immediate dominator). """ # Implementation is based on Modern Compiler Implementation, Andew W. # Appel, Chapter 19 Static Single-Assignment Form, algorithms 19.9 and # 19.10 (naive versions). predecessors = get_predecessors(func) dfs_tree, dfs_numbers = get_dfs_spanning_tree(func) # Mapping: basic block -> its immediate dominator. Once completely built, # we can build the dominator tree from it. imm_dominators = {} # Mapping: basic block -> semidominator semidominators = {} # Mapping: basic_block -> ??? TODO ancestors = {} # Mapping: basic_block -> ??? TODO buckets = collections.defaultdict(set) # Mapping: basic_block -> ??? TODO same_dominators = {} def ancestor_with_lowest_semi_no(basic_block): result = basic_block while result not in ancestors: bb_semi = semidominators.get(basic_block, None) result_semi = semidominators.get(result, None) if (dfs_numbers.get(bb_semi, 0) < dfs_numbers.get(result_semi, 0) ): result = basic_block result = ancestors[result] return result basic_blocks_dfs_order = list(sorted( (dfs_number, basic_block) for basic_block, dfs_number in dfs_numbers.items() )) for i, basic_block in reversed(basic_blocks_dfs_order): if i == 0: imm_dominators[basic_block] = None continue parent = dfs_tree.get_parent(basic_block) # Compute the semi-dominator for basic_block. semi_candidate = parent semi_candidate_number = dfs_numbers[semi_candidate] for pred in predecessors[basic_block]: s = ( pred if dfs_numbers[pred] <= i else semidominators.get(ancestor_with_lowest_semi_no(pred), None) ) s_no = dfs_numbers[s] if s_no < semi_candidate_number: semi_candidate, semi_candidate_number = s, s_no semidominators[basic_block] = semi_candidate buckets[semi_candidate].add(basic_block) ancestors[basic_block] = parent for bb in buckets[parent]: y = ancestor_with_lowest_semi_no(bb) if semidominators[y] == semidominators[bb]: imm_dominators[bb] = parent else: same_dominators[bb] = y buckets[parent] = set() for i, basic_block in basic_blocks_dfs_order[1:]: try: same_dom = same_dominators[basic_block] except KeyError: pass else: imm_dominators[basic_block] = imm_dominators[same_dom] return parent_links_to_tree(imm_dominators)
def __init__(self, function): self.function = function self.predecessors = get_predecessors(function) # Set of indices for basic blocks to remove. self.to_remove = set()