def visit_Subscript(self, node: ast.Subscript) -> Any: # Convert subscript to symbol name node_name = astutils.rname(node) if node_name in self.iconns: self.latest[node_name] += 1 new_name = f'{node_name}_{self.latest[node_name]}' subset = subsets.Range( astutils.subscript_to_slice(node, self.sdfg.arrays)[1]) # Check if range can be collapsed if _range_is_promotable(subset, self.defined): self.in_mapping[new_name] = (node_name, subset) return ast.copy_location(ast.Name(id=new_name, ctx=ast.Load()), node) else: self.do_not_remove.add(node_name) elif node_name in self.oconns: self.latest[node_name] += 1 new_name = f'{node_name}_{self.latest[node_name]}' subset = subsets.Range( astutils.subscript_to_slice(node, self.sdfg.arrays)[1]) # Check if range can be collapsed if _range_is_promotable(subset, self.defined): self.out_mapping[new_name] = (node_name, subset) return ast.copy_location( ast.Name(id=new_name, ctx=ast.Store()), node) else: self.do_not_remove.add(node_name) return self.generic_visit(node)
def delinearize_linearize( self, desc: data.Array, copy_shape: Tuple[symbolic.SymbolicType], rng: subsets.Range) -> Tuple[symbolic.SymbolicType]: """ Converts one N-dimensional iteration space to another M-dimensional space via linearization followed by delinearization. """ indices = [ symbolic.pystr_to_symbolic(f'__i{i}') for i in range(len(copy_shape)) ] # Special case for when both dimensionalities are equal if tuple(desc.shape) == tuple(copy_shape): return subsets.Range([(ind, ind, 1) for ind in indices]) if rng is not None: # Deal with offsets and strides in range indices = rng.coord_at(indices) linear_index = sum(indices[i] * data._prod(copy_shape[i + 1:]) for i in range(len(indices))) cur_index = [0] * len(desc.shape) divide_by = 1 for i in reversed(range(len(desc.shape))): cur_index[i] = (linear_index / divide_by) % desc.shape[i] divide_by = divide_by * desc.shape[i] return subsets.Range([(ind, ind, 1) for ind in cur_index])
def propagate(self, array, expressions, node_range): result = [(None, None, None)] * len(self.patterns_per_dim) overapprox_range = subsets.Range([ (rb.approx if isinstance(rb, symbolic.SymExpr) else rb, re.approx if isinstance(re, symbolic.SymExpr) else re, rs.approx if isinstance(rs, symbolic.SymExpr) else rs) for rb, re, rs in node_range ]) for i, smpattern in enumerate(self.patterns_per_dim): dexprs = [] for expr in expressions: if isinstance(expr[i], symbolic.SymExpr): dexprs.append(expr[i].approx) elif isinstance(expr[i], tuple): dexprs.append( (expr[i][0].approx if isinstance( expr[i][0], symbolic.SymExpr) else expr[i][0], expr[i][1].approx if isinstance( expr[i][1], symbolic.SymExpr) else expr[i][1], expr[i][2].approx if isinstance( expr[i][2], symbolic.SymExpr) else expr[i][2], expr.tile_sizes[i])) else: dexprs.append(expr[i]) result[i] = smpattern.propagate(array, dexprs, overapprox_range) # TODO(later): Not necessarily Range (general integer sets) return subsets.Range(result)
def coverage_dicts(sdfg, graph, map_entry, outer_range=True): ''' returns a tuple of two dicts: the first dict has as a key all data entering the map and its associated access range the second dict has as a key all data exiting the map and its associated access range if outer_range = True, substitutes outer ranges into min/max of inner access range ''' map_exit = graph.exit_node(map_entry) map = map_entry.map entry_coverage = {} exit_coverage = {} # create dicts with which we can replace all iteration # variable_mapping by their range map_min = {dace.symbol(param): e for param, e in zip(map.params, map.range.min_element())} map_max = {dace.symbol(param): e for param, e in zip(map.params, map.range.max_element())} # look at inner memlets at map entry for e in graph.out_edges(map_entry): if not e.data.subset: continue if outer_range: # get subset min_element = [m.subs(map_min) for m in e.data.subset.min_element()] max_element = [m.subs(map_max) for m in e.data.subset.max_element()] # create range rng = subsets.Range((min_e, max_e, 1) for min_e, max_e in zip(min_element, max_element)) else: rng = dcpy(e.data.subset) if e.data.data not in entry_coverage: entry_coverage[e.data.data] = rng else: old_coverage = entry_coverage[e.data.data] entry_coverage[e.data.data] = subsets.union(old_coverage, rng) # look at inner memlets at map exit for e in graph.in_edges(map_exit): if outer_range: # get subset min_element = [m.subs(map_min) for m in e.data.subset.min_element()] max_element = [m.subs(map_max) for m in e.data.subset.max_element()] # craete range rng = subsets.Range((min_e, max_e, 1) for min_e, max_e in zip(min_element, max_element)) else: rng = dcpy(e.data.subset) if e.data.data not in exit_coverage: exit_coverage[e.data.data] = rng else: old_coverage = exit_coverage[e.data] exit_coverage[e.data.data] = subsets.union(old_coverage, rng) # return both coverages as a tuple return (entry_coverage, exit_coverage)
def test_intersects_constant(): rng1 = subsets.Range([(0, 4, 1)]) rng2 = subsets.Range([(3, 4, 1)]) rng3 = subsets.Range([(1, 5, 1)]) rng4 = subsets.Range([(5, 7, 1)]) ind1 = subsets.Indices([0]) ind2 = subsets.Indices([1]) ind3 = subsets.Indices([5]) assert subsets.intersects(rng1, rng2) is True assert subsets.intersects(rng1, rng3) is True assert subsets.intersects(rng1, rng4) is False assert subsets.intersects(ind1, rng1) is True assert subsets.intersects(rng1, ind2) is True assert subsets.intersects(rng1, ind3) is False
def from_memlet(memlet: 'Memlet') -> 'Memlet': sbs = subsets.Range( memlet.subset.ndrange()) if memlet.subset is not None else None osbs = subsets.Range(memlet.other_subset.ndrange() ) if memlet.other_subset is not None else None result = Memlet(data=memlet.data, subset=sbs, other_subset=osbs, volume=memlet.volume, dynamic=memlet.dynamic, wcr=memlet.wcr, debuginfo=copy(memlet.debuginfo), wcr_nonatomic=memlet.wcr_nonatomic, allow_oob=memlet.allow_oob) result._is_data_src = memlet._is_data_src return result
def _create_strided_range(self, sdfg: SDFG, state: SDFGState, map_entry: nodes.MapEntry): map_exit = state.exit_node(map_entry) dim_idx = self.dim_idx new_dim_prefix = self.new_dim_prefix tile_size = self.tile_size divides_evenly = self.divides_evenly tile_stride = self.tile_stride if tile_stride == 0: tile_stride = tile_size if tile_stride != tile_size: raise NotImplementedError # Retrieve parameter and range of dimension to be strip-mined. target_dim = map_entry.map.params[dim_idx] td_from, td_to, td_step = map_entry.map.range[dim_idx] new_dim = self._find_new_dim(sdfg, state, map_entry, new_dim_prefix, target_dim) new_dim_range = (td_from, td_to, tile_size) new_map = nodes.Map(map_entry.map.label, [new_dim], subsets.Range([new_dim_range])) dimsym = dace.symbolic.pystr_to_symbolic(new_dim) td_from_new = dimsym if divides_evenly: td_to_new = dimsym + tile_size - 1 else: if isinstance(td_to, dace.symbolic.SymExpr): td_to = td_to.expr td_to_new = dace.symbolic.SymExpr( sympy.Min(dimsym + tile_size - 1, td_to), dimsym + tile_size - 1) td_step_new = td_step return new_dim, new_map, (td_from_new, td_to_new, td_step_new)
def _make_full_range(memlet: astnodes._Memlet): fullRange = sbs.Range([(0, s - 1, 1) for s in memlet.data.shape]) fullMemlet = astnodes._Memlet(memlet.data, memlet.dataname, memlet.attribute, fullRange.num_elements(), None, None, fullRange, memlet.veclen, None, None, {}) return fullMemlet
def _offset_refine( torefine: Dict[str, Tuple[Memlet, Set[int]]], outer_edges: Callable[[nodes.NestedSDFG, str], Iterable[MultiConnectorEdge[Memlet]]]): # Offset memlets inside negatively by "refine", modify outer # memlets to be "refine" for aname, (refine, indices) in torefine.items(): outer_edge = next(iter(outer_edges(nsdfg_node, aname))) new_memlet = helpers.unsqueeze_memlet(refine, outer_edge.data) outer_edge.data.subset = subsets.Range([ ns if i in indices else os for i, (os, ns) in enumerate( zip(outer_edge.data.subset, new_memlet.subset)) ]) if aname in refined: continue # Refine internal memlets for nstate in nsdfg.nodes(): for e in nstate.edges(): if e.data.data == aname: e.data.subset.offset(refine.subset, True, indices) # Refine accesses in interstate edges refiner = ASTRefiner(aname, refine.subset, nsdfg, indices) for isedge in nsdfg.edges(): for k, v in isedge.data.assignments.items(): vast = ast.parse(v) refiner.visit(vast) isedge.data.assignments[k] = astutils.unparse(vast) if isedge.data.condition.language is dtypes.Language.Python: for i, stmt in enumerate(isedge.data.condition.code): isedge.data.condition.code[i] = refiner.visit(stmt) else: raise NotImplementedError refined.add(aname)
def calc_set_image_range(map_idx, map_set, array_range): image = [] for a_range in array_range: new_range = list(a_range) for m_idx, m_range in zip(map_idx, map_set): symbol = symbolic.pystr_to_symbolic(m_idx) for i in range(3): if isinstance(m_range[i], SymExpr): exact = m_range[i].expr approx = m_range[i].approx else: exact = m_range[i] approx = overapproximate(m_range[i]) if isinstance(new_range[i], SymExpr): new_range[i] = SymExpr( new_range[i].expr.subs([(symbol, exact)]), new_range[i].approx.subs([(symbol, approx)])) elif issymbolic(new_range[i]): new_range[i] = SymExpr( new_range[i].subs([(symbol, exact)]), new_range[i].subs([(symbol, approx)])) else: new_range[i] = SymExpr(new_range[i], new_range[i]) image.append(new_range) return subsets.Range(image)
def calc_set_union(set_a, set_b): if isinstance(set_a, subsets.Indices) or isinstance(set_b, subsets.Indices): raise NotImplementedError('Set union with indices is not implemented.') if not (isinstance(set_a, subsets.Range) and isinstance(set_b, subsets.Range)): raise TypeError('Can only compute the union of ranges.') if len(set_a) != len(set_b): raise ValueError('Range dimensions do not match') union = [] for range_a, range_b in zip(set_a, set_b): r_union = [] for i in range(3): if isinstance(range_a[i], SymExpr): a_exact = range_a[i].expr a_approx = range_a[i].approx else: a_exact = range_a[i] a_approx = range_a[i] if isinstance(range_b[i], SymExpr): b_exact = range_b[i].expr b_approx = range_b[i].approx else: b_exact = range_b[i] b_approx = range_b[i] if i in {0, 2}: r_union.append(SymExpr(sympy.Min(a_exact, b_exact), sympy.Min(a_approx, b_approx))) else: r_union.append(SymExpr(sympy.Max(a_exact, b_exact), sympy.Max(a_approx, b_approx))) union.append(r_union) # union.append([ # sympy.Min(range_a[0], range_b[0]), # sympy.Max(range_a[1], range_b[1]), # sympy.Min(range_a[2], range_b[2]), # ]) return subsets.Range(union)
def parse_memlet_subset(array: data.Data, node: Union[ast.Name, ast.Subscript], das: Dict[str, Any], parsed_slice: Any = None) -> Tuple[subsets.Range, List[int]]: """ Parses an AST subset and returns access range, as well as new dimensions to add. :param array: Accessed data descriptor (used for filling in missing data, e.g., negative indices or empty shapes). :param node: AST node representing whole array or subset thereof. :param das: Dictionary of defined arrays and symbols mapped to their values. :return: A 2-tuple of (subset, list of new axis indices). """ # Get memlet range ndslice = [(0, s - 1, 1) for s in array.shape] extra_dims = [] arrdims: Dict[int, str] = {} if isinstance(node, ast.Subscript): # Parse and evaluate ND slice(s) (possibly nested) if parsed_slice: cnode = copy.deepcopy(node) cnode.slice = parsed_slice else: cnode = node ast_ndslices = astutils.subscript_to_ast_slice_recursive(cnode) offsets = list(range(len(array.shape))) # Loop over nd-slices (A[i][j][k]...) subset_array = [] for idx, ast_ndslice in enumerate(ast_ndslices): # Cut out dimensions that were indexed in the previous slice narray = copy.deepcopy(array) narray.shape = [ s for i, s in enumerate(array.shape) if i in offsets ] # Loop over the N dimensions ndslice, offsets, new_extra_dims, arrdims = _fill_missing_slices( das, ast_ndslice, narray, offsets) if new_extra_dims and idx != (len(ast_ndslices) - 1): raise NotImplementedError('New axes only implemented for last ' 'slice') if arrdims and len(ast_ndslices) != 1: raise NotImplementedError('Array dimensions not implemented ' 'for consecutive subscripts') extra_dims = new_extra_dims subset_array.append(_ndslice_to_subset(ndslice)) subset = subset_array[0] # Compose nested indices, e.g., of the form "A[i,:,j,:][k,l]" for i in range(1, len(subset_array)): subset = subset.compose(subset_array[i]) else: # Use entire range subset = _ndslice_to_subset(ndslice) if isinstance(subset, subsets.Indices): subset = subsets.Range([(i, i, 1) for i in subset]) return subset, extra_dims, arrdims
def _modify_memlet(sdfg, subset, data_name): desc = sdfg.arrays[data_name] if len(subset) == len(desc.shape): # Already in the right shape, modify new dimension subset = list(subset)[1:] new_subset = subsets.Range([('__dace_db_param', '__dace_db_param', 1)] + list(subset)) return new_subset
def calc_set_image_index(map_idx, map_set, array_idx): image = [] for a_idx in array_idx.indices: new_range = [a_idx, a_idx, 1] for m_idx, m_range in zip(map_idx, map_set): symbol = symbolic.pystr_to_symbolic(m_idx) new_range[0] = new_range[0].subs(symbol, m_range[0]) new_range[1] = new_range[1].subs(symbol, m_range[1]) image.append(new_range) return subsets.Range(image)
def _Subscript(self, t: ast.Subscript): from dace.frontend.python.astutils import subscript_to_slice target, rng = subscript_to_slice(t, self.sdfg.arrays) rng = subsets.Range(rng) if rng.num_elements() != 1: raise SyntaxError( 'Range subscripts disallowed in interstate edges') memlet = mmlt.Memlet(data=target, subset=rng) self.write(cpp_array_expr(self.sdfg, memlet))
def visit_Subscript(self, node: ast.Subscript) -> ast.Subscript: if astutils.rname(node.value) == self.to_refine: rng = subsets.Range( astutils.subscript_to_slice(node, self.sdfg.arrays, without_array=True)) rng.offset(self.subset, True, self.indices) return ast.copy_location( astutils.slice_to_subscript(self.to_refine, rng), node) return self.generic_visit(node)
def calc_set_image_range(map_idx, map_set, array_range): image = [] for a_range in array_range: new_range = a_range for m_idx, m_range in zip(map_idx, map_set): symbol = symbolic.pystr_to_symbolic(m_idx) new_range = [ new_range[i].subs(symbol, m_range[i]) for i in range(0, 3) ] image.append(new_range) return subsets.Range(image)
def _ndslice_to_subset(ndslice): is_tuple = [isinstance(x, tuple) for x in ndslice] if not any(is_tuple): return subsets.Indices(ndslice) else: if not all(is_tuple): # If a mix of ranges and indices is found, convert to range for i in range(len(ndslice)): if not is_tuple[i]: ndslice[i] = (ndslice[i], ndslice[i], 1) return subsets.Range(ndslice)
def dirichlet_tasklet(state, B, x0, y0, width, height, initval=0): # Set up map that only has a write output, without any input. This generates an empty memlet from the map # entry to the tasklet automatically _, me, mx = state.add_mapped_tasklet( 'boundary', dict(i='%s:%s' % (y0, y0 + height), j='%s:%s' % (x0, x0 + width)), {}, '''b = %f''' % initval, dict(b=dace.Memlet(data=B.data, subset='i,j')), external_edges=False) # Add the edge directly (i.e, without string parsing) using a Range object. # Notice that ranges are internally INCLUSIVE. out_subset = subsets.Range([(y0, y0 + height - 1, 1), (x0, x0 + width - 1, 1)]) state.add_nedge(mx, B, dace.Memlet(data=B.data, subset=out_subset))
def calc_set_image_range(map_idx, map_set, array_range): image = [] for a_range in array_range: new_range = a_range for m_idx, m_range in zip(map_idx, map_set): symbol = symbolic.pystr_to_symbolic(m_idx) new_range = [ new_range[i].subs(symbol, dace.symbolic.overapproximate(m_range[i])) if dace.symbolic.issymbolic(new_range[i]) else new_range[i] for i in range(0, 3) ] image.append(new_range) return subsets.Range(image)
def _check_cand(candidates, outer_edges): for cname, (cand, nstate, indices) in candidates.items(): if all(me == 0 for i, me in enumerate(cand.subset.min_element()) if i in indices): ignore.add(cname) continue # Ensure outer memlets begin with 0 outer_edge = next(iter(outer_edges(nsdfg, cname))) if any(me != 0 for i, me in enumerate( outer_edge.data.subset.min_element()) if i in indices): ignore.add(cname) continue # Check w.r.t. loops if len(nstate.ranges) > 0: # Re-annotate loop ranges, in case someone changed them # TODO: Move out of here! nstate.ranges = {} from dace.sdfg.propagation import _annotate_loop_ranges _annotate_loop_ranges(nsdfg.sdfg, []) memlet = propagation.propagate_subset( [cand], nsdfg.sdfg.arrays[cname], sorted(nstate.ranges.keys()), subsets.Range([ v.ndrange()[0] for _, v in sorted(nstate.ranges.items()) ])) if all(me == 0 for i, me in enumerate(memlet.subset.min_element()) if i in indices): ignore.add(cname) continue # Modify memlet to propagated one candidates[cname] = (memlet, nstate, indices) else: memlet = cand # If there are any symbols here that are not defined # in "defined_symbols" missing_symbols = (memlet.free_symbols - set(nsdfg.symbol_mapping.keys())) if missing_symbols: ignore.add(cname) continue
def parse_memlet_subset(array: data.Data, node: Union[ast.Name, ast.Subscript], das: Dict[str, Any]): array_dependencies = {} # Get memlet range ndslice = [(0, s - 1, 1) for s in array.shape] if isinstance(node, ast.Subscript): # Parse and evaluate ND slice(s) (possibly nested) ast_ndslices = astutils.subscript_to_ast_slice_recursive(node) offsets = list(range(len(array.shape))) # Loop over nd-slices (A[i][j][k]...) subset_array = [] for ast_ndslice in ast_ndslices: # Cut out dimensions that were indexed in the previous slice narray = copy.deepcopy(array) narray.shape = [ s for i, s in enumerate(array.shape) if i in offsets ] # Loop over the N dimensions ndslice, offsets = _fill_missing_slices(das, ast_ndslice, narray, offsets) subset_array.append(_ndslice_to_subset(ndslice)) subset = subset_array[0] # Compose nested indices, e.g., of the form "A[i,:,j,:][k,l]" for i in range(1, len(subset_array)): subset = subset.compose(subset_array[i]) # Compute additional array dependencies (as a result of # indirection) # for dim in subset: # if not isinstance(dim, tuple): dim = [dim] # for r in dim: # for expr in symbolic.swalk(r): # if symbolic.is_sympy_userfunction(expr): # arr = expr.func.__name__ # array_dependencies[arr] = self.curnode.globals[arr] else: # Use entire range subset = _ndslice_to_subset(ndslice) if isinstance(subset, subsets.Indices): subset = subsets.Range([(i, i, 1) for i in subset]) return subset
def calc_set_union(set_a, set_b): if isinstance(set_a, subsets.Indices) or isinstance( set_b, subsets.Indices): raise NotImplementedError('Set union with indices is not implemented.') if not (isinstance(set_a, subsets.Range) and isinstance(set_b, subsets.Range)): raise TypeError('Can only compute the union of ranges.') if len(set_a) != len(set_b): raise ValueError('Range dimensions do not match') union = [] for range_a, range_b in zip(set_a, set_b): union.append([ sympy.Min(range_a[0], range_b[0]), sympy.Max(range_a[1], range_b[1]), sympy.Min(range_a[2], range_b[2]), ]) return subsets.Range(union)
def pop_dims(subset, dims): popped = [] if isinstance(subset, subsets.Indices): indices = copy.deepcopy(subsets.Indices) for i in dims: popped.append(indices.pop(i)) return subsets.Indices(indices) else: ranges = copy.deepcopy(subset.ranges) tsizes = copy.deepcopy(subset.tile_sizes) for i in dims: r = ranges.pop(i) t = tsizes.pop(i) popped.append((r, t)) new_subset = subsets.Range(ranges) new_subset.tile_sizes = tsizes return new_subset, popped
def propagate(self, array, expressions, node_range): rng = [(None, None, 1)] * len(array.shape) node_range_gen = (range(rb, re, rs) for rb, re, rs in node_range) for ndind in itertools.product(*tuple(node_range_gen)): repldict = {p: ndind[i] for i, p in enumerate(self.params)} for expr in expressions: for dim, dexpr in enumerate(expr): evaldexpr = _subexpr(dexpr, repldict) rb, re, rs = rng[dim] if rb is None: rng[dim] = (evaldexpr, evaldexpr, 1) else: if evaldexpr < rb: rng[dim] = (evaldexpr, re, rs) if evaldexpr > re: # The +1 is because ranges are exclusive rng[dim] = (rb, evaldexpr, rs) return subsets.Range(rng)
def test_intersects_symbolic(): N, M = dace.symbol('N', positive=True), dace.symbol('M', positive=True) rng1 = subsets.Range([(0, N - 1, 1), (0, M - 1, 1)]) rng2 = subsets.Range([(0, 0, 1), (0, 0, 1)]) rng3_1 = subsets.Range([(N, N, 1), (0, 1, 1)]) rng3_2 = subsets.Range([(0, 1, 1), (M, M, 1)]) rng4 = subsets.Range([(N, N, 1), (M, M, 1)]) rng5 = subsets.Range([(0, 0, 1), (M, M, 1)]) rng6 = subsets.Range([(0, N, 1), (0, M, 1)]) rng7 = subsets.Range([(0, N - 1, 1), (N - 1, N, 1)]) ind1 = subsets.Indices([0, 1]) assert subsets.intersects(rng1, rng2) is True assert subsets.intersects(rng1, rng3_1) is False assert subsets.intersects(rng1, rng3_2) is False assert subsets.intersects(rng1, rng4) is False assert subsets.intersects(rng1, rng5) is False assert subsets.intersects(rng6, rng1) is True assert subsets.intersects(rng1, rng7) is None assert subsets.intersects(rng7, rng1) is None assert subsets.intersects(rng1, ind1) is None assert subsets.intersects(ind1, rng1) is None
def compose_and_push_back(first, second, dims=None, popped=None): if isinstance(first, subsets.Indices): subset = first.new_offset(second, negative=False) else: subset = first.compose(second) if dims and popped and len(dims) == len(popped): if isinstance(first, subsets.Indices): indices = subset.Indices for d, p in zip(reversed(dims), reversed(popped)): indices.insert(d, p) subset = subsets.Indices(indices) else: ranges = subset.ranges tsizes = subset.tile_sizes for d, (r, t) in zip(reversed(dims), reversed(popped)): ranges.insert(d, r) tsizes.insert(d, t) subset = subsets.Range(ranges) subset.tile_sizes = tsizes return subset
def calc_set_image_range(map_idx, map_set, array_range): image = [] for a_range in array_range: new_range = list(a_range) for m_idx, m_range in zip(map_idx, map_set): symbol = symbolic.pystr_to_symbolic(m_idx) for i in range(3): if isinstance(m_range[i], SymExpr): exact = m_range[i].expr approx = m_range[i].approx else: exact = m_range[i] approx = overapproximate(m_range[i]) if isinstance(new_range[i], SymExpr): new_range[i] = SymExpr( new_range[i].expr.subs([(symbol, exact)]), new_range[i].approx.subs([(symbol, approx)])) elif issymbolic(new_range[i]): new_range[i] = SymExpr( new_range[i].subs([(symbol, exact)]), new_range[i].subs([(symbol, approx)])) else: new_range[i] = SymExpr(new_range[i], new_range[i]) if isinstance(new_range[0], SymExpr): start = new_range[0].approx else: start = new_range[0] if isinstance(new_range[1], SymExpr): stop = new_range[1].approx else: stop = new_range[1] if isinstance(new_range[2], SymExpr): step = new_range[2].approx else: step = new_range[2] descending = (start > stop) == True posstep = (step > 0) == True if descending and posstep: new_range[0], new_range[1] = new_range[1], new_range[0] image.append(new_range) return subsets.Range(image)
def _create_from_tile_numbers(self, sdfg: SDFG, state: SDFGState, map_entry: nodes.MapEntry): map_exit = state.exit_node(map_entry) # Retrieve transformation properties. dim_idx = self.dim_idx new_dim_prefix = self.new_dim_prefix divides_evenly = self.divides_evenly number_of_tiles = self.tile_size tile_stride = self.tile_stride number_of_tiles = dace.symbolic.pystr_to_symbolic(number_of_tiles) # Retrieve parameter and range of dimension to be strip-mined. target_dim = map_entry.map.params[dim_idx] td_from, td_to, td_step = map_entry.map.range[dim_idx] tile_size = map_entry.map.range.size_exact()[dim_idx] / number_of_tiles if tile_stride == 0: tile_stride = tile_size if tile_stride != tile_size: raise NotImplementedError new_dim = self._find_new_dim(sdfg, state, map_entry, new_dim_prefix, target_dim) new_dim_range = (td_from, number_of_tiles - 1, 1) new_map = nodes.Map(map_entry.map.label, [new_dim], subsets.Range([new_dim_range])) dimsym = dace.symbolic.pystr_to_symbolic(new_dim) td_from_new = dimsym * tile_size if divides_evenly: td_to_new = (dimsym + 1) * tile_size - 1 else: if isinstance(td_to, dace.symbolic.SymExpr): td_to = td_to.expr td_to_new = dace.symbolic.SymExpr( sympy.Min((dimsym + 1) * tile_size - 1, td_to), (dimsym + 1) * tile_size - 1) td_step_new = td_step return new_dim, new_map, (td_from_new, td_to_new, td_step_new)
def calc_set_image_range(map_idx, map_set, array_range, strided): image = [] n = len(array_range) - len(strided) if n > 0: strided.append([strided[-1]] * n) for a_range, stride in zip(array_range, strided): new_range = list(a_range) for m_idx, m_range in zip(map_idx, map_set): symbol = symbolic.pystr_to_symbolic(m_idx) new_range[0] = new_range[0].subs( symbol, dace.symbolic.overapproximate(m_range[0])) new_range[1] = new_range[1].subs( symbol, dace.symbolic.overapproximate(m_range[1])) if stride: new_range[2] = symbolic.pystr_to_symbolic('%s / %s' % (str( new_range[2]), symbolic.symstr(m_range[1]))) else: new_range[2] = new_range[2].subs( symbol, dace.symbolic.overapproximate(m_range[2])) image.append(new_range) return subsets.Range(image)