def aggressive_coalesce_block(self): """Try to coalesce phi var with their pre/post variables""" ircfg = self.ssa.graph # Run coalesce on the post phi parallel copy for irblock in ircfg.blocks.values(): if not irblock_has_phi(irblock): continue parallel_copies = {} for dst in self.phi_destinations[irblock.loc_key]: parallel_copies[dst] = self.phi_new_var[dst] self.aggressive_coalesce_parallel_copy(parallel_copies, None) # Run coalesce on the pre phi parallel copy # Stand for the virtual parallel copies at the end of Phi's block # parents parent_to_parallel_copies = {} for dst in irblock[0]: new_var = self.phi_new_var[dst] for parent, src in self.phi_parent_sources[dst]: parent_to_parallel_copies.setdefault(parent, {})[new_var] = src for parent, parallel_copies in parent_to_parallel_copies.iteritems( ): self.aggressive_coalesce_parallel_copy(parallel_copies, parent)
def isolate_phi_nodes_block(self): """ Init structures and virtually insert parallel copy before/after each phi node """ ircfg = self.ssa.graph for irblock in ircfg.blocks.itervalues(): if not irblock_has_phi(irblock): continue for dst, sources in irblock[0].iteritems(): assert sources.is_op('Phi') new_var = self.create_copy_var(dst) self.phi_new_var[dst] = new_var var_to_parents = get_phi_sources_parent_block( self.ssa.graph, irblock.loc_key, sources.args) for src in sources.args: parents = var_to_parents[src] self.new_var_to_srcs_parents.setdefault( new_var, set()).update(parents) for parent in parents: self.phi_parent_sources.setdefault(dst, set()).add( (parent, src)) self.phi_destinations[irblock.loc_key] = set(irblock[0])
def __init__(self, ircfg): super(DiGraphLivenessSSA, self).__init__(ircfg) self.loc_key_to_phi_parents = {} for irblock in self.blocks.values(): if not irblock_has_phi(irblock): continue out = {} for sources in irblock[0].itervalues(): var_to_parents = get_phi_sources_parent_block( self, irblock.loc_key, sources.args) for var, var_parents in var_to_parents.iteritems(): out.setdefault(var, set()).update(var_parents) self.loc_key_to_phi_parents[irblock.loc_key] = out
def order_ssa_var_dom(self): """Compute dominance order of each ssa variable""" ircfg = self.ssa.graph # compute dominator tree dominator_tree = ircfg.compute_dominator_tree(self.head) # variable -> Varinfo self.var_to_varinfo = {} # live_index can later be used to compare dominance of AssignBlocks live_index = 0 # walk in DFS over the dominator tree for loc_key in dominator_tree.walk_depth_first_forward(self.head): irblock = ircfg.blocks[loc_key] # Create live index for phi new vars # They do not exist in the graph yet, so index is set to None if irblock_has_phi(irblock): for dst in irblock[0]: if not dst.is_id(): continue new_var = self.phi_new_var[dst] self.var_to_varinfo[new_var] = Varinfo( live_index, loc_key, None) live_index += 1 # Create live index for remaining assignments for index, assignblk in enumerate(irblock): used = False for dst in assignblk: if not dst.is_id(): continue if dst in self.ssa.immutable_ids: # Will not be considered by the current algo, ignore it # (for instance, IRDst) continue assert dst not in self.var_to_varinfo self.var_to_varinfo[dst] = Varinfo(live_index, loc_key, index) used = True if used: live_index += 1
def insert_parallel_copy(self): """ Naive Out-of-SSA from CSSA (without coalescing for now) - Replace Phi - Create room for parallel copies in Phi's parents """ ircfg = self.ssa.graph for irblock in ircfg.blocks.values(): if not irblock_has_phi(irblock): continue # Replace Phi with Phi's dst = new_var parallel_copies = {} for dst in self.phi_destinations[irblock.loc_key]: new_var = self.phi_new_var[dst] parallel_copies[dst] = new_var assignblks = list(irblock) assignblks[0] = AssignBlock(parallel_copies, irblock[0].instr) new_irblock = IRBlock(irblock.loc_key, assignblks) ircfg.blocks[irblock.loc_key] = new_irblock # Insert new_var = src in each Phi's parent, at the end of the block parent_to_parallel_copies = {} parallel_copies = {} for dst in irblock[0]: new_var = self.phi_new_var[dst] for parent, src in self.phi_parent_sources[dst]: parent_to_parallel_copies.setdefault(parent, {})[new_var] = src for parent, parallel_copies in parent_to_parallel_copies.iteritems( ): parent = ircfg.blocks[parent] assignblks = list(parent) assignblks.append( AssignBlock(parallel_copies, parent[-1].instr)) new_irblock = IRBlock(parent.loc_key, assignblks) ircfg.blocks[parent.loc_key] = new_irblock
def back_propagate_to_parent(self, todo, node, parent): parent_block = self.blocks[parent] cur_block = self.blocks[node] irblock = self.ircfg.blocks[node] if cur_block.infos[0].var_in == parent_block.infos[-1].var_out: return var_info = cur_block.infos[0].var_in.union( parent_block.infos[-1].var_out) if irblock_has_phi(irblock): # Remove phi special case out = set() phi_sources = self.loc_key_to_phi_parents[irblock.loc_key] for var in var_info: if var not in phi_sources: out.add(var) continue if parent in phi_sources[var]: out.add(var) var_info = out parent_block.infos[-1].var_out = var_info todo.add(parent)