def replace_properties_dict(node: Any, repl: Dict[str, str], symrepl: Dict[symbolic.SymbolicType, symbolic.SymbolicType] = None): symrepl = symrepl or { symbolic.pystr_to_symbolic(symname): symbolic.pystr_to_symbolic(new_name) if isinstance(new_name, str) else new_name for symname, new_name in repl.items() } for propclass, propval in node.properties(): if propval is None: continue pname = propclass.attr_name if isinstance(propclass, properties.SymbolicProperty): setattr(node, pname, propval.subs(symrepl)) elif isinstance(propclass, properties.DataProperty): if propval in repl: setattr(node, pname, repl[propval]) elif isinstance(propclass, (properties.RangeProperty, properties.ShapeProperty)): setattr(node, pname, _replsym(list(propval), symrepl)) elif isinstance(propclass, properties.CodeProperty): # Don't replace variables that appear as an input or an output # connector, as this should shadow the outer declaration. reduced_repl = set(repl.keys()) if hasattr(node, 'in_connectors'): reduced_repl -= set(node.in_connectors.keys()) | set(node.out_connectors.keys()) reduced_repl = {k: repl[k] for k in reduced_repl} code = propval.code if isinstance(code, str) and code: lang = propval.language if lang is dtypes.Language.CPP: # Replace in C++ code prefix = '' tokenized = tokenize_cpp.findall(code) for name, new_name in reduced_repl.items(): if name not in tokenized: continue # Use local variables and shadowing to replace replacement = f'auto {name} = {cppunparse.pyexpr2cpp(new_name)};\n' prefix = replacement + prefix if prefix: propval.code = prefix + code else: warnings.warn('Replacement of %s with %s was not made ' 'for string tasklet code of language %s' % (name, new_name, lang)) elif propval.code is not None: afr = ASTFindReplace(reduced_repl) for stmt in propval.code: afr.visit(stmt) elif (isinstance(propclass, properties.DictProperty) and pname == 'symbol_mapping'): # Symbol mappings for nested SDFGs for symname, sym_mapping in propval.items(): try: propval[symname] = symbolic.pystr_to_symbolic(str(sym_mapping)).subs(symrepl) except AttributeError: # If the symbolified value has no subs pass
def replace_properties(node: Any, symrepl: Dict[symbolic.symbol, symbolic.SymbolicType], name: str, new_name: str): for propclass, propval in node.properties(): if propval is None: continue pname = propclass.attr_name if isinstance(propclass, properties.SymbolicProperty): setattr(node, pname, propval.subs(symrepl)) elif isinstance(propclass, properties.DataProperty): if propval == name: setattr(node, pname, new_name) elif isinstance(propclass, (properties.RangeProperty, properties.ShapeProperty)): setattr(node, pname, _replsym(list(propval), symrepl)) elif isinstance(propclass, properties.CodeProperty): # Don't replace variables that appear as an input or an output # connector, as this should shadow the outer declaration. if hasattr(node, 'in_connectors'): if name in node.in_connectors: continue if hasattr(node, 'out_connectors'): if name in node.out_connectors: continue if isinstance(propval.code, str): if str(name) != str(new_name): lang = propval.language newcode = propval.code if not re.findall(r'[^\w]%s[^\w]' % name, newcode): continue if lang is dtypes.Language.CPP: # Replace in C++ code # Avoid import loop from dace.codegen.targets.cpp import sym2cpp # Use local variables and shadowing to replace replacement = 'auto %s = %s;\n' % (name, sym2cpp(new_name)) propval.code = replacement + newcode else: warnings.warn('Replacement of %s with %s was not made ' 'for string tasklet code of language %s' % (name, new_name, lang)) elif propval.code is not None: afr = ASTFindReplace({name: symbolic.symstr(new_name)}) for stmt in propval.code: afr.visit(stmt) elif (isinstance(propclass, properties.DictProperty) and pname == 'symbol_mapping'): # Symbol mappings for nested SDFGs for symname, sym_mapping in propval.items(): try: propval[symname] = symbolic.pystr_to_symbolic(str(sym_mapping)).subs(symrepl) except AttributeError: # If the symbolified value has no subs pass
def instantiate_loop( self, sdfg: sd.SDFG, loop_states: List[sd.SDFGState], loop_subgraph: gr.SubgraphView, itervar: str, value: symbolic.SymbolicType, state_suffix=None, ): # Using to/from JSON copies faster than deepcopy (which will also # copy the parent SDFG) new_states = [ sd.SDFGState.from_json(s.to_json(), context={'sdfg': sdfg}) for s in loop_states ] # Replace iterate with value in each state for state in new_states: state.set_label(state.label + '_' + itervar + '_' + ( state_suffix if state_suffix is not None else '%d' % value)) state.replace(itervar, value) # Add subgraph to original SDFG for edge in loop_subgraph.edges(): src = new_states[loop_states.index(edge.src)] dst = new_states[loop_states.index(edge.dst)] # Replace conditions in subgraph edges data: sd.InterstateEdge = copy.deepcopy(edge.data) if data.condition: ASTFindReplace({itervar: str(value)}).visit(data.condition) sdfg.add_edge(src, dst, data) return new_states
def replace_properties(node: Any, name: str, new_name: str): if str(name) == str(new_name): return symrepl = { symbolic.symbol(name): symbolic.pystr_to_symbolic(new_name) if isinstance(new_name, str) else new_name } for propclass, propval in node.properties(): if propval is None: continue pname = propclass.attr_name if isinstance(propclass, properties.SymbolicProperty): setattr(node, pname, propval.subs(symrepl)) elif isinstance(propclass, properties.DataProperty): if propval == name: setattr(node, pname, new_name) elif isinstance(propclass, (properties.RangeProperty, properties.ShapeProperty)): setattr(node, pname, _replsym(list(propval), symrepl)) elif isinstance(propclass, properties.CodeProperty): if isinstance(propval.code, str): if str(name) != str(new_name): lang = propval.language newcode = propval.code if not re.findall(r'[^\w]%s[^\w]' % name, newcode): continue if lang is dtypes.Language.CPP: # Replace in C++ code # Use local variables and shadowing to replace replacement = 'auto %s = %s;\n' % (name, new_name) propval.code = replacement + newcode else: warnings.warn( 'Replacement of %s with %s was not made ' 'for string tasklet code of language %s' % (name, new_name, lang)) elif propval.code is not None: for stmt in propval.code: ASTFindReplace({name: new_name}).visit(stmt) elif (isinstance(propclass, properties.DictProperty) and pname == 'symbol_mapping'): # Symbol mappings for nested SDFGs for symname, sym_mapping in propval.items(): propval[symname] = sym_mapping.subs(symrepl)
def apply(self, sdfg): # Obtain loop information guard: sd.SDFGState = sdfg.node(self.subgraph[DetectLoop._loop_guard]) begin: sd.SDFGState = sdfg.node(self.subgraph[DetectLoop._loop_begin]) after_state: sd.SDFGState = sdfg.node( self.subgraph[DetectLoop._exit_state]) # Obtain iteration variable, range, and stride guard_inedges = sdfg.in_edges(guard) condition_edge = sdfg.edges_between(guard, begin)[0] itervar = list(guard_inedges[0].data.assignments.keys())[0] condition = condition_edge.data.condition_sympy() rng = LoopUnroll._loop_range(itervar, guard_inedges, condition) # Loop must be unrollable if self.count == 0 and any( symbolic.issymbolic(r, sdfg.constants) for r in rng): raise ValueError('Loop cannot be fully unrolled, size is symbolic') if self.count != 0: raise NotImplementedError # TODO(later) # Find the state prior to the loop if rng[0] == symbolic.pystr_to_symbolic( guard_inedges[0].data.assignments[itervar]): before_state: sd.SDFGState = guard_inedges[0].src last_state: sd.SDFGState = guard_inedges[1].src else: before_state: sd.SDFGState = guard_inedges[1].src last_state: sd.SDFGState = guard_inedges[0].src # Get loop states loop_states = list( sdutil.dfs_topological_sort( sdfg, sources=[begin], condition=lambda _, child: child != guard)) first_id = loop_states.index(begin) last_id = loop_states.index(last_state) loop_subgraph = gr.SubgraphView(sdfg, loop_states) # Evaluate the real values of the loop start, end, stride = (symbolic.evaluate(r, sdfg.constants) for r in rng) # Create states for loop subgraph unrolled_states = [] for i in range(start, end + 1, stride): # Using to/from JSON copies faster than deepcopy (which will also # copy the parent SDFG) new_states = [ sd.SDFGState.from_json(s.to_json(), context={'sdfg': sdfg}) for s in loop_states ] # Replace iterate with value in each state for state in new_states: state.set_label(state.label + '_%s_%d' % (itervar, i)) state.replace(itervar, i) # Add subgraph to original SDFG for edge in loop_subgraph.edges(): src = new_states[loop_states.index(edge.src)] dst = new_states[loop_states.index(edge.dst)] # Replace conditions in subgraph edges data: sd.InterstateEdge = copy.deepcopy(edge.data) if data.condition: ASTFindReplace({itervar: str(i)}).visit(data.condition) sdfg.add_edge(src, dst, data) # Connect iterations with unconditional edges if len(unrolled_states) > 0: sdfg.add_edge(unrolled_states[-1][1], new_states[first_id], sd.InterstateEdge()) unrolled_states.append((new_states[first_id], new_states[last_id])) # Connect new states to before and after states without conditions if unrolled_states: sdfg.add_edge(before_state, unrolled_states[0][0], sd.InterstateEdge()) sdfg.add_edge(unrolled_states[-1][1], after_state, sd.InterstateEdge()) # Remove old states from SDFG sdfg.remove_nodes_from([guard] + loop_states)