def apply(self, sdfg): state = sdfg.nodes()[self.subgraph[StateAssignElimination._end_state]] edge = sdfg.in_edges(state)[0] # Since inter-state assignments that use an assigned value leads to # undefined behavior (e.g., {m: n, n: m}), we can replace each # assignment separately. keys_to_remove = set() assignments_to_consider = _assignments_to_consider(sdfg, edge) for varname, assignment in assignments_to_consider.items(): state.replace(varname, assignment) keys_to_remove.add(varname) repl_dict = {} for varname in keys_to_remove: # Remove assignments from edge del edge.data.assignments[varname] for e in sdfg.edges(): if varname in e.data.free_symbols: break else: # If removed assignment does not appear in any other edge, # replace and remove symbol if assignments_to_consider[varname] in sdfg.symbols: repl_dict[varname] = assignments_to_consider[varname] if varname in sdfg.symbols: sdfg.remove_symbol(varname) def _str_repl(s, d): for k, v in d.items(): s.replace(str(k), str(v)) if repl_dict: symbolic.safe_replace(repl_dict, lambda m: _str_repl(sdfg, m))
def apply(self, _, sdfg: SDFG): state = self.end_state edge = sdfg.in_edges(state)[0] # Since inter-state assignments that use an assigned value leads to # undefined behavior (e.g., {m: n, n: m}), we can replace each # assignment separately. assignments_to_consider = _assignments_to_consider(sdfg, edge, True) def _str_repl(s, d, **kwargs): for k, v in d.items(): s.replace(str(k), str(v), **kwargs) # Replace in state, and all successors symbolic.safe_replace(assignments_to_consider, lambda m: _str_repl(state, m)) visited = {edge} for isedge in sdfg.bfs_edges(state): if isedge not in visited: symbolic.safe_replace( assignments_to_consider, lambda m: _str_repl(isedge.data, m, replace_keys=False)) visited.add(isedge) if isedge.dst not in visited: symbolic.safe_replace(assignments_to_consider, lambda m: _str_repl(isedge.dst, m)) visited.add(isedge.dst) repl_dict = {} for varname in assignments_to_consider.keys(): # Remove assignments from edge del edge.data.assignments[varname] for e in sdfg.edges(): if varname in e.data.free_symbols: break else: # If removed assignment does not appear in any other edge, # replace and remove symbol if varname in sdfg.symbols: sdfg.remove_symbol(varname) # if assignments_to_consider[varname] in sdfg.symbols: if varname in sdfg.free_symbols: repl_dict[varname] = assignments_to_consider[varname] if repl_dict: symbolic.safe_replace(repl_dict, lambda m: _str_repl(sdfg, m))
def can_be_applied(graph, candidate, expr_index, sdfg, strict=False): state = graph.nodes()[candidate[StateAssignElimination._end_state]] out_edges = graph.out_edges(state) in_edges = graph.in_edges(state) # We only match end states with one source and at least one assignment if len(in_edges) != 1: return False edge = in_edges[0] assignments_to_consider = _assignments_to_consider(sdfg, edge) # No assignments to eliminate if len(assignments_to_consider) == 0: return False # If this is an end state, there are no other edges to consider if len(out_edges) == 0: return True # Otherwise, ensure the symbols are never set/used again in edges akeys = set(assignments_to_consider.keys()) for e in sdfg.edges(): if e is edge: continue if e.data.free_symbols & akeys: return False # If used in any state that is not the current one, fail for s in sdfg.nodes(): if s is state: continue if s.free_symbols & akeys: return False return True