Skip to content

Commit

Permalink
Merge branch 'master' into Inappropriate_Logic-28snitch.py71168730992…
Browse files Browse the repository at this point in the history
…70303797.diff
  • Loading branch information
phschaad authored Nov 2, 2023
2 parents b8615af + 9ff33a7 commit e084950
Show file tree
Hide file tree
Showing 102 changed files with 6,257 additions and 1,003 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/general-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7,'3.11']
python-version: [3.7,'3.12']
simplify: [0,1,autoopt]

steps:
Expand Down
6 changes: 5 additions & 1 deletion dace/cli/sdfv.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ def view(sdfg: dace.SDFG, filename: Optional[Union[str, int]] = None):
"""
# If vscode is open, try to open it inside vscode
if filename is None:
if 'VSCODE_IPC_HOOK_CLI' in os.environ or 'VSCODE_GIT_IPC_HANDLE' in os.environ:
if (
'VSCODE_IPC_HOOK' in os.environ
or 'VSCODE_IPC_HOOK_CLI' in os.environ
or 'VSCODE_GIT_IPC_HANDLE' in os.environ
):
filename = tempfile.mktemp(suffix='.sdfg')
sdfg.save(filename)
os.system(f'code {filename}')
Expand Down
5 changes: 3 additions & 2 deletions dace/codegen/compiled_sdfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ def get_workspace_sizes(self) -> Dict[dtypes.StorageType, int]:
result: Dict[dtypes.StorageType, int] = {}
for storage in self.external_memory_types:
func = self._lib.get_symbol(f'__dace_get_external_memory_size_{storage.name}')
func.restype = ctypes.c_size_t
result[storage] = func(self._libhandle, *self._lastargs[1])

return result
Expand Down Expand Up @@ -449,8 +450,8 @@ def _construct_args(self, kwargs) -> Tuple[Tuple[Any], Tuple[Any]]:
raise TypeError('Passing an object (type %s) to an array in argument "%s"' %
(type(arg).__name__, a))
elif dtypes.is_array(arg) and not isinstance(atype, dt.Array):
# GPU scalars are pointers, so this is fine
if atype.storage != dtypes.StorageType.GPU_Global:
# GPU scalars and return values are pointers, so this is fine
if atype.storage != dtypes.StorageType.GPU_Global and not a.startswith('__return'):
raise TypeError('Passing an array to a scalar (type %s) in argument "%s"' % (atype.dtype.ctype, a))
elif (not isinstance(atype, (dt.Array, dt.Structure)) and
not isinstance(atype.dtype, dtypes.callback) and
Expand Down
10 changes: 6 additions & 4 deletions dace/codegen/control_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
x < 5
/------>[s2]--------\\
[s1] \ ->[s5]
[s1] \\ ->[s5]
------>[s3]->[s4]--/
x >= 5
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
67 changes: 58 additions & 9 deletions dace/codegen/cppunparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import numpy as np
import os
import tokenize
import warnings

import sympy
import dace
Expand All @@ -86,6 +87,21 @@
from dace import dtypes
from dace.codegen.tools import type_inference


if sys.version_info < (3, 8):
BytesConstant = ast.Bytes
EllipsisConstant = ast.Ellipsis
NameConstant = ast.NameConstant
NumConstant = ast.Num
StrConstant = ast.Str
else:
BytesConstant = ast.Constant
EllipsisConstant = ast.Constant
NameConstant = ast.Constant
NumConstant = ast.Constant
StrConstant = ast.Constant


# Large float and imaginary literals get turned into infinities in the AST.
# We unparse those infinities to INFSTR.
INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)
Expand Down Expand Up @@ -573,7 +589,7 @@ def _generic_FunctionDef(self, t, is_async=False):
self.write('/* async */ ')

if getattr(t, "returns", False):
if isinstance(t.returns, ast.NameConstant):
if isinstance(t.returns, NameConstant):
if t.returns.value is None:
self.write('void')
else:
Expand Down Expand Up @@ -728,11 +744,27 @@ def _Repr(self, t):
raise NotImplementedError('Invalid C++')

def _Num(self, t):
repr_n = repr(t.n)
t_n = t.value if sys.version_info >= (3, 8) else t.n
repr_n = repr(t_n)
# For complex values, use DTYPE_TO_TYPECLASS dictionary
if isinstance(t.n, complex):
if isinstance(t_n, complex):
dtype = dtypes.DTYPE_TO_TYPECLASS[complex]

# Handle large integer values
if isinstance(t_n, int):
bits = t_n.bit_length()
if bits == 32: # Integer, potentially unsigned
if t_n >= 0: # unsigned
repr_n += 'U'
else: # signed, 64-bit
repr_n += 'LL'
elif 32 < bits <= 63:
repr_n += 'LL'
elif bits == 64 and t_n >= 0:
repr_n += 'ULL'
elif bits >= 64:
warnings.warn(f'Value wider than 64 bits encountered in expression ({t_n}), emitting as-is')

if repr_n.endswith("j"):
self.write("%s(0, %s)" % (dtype, repr_n.replace("inf", INFSTR)[:-1]))
else:
Expand Down Expand Up @@ -831,8 +863,23 @@ def _Tuple(
self.write(")")

unop = {"Invert": "~", "Not": "!", "UAdd": "+", "USub": "-"}
unop_lambda = {'Invert': (lambda x: ~x), 'Not': (lambda x: not x), 'UAdd': (lambda x: +x), 'USub': (lambda x: -x)}

def _UnaryOp(self, t):
# Dispatch constants after applying the operation
if sys.version_info[:2] < (3, 8):
if isinstance(t.operand, ast.Num):
newval = self.unop_lambda[t.op.__class__.__name__](t.operand.n)
newnode = ast.Num(n=newval)
self.dispatch(newnode)
return
else:
if isinstance(t.operand, ast.Constant):
newval = self.unop_lambda[t.op.__class__.__name__](t.operand.value)
newnode = ast.Constant(value=newval)
self.dispatch(newnode)
return

self.write("(")
self.write(self.unop[t.op.__class__.__name__])
self.write(" ")
Expand Down Expand Up @@ -867,13 +914,13 @@ def _BinOp(self, t):
self.write(")")
# Special cases for powers
elif t.op.__class__.__name__ == 'Pow':
if isinstance(t.right, (ast.Num, ast.Constant, ast.UnaryOp)):
if isinstance(t.right, (NumConstant, ast.Constant, ast.UnaryOp)):
power = None
if isinstance(t.right, (ast.Num, ast.Constant)):
power = t.right.n
if isinstance(t.right, (NumConstant, ast.Constant)):
power = t.right.value if sys.version_info >= (3, 8) else t.right.n
elif isinstance(t.right, ast.UnaryOp) and isinstance(t.right.op, ast.USub):
if isinstance(t.right.operand, (ast.Num, ast.Constant)):
power = -t.right.operand.n
if isinstance(t.right.operand, (NumConstant, ast.Constant)):
power = - (t.right.operand.value if sys.version_info >= (3, 8) else t.right.operand.n)

if power is not None and int(power) == power:
negative = power < 0
Expand Down Expand Up @@ -953,7 +1000,9 @@ def _Attribute(self, t):
# Special case: 3.__abs__() is a syntax error, so if t.value
# is an integer literal then we need to either parenthesize
# it or add an extra space to get 3 .__abs__().
if (isinstance(t.value, (ast.Num, ast.Constant)) and isinstance(t.value.n, int)):
if isinstance(t.value, ast.Constant) and isinstance(t.value.value, int):
self.write(" ")
elif sys.version_info < (3, 8) and isinstance(t.value, ast.Num) and isinstance(t.value.n, int):
self.write(" ")
if (isinstance(t.value, ast.Name) and t.value.id in ('dace', 'dace::math', 'dace::cmath')):
self.write("::")
Expand Down
2 changes: 1 addition & 1 deletion dace/codegen/instrumentation/papi.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ class PAPIUtils(object):
def available_counters() -> Dict[str, int]:
"""
Returns the available PAPI counters on this machine. Only works on
\*nix based systems with ``grep`` and ``papi-tools`` installed.
*nix based systems with ``grep`` and ``papi-tools`` installed.
:return: A set of available PAPI counters in the form of a dictionary
mapping from counter name to the number of native hardware
Expand Down
14 changes: 10 additions & 4 deletions dace/codegen/targets/cpp.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved.
# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved.
"""
Helper functions for C++ code generation.
NOTE: The C++ code generator is currently located in cpu.py.
Expand All @@ -9,6 +9,7 @@
import itertools
import math
import numbers
import sys
import warnings

import sympy as sp
Expand Down Expand Up @@ -218,6 +219,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)):
Expand Down Expand Up @@ -992,8 +998,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))

Expand Down Expand Up @@ -1271,7 +1276,8 @@ def visit_BinOp(self, node: ast.BinOp):
evaluated_constant = symbolic.evaluate(unparsed, self.constants)
evaluated = symbolic.symstr(evaluated_constant, cpp_mode=True)
value = ast.parse(evaluated).body[0].value
if isinstance(evaluated_node, numbers.Number) and evaluated_node != value.n:
if isinstance(evaluated_node, numbers.Number) and evaluated_node != (
value.value if sys.version_info >= (3, 8) else value.n):
raise TypeError
node.right = ast.parse(evaluated).body[0].value
except (TypeError, AttributeError, NameError, KeyError, ValueError, SyntaxError):
Expand Down
30 changes: 13 additions & 17 deletions dace/codegen/targets/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -331,7 +328,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
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -1517,9 +1511,10 @@ def make_restrict(expr: str) -> str:
arguments += [
f'{atype} {restrict} {aname}' for (atype, aname, _), restrict in zip(memlet_references, restrict_args)
]
fsyms = node.sdfg.used_symbols(all_symbols=False, keep_defined_in_mapping=True)
arguments += [
f'{node.sdfg.symbols[aname].as_arg(aname)}' for aname in sorted(node.symbol_mapping.keys())
if aname not in sdfg.constants
if aname in fsyms and aname not in sdfg.constants
]
arguments = ', '.join(arguments)
return f'void {sdfg_label}({arguments}) {{'
Expand All @@ -1528,9 +1523,10 @@ def generate_nsdfg_call(self, sdfg, state, node, memlet_references, sdfg_label,
prepend = []
if state_struct:
prepend = ['__state']
fsyms = node.sdfg.used_symbols(all_symbols=False, keep_defined_in_mapping=True)
args = ', '.join(prepend + [argval for _, _, argval in memlet_references] + [
cpp.sym2cpp(symval)
for symname, symval in sorted(node.symbol_mapping.items()) if symname not in sdfg.constants
cpp.sym2cpp(symval) for symname, symval in sorted(node.symbol_mapping.items())
if symname in fsyms and symname not in sdfg.constants
])
return f'{sdfg_label}({args});'

Expand Down Expand Up @@ -1814,11 +1810,11 @@ def _generate_MapEntry(

# Find if bounds are used within the scope
scope = state_dfg.scope_subgraph(node, False, False)
fsyms = scope.free_symbols
fsyms = self._frame.free_symbols(scope)
# Include external edges
for n in scope.nodes():
for e in state_dfg.all_edges(n):
fsyms |= e.data.free_symbols
fsyms |= e.data.used_symbols(False, e)
fsyms = set(map(str, fsyms))

ntid_is_used = '__omp_num_threads' in fsyms
Expand Down
15 changes: 11 additions & 4 deletions dace/codegen/targets/cuda.py
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,13 @@ def generate_kernel_scope(self, sdfg: SDFG, dfg_scope: ScopeSubgraphView, state_
kernel_params: list, function_stream: CodeIOStream, kernel_stream: CodeIOStream):
node = dfg_scope.source_nodes()[0]

# Get the thread/block index type
ttype = Config.get('compiler', 'cuda', 'thread_id_type')
tidtype = getattr(dtypes, ttype, False)
if not isinstance(tidtype, dtypes.typeclass):
raise ValueError(f'Configured type "{ttype}" for ``thread_id_type`` does not match any DaCe data type. '
'See ``dace.dtypes`` for available types (for example ``int32``).')

# allocating shared memory for dynamic threadblock maps
if has_dtbmap:
kernel_stream.write(
Expand Down Expand Up @@ -1990,8 +1997,8 @@ def generate_kernel_scope(self, sdfg: SDFG, dfg_scope: ScopeSubgraphView, state_

expr = _topy(bidx[i]).replace('__DAPB%d' % i, block_expr)

kernel_stream.write('int %s = %s;' % (varname, expr), sdfg, state_id, node)
self._dispatcher.defined_vars.add(varname, DefinedType.Scalar, 'int')
kernel_stream.write(f'{tidtype.ctype} {varname} = {expr};', sdfg, state_id, node)
self._dispatcher.defined_vars.add(varname, DefinedType.Scalar, tidtype.ctype)

# Delinearize beyond the third dimension
if len(krange) > 3:
Expand All @@ -2010,8 +2017,8 @@ def generate_kernel_scope(self, sdfg: SDFG, dfg_scope: ScopeSubgraphView, state_
)

expr = _topy(bidx[i]).replace('__DAPB%d' % i, block_expr)
kernel_stream.write('int %s = %s;' % (varname, expr), sdfg, state_id, node)
self._dispatcher.defined_vars.add(varname, DefinedType.Scalar, 'int')
kernel_stream.write(f'{tidtype.ctype} {varname} = {expr};', sdfg, state_id, node)
self._dispatcher.defined_vars.add(varname, DefinedType.Scalar, tidtype.ctype)

# Dispatch internal code
assert CUDACodeGen._in_device_code is False
Expand Down
4 changes: 2 additions & 2 deletions dace/codegen/targets/framecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,8 @@ def generate_code(self,

# NOTE: NestedSDFGs frequently contain tautologies in their symbol mapping, e.g., `'i': i`. Do not
# redefine the symbols in such cases.
if (not is_top_level and isvarName in sdfg.parent_nsdfg_node.symbol_mapping.keys()
and str(sdfg.parent_nsdfg_node.symbol_mapping[isvarName] == isvarName)):
if (not is_top_level and isvarName in sdfg.parent_nsdfg_node.symbol_mapping
and str(sdfg.parent_nsdfg_node.symbol_mapping[isvarName]) == str(isvarName)):
continue
isvar = data.Scalar(isvarType)
callsite_stream.write('%s;\n' % (isvar.as_arg(with_types=True, name=isvarName)), sdfg)
Expand Down
Loading

0 comments on commit e084950

Please sign in to comment.