Пример #1
0
    def test_reference_property(self):

        from_string = dace.memlet.Memlet.__properties__["data"].from_string

        sdfg = dace.SDFG("test_sdfg",
                         OrderedDict([("foo", dace.dtypes.float32)]))

        state0 = dace.SDFGState("s0", sdfg)
        state1 = dace.SDFGState("s1", sdfg)
        sdfg.add_node(state0)
        sdfg.add_node(state1)

        _, arr0 = sdfg.add_array("arr0", (16, 16), dace.dtypes.float32)
        data0 = dace.graph.nodes.AccessNode('arr0')

        state0.add_node(data0)
        sdfg.add_array("arr1", (16, 16), dace.dtypes.float32)
        state0.add_node(dace.graph.nodes.AccessNode('arr1'))
        sdfg.add_array("arr2", (16, 16), dace.dtypes.float32)
        state1.add_node(dace.graph.nodes.AccessNode('arr2'))

        memlet = dace.memlet.Memlet('arr2', 1, "0:N", 1)

        with self.assertRaises(TypeError):
            # Must pass SDFG as second argument
            memlet = dace.memlet.Memlet(
                dace.memlet.Memlet.__properties__["data"].from_string("arr0"),
                None, 1, "i", 1)

        memlet.data = 'arr0'

        self.assertEqual(sdfg.arrays[memlet.data], arr0)
Пример #2
0
    def test_reference_property(self):

        from_string = dace.memlet.Memlet.__properties__["data"].from_string

        sdfg = dace.SDFG("test_sdfg",
                         OrderedDict([("foo", dace.dtypes.float32)]))

        state0 = dace.SDFGState("s0", sdfg)
        state1 = dace.SDFGState("s1", sdfg)
        sdfg.add_node(state0)
        sdfg.add_node(state1)

        _, arr0 = sdfg.add_array("arr0", (16, 16), dace.dtypes.float32)
        data0 = dace.sdfg.nodes.AccessNode('arr0')

        state0.add_node(data0)
        sdfg.add_array("arr1", (16, 16), dace.dtypes.float32)
        state0.add_node(dace.sdfg.nodes.AccessNode('arr1'))
        sdfg.add_array("arr2", (16, 16), dace.dtypes.float32)
        state1.add_node(dace.sdfg.nodes.AccessNode('arr2'))

        memlet = dace.memlet.Memlet.simple('arr2', '0:N', num_accesses=1)
        memlet.data = 'arr0'

        self.assertEqual(sdfg.arrays[memlet.data], arr0)
Пример #3
0
    def generate_code(self, sdfg=None, state=None):
        if sdfg is None:
            sdfg = dace.SDFG("dacelab", OrderedDict(), {})
            prevstate = None
            for s in self.statements:
                state = len(sdfg.nodes())
                newstate = dace.SDFGState("s" + str(state),
                                          sdfg,
                                          debuginfo=s.context)
                sdfg.add_node(newstate)
                last_state = s.generate_code(sdfg, state)
                if prevstate is not None:
                    edge = dace.sdfg.InterstateEdge()
                    sdfg.add_edge(prevstate, newstate, edge)
                if last_state is None:
                    prevstate = newstate
                else:
                    prevstate = sdfg.nodes()[last_state]

            return sdfg
        else:
            raise ValueError(
                "Appending statements to an SDFG is not supported.")
Пример #4
0
 def AddState(self, statelabel):
     newstate = dace.SDFGState(statelabel, self.sdfg)
     self.sdfg.add_node(newstate)
     self.rendered_sdfg.set_dotcode(self.sdfg.draw())
     self.sdfg_changed = True
Пример #5
0
    def generate_code(self, sdfg, state):
        from .ast_range import AST_RangeExpression
        # This ignores matlab semantics and only works for loops of the form
        # for var = start:end where start and end are expressions which
        # evaluate to scalars.
        if isinstance(self.initializer, AST_RangeExpression):
            # Generate the initializer:
            # lhs and rhs of the iteration range as two transients, and a
            # transient for i (we also have a symbol for i which states will
            # use)
            initializer_state_num = state
            s = sdfg.nodes()[state]
            self.initializer.lhs.generate_code(sdfg, state)
            lhs_node = self.initializer.lhs.get_datanode(sdfg, state)
            self.initializer.rhs.generate_code(sdfg, state)
            rhs_node = self.initializer.rhs.get_datanode(sdfg, state)
            sdfg.add_transient(self.var.get_name_in_sdfg(sdfg), [1], self.initializer.lhs.get_basetype())
            var_node = s.add_access(self.var.get_name_in_sdfg(sdfg))
            s.add_edge(lhs_node, None, var_node, None,
                       dace.memlet.Memlet.from_array(var_node.data, var_node.desc(sdfg)))
            loop_guard_var = '_loopiter_' + str(state)
            loop_end_var = '_loopend_' + str(state)

            # Generate guard state, write loop iter symbol into loop iter
            # datanode
            guard_state_num = initializer_state_num + 1
            s_guard = sdfg.add_state('s' + str(guard_state_num))
            task = s_guard.add_tasklet('reinitloopiter', {}, {'out'}, "out=" + loop_guard_var)

            if self.var.get_name_in_sdfg(sdfg) not in sdfg.arrays:
                sdfg.add_transient(self.var.get_name_in_sdfg(sdfg), [1], self.initializer.lhs.get_basetype())
            trans = s_guard.add_access(self.var.get_name_in_sdfg(sdfg))
            # Workaround until "condition for putting a variable as top-level
            # doesn't take inter-state edges into account" is solved.
            # When fixed, the line below can be removed.
            self.initializer.rhs.generate_code(sdfg, guard_state_num)

            s_guard.add_edge(task, 'out', trans, None, dace.memlet.Memlet.from_array(trans.data, trans.desc(sdfg)))
            lg_init = dace.sdfg.InterstateEdge(
                assignments={
                    loop_guard_var: self.var.get_name_in_sdfg(sdfg) + '(0)',
                    loop_end_var: self.initializer.rhs.get_name_in_sdfg(sdfg) + '(0)'
                })
            sdfg.add_edge(sdfg.nodes()[state], s_guard, lg_init)

            # Add state for each statement within the for loop
            prev = s_guard
            for s in self.stmts.statements:
                state = len(sdfg.nodes())
                newstate = dace.SDFGState("s" + str(state), sdfg, debuginfo=s.context)
                sdfg.add_node(newstate)
                last_state = s.generate_code(sdfg, state)
                if last_state is None: last_state = state
                if prev != s_guard:
                    edge = dace.sdfg.InterstateEdge()
                    sdfg.add_edge(prev, newstate, edge)
                else:
                    edge = dace.sdfg.InterstateEdge(condition=dace.properties.CodeProperty.from_string(
                        loop_guard_var + " <= " + loop_end_var, language=dace.dtypes.Language.Python))
                    sdfg.add_edge(prev, newstate, edge)
                prev = sdfg.nodes()[last_state]

            # Create inter-state back-edge
            edge = dace.sdfg.InterstateEdge(assignments={loop_guard_var: loop_guard_var + '+1'})
            sdfg.add_edge(prev, s_guard, edge)

            # Create the loop exit state
            state = len(sdfg.nodes())
            s_lexit = dace.SDFGState("s" + str(state), sdfg, debuginfo=s.context)
            lend_val = str(self.initializer.get_dims()[-1])
            for_exit = dace.sdfg.InterstateEdge(condition=dace.properties.CodeProperty.from_string(
                loop_guard_var + " > " + loop_end_var, language=dace.dtypes.Language.Python))
            sdfg.add_edge(s_guard, s_lexit, for_exit)

            return state

        else:
            raise NotImplementedError("Loops over anything but ranges are not implemented.")
Пример #6
0
    def generate_code_proper(self, sdfg, state):
        # This follows matlab semantics, i.e., a loop iterates over the columns
        # of a matrix. This does not work well for sdfgs for all but the
        # simplest case (a matrix which is a compile time constant, ie. 1:10).
        # To support programs like Cholesky, we try to transform the matlab for
        # loop into a C-style loop, this is implemented in generate_code().

        # Generate the initializer:
        # Each iteration of the for loop will use one column
        initializer_state_num = state
        self.initializer.generate_code(sdfg, state)
        loop_guard_var = '_lg_' + str(state)
        # Generate an (empty) guard state
        guard_state_num = initializer_state_num + 1
        s_guard = sdfg.add_state('s' + str(guard_state_num))
        lg_init = dace.sdfg.InterstateEdge(assignments={loop_guard_var: '0'})
        sdfg.add_edge(sdfg.nodes()[state], s_guard, lg_init)

        # Read a column of the initializer
        get_initializer_state_num = guard_state_num + 1
        s_getinit = sdfg.add_state('s' + str(get_initializer_state_num))
        initializer_name = self.initializer.get_name_in_sdfg(sdfg)
        loopvar_name = self.var.get_name_in_sdfg(sdfg)
        dims = self.initializer.get_dims()[:1]
        sdfg.add_transient(loopvar_name, dims, self.initializer.get_basetype())
        part = s_getinit.add_access(loopvar_name)
        sdfg.add_transient(initializer_name, self.initializer.get_dims(), self.initializer.get_basetype())
        full = s_getinit.add_read(initializer_name)
        s_getinit.add_edge(full, None, part, None, dace.memlet.Memlet.simple(initializer_name, 'i,0'))

        # Add edge from guard to getinit
        lend_val = str(self.initializer.get_dims()[-1])
        for_entry = dace.sdfg.InterstateEdge(condition=dace.properties.CodeProperty.from_string(
            loop_guard_var + " < " + lend_val, language=dace.dtypes.Language.Python))
        sdfg.add_edge(s_guard, s_getinit, for_entry)

        # Add state for each statement within the for loop
        prev = s_getinit
        for s in self.stmts.statements:
            state = len(sdfg.nodes())
            newstate = dace.SDFGState("s" + str(state), sdfg, debuginfo=s.context)
            sdfg.add_node(newstate)
            last_state = s.generate_code(sdfg, state)
            if last_state is None: last_state = state
            edge = dace.sdfg.InterstateEdge()
            sdfg.add_edge(prev, newstate, edge)
            prev = sdfg.nodes()[last_state]

        # Create inter-state back-edge
        edge = dace.sdfg.InterstateEdge(assignments={loop_guard_var: loop_guard_var + '+1'})
        sdfg.add_edge(prev, s_guard, edge)

        # Create the loop exit state
        state = len(sdfg.nodes())
        s_lexit = dace.SDFGState("s" + str(state), sdfg, debuginfo=s.context)
        lend_val = str(self.initializer.get_dims()[-1])
        for_exit = dace.sdfg.InterstateEdge(condition=dace.properties.CodeProperty.from_string(
            loop_guard_var + " >= " + lend_val, language=dace.dtypes.Language.Python))
        sdfg.add_edge(s_guard, s_lexit, for_exit)

        return state
Пример #7
0
class BasicRegisterCache(Transformation):
    _before_state = dace.SDFGState()
    _loop_state = dace.SDFGState()
    _guard_state = dace.SDFGState()

    array = Property(dtype=str,
                     desc='Name of the array to replace by a register cache')

    @staticmethod
    def expressions():
        sdfg = dace.SDFG('_')
        before_state, loop_state, guard_state = (
            BasicRegisterCache._before_state, BasicRegisterCache._loop_state,
            BasicRegisterCache._guard_state)
        sdfg.add_nodes_from((before_state, loop_state, guard_state))
        sdfg.add_edge(before_state, guard_state, dace.InterstateEdge())
        sdfg.add_edge(guard_state, loop_state, dace.InterstateEdge())
        sdfg.add_edge(loop_state, guard_state, dace.InterstateEdge())
        return [sdfg]

    @staticmethod
    def can_be_applied(graph, candidate, expr_index, sdfg, strict=False):
        return True

    def _buffer_memlets(self, states):
        for state in states:
            for edge in state.edges():
                src, dst = edge.src, edge.dst
                if (isinstance(src, nodes.AccessNode)
                        and src.data == self.array
                        or isinstance(dst, nodes.AccessNode)
                        and dst.data == self.array):
                    yield edge.data

    def _get_loop_axis(self, loop_state, loop_var):
        def contains_loop_var(subset_range):
            return any(loop_var in {s.name
                                    for s in r.free_symbols}
                       for r in subset_range)

        for memlet in self._buffer_memlets([loop_state]):
            return [contains_loop_var(r)
                    for r in memlet.subset.ranges].index(True)

    def _get_buffer_size(self, state, loop_var, loop_axis):
        min_offset, max_offset = 1000, -1000
        for memlet in self._buffer_memlets([state]):
            rb, re, _ = memlet.subset.ranges[loop_axis]
            rb_offset = rb - symbolic.symbol(loop_var)
            re_offset = re - symbolic.symbol(loop_var)
            min_offset = min(min_offset, rb_offset, re_offset)
            max_offset = max(max_offset, rb_offset, re_offset)
        return max_offset - min_offset + 1

    def _replace_indices(self, states, loop_var, loop_axis, buffer_size):
        for memlet in self._buffer_memlets(states):
            rb, re, rs = memlet.subset.ranges[loop_axis]
            memlet.subset.ranges[loop_axis] = (rb % buffer_size,
                                               re % buffer_size, rs)

    def apply(self, sdfg: dace.SDFG):
        before_state = sdfg.node(self.subgraph[self._before_state])
        loop_state = sdfg.node(self.subgraph[self._loop_state])
        guard_state = sdfg.node(self.subgraph[self._guard_state])
        loop_var = next(iter(sdfg.in_edges(guard_state)[0].data.assignments))

        loop_axis = self._get_loop_axis(loop_state, loop_var)

        buffer_size = self._get_buffer_size(loop_state, loop_var, loop_axis)
        self._replace_indices(sdfg.states(), loop_var, loop_axis, buffer_size)

        array = sdfg.arrays[self.array]
        # TODO: generalize
        if array.shape[loop_axis] == array.total_size:
            array.shape = tuple(buffer_size if i == loop_axis else s
                                for i, s in enumerate(array.shape))
            array.total_size = buffer_size