def is_write_conflicted(dfg, edge, datanode=None, sdfg_schedule=None): """ Detects whether a write-conflict-resolving edge can be emitted without using atomics or critical sections. """ if edge.data.wcr_nonatomic: return False # If it's an entire SDFG, it's probably write-conflicted if isinstance(dfg, SDFG): if datanode is None: return True in_edges = find_incoming_edges(datanode, dfg) if len(in_edges) != 1: return True if (isinstance(in_edges[0].src, nodes.ExitNode) and in_edges[0].src.map.schedule == dtypes.ScheduleType.Sequential): return False return True # Traverse memlet path to determine conflicts. # If no conflicts will occur, write without atomics # (e.g., if the array has been defined in a non-parallel schedule context) # TODO: This is not perfect (need to take indices into consideration) path = dfg.memlet_path(edge) for e in path: if (isinstance(e.dst, nodes.ExitNode) and e.dst.map.schedule != dtypes.ScheduleType.Sequential): return True # Should never happen (no such thing as write-conflicting reads) if (isinstance(e.src, nodes.EntryNode) and e.src.map.schedule != dtypes.ScheduleType.Sequential): return True # If SDFG schedule is not None (top-level) or not sequential if (sdfg_schedule is not None and sdfg_schedule != dtypes.ScheduleType.Sequential): return True return False
def is_write_conflicted(dfg, edge, datanode=None, sdfg_schedule=None): """ Detects whether a write-conflict-resolving edge can be emitted without using atomics or critical sections. """ if edge.data.wcr_nonatomic or edge.data.wcr is None: return False # If it's an entire SDFG, it's probably write-conflicted if isinstance(dfg, SDFG): if datanode is None: return True in_edges = find_incoming_edges(datanode, dfg) if len(in_edges) != 1: return True if (isinstance(in_edges[0].src, nodes.ExitNode) and in_edges[0].src.map.schedule == dtypes.ScheduleType.Sequential): return False return True # Traverse memlet path to determine conflicts. # If no conflicts will occur, write without atomics # (e.g., if the array has been defined in a non-parallel schedule context) while edge is not None: path = dfg.memlet_path(edge) for e in path: if (isinstance(e.dst, nodes.ExitNode) and e.dst.map.schedule != dtypes.ScheduleType.Sequential): if _check_map_conflicts(e.dst.map, e): # This map is parallel w.r.t. WCR # print('PAR: Continuing from map') continue # print('SEQ: Map is conflicted') return True # Should never happen (no such thing as write-conflicting reads) if (isinstance(e.src, nodes.EntryNode) and e.src.map.schedule != dtypes.ScheduleType.Sequential): warnings.warn( 'Unexpected WCR path to have write-conflicting reads') return True sdfg = dfg.parent dst = path[-1].dst # Unexpected case if not isinstance(dst, nodes.AccessNode): warnings.warn('Unexpected WCR path to not end in access node') return True # If this is a nested SDFG and the access leads outside if not sdfg.arrays[dst.data].transient: if sdfg.parent_nsdfg_node is not None: dfg = sdfg.parent nsdfg = sdfg.parent_nsdfg_node edge = next(iter(dfg.out_edges_by_connector(nsdfg, dst.data))) else: break else: # Memlet path ends here, transient. We can thus safely write here edge = None # print('PAR: Reached transient') return False return False