diff --git a/dace/codegen/targets/cpu.py b/dace/codegen/targets/cpu.py index 3ac2d210c9..a2bc44caea 100644 --- a/dace/codegen/targets/cpu.py +++ b/dace/codegen/targets/cpu.py @@ -644,6 +644,9 @@ def _emit_copy( elif isinstance(src_node, nodes.CodeNode) and isinstance(dst_node, nodes.CodeNode): # Code->Code copy (not read nor write) raise RuntimeError("Copying between code nodes is only supported as part of the participating nodes") + elif uconn is None and vconn is None and memlet.data is None and dst_schedule == dtypes.ScheduleType.Sequential: + # Sequential dependency edge + return else: raise LookupError("Memlet does not point to any of the nodes") diff --git a/tests/codegen/dependency_edge_test.py b/tests/codegen/dependency_edge_test.py new file mode 100644 index 0000000000..5fca6fed22 --- /dev/null +++ b/tests/codegen/dependency_edge_test.py @@ -0,0 +1,67 @@ +# Copyright 2019-2022 ETH Zurich and the DaCe authors. All rights reserved. + +import pytest +import dace +import numpy as np + +@pytest.mark.parametrize("reverse", [True, False]) +def test_mapped_dependency_edge(reverse): + """ Tests dependency edges in a map scope """ + + sdfg = dace.SDFG("mapped_dependency_edge") + state = sdfg.add_state() + + sdfg.add_array("A", shape=[2], dtype=dace.int32) + sdfg.add_array("B", shape=[2], dtype=dace.int32) + sdfg.add_transient("tmp_A", shape=[1], dtype=dace.int32) + sdfg.add_transient("tmp_B", shape=[1], dtype=dace.int32) + + map_entry, map_exit = state.add_map("map", {"i": "0:2"}, schedule=dace.dtypes.ScheduleType.Sequential) + map_entry.add_in_connector("IN_A") + map_entry.add_in_connector("IN_B") + map_entry.add_out_connector("OUT_A") + map_entry.add_out_connector("OUT_B") + map_exit.add_in_connector("IN_A") + map_exit.add_out_connector("OUT_A") + + A1 = state.add_read("A") + A2 = state.add_write("A") + A3 = state.add_write("A") + A4 = state.add_write("A") + B = state.add_read("B") + tmp_A = state.add_write("tmp_A") + tmp_B = state.add_write("tmp_B") + + state.add_edge(A1, None, map_entry, "IN_A", dace.Memlet("A[0:2]")) + state.add_edge(B, None, map_entry, "IN_B", dace.Memlet("B[0:2]")) + + state.add_edge(map_entry, "OUT_A", tmp_A, None, dace.Memlet("A[i]")) + state.add_edge(map_entry, "OUT_B", tmp_B, None, dace.Memlet("B[i]")) + + state.add_edge(tmp_A, None, A2, None, dace.Memlet("tmp_A[0] -> ((i+1)%2)")) + if not reverse: + state.add_edge(A2, None, tmp_B, None, dace.Memlet()) # Dependency Edge + state.add_edge(A2, None, map_exit, "IN_A", dace.Memlet("A[0:2]")) + + state.add_edge(tmp_B, None, A3, None, dace.Memlet("tmp_B[0] -> ((i+1)%2)")) + if reverse: + state.add_edge(A3, None, tmp_A, None, dace.Memlet()) # Dependency Edge + state.add_edge(A3, None, map_exit, "IN_A", dace.Memlet("A[0:2]")) + + state.add_edge(map_exit, "OUT_A", A4, None, dace.Memlet("A[0:2]")) + + sdfg.validate() + a = np.random.randint(0, 100, 2).astype(np.int32) + b = np.random.randint(0, 100, 2).astype(np.int32) + sdfg(A=a, B=b) + + if reverse: + assert a[0] == a[1] + else: + assert a[0] == b[1] and a[1] == b[0] + + +if __name__ == "__main__": + test_mapped_dependency_edge(False) + test_mapped_dependency_edge(True) +