From 36010fa348cd751d2c53f9041c4ce6ba3d4f5ae9 Mon Sep 17 00:00:00 2001 From: Tal Ben-Nun Date: Thu, 14 Sep 2023 08:17:59 -0700 Subject: [PATCH 01/13] Support attributes in symbolic expressions --- dace/symbolic.py | 109 ++++++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 48 deletions(-) diff --git a/dace/symbolic.py b/dace/symbolic.py index 0ab6e3f6ff..ccca2f2c9c 100644 --- a/dace/symbolic.py +++ b/dace/symbolic.py @@ -658,6 +658,7 @@ def eval(cls, x, y): def _eval_is_boolean(self): return True + class IfExpr(sympy.Function): @classmethod @@ -723,6 +724,19 @@ class IsNot(sympy.Function): pass +class Attr(sympy.Function): + """ + Represents a get-attribute call on a function, equivalent to ``a.b`` in Python. + """ + + @property + def free_symbols(self): + return {sympy.Symbol(str(self))} + + def __str__(self): + return f'{self.args[0]}.{self.args[1]}' + + def sympy_intdiv_fix(expr): """ Fix for SymPy printing out reciprocal values when they should be integral in "ceiling/floor" sympy functions. @@ -926,10 +940,9 @@ def _process_is(elem: Union[Is, IsNot]): return expr -class SympyBooleanConverter(ast.NodeTransformer): +class PythonOpToSympyConverter(ast.NodeTransformer): """ - Replaces boolean operations with the appropriate SymPy functions to avoid - non-symbolic evaluation. + Replaces various operations with the appropriate SymPy functions to avoid non-symbolic evaluation. """ _ast_to_sympy_comparators = { ast.Eq: 'Eq', @@ -945,12 +958,37 @@ class SympyBooleanConverter(ast.NodeTransformer): ast.NotIn: 'NotIn', } + _ast_to_sympy_functions = { + ast.BitAnd: 'BitwiseAnd', + ast.BitOr: 'BitwiseOr', + ast.BitXor: 'BitwiseXor', + ast.Invert: 'BitwiseNot', + ast.LShift: 'LeftShift', + ast.RShift: 'RightShift', + ast.FloorDiv: 'int_floor', + } + def visit_UnaryOp(self, node): if isinstance(node.op, ast.Not): func_node = ast.copy_location(ast.Name(id=type(node.op).__name__, ctx=ast.Load()), node) new_node = ast.Call(func=func_node, args=[self.visit(node.operand)], keywords=[]) return ast.copy_location(new_node, node) - return node + elif isinstance(node.op, ast.Invert): + func_node = ast.copy_location(ast.Name(id=self._ast_to_sympy_functions[type(node.op)], ctx=ast.Load()), + node) + new_node = ast.Call(func=func_node, args=[self.visit(node.operand)], keywords=[]) + return ast.copy_location(new_node, node) + return self.generic_visit(node) + + def visit_BinOp(self, node): + if type(node.op) in self._ast_to_sympy_functions: + func_node = ast.copy_location(ast.Name(id=self._ast_to_sympy_functions[type(node.op)], ctx=ast.Load()), + node) + new_node = ast.Call(func=func_node, + args=[self.visit(value) for value in (node.left, node.right)], + keywords=[]) + return ast.copy_location(new_node, node) + return self.generic_visit(node) def visit_BoolOp(self, node): func_node = ast.copy_location(ast.Name(id=type(node.op).__name__, ctx=ast.Load()), node) @@ -970,8 +1008,7 @@ def visit_Compare(self, node: ast.Compare): raise NotImplementedError op = node.ops[0] arguments = [node.left, node.comparators[0]] - func_node = ast.copy_location( - ast.Name(id=SympyBooleanConverter._ast_to_sympy_comparators[type(op)], ctx=ast.Load()), node) + func_node = ast.copy_location(ast.Name(id=self._ast_to_sympy_comparators[type(op)], ctx=ast.Load()), node) new_node = ast.Call(func=func_node, args=[self.visit(arg) for arg in arguments], keywords=[]) return ast.copy_location(new_node, node) @@ -984,40 +1021,18 @@ def visit_NameConstant(self, node): return self.visit_Constant(node) def visit_IfExp(self, node): - new_node = ast.Call(func=ast.Name(id='IfExpr', ctx=ast.Load), args=[node.test, node.body, node.orelse], keywords=[]) + new_node = ast.Call(func=ast.Name(id='IfExpr', ctx=ast.Load), + args=[self.visit(node.test), + self.visit(node.body), + self.visit(node.orelse)], + keywords=[]) return ast.copy_location(new_node, node) -class BitwiseOpConverter(ast.NodeTransformer): - """ - Replaces C/C++ bitwise operations with functions to avoid sympification to boolean operations. - """ - _ast_to_sympy_functions = { - ast.BitAnd: 'BitwiseAnd', - ast.BitOr: 'BitwiseOr', - ast.BitXor: 'BitwiseXor', - ast.Invert: 'BitwiseNot', - ast.LShift: 'LeftShift', - ast.RShift: 'RightShift', - ast.FloorDiv: 'int_floor', - } - - def visit_UnaryOp(self, node): - if isinstance(node.op, ast.Invert): - func_node = ast.copy_location( - ast.Name(id=BitwiseOpConverter._ast_to_sympy_functions[type(node.op)], ctx=ast.Load()), node) - new_node = ast.Call(func=func_node, args=[self.visit(node.operand)], keywords=[]) - return ast.copy_location(new_node, node) - return self.generic_visit(node) - - def visit_BinOp(self, node): - if type(node.op) in BitwiseOpConverter._ast_to_sympy_functions: - func_node = ast.copy_location( - ast.Name(id=BitwiseOpConverter._ast_to_sympy_functions[type(node.op)], ctx=ast.Load()), node) - new_node = ast.Call(func=func_node, - args=[self.visit(value) for value in (node.left, node.right)], - keywords=[]) - return ast.copy_location(new_node, node) - return self.generic_visit(node) + def visit_Attribute(self, node): + new_node = ast.Call(func=ast.Name(id='Attr', ctx=ast.Load), + args=[self.visit(node.value), ast.Name(id=node.attr, ctx=ast.Load)], + keywords=[]) + return ast.copy_location(new_node, node) @lru_cache(maxsize=16384) @@ -1070,21 +1085,17 @@ def pystr_to_symbolic(expr, symbol_map=None, simplify=None) -> sympy.Basic: 'int_ceil': int_ceil, 'IfExpr': IfExpr, 'Mod': sympy.Mod, + 'Attr': Attr, } # _clash1 enables all one-letter variables like N as symbols # _clash also allows pi, beta, zeta and other common greek letters locals.update(_sympy_clash) if isinstance(expr, str): - # Sympy processes "not/and/or" as direct evaluation. Replace with - # And/Or(x, y), Not(x) - if re.search(r'\bnot\b|\band\b|\bor\b|\bNone\b|==|!=|\bis\b|\bif\b', expr): - expr = unparse(SympyBooleanConverter().visit(ast.parse(expr).body[0])) - - # NOTE: If the expression contains bitwise operations, replace them with user-functions. - # NOTE: Sympy does not support bitwise operations and converts them to boolean operations. - if re.search('[&]|[|]|[\^]|[~]|[<<]|[>>]|[//]', expr): - expr = unparse(BitwiseOpConverter().visit(ast.parse(expr).body[0])) + # Sympy processes "not/and/or" as direct evaluation. Replace with And/Or(x, y), Not(x) + # Also replaces bitwise operations with user-functions since SymPy does not support bitwise operations. + if re.search(r'\bnot\b|\band\b|\bor\b|\bNone\b|==|!=|\bis\b|\bif\b|[&]|[|]|[\^]|[~]|[<<]|[>>]|[//]|[\.]', expr): + expr = unparse(PythonOpToSympyConverter().visit(ast.parse(expr).body[0])) # TODO: support SymExpr over-approximated expressions try: @@ -1125,6 +1136,8 @@ def _print_Function(self, expr): return f'(({self._print(expr.args[0])}) and ({self._print(expr.args[1])}))' if str(expr.func) == 'OR': return f'(({self._print(expr.args[0])}) or ({self._print(expr.args[1])}))' + if str(expr.func) == 'Attr': + return f'{self._print(expr.args[0])}.{self._print(expr.args[1])}' return super()._print_Function(expr) def _print_Mod(self, expr): @@ -1377,6 +1390,6 @@ def equal(a: SymbolicType, b: SymbolicType, is_length: bool = True) -> Union[boo if is_length: for arg in args: facts += [sympy.Q.integer(arg), sympy.Q.positive(arg)] - + with sympy.assuming(*facts): return sympy.ask(sympy.Q.is_true(sympy.Eq(*args))) From 0bbe5c4778d8a8654c3679b3d5695b3f3dc63658 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Thu, 14 Sep 2023 19:43:14 +0200 Subject: [PATCH 02/13] Added subscript visitor method. --- dace/symbolic.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dace/symbolic.py b/dace/symbolic.py index ccca2f2c9c..92a1d6cb56 100644 --- a/dace/symbolic.py +++ b/dace/symbolic.py @@ -1027,6 +1027,15 @@ def visit_IfExp(self, node): self.visit(node.orelse)], keywords=[]) return ast.copy_location(new_node, node) + + def visit_Subscript(self, node): + if isinstance(node.value, ast.Attribute): + attr = ast.Subscript(value=ast.Name(id=node.value.attr, ctx=ast.Load()), slice=node.slice, ctx=ast.Load()) + new_node = ast.Call(func=ast.Name(id='Attr', ctx=ast.Load), + args=[self.visit(node.value.value), self.visit(attr)], + keywords=[]) + return ast.copy_location(new_node, node) + return self.generic_visit(node) def visit_Attribute(self, node): new_node = ast.Call(func=ast.Name(id='Attr', ctx=ast.Load), From 29b269bfedb3659a932bdaeb19c93c223e77e787 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Thu, 14 Sep 2023 19:43:50 +0200 Subject: [PATCH 03/13] Added test. --- tests/sdfg/data/structure_test.py | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/sdfg/data/structure_test.py b/tests/sdfg/data/structure_test.py index 02b8f0c174..fa22420d53 100644 --- a/tests/sdfg/data/structure_test.py +++ b/tests/sdfg/data/structure_test.py @@ -443,6 +443,54 @@ def test_direct_read_structure(): assert np.allclose(B, ref) +def test_direct_read_structure_loops(): + + M, N, nnz = (dace.symbol(s) for s in ('M', 'N', 'nnz')) + csr_obj = dace.data.Structure(dict(indptr=dace.int32[M + 1], indices=dace.int32[nnz], data=dace.float32[nnz]), + name='CSRMatrix') + + sdfg = dace.SDFG('csr_to_dense_direct_loops') + + sdfg.add_datadesc('A', csr_obj) + sdfg.add_array('B', [M, N], dace.float32) + + state = sdfg.add_state() + + indices = state.add_access('A.indices') + data = state.add_access('A.data') + B = state.add_access('B') + + t = state.add_tasklet('indirection', {'j', '__val'}, {'__out'}, '__out[i, j] = __val') + state.add_edge(indices, None, t, 'j', dace.Memlet(data='A.indices', subset='idx')) + state.add_edge(data, None, t, '__val', dace.Memlet(data='A.data', subset='idx')) + state.add_edge(t, '__out', B, None, dace.Memlet(data='B', subset='0:M, 0:N', volume=1)) + + idx_before, idx_guard, idx_after = sdfg.add_loop(None, state, None, 'idx', 'A.indptr[i]', 'idx < A.indptr[i+1]', 'idx + 1') + i_before, i_guard, i_after = sdfg.add_loop(None, idx_before, None, 'i', '0', 'i < M', 'i + 1') + + sdfg.view() + + func = sdfg.compile() + + rng = np.random.default_rng(42) + A = sparse.random(20, 20, density=0.1, format='csr', dtype=np.float32, random_state=rng) + B = np.zeros((20, 20), dtype=np.float32) + + inpA = csr_obj.dtype._typeclass.as_ctypes()(indptr=A.indptr.__array_interface__['data'][0], + indices=A.indices.__array_interface__['data'][0], + data=A.data.__array_interface__['data'][0], + rows=A.shape[0], + cols=A.shape[1], + M=A.shape[0], + N=A.shape[1], + nnz=A.nnz) + + func(A=inpA, B=B, M=20, N=20, nnz=A.nnz) + ref = A.toarray() + + assert np.allclose(B, ref) + + def test_direct_read_nested_structure(): M, N, nnz = (dace.symbol(s) for s in ('M', 'N', 'nnz')) csr_obj = dace.data.Structure(dict(indptr=dace.int32[M + 1], indices=dace.int32[nnz], data=dace.float32[nnz]), @@ -505,3 +553,4 @@ def test_direct_read_nested_structure(): test_write_nested_structure() test_direct_read_structure() test_direct_read_nested_structure() + test_direct_read_structure_loops() From dcad52abdd59efe67af866f3fc518fe325629b55 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Thu, 14 Sep 2023 20:02:44 +0200 Subject: [PATCH 04/13] Updated Attr.free_symbols. --- dace/symbolic.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dace/symbolic.py b/dace/symbolic.py index 92a1d6cb56..3e05276ba9 100644 --- a/dace/symbolic.py +++ b/dace/symbolic.py @@ -731,7 +731,12 @@ class Attr(sympy.Function): @property def free_symbols(self): - return {sympy.Symbol(str(self))} + # return {sympy.Symbol(str(self))} + # NOTE: This makes it possible to easily pass validation checks such as: + # Are all interstate edge read symbols already defined? + # However, it may fail when we want to reconstruct the read memlets + # TODO: Find a better way to do this + return self.args[0].free_symbols def __str__(self): return f'{self.args[0]}.{self.args[1]}' From 59b8a0a8a23ab92795a855e77077e45bd935d924 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 18:31:37 +0200 Subject: [PATCH 05/13] Restore returning symbols with dotted name. --- dace/symbolic.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/dace/symbolic.py b/dace/symbolic.py index f1ca8d22d6..f3dfcfb36d 100644 --- a/dace/symbolic.py +++ b/dace/symbolic.py @@ -732,12 +732,7 @@ class Attr(sympy.Function): @property def free_symbols(self): - # return {sympy.Symbol(str(self))} - # NOTE: This makes it possible to easily pass validation checks such as: - # Are all interstate edge read symbols already defined? - # However, it may fail when we want to reconstruct the read memlets - # TODO: Find a better way to do this - return self.args[0].free_symbols + return {sympy.Symbol(str(self))} def __str__(self): return f'{self.args[0]}.{self.args[1]}' From a735a9f2e0c13155d9eed172399abe5268ee5e48 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 18:32:44 +0200 Subject: [PATCH 06/13] When inferring the type of attributes, check for Structures and return the corresponding field type if necessary. --- dace/codegen/tools/type_inference.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dace/codegen/tools/type_inference.py b/dace/codegen/tools/type_inference.py index 3d91e5f964..8ee8632c65 100644 --- a/dace/codegen/tools/type_inference.py +++ b/dace/codegen/tools/type_inference.py @@ -405,6 +405,9 @@ def _infer_dtype(t: Union[ast.Name, ast.Attribute]): def _Attribute(t, symbols, inferred_symbols): inferred_type = _dispatch(t.value, symbols, inferred_symbols) + if (isinstance(inferred_type, dtypes.pointer) and isinstance(inferred_type.base_type, dtypes.struct) and + t.attr in inferred_type.base_type.fields): + return inferred_type.base_type.fields[t.attr] return inferred_type From e34ca3c7308449b0c46668e79defae6b42c2fcae Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 18:33:14 +0200 Subject: [PATCH 07/13] Replace dots with arrows in for-loop code. --- dace/codegen/control_flow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dace/codegen/control_flow.py b/dace/codegen/control_flow.py index 1b97241e47..87a043b4db 100644 --- a/dace/codegen/control_flow.py +++ b/dace/codegen/control_flow.py @@ -393,6 +393,8 @@ def as_cpp(self, codegen, symbols) -> str: expr = f'{preinit}\nfor ({init}; {cond}; {update}) {{\n' expr += _clean_loop_body(self.body.as_cpp(codegen, symbols)) expr += '\n}\n' + # TODO: Check that the dot is used to access struct members + expr = expr.replace('.', '->') return expr @property From 6490b2f6c2eaf0f653278e714e47dbe714fadece Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 18:33:39 +0200 Subject: [PATCH 08/13] Fixed tests. --- tests/sdfg/data/structure_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/sdfg/data/structure_test.py b/tests/sdfg/data/structure_test.py index fa22420d53..55e3a936a7 100644 --- a/tests/sdfg/data/structure_test.py +++ b/tests/sdfg/data/structure_test.py @@ -466,9 +466,7 @@ def test_direct_read_structure_loops(): state.add_edge(t, '__out', B, None, dace.Memlet(data='B', subset='0:M, 0:N', volume=1)) idx_before, idx_guard, idx_after = sdfg.add_loop(None, state, None, 'idx', 'A.indptr[i]', 'idx < A.indptr[i+1]', 'idx + 1') - i_before, i_guard, i_after = sdfg.add_loop(None, idx_before, None, 'i', '0', 'i < M', 'i + 1') - - sdfg.view() + i_before, i_guard, i_after = sdfg.add_loop(None, idx_before, None, 'i', '0', 'i < M', 'i + 1', loop_end_state=idx_after) func = sdfg.compile() From 2eda9daad8b120543b37c2f1a943144c8451033b Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 21:48:40 +0200 Subject: [PATCH 09/13] Replace dots only in the for-loop header. --- dace/codegen/control_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dace/codegen/control_flow.py b/dace/codegen/control_flow.py index 87a043b4db..a9fbc35db6 100644 --- a/dace/codegen/control_flow.py +++ b/dace/codegen/control_flow.py @@ -391,10 +391,10 @@ def as_cpp(self, codegen, symbols) -> str: update = f'{self.itervar} = {self.update}' expr = f'{preinit}\nfor ({init}; {cond}; {update}) {{\n' - expr += _clean_loop_body(self.body.as_cpp(codegen, symbols)) - expr += '\n}\n' # TODO: Check that the dot is used to access struct members expr = expr.replace('.', '->') + expr += _clean_loop_body(self.body.as_cpp(codegen, symbols)) + expr += '\n}\n' return expr @property From 74002ce531789beb41bb1c50737b4c369069425b Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 23:34:28 +0200 Subject: [PATCH 10/13] ForLoop now generates the init code by unparsing the init interstate edge. --- dace/codegen/control_flow.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dace/codegen/control_flow.py b/dace/codegen/control_flow.py index a9fbc35db6..28bf38f14d 100644 --- a/dace/codegen/control_flow.py +++ b/dace/codegen/control_flow.py @@ -360,6 +360,9 @@ class ForScope(ControlFlow): init_edges: List[InterstateEdge] #: All initialization edges def as_cpp(self, codegen, symbols) -> str: + + sdfg = self.guard.parent + # Initialize to either "int i = 0" or "i = 0" depending on whether # the type has been defined defined_vars = codegen.dispatcher.defined_vars @@ -369,9 +372,8 @@ def as_cpp(self, codegen, symbols) -> str: init = self.itervar else: init = f'{symbols[self.itervar]} {self.itervar}' - init += ' = ' + self.init - - sdfg = self.guard.parent + init += ' = ' + unparse_interstate_edge(self.init_edges[0].data.assignments[self.itervar], + sdfg, codegen=codegen) preinit = '' if self.init_edges: @@ -391,8 +393,6 @@ def as_cpp(self, codegen, symbols) -> str: update = f'{self.itervar} = {self.update}' expr = f'{preinit}\nfor ({init}; {cond}; {update}) {{\n' - # TODO: Check that the dot is used to access struct members - expr = expr.replace('.', '->') expr += _clean_loop_body(self.body.as_cpp(codegen, symbols)) expr += '\n}\n' return expr From 927cb04de3eff6c216f3db2840431c2d590e0b1c Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 23:35:37 +0200 Subject: [PATCH 11/13] cpp.ptr replaces dots with arrows for structure data. --- dace/codegen/targets/cpp.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dace/codegen/targets/cpp.py b/dace/codegen/targets/cpp.py index d3d4f50ccd..c3bf9c4027 100644 --- a/dace/codegen/targets/cpp.py +++ b/dace/codegen/targets/cpp.py @@ -218,6 +218,11 @@ def ptr(name: str, desc: data.Data, sdfg: SDFG = None, framecode=None) -> str: from dace.codegen.targets.framecode import DaCeCodeGenerator # Avoid import loop framecode: DaCeCodeGenerator = framecode + if '.' in name: + root = name.split('.')[0] + if root in sdfg.arrays and isinstance(sdfg.arrays[root], data.Structure): + name = name.replace('.', '->') + # Special case: If memory is persistent and defined in this SDFG, add state # struct to name if (desc.transient and desc.lifetime in (dtypes.AllocationLifetime.Persistent, dtypes.AllocationLifetime.External)): @@ -992,8 +997,7 @@ def _Name(self, t: ast.Name): if t.id not in self.sdfg.arrays: return super()._Name(t) - # Replace values with their code-generated names (for example, - # persistent arrays) + # Replace values with their code-generated names (for example, persistent arrays) desc = self.sdfg.arrays[t.id] self.write(ptr(t.id, desc, self.sdfg, self.codegen)) From 000118935509a7a4b80fde1f354ef1c087c31331 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Wed, 27 Sep 2023 23:36:33 +0200 Subject: [PATCH 12/13] Defined/declared nested data now uses arrows instead of dots in their name. No more explicit replacement of dots in the allocation methods. --- dace/codegen/targets/cpu.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dace/codegen/targets/cpu.py b/dace/codegen/targets/cpu.py index 0464672390..f91d1350bb 100644 --- a/dace/codegen/targets/cpu.py +++ b/dace/codegen/targets/cpu.py @@ -59,11 +59,11 @@ def __init__(self, frame_codegen, sdfg): def _visit_structure(struct: data.Structure, args: dict, prefix: str = ''): for k, v in struct.members.items(): if isinstance(v, data.Structure): - _visit_structure(v, args, f'{prefix}.{k}') + _visit_structure(v, args, f'{prefix}->{k}') elif isinstance(v, data.StructArray): - _visit_structure(v.stype, args, f'{prefix}.{k}') + _visit_structure(v.stype, args, f'{prefix}->{k}') elif isinstance(v, data.Data): - args[f'{prefix}.{k}'] = v + args[f'{prefix}->{k}'] = v # Keeps track of generated connectors, so we know how to access them in nested scopes arglist = dict(self._frame.arglist) @@ -221,8 +221,8 @@ def allocate_view(self, sdfg: SDFG, dfg: SDFGState, state_id: int, node: nodes.A if isinstance(v, data.Data): ctypedef = dtypes.pointer(v.dtype).ctype if isinstance(v, data.Array) else v.dtype.ctype defined_type = DefinedType.Scalar if isinstance(v, data.Scalar) else DefinedType.Pointer - self._dispatcher.declared_arrays.add(f"{name}.{k}", defined_type, ctypedef) - self._dispatcher.defined_vars.add(f"{name}.{k}", defined_type, ctypedef) + self._dispatcher.declared_arrays.add(f"{name}->{k}", defined_type, ctypedef) + self._dispatcher.defined_vars.add(f"{name}->{k}", defined_type, ctypedef) # TODO: Find a better way to do this (the issue is with pointers of pointers) if atype.endswith('*'): atype = atype[:-1] @@ -299,9 +299,9 @@ def allocate_array(self, sdfg, dfg, state_id, node, nodedesc, function_stream, d name = node.data alloc_name = cpp.ptr(name, nodedesc, sdfg, self._frame) name = alloc_name - # NOTE: `expr` may only be a name or a sequence of names and dots. The latter indicates nested data and - # NOTE: structures. Since structures are implemented as pointers, we replace dots with arrows. - alloc_name = alloc_name.replace('.', '->') + # # NOTE: `expr` may only be a name or a sequence of names and dots. The latter indicates nested data and + # # NOTE: structures. Since structures are implemented as pointers, we replace dots with arrows. + # alloc_name = alloc_name.replace('.', '->') if nodedesc.transient is False: return @@ -331,7 +331,7 @@ def allocate_array(self, sdfg, dfg, state_id, node, nodedesc, function_stream, d if isinstance(v, data.Data): ctypedef = dtypes.pointer(v.dtype).ctype if isinstance(v, data.Array) else v.dtype.ctype defined_type = DefinedType.Scalar if isinstance(v, data.Scalar) else DefinedType.Pointer - self._dispatcher.declared_arrays.add(f"{name}.{k}", defined_type, ctypedef) + self._dispatcher.declared_arrays.add(f"{name}->{k}", defined_type, ctypedef) self.allocate_array(sdfg, dfg, state_id, nodes.AccessNode(f"{name}.{k}"), v, function_stream, declaration_stream, allocation_stream) return @@ -1184,9 +1184,9 @@ def memlet_definition(self, if not types: types = self._dispatcher.defined_vars.get(ptr, is_global=True) var_type, ctypedef = types - # NOTE: `expr` may only be a name or a sequence of names and dots. The latter indicates nested data and - # NOTE: structures. Since structures are implemented as pointers, we replace dots with arrows. - ptr = ptr.replace('.', '->') + # # NOTE: `expr` may only be a name or a sequence of names and dots. The latter indicates nested data and + # # NOTE: structures. Since structures are implemented as pointers, we replace dots with arrows. + # ptr = ptr.replace('.', '->') if fpga.is_fpga_array(desc): decouple_array_interfaces = Config.get_bool("compiler", "xilinx", "decouple_array_interfaces") From 306d7a9ea98a3abcd0e474ab83530ac4bf9585ea Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Thu, 28 Sep 2023 10:25:29 +0200 Subject: [PATCH 13/13] Removed commented out code. --- dace/codegen/targets/cpu.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dace/codegen/targets/cpu.py b/dace/codegen/targets/cpu.py index f91d1350bb..a796da9eed 100644 --- a/dace/codegen/targets/cpu.py +++ b/dace/codegen/targets/cpu.py @@ -299,9 +299,6 @@ def allocate_array(self, sdfg, dfg, state_id, node, nodedesc, function_stream, d name = node.data alloc_name = cpp.ptr(name, nodedesc, sdfg, self._frame) name = alloc_name - # # NOTE: `expr` may only be a name or a sequence of names and dots. The latter indicates nested data and - # # NOTE: structures. Since structures are implemented as pointers, we replace dots with arrows. - # alloc_name = alloc_name.replace('.', '->') if nodedesc.transient is False: return @@ -1184,9 +1181,6 @@ def memlet_definition(self, if not types: types = self._dispatcher.defined_vars.get(ptr, is_global=True) var_type, ctypedef = types - # # NOTE: `expr` may only be a name or a sequence of names and dots. The latter indicates nested data and - # # NOTE: structures. Since structures are implemented as pointers, we replace dots with arrows. - # ptr = ptr.replace('.', '->') if fpga.is_fpga_array(desc): decouple_array_interfaces = Config.get_bool("compiler", "xilinx", "decouple_array_interfaces")