def build_checker(): if hasattr(build_checker, "dll"): return build_checker.dll checker_code_path = os.path.join( os.path.dirname(inspect.getfile(daceml.onnx)), "include", "op_checker.h") with open(checker_code_path, "r") as f: checker_code = f.read() program = CodeObject("onnx_op_checker", checker_code, "cpp", cpu.CPUCodeGen, "ONNXOpChecker", environments={"ONNXRuntime"}) BUILD_PATH = os.path.join('.dacecache', "onnx_op_checker") generate_program_folder(None, [program], BUILD_PATH) configure_and_compile(BUILD_PATH) checker_dll = ctypes.CDLL(get_binary_name(BUILD_PATH, "onnx_op_checker")) build_checker.dll = checker_dll return checker_dll
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. @param sdfg: The SDFG to use @return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() frame = framecode.DaCeCodeGenerator() # Instantiate all targets (who register themselves with framecodegen) targets = { name: STRING_TO_TARGET[name](frame, sdfg) for name in _TARGET_REGISTER_ORDER } # Generate frame code (and the rest of the code) global_code, frame_code, used_targets = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame', meta_info=PerfMetaInfoStatic.info if PerfSettings.perf_enable_vectorization_analysis() else PerfMetaInfo()) ] PerfMetaInfoStatic.info = PerfMetaInfo() # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) return target_objects
def get_generated_codeobjects(self): fileheader = CodeIOStream() sdfg = self._global_sdfg self._frame.generate_fileheader(sdfg, fileheader, 'mpi') params_comma = self._global_sdfg.init_signature( free_symbols=self._frame.free_symbols(self._global_sdfg)) if params_comma: params_comma = ', ' + params_comma codeobj = CodeObject( sdfg.name + '_mpi', """ #include <dace/dace.h> #include <mpi.h> MPI_Comm __dace_mpi_comm; int __dace_comm_size = 1; int __dace_comm_rank = 0; {file_header} DACE_EXPORTED int __dace_init_mpi({sdfg.name}_t *__state{params}); DACE_EXPORTED void __dace_exit_mpi({sdfg.name}_t *__state); int __dace_init_mpi({sdfg.name}_t *__state{params}) {{ int isinit = 0; if (MPI_Initialized(&isinit) != MPI_SUCCESS) return 1; if (!isinit) {{ if (MPI_Init(NULL, NULL) != MPI_SUCCESS) return 1; }} MPI_Comm_dup(MPI_COMM_WORLD, &__dace_mpi_comm); MPI_Comm_rank(__dace_mpi_comm, &__dace_comm_rank); MPI_Comm_size(__dace_mpi_comm, &__dace_comm_size); printf(\"MPI was initialized on proc %i of %i\\n\", __dace_comm_rank, __dace_comm_size); return 0; }} void __dace_exit_mpi({sdfg.name}_t *__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); }} """.format(params=params_comma, sdfg=sdfg, file_header=fileheader.getvalue()), 'cpp', MPICodeGen, 'MPI') return [codeobj]
def __init__(self, frame_codegen, sdfg): self._frame = frame_codegen self._dispatcher = frame_codegen.dispatcher dispatcher = self._dispatcher fileheader = CodeIOStream() self._frame.generate_fileheader(sdfg, fileheader) self._codeobj = CodeObject( sdfg.name + '_mpi', """ #include <dace/dace.h> #include <mpi.h> MPI_Comm __dace_mpi_comm; int __dace_comm_size = 1; int __dace_comm_rank = 0; {file_header} DACE_EXPORTED int __dace_init_mpi({params}); DACE_EXPORTED void __dace_exit_mpi({params}); int __dace_init_mpi({params}) {{ int isinit = 0; if (MPI_Initialized(&isinit) != MPI_SUCCESS) return 1; if (!isinit) {{ if (MPI_Init(NULL, NULL) != MPI_SUCCESS) return 1; }} MPI_Comm_dup(MPI_COMM_WORLD, &__dace_mpi_comm); MPI_Comm_rank(__dace_mpi_comm, &__dace_comm_rank); MPI_Comm_size(__dace_mpi_comm, &__dace_comm_size); printf(\"MPI was initialized on proc %i of %i\\n\", __dace_comm_rank, __dace_comm_size); return 0; }} void __dace_exit_mpi({params}) {{ MPI_Comm_free(&__dace_mpi_comm); MPI_Finalize(); printf(\"MPI was finalized on proc %i of %i\\n\", __dace_comm_rank, __dace_comm_size); }} """.format(params=sdfg.signature(), file_header=fileheader.getvalue()), 'cpp', MPICodeGen, 'MPI') # Register dispatchers dispatcher.register_map_dispatcher(dtypes.ScheduleType.MPI, self)
def generate_node(self, sdfg, dfg, state_id, node, function_stream, callsite_stream): if self.node_dispatch_predicate(sdfg, dfg, node): function_uid = str(sdfg.sdfg_id) + "_" + str(state_id) + "_" + str( dfg.node_id(node)) node.code.code = node.code.code.replace( "mlir_entry", "mlir_entry_" + function_uid) self._codeobjects.append( CodeObject(node.name, node.code.code, "mlir", MLIRCodeGen, node.name + "_Source")) self._cpu_codegen.generate_node(sdfg, dfg, state_id, node, function_stream, callsite_stream)
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. :param sdfg: The SDFG to use :return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() if Config.get_bool('testing', 'serialization'): from dace.sdfg import SDFG import filecmp import shutil import tempfile with tempfile.TemporaryDirectory() as tmp_dir: sdfg.save(f'{tmp_dir}/test.sdfg') sdfg2 = SDFG.from_file(f'{tmp_dir}/test.sdfg') sdfg2.save(f'{tmp_dir}/test2.sdfg') print('Testing SDFG serialization...') if not filecmp.cmp(f'{tmp_dir}/test.sdfg', f'{tmp_dir}/test2.sdfg'): shutil.move(f"{tmp_dir}/test.sdfg", "test.sdfg") shutil.move(f"{tmp_dir}/test2.sdfg", "test2.sdfg") raise RuntimeError( 'SDFG serialization failed - files do not match') # Run with the deserialized version # NOTE: This means that all subsequent modifications to `sdfg` # are not reflected outside of this function (e.g., library # node expansion). sdfg = sdfg2 # Before generating the code, run type inference on the SDFG connectors infer_types.infer_connector_types(sdfg) # Set default storage/schedule types in SDFG infer_types.set_default_schedule_and_storage_types(sdfg, None) # Recursively expand library nodes that have not yet been expanded sdfg.expand_library_nodes() # After expansion, run another pass of connector/type inference infer_types.infer_connector_types(sdfg) infer_types.set_default_schedule_and_storage_types(sdfg, None) frame = framecode.DaCeCodeGenerator() # Instantiate CPU first (as it is used by the other code generators) # TODO: Refactor the parts used by other code generators out of CPU default_target = cpu.CPUCodeGen for k, v in target.TargetCodeGenerator.extensions().items(): # If another target has already been registered as CPU, use it instead if v['name'] == 'cpu': default_target = k targets = {'cpu': default_target(frame, sdfg)} # Instantiate the rest of the targets targets.update({ v['name']: k(frame, sdfg) for k, v in target.TargetCodeGenerator.extensions().items() if v['name'] not in targets }) # Instantiate all instrumentation providers in SDFG provider_mapping = InstrumentationProvider.get_provider_mapping() frame._dispatcher.instrumentation[ dtypes.InstrumentationType.No_Instrumentation] = None for node, _ in sdfg.all_nodes_recursive(): if hasattr(node, 'instrument'): frame._dispatcher.instrumentation[node.instrument] = \ provider_mapping[node.instrument] elif hasattr(node, 'consume'): frame._dispatcher.instrumentation[node.consume.instrument] = \ provider_mapping[node.consume.instrument] elif hasattr(node, 'map'): frame._dispatcher.instrumentation[node.map.instrument] = \ provider_mapping[node.map.instrument] if sdfg.instrument != dtypes.InstrumentationType.No_Instrumentation: frame._dispatcher.instrumentation[sdfg.instrument] = \ provider_mapping[sdfg.instrument] frame._dispatcher.instrumentation = { k: v() if v is not None else None for k, v in frame._dispatcher.instrumentation.items() } # Generate frame code (and the rest of the code) (global_code, frame_code, used_targets, used_environments) = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame', environments=used_environments, sdfg=sdfg) ] # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) # add a header file for calling the SDFG dummy = CodeObject(sdfg.name, generate_headers(sdfg), 'h', cpu.CPUCodeGen, 'CallHeader', target_type='../../include', linkable=False) target_objects.append(dummy) for env in dace.library.get_environments_and_dependencies( used_environments): if hasattr(env, "codeobjects"): target_objects.extend(env.codeobjects) # add a dummy main function to show how to call the SDFG dummy = CodeObject(sdfg.name + "_main", generate_dummy(sdfg), 'cpp', cpu.CPUCodeGen, 'SampleMain', target_type='../../sample', linkable=False) target_objects.append(dummy) return target_objects
def get_generated_codeobjects(self): execution_mode = Config.get("compiler", "xilinx", "mode") kernel_file_name = "DACE_BINARY_DIR \"/{}".format(self._program_name) if execution_mode == "software_emulation": kernel_file_name += "_sw_emu.xclbin\"" xcl_emulation_mode = "\"sw_emu\"" xilinx_sdx = "DACE_VITIS_DIR" elif execution_mode == "hardware_emulation": kernel_file_name += "_hw_emu.xclbin\"" xcl_emulation_mode = "\"hw_emu\"" xilinx_sdx = "DACE_VITIS_DIR" elif execution_mode == "hardware" or execution_mode == "simulation": kernel_file_name += "_hw.xclbin\"" xcl_emulation_mode = None xilinx_sdx = None else: raise cgx.CodegenError( "Unknown Xilinx execution mode: {}".format(execution_mode)) set_env_vars = "" set_str = "dace::set_environment_variable(\"{}\", {});\n" unset_str = "dace::unset_environment_variable(\"{}\");\n" set_env_vars += (set_str.format("XCL_EMULATION_MODE", xcl_emulation_mode) if xcl_emulation_mode is not None else unset_str.format("XCL_EMULATION_MODE")) set_env_vars += (set_str.format("XILINX_SDX", xilinx_sdx) if xilinx_sdx is not None else unset_str.format("XILINX_SDX")) set_env_vars += set_str.format( "EMCONFIG_PATH", "DACE_BINARY_DIR" ) if execution_mode == 'hardware_emulation' else unset_str.format( "EMCONFIG_PATH") host_code = CodeIOStream() host_code.write("""\ #include "dace/xilinx/host.h" #include "dace/dace.h" """) if len(self._dispatcher.instrumentation) > 1: host_code.write("""\ #include "dace/perf/reporting.h" #include <chrono> #include <iomanip> #include <iostream> #include <limits> """) host_code.write("\n\n") self._frame.generate_fileheader(self._global_sdfg, host_code, 'xilinx_host') params_comma = self._global_sdfg.signature(with_arrays=False) if params_comma: params_comma = ', ' + params_comma host_code.write(""" DACE_EXPORTED int __dace_init_xilinx({sdfg.name}_t *__state{signature}) {{ {environment_variables} __state->fpga_context = new dace::fpga::Context(); __state->fpga_context->Get().MakeProgram({kernel_file_name}); return 0; }} DACE_EXPORTED void __dace_exit_xilinx({sdfg.name}_t *__state) {{ delete __state->fpga_context; }} {host_code}""".format(signature=params_comma, sdfg=self._global_sdfg, environment_variables=set_env_vars, kernel_file_name=kernel_file_name, host_code="".join([ "{separator}\n// Kernel: {kernel_name}" "\n{separator}\n\n{code}\n\n".format( separator="/" * 79, kernel_name=name, code=code) for (name, code) in self._host_codes ]))) host_code_obj = CodeObject(self._program_name, host_code.getvalue(), "cpp", XilinxCodeGen, "Xilinx", target_type="host") kernel_code_objs = [ CodeObject(kernel_name, code, "cpp", XilinxCodeGen, "Xilinx", target_type="device") for (kernel_name, code) in self._kernel_codes ] # Memory bank and streaming interfaces connectivity configuration file link_cfg = CodeIOStream() self._other_codes["link.cfg"] = link_cfg link_cfg.write("[connectivity]") are_assigned = [v is not None for v in self._bank_assignments.values()] if any(are_assigned): if not all(are_assigned): raise RuntimeError("Some, but not all global memory arrays " "were assigned to memory banks: {}".format( self._bank_assignments)) # Emit mapping from kernel memory interfaces to DRAM banks for (kernel_name, interface_name), ( memory_type, memory_bank) in self._bank_assignments.items(): link_cfg.write( f"sp={kernel_name}_1.m_axi_{interface_name}:{memory_type}[{memory_bank}]" ) # Emit mapping between inter-kernel streaming interfaces for _, (src, dst) in self._stream_connections.items(): link_cfg.write(f"stream_connect={src}:{dst}") other_objs = [] for name, code in self._other_codes.items(): name = name.split(".") other_objs.append( CodeObject(name[0], code.getvalue(), ".".join(name[1:]), XilinxCodeGen, "Xilinx", target_type="device")) return [host_code_obj] + kernel_code_objs + other_objs
def get_generated_codeobjects(self): execution_mode = Config.get("compiler", "xilinx", "mode") kernel_file_name = "DACE_BINARY_DIR \"/{}".format(self._program_name) if execution_mode == "software_emulation": kernel_file_name += "_sw_emu.xclbin\"" xcl_emulation_mode = "\"sw_emu\"" xilinx_sdx = "DACE_VITIS_DIR" elif execution_mode == "hardware_emulation": kernel_file_name += "_hw_emu.xclbin\"" xcl_emulation_mode = "\"hw_emu\"" xilinx_sdx = "DACE_VITIS_DIR" elif execution_mode == "hardware" or execution_mode == "simulation": kernel_file_name += "_hw.xclbin\"" xcl_emulation_mode = None xilinx_sdx = None else: raise dace.codegen.codegen.CodegenError( "Unknown Xilinx execution mode: {}".format(execution_mode)) set_env_vars = "" set_str = "dace::set_environment_variable(\"{}\", {});\n" unset_str = "dace::unset_environment_variable(\"{}\");\n" set_env_vars += (set_str.format("XCL_EMULATION_MODE", xcl_emulation_mode) if xcl_emulation_mode is not None else unset_str.format("XCL_EMULATION_MODE")) set_env_vars += (set_str.format("XILINX_SDX", xilinx_sdx) if xilinx_sdx is not None else unset_str.format("XILINX_SDX")) host_code = CodeIOStream() host_code.write("""\ #include "dace/xilinx/host.h" #include "dace/dace.h" #include <iostream>\n\n""") self._frame.generate_fileheader(self._global_sdfg, host_code) host_code.write(""" dace::fpga::Context *dace::fpga::_context; DACE_EXPORTED int __dace_init_xilinx({signature}) {{ {environment_variables} dace::fpga::_context = new dace::fpga::Context(); dace::fpga::_context->Get().MakeProgram({kernel_file_name}); return 0; }} DACE_EXPORTED void __dace_exit_xilinx({signature}) {{ delete dace::fpga::_context; }} {host_code}""".format(signature=self._global_sdfg.signature(), environment_variables=set_env_vars, kernel_file_name=kernel_file_name, host_code="".join([ "{separator}\n// Kernel: {kernel_name}" "\n{separator}\n\n{code}\n\n".format(separator="/" * 79, kernel_name=name, code=code) for (name, code) in self._host_codes ]))) host_code_obj = CodeObject(self._program_name, host_code.getvalue(), "cpp", XilinxCodeGen, "Xilinx", target_type="host") kernel_code_objs = [ CodeObject(kernel_name, code, "cpp", XilinxCodeGen, "Xilinx", target_type="device") for (kernel_name, code) in self._kernel_codes ] # Configuration file with interface assignments are_assigned = [ v is not None for v in self._interface_assignments.values() ] bank_assignment_code = [] if any(are_assigned): if not all(are_assigned): raise RuntimeError("Some, but not all global memory arrays " "were assigned to memory banks: {}".format( self._interface_assignments)) are_assigned = True else: are_assigned = False for name, _ in self._host_codes: # Only iterate over assignments if any exist if are_assigned: for (kernel_name, interface_name), ( memory_type, memory_bank) in self._interface_assignments.items(): if kernel_name != name: continue bank_assignment_code.append("{},{},{}".format( interface_name, memory_type.name, memory_bank)) # Create file even if there are no assignments kernel_code_objs.append( CodeObject("{}_memory_interfaces".format(name), "\n".join(bank_assignment_code), "csv", XilinxCodeGen, "Xilinx", target_type="device")) return [host_code_obj] + kernel_code_objs
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. :param sdfg: The SDFG to use :return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() if Config.get_bool('testing', 'serialization'): from dace.sdfg import SDFG import filecmp sdfg.save('test.sdfg') sdfg2 = SDFG.from_file('test.sdfg') sdfg2.save('test2.sdfg') print('Testing SDFG serialization...') if not filecmp.cmp('test.sdfg', 'test2.sdfg'): raise RuntimeError( 'SDFG serialization failed - files do not match') os.remove('test.sdfg') os.remove('test2.sdfg') # Run with the deserialized version sdfg = sdfg2 frame = framecode.DaCeCodeGenerator() # Instantiate CPU first (as it is used by the other code generators) # TODO: Refactor the parts used by other code generators out of CPU default_target = cpu.CPUCodeGen for k, v in target.TargetCodeGenerator.extensions().items(): # If another target has already been registered as CPU, use it instead if v['name'] == 'cpu': default_target = k targets = {'cpu': default_target(frame, sdfg)} # Instantiate the rest of the targets targets.update({ v['name']: k(frame, sdfg) for k, v in target.TargetCodeGenerator.extensions().items() if v['name'] not in targets }) # Instantiate all instrumentation providers in SDFG provider_mapping = InstrumentationProvider.get_provider_mapping() frame._dispatcher.instrumentation[ dtypes.InstrumentationType.No_Instrumentation] = None for node, _ in sdfg.all_nodes_recursive(): if hasattr(node, 'instrument'): frame._dispatcher.instrumentation[node.instrument] = \ provider_mapping[node.instrument] elif hasattr(node, 'consume'): frame._dispatcher.instrumentation[node.consume.instrument] = \ provider_mapping[node.consume.instrument] elif hasattr(node, 'map'): frame._dispatcher.instrumentation[node.map.instrument] = \ provider_mapping[node.map.instrument] frame._dispatcher.instrumentation = { k: v() if v is not None else None for k, v in frame._dispatcher.instrumentation.items() } # Generate frame code (and the rest of the code) (global_code, frame_code, used_targets, used_environments) = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame', environments=used_environments) ] # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) # add a header file for calling the SDFG dummy = CodeObject(sdfg.name, generate_headers(sdfg), 'h', cpu.CPUCodeGen, 'CallHeader', linkable=False) target_objects.append(dummy) # add a dummy main function to show how to call the SDFG dummy = CodeObject(sdfg.name + "_main", generate_dummy(sdfg), 'cpp', cpu.CPUCodeGen, 'DummyMain', linkable=False) target_objects.append(dummy) return target_objects
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. @param sdfg: The SDFG to use @return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() if Config.get_bool('experimental', 'test_serialization'): from dace.sdfg import SDFG import filecmp sdfg.save('test.sdfg') sdfg2 = SDFG.from_file('test.sdfg') sdfg2.save('test2.sdfg') print('Testing SDFG serialization...') if not filecmp.cmp('test.sdfg', 'test2.sdfg'): raise RuntimeError( 'SDFG serialization failed - files do not match') os.remove('test.sdfg') os.remove('test2.sdfg') # Run with the deserialized version sdfg = sdfg2 frame = framecode.DaCeCodeGenerator() # Instantiate all targets (who register themselves with framecodegen) targets = { name: STRING_TO_TARGET[name](frame, sdfg) for name in _TARGET_REGISTER_ORDER } # Instantiate all instrumentation providers in SDFG frame._dispatcher.instrumentation[ dtypes.InstrumentationType.No_Instrumentation] = None for node, _ in sdfg.all_nodes_recursive(): if hasattr(node, 'instrument'): frame._dispatcher.instrumentation[node.instrument] = \ INSTRUMENTATION_PROVIDERS[node.instrument] elif hasattr(node, 'consume'): frame._dispatcher.instrumentation[node.consume.instrument] = \ INSTRUMENTATION_PROVIDERS[node.consume.instrument] elif hasattr(node, 'map'): frame._dispatcher.instrumentation[node.map.instrument] = \ INSTRUMENTATION_PROVIDERS[node.map.instrument] frame._dispatcher.instrumentation = { k: v() if v is not None else None for k, v in frame._dispatcher.instrumentation.items() } # Generate frame code (and the rest of the code) global_code, frame_code, used_targets = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame') ] # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) return target_objects
def get_generated_codeobjects(self): execution_mode = Config.get("compiler", "xilinx", "mode") kernel_file_name = "DACE_BINARY_DIR \"/{}".format(self._program_name) if execution_mode == "software_emulation": kernel_file_name += "_sw_emu.xclbin\"" xcl_emulation_mode = "\"sw_emu\"" xilinx_sdx = "DACE_VITIS_DIR" elif execution_mode == "hardware_emulation": kernel_file_name += "_hw_emu.xclbin\"" xcl_emulation_mode = "\"hw_emu\"" xilinx_sdx = "DACE_VITIS_DIR" elif execution_mode == "hardware" or execution_mode == "simulation": kernel_file_name += "_hw.xclbin\"" xcl_emulation_mode = None xilinx_sdx = None else: raise dace.codegen.codegen.CodegenError( "Unknown Xilinx execution mode: {}".format(execution_mode)) set_env_vars = "" set_str = "dace::set_environment_variable(\"{}\", {});\n" unset_str = "dace::unset_environment_variable(\"{}\");\n" set_env_vars += (set_str.format("XCL_EMULATION_MODE", xcl_emulation_mode) if xcl_emulation_mode is not None else unset_str.format("XCL_EMULATION_MODE")) set_env_vars += (set_str.format("XILINX_SDX", xilinx_sdx) if xilinx_sdx is not None else unset_str.format("XILINX_SDX")) host_code = CodeIOStream() host_code.write("""\ #include "dace/xilinx/host.h" #include "dace/dace.h" #include <iostream>\n\n""") self._frame.generate_fileheader(self._global_sdfg, host_code) host_code.write(""" dace::fpga::Context *dace::fpga::_context; DACE_EXPORTED int __dace_init_xilinx({signature}) {{ {environment_variables} dace::fpga::_context = new dace::fpga::Context(); dace::fpga::_context->Get().MakeProgram({kernel_file_name}); return 0; }} DACE_EXPORTED void __dace_exit_xilinx({signature}) {{ delete dace::fpga::_context; }} {host_code}""".format(signature=self._global_sdfg.signature(), environment_variables=set_env_vars, kernel_file_name=kernel_file_name, host_code="".join([ "{separator}\n// Kernel: {kernel_name}" "\n{separator}\n\n{code}\n\n".format( separator="/" * 79, kernel_name=name, code=code) for (name, code) in self._host_codes ]))) host_code_obj = CodeObject(self._program_name, host_code.getvalue(), "cpp", XilinxCodeGen, "Xilinx", target_type="host") kernel_code_objs = [ CodeObject(kernel_name, code, "cpp", XilinxCodeGen, "Xilinx", target_type="device") for (kernel_name, code) in self._kernel_codes ] return [host_code_obj] + kernel_code_objs