Beispiel #1
0
    def generate_transition(self,
                            sdfg: SDFG,
                            edge: Edge[InterstateEdge],
                            successor: SDFGState = None) -> str:
        """ 
        Helper function that generates a state transition (conditional goto) 
        from a state and an SDFG edge.
        :param sdfg: The parent SDFG.
        :param edge: The state transition edge to generate.
        :param successor: If not None, the state that will be generated right
                          after the current state (used to avoid extraneous 
                          gotos).
        :return: A c++ string representing the state transition code.
        """
        expr = ''
        condition_string = cpp.unparse_interstate_edge(
            edge.data.condition.code[0], sdfg)

        if not edge.data.is_unconditional():
            expr += f'if ({condition_string}) {{\n'

        if len(edge.data.assignments) > 0:
            expr += ';\n'.join([
                "{} = {}".format(variable,
                                 cpp.unparse_interstate_edge(value, sdfg))
                for variable, value in edge.data.assignments.items()
            ] + [''])

        if successor is None or edge.dst is not successor:
            expr += 'goto __state_{}_{};\n'.format(sdfg.sdfg_id,
                                                   edge.dst.label)

        if not edge.data.is_unconditional():
            expr += '}\n'
        return expr
Beispiel #2
0
    def as_cpp(self, defined_vars, symbols) -> str:
        # Initialize to either "int i = 0" or "i = 0" depending on whether
        # the type has been defined
        init = ''
        if self.init is not None:
            if defined_vars.has(self.itervar):
                init = self.itervar
            else:
                init = f'{symbols[self.itervar]} {self.itervar}'
            init += ' = ' + self.init

        sdfg = self.guard.parent

        preinit = ''
        if self.init_edges:
            for edge in self.init_edges:
                for k, v in edge.data.assignments.items():
                    if k != self.itervar:
                        cppinit = cpp.unparse_interstate_edge(v, sdfg)
                        preinit += f'{k} = {cppinit};\n'

        if self.condition is not None:
            cond = cpp.unparse_interstate_edge(self.condition.code[0], sdfg)
        else:
            cond = ''

        update = ''
        if self.update is not None:
            update = f'{self.itervar} = {self.update}'

        expr = f'{preinit}\nfor ({init}; {cond}; {update}) {{\n'
        expr += _clean_loop_body(self.body.as_cpp(defined_vars, symbols))
        expr += '\n}\n'
        return expr
Beispiel #3
0
    def as_cpp(self, defined_vars, symbols) -> str:
        # Initialize to either "int i = 0" or "i = 0" depending on whether
        # the type has been defined
        init = ''
        if self.init is not None:
            if defined_vars.has(self.itervar):
                init = self.itervar
            else:
                init = f'{symbols[self.itervar]} {self.itervar}'
            init += ' = ' + self.init

        if self.condition is not None:
            sdfg = self.guard.parent
            cond = cpp.unparse_interstate_edge(self.condition.code[0], sdfg)
        else:
            cond = ''

        update = ''
        if self.update is not None:
            update = f'{self.itervar} = {self.update}'

        expr = f'for ({init}; {cond}; {update}) {{\n'
        expr += self.body.as_cpp(defined_vars, symbols)
        expr += '\n}\n'
        return expr
Beispiel #4
0
    def as_cpp(self, defined_vars, symbols) -> str:
        if self.test is not None:
            test = cpp.unparse_interstate_edge(self.test.code[0], self.sdfg)
        else:
            test = 'true'

        expr = 'do {\n'
        expr += self.body.as_cpp(defined_vars, symbols)
        expr += f'\n}} while ({test});\n'
        return expr
Beispiel #5
0
    def as_cpp(self, codegen, symbols) -> str:
        if self.test is not None:
            test = cpp.unparse_interstate_edge(self.test.code[0], self.sdfg, codegen=codegen)
        else:
            test = 'true'

        expr = 'do {\n'
        expr += _clean_loop_body(self.body.as_cpp(codegen, symbols))
        expr += f'\n}} while ({test});\n'
        return expr
Beispiel #6
0
    def as_cpp(self, defined_vars, symbols) -> str:
        if self.test is not None:
            sdfg = self.guard.parent
            test = cpp.unparse_interstate_edge(self.test.code[0], sdfg)
        else:
            test = 'true'

        expr = f'while ({test}) {{\n'
        expr += self.body.as_cpp(defined_vars, symbols)
        expr += '\n}\n'
        return expr
Beispiel #7
0
 def as_cpp(self, codegen, symbols) -> str:
     condition_string = cpp.unparse_interstate_edge(self.condition.code[0], self.sdfg, codegen=codegen)
     expr = f'if ({condition_string}) {{\n'
     expr += self.body.as_cpp(codegen, symbols)
     expr += '\n}'
     if self.orelse:
         expr += ' else {\n'
         expr += self.orelse.as_cpp(codegen, symbols)
         expr += '\n}'
     expr += '\n'
     return expr
Beispiel #8
0
    def as_cpp(self, codegen, symbols) -> str:
        if self.test is not None:
            sdfg = self.guard.parent
            test = cpp.unparse_interstate_edge(self.test.code[0], sdfg, codegen=codegen)
        else:
            test = 'true'

        expr = f'while ({test}) {{\n'
        expr += _clean_loop_body(self.body.as_cpp(codegen, symbols))
        expr += '\n}\n'
        return expr
Beispiel #9
0
    def generate_transition(self,
                            sdfg: SDFG,
                            edge: Edge[InterstateEdge],
                            successor: SDFGState = None,
                            assignments_only: bool = False,
                            framecode: 'DaCeCodeGenerator' = None) -> str:
        """ 
        Helper function that generates a state transition (conditional goto) 
        from a state and an SDFG edge.
        :param sdfg: The parent SDFG.
        :param edge: The state transition edge to generate.
        :param successor: If not None, the state that will be generated right
                          after the current state (used to avoid extraneous 
                          gotos).
        :param assignments_only: If True, generates only the assignments
                                 of the inter-state edge.
        :param framecode: Code generator object (used for allocation information).
        :return: A c++ string representing the state transition code.
        """
        expr = ''
        condition_string = cpp.unparse_interstate_edge(edge.data.condition.code[0], sdfg, codegen=framecode)

        if not edge.data.is_unconditional() and not assignments_only:
            expr += f'if ({condition_string}) {{\n'

        if len(edge.data.assignments) > 0:
            expr += ';\n'.join([
                "{} = {}".format(variable, cpp.unparse_interstate_edge(value, sdfg, codegen=framecode))
                for variable, value in edge.data.assignments.items()
            ] + [''])

        if ((successor is None or edge.dst is not successor) and not assignments_only):
            expr += 'goto __state_{}_{};\n'.format(sdfg.sdfg_id, edge.dst.label)

        if not edge.data.is_unconditional() and not assignments_only:
            expr += '}\n'
        return expr
Beispiel #10
0
    def as_cpp(self, codegen, symbols) -> str:
        expr = ''
        for i, (condition, body) in enumerate(self.body):
            # First block in the chain is just "if", rest are "else if"
            prefix = '' if i == 0 else ' else '

            condition_string = cpp.unparse_interstate_edge(condition.code[0], self.sdfg, codegen=codegen)
            expr += f'{prefix}if ({condition_string}) {{\n'
            expr += body.as_cpp(codegen, symbols)
            expr += '\n}'

        # If we generate an if/else if blocks, we cannot guarantee that all
        # cases have been covered. In SDFG semantics, this means that the SDFG
        # execution should end, so we emit an "else goto exit" here.
        if len(self.body) > 0:
            expr += ' else {\n'
        expr += 'goto __state_exit_{};\n'.format(self.sdfg.sdfg_id)
        if len(self.body) > 0:
            expr += '\n}'
        return expr
Beispiel #11
0
    def _generate_transition(self, sdfg, sid, callsite_stream, edge,
                             assignments):
        condition_string = unparse_interstate_edge(edge.data.condition.code[0],
                                                   sdfg)
        always_true = self._is_always_true(condition_string)

        if not always_true:
            callsite_stream.write("if ({}) {{".format(condition_string), sdfg,
                                  sid)

        if len(assignments) > 0:
            callsite_stream.write(
                ";\n".join(
                    DaCeCodeGenerator._generate_assignments(assignments, sdfg)
                    + [""]), sdfg, sid)

        callsite_stream.write(
            "goto __state_{}_{};".format(sdfg.sdfg_id, edge.dst.label), sdfg,
            sid)

        if not always_true:
            callsite_stream.write("}")
Beispiel #12
0
    def generate_states(self, sdfg, scope_label, control_flow, global_stream,
                        callsite_stream, scope, states_generated,
                        generated_edges):

        states_topological = list(sdfg.topological_sort(sdfg.start_state))
        states_to_generate = collections.deque([
            s for s in states_topological
            if s in scope and s not in states_generated
        ])
        if len(states_to_generate) == 0:
            return

        while len(states_to_generate) > 0:

            state = states_to_generate.popleft()
            # When generating control flow constructs, we will not necessarily
            # move in topological order, so make sure this state has not
            # already been generated.
            if state in states_generated or state not in scope:
                continue
            states_generated.add(state)

            sid = sdfg.node_id(state)

            callsite_stream.write(
                "__state_{}_{}:;\n".format(sdfg.sdfg_id, state.label), sdfg,
                sid)

            # Don't generate brackets and comments for empty states
            if len([n for n in state.nodes()]) > 0:

                callsite_stream.write('{', sdfg, sid)

                self._dispatcher.dispatch_state(sdfg, state, global_stream,
                                                callsite_stream)

                callsite_stream.write('}', sdfg, sid)

            out_edges = sdfg.out_edges(state)

            # Write conditional branches to next states
            for edge in out_edges:

                generate_assignments = True
                generate_transition = True

                # Handle specialized control flow
                if (dace.config.Config.get_bool('optimizer',
                                                'detect_control_flow')):

                    for control in control_flow[edge]:

                        if isinstance(control, cflow.LoopAssignment):
                            # Generate the transition, but leave the
                            # assignments to the loop
                            generate_transition &= True
                            generate_assignments &= False

                        elif isinstance(control, cflow.LoopBack):
                            generate_transition &= False
                            generate_assignments &= False

                        elif isinstance(control, cflow.LoopExit):
                            # Need to strip the condition, so generate it from
                            # the loop entry
                            generate_transition &= False
                            generate_assignments &= True

                        elif isinstance(control, cflow.LoopEntry):
                            generate_transition &= False
                            generate_assignments &= False

                            if control.scope.assignment is not None:
                                assignment_edge = control.scope.assignment.edge
                                init_assignments = ", ".join(
                                    DaCeCodeGenerator._generate_assignments(
                                        assignment_edge.data.assignments,
                                        sdfg))
                                generated_edges.add(assignment_edge)
                            else:
                                init_assignments = ""

                            back_edge = control.scope.back.edge
                            continue_assignments = ", ".join(
                                DaCeCodeGenerator._generate_assignments(
                                    back_edge.data.assignments, sdfg))
                            generated_edges.add(back_edge)

                            entry_edge = control.scope.entry.edge
                            condition = unparse_interstate_edge(
                                entry_edge.data.condition.code[0], sdfg)
                            generated_edges.add(entry_edge)

                            if (len(init_assignments) > 0
                                    or len(continue_assignments) > 0):
                                callsite_stream.write(
                                    "for ({}; {}; {}) {{".format(
                                        init_assignments, condition,
                                        continue_assignments), sdfg, sid)
                            else:
                                callsite_stream.write(
                                    "while ({}) {{".format(condition), sdfg,
                                    sid)

                            # Generate loop body
                            self.generate_states(
                                sdfg, entry_edge.src.label + "_loop",
                                control_flow, global_stream, callsite_stream,
                                control.scope, states_generated,
                                generated_edges)

                            callsite_stream.write("}", sdfg, sid)

                            exit_edge = control.scope.exit.edge

                            # Update states to generate after nested call
                            states_to_generate = collections.deque([
                                s for s in states_to_generate
                                if s not in states_generated
                            ])
                            # If the next state to be generated is the exit
                            # state, we can omit the goto
                            if (len(states_to_generate) > 0
                                    and states_to_generate[0] == exit_edge.dst
                                    and exit_edge.dst not in states_generated):
                                pass
                            elif edge in generated_edges:
                                # This edge has more roles, goto doesn't apply
                                pass
                            else:
                                callsite_stream.write(
                                    "goto __state_{}_{};".format(
                                        sdfg.sdfg_id,
                                        control.scope.exit.edge.dst))
                                generated_edges.add(control.scope.exit.edge)

                        elif isinstance(control, cflow.IfExit):
                            generate_transition &= True
                            generate_assignments &= True

                        elif isinstance(control, cflow.IfEntry):
                            generate_transition &= False
                            generate_assignments &= True

                            if len(set(control.scope) - states_generated) == 0:
                                continue

                            then_scope = control.scope.if_then_else.then_scope
                            else_scope = control.scope.if_then_else.else_scope

                            then_entry = then_scope.entry.edge

                            condition = unparse_interstate_edge(
                                then_entry.data.condition.code[0], sdfg)

                            callsite_stream.write(
                                "if ({}) {{".format(condition), sdfg, sid)
                            generated_edges.add(then_entry)

                            # Generate the then-scope
                            self.generate_states(sdfg, state.label + "_then",
                                                 control_flow, global_stream,
                                                 callsite_stream, then_scope,
                                                 states_generated,
                                                 generated_edges)

                            callsite_stream.write("} else {", sdfg, sid)
                            generated_edges.add(else_scope.entry.edge)

                            # Generate the else-scope
                            self.generate_states(sdfg, state.label + "_else",
                                                 control_flow, global_stream,
                                                 callsite_stream, else_scope,
                                                 states_generated,
                                                 generated_edges)

                            callsite_stream.write("}", sdfg, sid)
                            generated_edges.add(else_scope.exit.edge)

                            # Update states to generate after nested call
                            states_to_generate = collections.deque([
                                s for s in states_to_generate
                                if s not in states_generated
                            ])

                            if_exit_state = control.scope.exit.edge.dst

                            if ((if_exit_state not in states_generated) and
                                ((len(states_to_generate) > 0) and
                                 (states_to_generate[0] == if_exit_state))):
                                pass
                            else:
                                callsite_stream.write(
                                    "goto __state_{}_{};".format(
                                        sdfg.sdfg_id,
                                        control.scope.exit.edge.dst))

                        else:

                            raise TypeError(
                                "Unknown control flow \"{}\"".format(
                                    type(control).__name__))

                if generate_assignments and len(edge.data.assignments) > 0:
                    assignments_to_generate = edge.data.assignments
                else:
                    assignments_to_generate = {}

                if generate_transition:

                    if ((len(out_edges) == 1)
                            and (edge.dst not in states_generated)
                            and ((len(states_to_generate) > 0) and
                                 (states_to_generate[0] == edge.dst))):
                        # If there is only one outgoing edge, the target will
                        # be generated next, we can omit the goto
                        pass
                    elif (len(out_edges) == 1 and len(states_to_generate) == 0
                          and (edge.dst not in scope)):
                        # This scope has ended, and we don't need to generate
                        # any output edge
                        pass
                    else:
                        self._generate_transition(sdfg, sid, callsite_stream,
                                                  edge,
                                                  assignments_to_generate)
                        # Assignments will be generated in the transition
                        generate_assignments = False

                if generate_assignments:

                    callsite_stream.write(
                        ";\n".join(
                            DaCeCodeGenerator._generate_assignments(
                                assignments_to_generate, sdfg) + [""]), sdfg,
                        sid)
                generated_edges.add(edge)
                # End of out_edges loop

            if (((len(out_edges) == 0) or
                 (not isinstance(scope, cflow.ControlFlowScope) and
                  (len(states_to_generate) == 0)))
                    and (len(states_generated) != sdfg.number_of_nodes())):
                callsite_stream.write(
                    "goto __state_exit_{}_{};".format(sdfg.sdfg_id,
                                                      scope_label), sdfg, sid)

        # Write exit state
        callsite_stream.write(
            "__state_exit_{}_{}:;".format(sdfg.sdfg_id, scope_label), sdfg)
Beispiel #13
0
 def _generate_assignments(assignments, sdfg):
     return [
         "{} = {}".format(variable, unparse_interstate_edge(value, sdfg))
         for variable, value in assignments.items()
     ]