def sym2cpp(s, arrayexprs: Optional[Set[str]] = None) -> Union[str, List[str]]: """ Converts an array of symbolic variables (or one) to C++ strings. :param s: Symbolic expression to convert. :param arrayexprs: Set of names of arrays, used to convert SymPy user-functions back to array expressions. :return: C++-compilable expression or list thereof. """ if not isinstance(s, list): return cppunparse.pyexpr2cpp(symbolic.symstr(s, arrayexprs)) return [cppunparse.pyexpr2cpp(symbolic.symstr(d, arrayexprs)) for d in s]
def generate_scope(self, sdfg, dfg_scope, state_id, function_stream, callsite_stream): # Take care of map header assert len(dfg_scope.source_nodes()) == 1 map_header = dfg_scope.source_nodes()[0] function_stream.write('extern int __dace_comm_size, __dace_comm_rank;', sdfg, state_id, map_header) # Add extra opening brace (dynamic map ranges, closed in MapExit # generator) callsite_stream.write('{', sdfg, state_id, map_header) if len(map_header.map.params) > 1: raise NotImplementedError( 'Multi-dimensional MPI maps are not supported') state = sdfg.node(state_id) symtypes = map_header.new_symbols(sdfg, state, state.symbols_defined_at(map_header)) for var, r in zip(map_header.map.params, map_header.map.range): begin, end, skip = r callsite_stream.write('{\n', sdfg, state_id, map_header) callsite_stream.write( '%s %s = %s + __dace_comm_rank * (%s);\n' % (symtypes[var], var, cppunparse.pyexpr2cpp(symbolic.symstr(begin)), cppunparse.pyexpr2cpp(symbolic.symstr(skip))), sdfg, state_id, map_header) to_allocate = dace.sdfg.local_transients(sdfg, dfg_scope, map_header) allocated = set() for child in dfg_scope.scope_children()[map_header]: if not isinstance(child, nodes.AccessNode): continue if child.data not in to_allocate or child.data in allocated: continue allocated.add(child.data) self._dispatcher.dispatch_allocate(sdfg, dfg_scope, state_id, child, function_stream, callsite_stream) self._dispatcher.dispatch_subgraph(sdfg, dfg_scope, state_id, function_stream, callsite_stream, skip_entry_node=True)
def _test_pyexpr2cpp(func, expected_string): result = cppunparse.pyexpr2cpp(func) if result != expected_string: print("ERROR in pyexpr2cpp, expected:\n%s\n\ngot:\n%s\n" % (expected_string, result)) return False return True
def generate_scope(self, sdfg, dfg_scope, state_id, function_stream, callsite_stream): # Take care of map header assert len(dfg_scope.source_nodes()) == 1 map_header = dfg_scope.source_nodes()[0] function_stream.write('extern int __dace_comm_size, __dace_comm_rank;', sdfg, state_id, map_header) if len(map_header.map.params) > 1: raise NotImplementedError( 'Multi-dimensional MPI maps are not supported') for var, r in zip(map_header.map.params, map_header.map.range): begin, end, skip = r callsite_stream.write('{\n', sdfg, state_id, map_header) callsite_stream.write( 'auto %s = %s + __dace_comm_rank * (%s);\n' % (var, cppunparse.pyexpr2cpp(symbolic.symstr(begin)), cppunparse.pyexpr2cpp(symbolic.symstr(skip))), sdfg, state_id, map_header) to_allocate = dace.sdfg.local_transients(sdfg, dfg_scope, map_header) allocated = set() for child in dfg_scope.scope_dict(node_to_children=True)[map_header]: if not isinstance(child, nodes.AccessNode): continue if child.data not in to_allocate or child.data in allocated: continue allocated.add(child.data) self._dispatcher.dispatch_allocate(sdfg, dfg_scope, state_id, child, function_stream, callsite_stream) self._dispatcher.dispatch_initialize(sdfg, dfg_scope, state_id, child, function_stream, callsite_stream) self._dispatcher.dispatch_subgraph(sdfg, dfg_scope, state_id, function_stream, callsite_stream, skip_entry_node=True)
def generate_scope(self, sdfg, dfg_scope, state_id, function_stream, callsite_stream): # Take care of map header assert len(dfg_scope.source_nodes()) == 1 map_header = dfg_scope.source_nodes()[0] function_stream.write('extern int __dace_comm_size, __dace_comm_rank;', sdfg, state_id, map_header) # Add extra opening brace (dynamic map ranges, closed in MapExit # generator) callsite_stream.write('{', sdfg, state_id, map_header) if len(map_header.map.params) > 1: raise NotImplementedError( 'Multi-dimensional MPI maps are not supported') state = sdfg.node(state_id) symtypes = map_header.new_symbols(sdfg, state, state.symbols_defined_at(map_header)) for var, r in zip(map_header.map.params, map_header.map.range): begin, end, skip = r callsite_stream.write('{\n', sdfg, state_id, map_header) callsite_stream.write( '%s %s = %s + __dace_comm_rank * (%s);\n' % (symtypes[var], var, cppunparse.pyexpr2cpp(symbolic.symstr(begin)), cppunparse.pyexpr2cpp(symbolic.symstr(skip))), sdfg, state_id, map_header) self._frame.allocate_arrays_in_scope(sdfg, map_header, function_stream, callsite_stream) self._dispatcher.dispatch_subgraph(sdfg, dfg_scope, state_id, function_stream, callsite_stream, skip_entry_node=True)
def _cases_from_branches( edges: List[Edge[InterstateEdge]], cblocks: Dict[Edge[InterstateEdge], GeneralBlock], ) -> Tuple[str, Dict[str, GeneralBlock]]: """ If the input list of edges correspond to a switch/case scope (with all conditions being "x == y" for a unique symbolic x and integers y), returns the switch/case scope parameters. :param edges: List of inter-state edges. :return: Tuple of (case variable C++ expression, mapping from case to control flow block). If not a valid switch/case scope, returns None. """ cond = edges[0].data.condition_sympy() if not isinstance(cond, sp.Basic): return None a = sp.Wild('a') b = sp.Wild('b', properties=[lambda k: k.is_Integer]) m = cond.match(sp.Eq(a, b)) if m: # Obtain original code for variable call_or_compare = edges[0].data.condition.code[0].value if isinstance(call_or_compare, ast.Call): astvar = call_or_compare.args[0] else: # Binary comparison astvar = call_or_compare.left else: # Try integer == symbol m = cond.match(sp.Eq(b, a)) if m: call_or_compare = edges[0].data.condition.code[0].value if isinstance(call_or_compare, ast.Call): astvar = call_or_compare.args[1] else: # Binary comparison astvar = call_or_compare.right else: return None # Get C++ expression from AST switchvar = cppunparse.pyexpr2cpp(astvar) # Check that all edges match criteria result = {} for e in edges: ematch = e.data.condition_sympy().match(sp.Eq(m[a], b)) if not ematch: ematch = e.data.condition_sympy().match(sp.Eq(b, m[a])) if not ematch: return None # Create mapping to codeblocks result[cpp.sym2cpp(ematch[b])] = cblocks[e] return switchvar, result
def visit_Call(self, node): if isinstance(node.func, ast.Name) and (node.func.id.startswith('__DACESTRUCT_') or node.func.id in self._structs): fields = ', '.join([ '.%s = %s' % (rname(arg.arg), cppunparse.pyexpr2cpp(arg.value)) for arg in sorted(node.keywords, key=lambda x: x.arg) ]) tname = node.func.id if node.func.id.startswith('__DACESTRUCT_'): tname = node.func.id[len('__DACESTRUCT_'):] return ast.copy_location( ast.Name(id="%s { %s }" % (tname, fields), ctx=ast.Load), node) return self.generic_visit(node)
def size_string(self): return (" * ".join( [cppunparse.pyexpr2cpp(symbolic.symstr(s)) for s in self.shape]))
def _sym2cpp(s, arrayexprs): return cppunparse.pyexpr2cpp(symbolic.symstr(s, arrayexprs))
def sym2cpp(s): """ Converts an array of symbolic variables (or one) to C++ strings. """ if not isinstance(s, list): return cppunparse.pyexpr2cpp(symbolic.symstr(s)) return [cppunparse.pyexpr2cpp(symbolic.symstr(d)) for d in s]
def memlet_view_ctor(self, sdfg, memlet, direction): useskip = False memlet_params = [] memlet_name = memlet.data if isinstance(sdfg.arrays[memlet.data], data.Scalar): raise ValueError("This should never have happened") if isinstance(memlet.subset, subsets.Indices): # Compute address memlet_params.append(cpp_array_expr(sdfg, memlet, False)) dims = 0 elif isinstance(memlet.subset, subsets.Range): dims = len(memlet.subset.ranges) #memlet_params.append("") # Dimensions to remove from view (due to having one value) indexdims = [] nonIndexDims = [] for dim, (rb, re, rs) in enumerate(memlet.subset.ranges): if rs != 1: useskip = True try: if (re - rb) == 0: indexdims.append(dim) else: nonIndexDims.append(dim) except TypeError: # cannot determine truth value of Relational nonIndexDims.append(dim) if len(nonIndexDims) > 1 and len(indexdims) > 0: raise NotImplementedError( 'subviews of more than one dimension ' + 'not implemented') elif len( nonIndexDims) == 1 and len(indexdims) > 0: # One dimension indexdim = nonIndexDims[0] # Contiguous dimension if indexdim == dims - 1: memlet_params[-1] += ' + %s' % cpp_array_expr( sdfg, memlet, False) memlet_params.append( '0, %s' % (sym2cpp(memlet.subset.ranges[-1][1] - memlet.subset.ranges[-1][0]))) else: # Non-contiguous dimension useskip = True memlet_params[-1] += ' + %s' % cpp_array_expr( sdfg, memlet, False) memlet_range = memlet.subset.ranges[indexdim] memlet_stride = sdfg.arrays[memlet.data].strides[indexdim] memlet_stride = sym2cpp(memlet_stride) memlet_params.append( '0, %s, %s' % (sym2cpp(memlet_range[1] - memlet_range[0]), sym2cpp(memlet_stride))) # Subtract index dimensions from array dimensions dims -= len(indexdims) elif len(indexdims) == 0: for (rb, re, rs), s in zip(memlet.subset.ranges, sdfg.arrays[memlet.data].shape): if useskip: memlet_params.append( '%s, %s, %s' % (cppunparse.pyexpr2cpp(symbolic.symstr(rb)), cppunparse.pyexpr2cpp(symbolic.symstr(s)), cppunparse.pyexpr2cpp(symbolic.symstr(rs)))) else: memlet_params.append( '%s, %s' % (cppunparse.pyexpr2cpp(symbolic.symstr(rb)), cppunparse.pyexpr2cpp(symbolic.symstr(s)))) elif len(nonIndexDims) == 0: # Scalar view if len(memlet_params) > 0: # Compute address memlet_params[-1] += ' + ' + cpp_array_expr( sdfg, memlet, False) else: memlet_params.append(cpp_array_expr(sdfg, memlet, False)) dims = 0 else: raise RuntimeError('Memlet type "%s" not implemented' % memlet.subset) if dims == 0: return 'dace::ArrayViewImmaterial%s%s<%s, %s, int32_t> ("%s", %s)' % ( 'In' if direction == "in" else "Out", 'Skip' if useskip else '', sdfg.arrays[memlet.data].dtype.ctype, symbolic.symstr( memlet.veclen), memlet.data, ', '.join(memlet_params)) else: return 'dace::ArrayViewImmaterial%s%s<%s, %s, int32_t, %s> ("%s", %s)' % ( 'In' if direction == "in" else "Out", 'Skip' if useskip else '', sdfg.arrays[memlet.data].dtype.ctype, symbolic.symstr(memlet.veclen), ', '.join([ str(s) for s in memlet.subset.bounding_box_size() ]), memlet.data, ', '.join(memlet_params))