Skip to content

Commit

Permalink
Better mangling of the state struct in the code generator (#1413)
Browse files Browse the repository at this point in the history
This PR addresses issue #1396, by modifying the way how the name of the
state struct is created.
  • Loading branch information
philip-paul-mueller authored Nov 7, 2023
1 parent e748720 commit f3781b1
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 40 deletions.
3 changes: 2 additions & 1 deletion dace/codegen/compiled_sdfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ def get_state_struct(self) -> ctypes.Structure:
return ctypes.cast(self._libhandle, ctypes.POINTER(self._try_parse_state_struct())).contents

def _try_parse_state_struct(self) -> Optional[Type[ctypes.Structure]]:
from dace.codegen.targets.cpp import mangle_dace_state_struct_name # Avoid import cycle
# the path of the main sdfg file containing the state struct
main_src_path = os.path.join(os.path.dirname(os.path.dirname(self._lib._library_filename)), "src", "cpu",
self._sdfg.name + ".cpp")
Expand All @@ -247,7 +248,7 @@ def _try_parse_state_struct(self) -> Optional[Type[ctypes.Structure]]:
code_flat = code.replace("\n", " ")

# try to find the first struct definition that matches the name we are looking for in the sdfg file
match = re.search(f"struct {self._sdfg.name}_t {{(.*?)}};", code_flat)
match = re.search(f"struct {mangle_dace_state_struct_name(self._sdfg)} {{(.*?)}};", code_flat)
if match is None or len(match.groups()) != 1:
return None

Expand Down
2 changes: 1 addition & 1 deletion dace/codegen/instrumentation/data/data_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def __init__(self):

def _generate_report_setter(self, sdfg: SDFG) -> str:
return f'''
DACE_EXPORTED void __dace_set_instrumented_data_report({sdfg.name}_t *__state, const char *dirpath) {{
DACE_EXPORTED void __dace_set_instrumented_data_report({cpp.mangle_dace_state_struct_name(sdfg)} *__state, const char *dirpath) {{
__state->serializer->set_folder(dirpath);
}}
'''
Expand Down
16 changes: 16 additions & 0 deletions dace/codegen/targets/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@
from dace.codegen.dispatcher import TargetDispatcher


def mangle_dace_state_struct_name(sdfg: Union[SDFG, str]) -> str:
"""This function creates a unique type name for the `SDFG`'s state `struct`.
The function uses the `compiler.codegen_state_struct_suffix`
configuration entry for deriving the type name of the state `struct`.
:param sdfg: The SDFG for which the name should be generated.
"""
name = sdfg if isinstance(sdfg, str) else sdfg.name
state_suffix = Config.get("compiler", "codegen_state_struct_suffix")
type_name = f"{name}{state_suffix}"
if not dtypes.validate_name(type_name):
raise ValueError(f"The mangled type name `{type_name}` of the state struct of SDFG '{name}' is invalid.")
return type_name


def copy_expr(
dispatcher,
sdfg,
Expand Down
2 changes: 1 addition & 1 deletion dace/codegen/targets/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ def generate_nsdfg_header(self, sdfg, state, state_id, node, memlet_references,

if state_struct:
toplevel_sdfg: SDFG = sdfg.sdfg_list[0]
arguments.append(f'{toplevel_sdfg.name}_t *__state')
arguments.append(f'{cpp.mangle_dace_state_struct_name(toplevel_sdfg)} *__state')

# Add "__restrict__" keywords to arguments that do not alias with others in the context of this SDFG
restrict_args = []
Expand Down
23 changes: 10 additions & 13 deletions dace/codegen/targets/cuda.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved.
import ast
import copy
import ctypes
import functools
import os
import warnings
from typing import Any, Dict, List, Set, Tuple, Union
from typing import Dict, List, Set, Tuple, Union

import networkx as nx
import sympy
Expand All @@ -14,7 +11,6 @@
import dace
from dace import data as dt
from dace import dtypes, registry
from dace import sdfg as sd
from dace import subsets, symbolic
from dace.codegen import common, cppunparse
from dace.codegen.codeobject import CodeObject
Expand All @@ -23,7 +19,7 @@
from dace.codegen.targets import cpp
from dace.codegen.common import update_persistent_desc
from dace.codegen.targets.cpp import (codeblock_to_cpp, cpp_array_expr, memlet_copy_to_absolute_strides, sym2cpp,
synchronize_streams, unparse_cr, unparse_cr_split)
synchronize_streams, unparse_cr, mangle_dace_state_struct_name)
from dace.codegen.targets.target import IllegalCopy, TargetCodeGenerator, make_absolute
from dace.config import Config
from dace.frontend import operations
Expand Down Expand Up @@ -345,12 +341,12 @@ def get_generated_codeobjects(self):
{file_header}
DACE_EXPORTED int __dace_init_cuda({sdfg.name}_t *__state{params});
DACE_EXPORTED int __dace_exit_cuda({sdfg.name}_t *__state);
DACE_EXPORTED int __dace_init_cuda({sdfg_state_name} *__state{params});
DACE_EXPORTED int __dace_exit_cuda({sdfg_state_name} *__state);
{other_globalcode}
int __dace_init_cuda({sdfg.name}_t *__state{params}) {{
int __dace_init_cuda({sdfg_state_name} *__state{params}) {{
int count;
// Check that we are able to run {backend} code
Expand Down Expand Up @@ -389,7 +385,7 @@ def get_generated_codeobjects(self):
return 0;
}}
int __dace_exit_cuda({sdfg.name}_t *__state) {{
int __dace_exit_cuda({sdfg_state_name} *__state) {{
{exitcode}
// Synchronize and check for CUDA errors
Expand All @@ -409,7 +405,7 @@ def get_generated_codeobjects(self):
return __err;
}}
DACE_EXPORTED bool __dace_gpu_set_stream({sdfg.name}_t *__state, int streamid, gpuStream_t stream)
DACE_EXPORTED bool __dace_gpu_set_stream({sdfg_state_name} *__state, int streamid, gpuStream_t stream)
{{
if (streamid < 0 || streamid >= {nstreams})
return false;
Expand All @@ -419,14 +415,15 @@ def get_generated_codeobjects(self):
return true;
}}
DACE_EXPORTED void __dace_gpu_set_all_streams({sdfg.name}_t *__state, gpuStream_t stream)
DACE_EXPORTED void __dace_gpu_set_all_streams({sdfg_state_name} *__state, gpuStream_t stream)
{{
for (int i = 0; i < {nstreams}; ++i)
__state->gpu_context->streams[i] = stream;
}}
{localcode}
""".format(params=params_comma,
sdfg_state_name=mangle_dace_state_struct_name(self._global_sdfg),
initcode=initcode.getvalue(),
exitcode=exitcode.getvalue(),
other_globalcode=self._globalcode.getvalue(),
Expand Down Expand Up @@ -1567,7 +1564,7 @@ def generate_scope(self, sdfg, dfg_scope, state_id, function_stream, callsite_st
self.scope_entry_stream = old_entry_stream
self.scope_exit_stream = old_exit_stream

state_param = [f'{self._global_sdfg.name}_t *__state']
state_param = [f'{mangle_dace_state_struct_name(self._global_sdfg)} *__state']

# Write callback function definition
self._localcode.write(
Expand Down
2 changes: 1 addition & 1 deletion dace/codegen/targets/fpga.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ def generate_state(self, sdfg: dace.SDFG, state: dace.SDFGState, function_stream
kernel_args_opencl = []

# Include state in args
kernel_args_opencl.append(f"{self._global_sdfg.name}_t *__state")
kernel_args_opencl.append(f"{cpp.mangle_dace_state_struct_name(self._global_sdfg)} *__state")
kernel_args_call_host.append(f"__state")

for is_output, arg_name, arg, interface_id in state_parameters:
Expand Down
26 changes: 14 additions & 12 deletions dace/codegen/targets/framecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def generate_fileheader(self, sdfg: SDFG, global_stream: CodeIOStream, backend:
:param global_stream: Stream to write to (global).
:param backend: Whose backend this header belongs to.
"""
from dace.codegen.targets.cpp import mangle_dace_state_struct_name # Avoid circular import
# Hash file include
if backend == 'frame':
global_stream.write('#include "../../include/hash.h"\n', sdfg)
Expand Down Expand Up @@ -181,7 +182,7 @@ def _emit_definitions(dtype: dtypes.typeclass, wrote_something: bool) -> bool:
# Write state struct
structstr = '\n'.join(self.statestruct)
global_stream.write(f'''
struct {sdfg.name}_t {{
struct {mangle_dace_state_struct_name(sdfg)} {{
{structstr}
}};
Expand Down Expand Up @@ -226,6 +227,7 @@ def generate_footer(self, sdfg: SDFG, global_stream: CodeIOStream, callsite_stre
:param callsite_stream: Stream to write to (at call site).
"""
import dace.library
from dace.codegen.targets.cpp import mangle_dace_state_struct_name # Avoid circular import
fname = sdfg.name
params = sdfg.signature(arglist=self.arglist)
paramnames = sdfg.signature(False, for_call=True, arglist=self.arglist)
Expand Down Expand Up @@ -255,26 +257,25 @@ def generate_footer(self, sdfg: SDFG, global_stream: CodeIOStream, callsite_stre
initparamnames_comma = (', ' + initparamnames) if initparamnames else ''
callsite_stream.write(
f'''
DACE_EXPORTED void __program_{fname}({fname}_t *__state{params_comma})
DACE_EXPORTED void __program_{fname}({mangle_dace_state_struct_name(fname)} *__state{params_comma})
{{
__program_{fname}_internal(__state{paramnames_comma});
}}''', sdfg)

for target in self._dispatcher.used_targets:
if target.has_initializer:
callsite_stream.write(
'DACE_EXPORTED int __dace_init_%s(%s_t *__state%s);\n' %
(target.target_name, sdfg.name, initparams_comma), sdfg)
f'DACE_EXPORTED int __dace_init_{target.target_name}({mangle_dace_state_struct_name(sdfg)} *__state{initparams_comma});\n', sdfg)
if target.has_finalizer:
callsite_stream.write(
'DACE_EXPORTED int __dace_exit_%s(%s_t *__state);\n' % (target.target_name, sdfg.name), sdfg)
f'DACE_EXPORTED int __dace_exit_{target.target_name}({mangle_dace_state_struct_name(sdfg)} *__state);\n', sdfg)

callsite_stream.write(
f"""
DACE_EXPORTED {sdfg.name}_t *__dace_init_{sdfg.name}({initparams})
DACE_EXPORTED {mangle_dace_state_struct_name(sdfg)} *__dace_init_{sdfg.name}({initparams})
{{
int __result = 0;
{sdfg.name}_t *__state = new {sdfg.name}_t;
{mangle_dace_state_struct_name(sdfg)} *__state = new {mangle_dace_state_struct_name(sdfg)};
""", sdfg)

Expand Down Expand Up @@ -306,7 +307,7 @@ def generate_footer(self, sdfg: SDFG, global_stream: CodeIOStream, callsite_stre
return __state;
}}
DACE_EXPORTED int __dace_exit_{sdfg.name}({sdfg.name}_t *__state)
DACE_EXPORTED int __dace_exit_{sdfg.name}({mangle_dace_state_struct_name(sdfg)} *__state)
{{
int __err = 0;
""", sdfg)
Expand Down Expand Up @@ -352,6 +353,7 @@ def generate_external_memory_management(self, sdfg: SDFG, callsite_stream: CodeI
can be ``CPU_Heap`` or any other ``dtypes.StorageType``); and (2) set the externally-allocated
pointer to the generated code's internal state (``__dace_set_external_memory_<STORAGE>``).
"""
from dace.codegen.targets.cpp import mangle_dace_state_struct_name # Avoid circular import

# Collect external arrays
ext_arrays: Dict[dtypes.StorageType, List[Tuple[SDFG, str, data.Data]]] = collections.defaultdict(list)
Expand All @@ -374,7 +376,7 @@ def generate_external_memory_management(self, sdfg: SDFG, callsite_stream: CodeI
# Size query functions
callsite_stream.write(
f'''
DACE_EXPORTED size_t __dace_get_external_memory_size_{storage.name}({sdfg.name}_t *__state{initparams_comma})
DACE_EXPORTED size_t __dace_get_external_memory_size_{storage.name}({mangle_dace_state_struct_name(sdfg)} *__state{initparams_comma})
{{
return {sym2cpp(size)};
}}
Expand All @@ -383,7 +385,7 @@ def generate_external_memory_management(self, sdfg: SDFG, callsite_stream: CodeI
# Pointer set functions
callsite_stream.write(
f'''
DACE_EXPORTED void __dace_set_external_memory_{storage.name}({sdfg.name}_t *__state, char *ptr{initparams_comma})
DACE_EXPORTED void __dace_set_external_memory_{storage.name}({mangle_dace_state_struct_name(sdfg)} *__state, char *ptr{initparams_comma})
{{''', sdfg)

offset = 0
Expand Down Expand Up @@ -828,7 +830,6 @@ def generate_code(self,
code, and a set of targets that have been used in the
generation of this SDFG.
"""

if len(sdfg_id) == 0 and sdfg.sdfg_id != 0:
sdfg_id = '_%d' % sdfg.sdfg_id

Expand Down Expand Up @@ -923,6 +924,7 @@ def generate_code(self,
# Get all environments used in the generated code, including
# dependent environments
import dace.library # Avoid import loops
from dace.codegen.targets.cpp import mangle_dace_state_struct_name
self.environments = dace.library.get_environments_and_dependencies(self._dispatcher.used_environments)

self.generate_header(sdfg, header_global_stream, header_stream)
Expand All @@ -931,7 +933,7 @@ def generate_code(self,
params = sdfg.signature(arglist=self.arglist)
if params:
params = ', ' + params
function_signature = ('void __program_%s_internal(%s_t *__state%s)\n{\n' % (sdfg.name, sdfg.name, params))
function_signature = f'void __program_{sdfg.name}_internal({mangle_dace_state_struct_name(sdfg)}*__state{params})\n{{'

self.generate_footer(sdfg, footer_global_stream, footer_stream)
self.generate_external_memory_management(sdfg, footer_stream)
Expand Down
7 changes: 3 additions & 4 deletions dace/codegen/targets/intel_fpga.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import functools
import copy
import itertools
import os
import re
from six import StringIO
import numpy as np

Expand Down Expand Up @@ -143,19 +141,20 @@ def get_generated_codeobjects(self):
params_comma = ', ' + params_comma

host_code.write("""
DACE_EXPORTED int __dace_init_intel_fpga({sdfg.name}_t *__state{signature}) {{{emulation_flag}
DACE_EXPORTED int __dace_init_intel_fpga({sdfg_state_name} *__state{signature}) {{{emulation_flag}
__state->fpga_context = new dace_fpga_context();
__state->fpga_context->Get().MakeProgram({kernel_file_name});
return 0;
}}
DACE_EXPORTED int __dace_exit_intel_fpga({sdfg.name}_t *__state) {{
DACE_EXPORTED int __dace_exit_intel_fpga({sdfg_state_name} *__state) {{
delete __state->fpga_context;
return 0;
}}
{host_code}""".format(signature=params_comma,
sdfg=self._global_sdfg,
sdfg_state_name=cpp.mangle_dace_state_struct_name(self._global_sdfg),
emulation_flag=emulation_flag,
kernel_file_name=kernel_file_name,
host_code="".join([
Expand Down
11 changes: 6 additions & 5 deletions dace/codegen/targets/mpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from dace.codegen.prettycode import CodeIOStream
from dace.codegen.codeobject import CodeObject
from dace.codegen.targets.target import TargetCodeGenerator, make_absolute
from dace.codegen.targets.cpp import mangle_dace_state_struct_name
from dace.sdfg import nodes, SDFG
from dace.config import Config

Expand Down Expand Up @@ -45,10 +46,10 @@ def get_generated_codeobjects(self):
{file_header}
DACE_EXPORTED int __dace_init_mpi({sdfg.name}_t *__state{params});
DACE_EXPORTED int __dace_exit_mpi({sdfg.name}_t *__state);
DACE_EXPORTED int __dace_init_mpi({sdfg_state_name} *__state{params});
DACE_EXPORTED int __dace_exit_mpi({sdfg_state_name} *__state);
int __dace_init_mpi({sdfg.name}_t *__state{params}) {{
int __dace_init_mpi({sdfg_state_name} *__state{params}) {{
int isinit = 0;
if (MPI_Initialized(&isinit) != MPI_SUCCESS)
return 1;
Expand All @@ -66,15 +67,15 @@ def get_generated_codeobjects(self):
return 0;
}}
int __dace_exit_mpi({sdfg.name}_t *__state) {{
int __dace_exit_mpi({sdfg_state_name} *__state) {{
MPI_Comm_free(&__dace_mpi_comm);
MPI_Finalize();
printf(\"MPI was finalized on proc %i of %i\\n\", __dace_comm_rank,
__dace_comm_size);
return 0;
}}
""".format(params=params_comma, sdfg=sdfg, file_header=fileheader.getvalue()), 'cpp', MPICodeGen, 'MPI')
""".format(params=params_comma, sdfg=sdfg, sdfg_state_name=mangle_dace_state_struct_name(sdfg), file_header=fileheader.getvalue()), 'cpp', MPICodeGen, 'MPI')
return [codeobj]

@staticmethod
Expand Down
6 changes: 4 additions & 2 deletions dace/codegen/targets/xilinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import re
import numpy as np
import ast

import dace
from dace import data as dt, registry, dtypes, subsets
from dace.config import Config
Expand Down Expand Up @@ -141,21 +142,22 @@ def get_generated_codeobjects(self):
params_comma = ', ' + params_comma

host_code.write("""
DACE_EXPORTED int __dace_init_xilinx({sdfg.name}_t *__state{signature}) {{
DACE_EXPORTED int __dace_init_xilinx({sdfg_state_name} *__state{signature}) {{
{environment_variables}
__state->fpga_context = new dace_fpga_context();
__state->fpga_context->Get().MakeProgram({kernel_file_name});
return 0;
}}
DACE_EXPORTED int __dace_exit_xilinx({sdfg.name}_t *__state) {{
DACE_EXPORTED int __dace_exit_xilinx({sdfg_state_name} *__state) {{
delete __state->fpga_context;
return 0;
}}
{host_code}""".format(signature=params_comma,
sdfg=self._global_sdfg,
sdfg_state_name=cpp.mangle_dace_state_struct_name(self._global_sdfg),
environment_variables=set_env_vars,
kernel_file_name=kernel_file_name,
host_code="".join([
Expand Down
9 changes: 9 additions & 0 deletions dace/config_schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ required:
of the code generator that generated it. Used for debugging
code generation.
codegen_state_struct_suffix:
type: str
default: "_state_t"
title: Suffix used by the code generator to mangle the state struct.
description: >
For every SDFG the code generator is is processing a state struct is generated.
The typename of this struct is derived by appending this value to the SDFG's name.
Note that the suffix may only contains letters, digits and underscores.
default_data_types:
type : str
default: Python
Expand Down

0 comments on commit f3781b1

Please sign in to comment.