20 cpp_printer = DSL.printers.CPPPrinter(spaces_per_tab=4)
21 omp_printer = DSL.printers.OMPPrinter(spaces_per_tab=4)
22 sycl_printer = DSL.printers.SYCLPrinter(spaces_per_tab=4)
24 mlir_printer = DSL.printers.MLIRPrinter(spaces_per_tab=4, use_omp=
False)
25 mlir_omp_printer = DSL.printers.MLIRPrinter(spaces_per_tab=4, use_omp=
True)
27 cpp_trees.append(DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms))
28 cpp_trees.append(DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms, stateless =
True))
29 cpp_trees.append(DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms, stateless =
True, use_accelerator=
True, use_memory_manager=
True))
31 if not os.path.exists(
"kernels"):
32 os.makedirs(
"kernels")
34 declaration_file = open(f
"kernels/{solver_filename}.h",
"w")
35 definition_file = open(f
"kernels/{solver_filename}.cpph",
"w")
36 declaration_file.write(
"#pragma once\n")
37 declaration_file.write(solver_includes)
38 for i, tree
in enumerate(cpp_trees):
39 if not tree.use_accelerator:
40 declaration_file.write(tree.print_declaration(cpp_printer))
41 declaration_file.write(tree.print_declaration_with_timer(cpp_printer))
42 definition_file.write(tree.print(cpp_printer))
43 definition_file.write(tree.print_definition_with_timer(cpp_printer))
45 if tree.use_accelerator:
46 declaration_file.write(
"#if defined (GPUOffloadingOMP)\n")
47 definition_file.write(
"#if defined (GPUOffloadingOMP)\n")
49 declaration_file.write(
"#if defined (SharedOMP)\n")
50 definition_file.write(
"#if defined (SharedOMP)\n")
52 declaration_file.write(tree.print_declaration(omp_printer))
53 declaration_file.write(tree.print_declaration_with_timer(omp_printer))
54 definition_file.write(tree.print(omp_printer))
55 definition_file.write(tree.print_definition_with_timer(omp_printer))
56 declaration_file.write (
"#endif\n")
57 definition_file.write (
"#endif\n")
59 declaration_file.write(
"#if defined (GPUOffloadingSYCL)\n")
60 definition_file.write(
"#if defined (GPUOffloadingSYCL)\n")
61 declaration_file.write(tree.print_declaration(sycl_printer))
62 declaration_file.write(tree.print_declaration_with_timer(sycl_printer))
63 definition_file.write(tree.print(sycl_printer))
64 definition_file.write(tree.print_definition_with_timer(sycl_printer))
65 declaration_file.write (
"#endif\n")
66 definition_file.write (
"#endif\n")
68 declaration_file.write(f
"""#ifdef USE_MLIR
69#include "MLIRbridge.cpph"
71#include "{solver_filename}.cpph"
74 declaration_file.close()
75 definition_file.close()
78 mlir_function_definition = DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms)
79 mlir_stateless_function_definition = DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms, stateless=
True)
80 gpu_namespace = solver_namespace.copy()
81 gpu_namespace = gpu_namespace + [
"mlir",
"gpu"]
82 mlir_gpu_function_definition = DSL.Parser().parse(function, template_parameters, functor_arguments, gpu_namespace, enabled_pde_terms, stateless=
True, use_accelerator=
True)
84 mlir_cpu_function_definitions = [
85 mlir_function_definition,
86 mlir_stateless_function_definition
90 file = open(f
"kernels/{solver_filename}.mlir",
"w")
91 file.write(DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms).print(mlir_printer))
94 file = open(f
"kernels/{solver_filename}_omp.mlir",
"w")
95 file.write(DSL.Parser().parse(function, template_parameters, functor_arguments, solver_namespace, enabled_pde_terms).print(mlir_omp_printer))
99 with open(
"MLIRbridge.cpph",
'w')
as file:
101#include "MemRefDescriptor.cpph"
103// MLIR-compatible structure using memref descriptors
104struct MLIRCellData {{
105 MemRefDescriptor2D QIn; // Field 0
106 MemRefDescriptor2D QOut; // Field 1
107 MemRefDescriptorNested cellCentre; // Field 2
108 MemRefDescriptorNested cellSize; // Field 3
109 MemRefDescriptor1D t; // Field 4
110 MemRefDescriptor1D dt; // Field 5
111 MemRefDescriptor1D id; // Field 6
112 int64_t numberOfCells; // Field 7
113 int64_t memoryLocation; // Field 8
114 int64_t targetDevice; // Field 9
115 double** QOut_legacy; // Field 10
116 double* maxEigenvalue; // Field 11
118void convertToMLIRStruct(exahype2::CellData<double, double>* patchData, MLIRCellData* mlir_data);
119void convertToMLIRStructGPU(exahype2::CellData<double, double>* copyCellData, MLIRCellData* mlir_data);
120void cleanupMLIRStruct(MLIRCellData* mlir_data);
121void cleanupMLIRStructGPU(MLIRCellData* mlir_data);
122void copybackMLIRresults(exahype2::CellData<double, double>* patchData, MLIRCellData* mlir_data);
124 file.write(f
"""extern "C" void {solver_dictionary["KERNEL_NAME"]}_MLIR_wrapper(exahype2::CellData<double, double>* patchData, bool use_omp);\n""")
125 for definition
in mlir_cpu_function_definitions:
126 definition._arguments[0]._type = DSL.SyntaxTree.TCustom(
"CellData<double, double>&")
127 file.write(definition.print_declaration(mlir_printer))
128 file.write(definition.print_declaration_with_timer(mlir_printer))
129 file.write(definition.print_declaration(mlir_omp_printer))
130 file.write(definition.print_declaration_with_timer(mlir_omp_printer))
131 definition._arguments[0]._type = DSL.SyntaxTree.TCustom(
"MLIRCellData*")
132 file.write(definition.print_declaration(mlir_printer))
133 file.write(definition.print_declaration_with_timer(mlir_printer))
134 file.write(definition.print_declaration(mlir_omp_printer))
135 file.write(definition.print_declaration_with_timer(mlir_omp_printer))
137 file.write(
"#ifdef MLIR_GPU\n")
138 mlir_gpu_function_definition._arguments[1]._type = DSL.SyntaxTree.TCustom(
"MLIRCellData*")
139 file.write(mlir_gpu_function_definition.print_declaration(cpp_printer))
140 file.write(mlir_gpu_function_definition.print_declaration_with_timer(cpp_printer))
144 memref_constructors =
""""""
145 for argument
in functor_arguments:
146 if argument._is_function:
147 argument_names.append(argument.id +
"_bridge")
149 argument_names.append(argument.id +
"_memref")
150 memref_constructors += f
"""
151 auto {argument.id}_memref = MemRefDescriptor1D();
152 {argument.id}_memref.allocated = const_cast<double*>({solver_dictionary["SOLVER_CLASS_NAMESPACE"]}::{solver_dictionary["SOLVER_CLASS"]}::{argument.id});
153 {argument.id}_memref.aligned = const_cast<double*>({solver_dictionary["SOLVER_CLASS_NAMESPACE"]}::{solver_dictionary["SOLVER_CLASS"]}::{argument.id});
154 {argument.id}_memref.offset = 0;
155 {argument.id}_memref.sizes[0] = {solver_dictionary["SOLVER_CLASS_NAMESPACE"]}::{solver_dictionary["SOLVER_CLASS"]}::DGOrder + 1;
156 {argument.id}_memref.strides[0] = 1;
158 solver_dictionary[
"FUNCTION_ARGUMENTS"] =
",".join(argument_names)
159 solver_dictionary[
"MEMREF_CONSTRUCTORS"] = memref_constructors
161 template_strings = [argument.print(cpp_printer)
for argument
in mlir_function_definition._template]
162 solver_dictionary[
"TEMPLATE_DEFINITION"] =
"template <" +
",".join(template_strings) +
">\n"
163 filepath = os.path.realpath(__file__)
164 filepath_root = filepath[0:filepath.find(
"dslhype/")]
165 with open(filepath_root +
"dslhype/MLIRbridge.template.cpp",
'r')
as template_file:
166 mlir_bridge_template = template_file.read()
167 mlir_bridge_cpp = jinja2.Template(mlir_bridge_template).render(**solver_dictionary)
168 with open(
"MLIRbridge.cpp",
'w')
as file:
169 file.write(mlir_bridge_cpp)
171def set_mlir_environment(project, filename_root, physics_file, dimensions, use_gpu, flatten_memrefs=False, inline_functions=False, nested_parallel_ops_to_for_ops=-1, imperfect_nested_loops_to_perfect=False, nested_parallel_ops_to_multidimensional=False, use_omp_tasks=False, omp_task_version="taskloop", omp_single_region=False, max_patch_size=-1, use_memory_fusion=False, use_loop_fusion=False):
172 print(f
"Enabling MLIR kernel compilation support for {dimensions}D...")
174 serial_pipeline_builder = DSL.PipelineBuilder()
176 serial_pipeline_builder.enable_flatten_memrefs()
178 serial_pipeline_builder.enable_inline_polygeist_functions(physics_file)
179 if imperfect_nested_loops_to_perfect:
180 serial_pipeline_builder.enable_imperfect_nested_loops_to_perfect()
181 if nested_parallel_ops_to_multidimensional:
182 serial_pipeline_builder.enable_nested_parallel_ops_to_multidimensional()
183 if nested_parallel_ops_to_for_ops > -1:
184 serial_pipeline_builder.enable_nested_parallel_ops_to_for_ops(nested_parallel_ops_to_for_ops)
185 if max_patch_size > -1:
186 serial_pipeline_builder.enable_memory_reuse(max_patch_size)
187 if use_memory_fusion:
188 serial_pipeline_builder.enable_memory_fusion()
190 serial_pipeline_builder.enable_loop_fusion()
192 serial_pipeline = serial_pipeline_builder.generate_opt_commands()
193 project.output.makefile.d[
"SERIAL_PIPELINE"] = serial_pipeline
195 omp_pipeline_builder = DSL.PipelineBuilder()
196 omp_pipeline_builder.enable_omp(use_omp_tasks, omp_task_version, omp_single_region)
198 omp_pipeline_builder.enable_flatten_memrefs()
200 omp_pipeline_builder.enable_inline_polygeist_functions(physics_file)
201 if imperfect_nested_loops_to_perfect:
202 omp_pipeline_builder.enable_imperfect_nested_loops_to_perfect()
203 if nested_parallel_ops_to_multidimensional:
204 omp_pipeline_builder.enable_nested_parallel_ops_to_multidimensional()
205 if nested_parallel_ops_to_for_ops > -1:
206 omp_pipeline_builder.enable_nested_parallel_ops_to_for_ops(nested_parallel_ops_to_for_ops)
207 if max_patch_size > -1:
208 omp_pipeline_builder.enable_memory_reuse(max_patch_size)
209 if use_memory_fusion:
210 omp_pipeline_builder.enable_memory_fusion()
212 omp_pipeline_builder.enable_loop_fusion()
213 omp_pipeline = omp_pipeline_builder.generate_opt_commands()
214 project.output.makefile.d[
"OMP_PIPELINE"] = omp_pipeline
217 os.environ[
'MLIR_DIMENSIONS'] = str(dimensions)
218 filepath = os.path.realpath(__file__)
219 peano_dir = filepath[0:filepath.find(
"python/")]
222 project.output.makefile.add_cpp_file(
"MLIRbridge.cpp")
223 project.output.makefile.add_CXX_flag(
"-DUSE_MLIR")
226 project.output.makefile.add_linker_flag(
"-lomp")
228 print(
"Enabling MLIR GPU kernel compilation support")
229 project.output.makefile.add_linker_flag(
"-lomptarget")
230 gpu_pipeline_builder = DSL.PipelineBuilder()
231 gpu_pipeline_builder.enable_gpu(project.output.makefile.d[
"GPU_VENDOR"], project.output.makefile.d[
"GPU_ARCH"], physics_file)
232 if imperfect_nested_loops_to_perfect:
233 gpu_pipeline_builder.enable_imperfect_nested_loops_to_perfect()
234 if nested_parallel_ops_to_multidimensional:
235 gpu_pipeline_builder.enable_nested_parallel_ops_to_multidimensional()
236 if nested_parallel_ops_to_for_ops > -1:
237 gpu_pipeline_builder.enable_nested_parallel_ops_to_for_ops(nested_parallel_ops_to_for_ops)
238 if max_patch_size > -1:
239 gpu_pipeline_builder.enable_memory_reuse(max_patch_size)
240 if use_memory_fusion:
241 gpu_pipeline_builder.enable_memory_fusion()
243 gpu_pipeline_builder.enable_loop_fusion()
244 project.output.makefile.d[
"GPU_PIPELINE"] = gpu_pipeline_builder.generate_opt_commands()
246 project.output.makefile.d[
"MLIR_GPU"] =
True
247 project.output.makefile.add_CXX_flag(
"-DMLIR_GPU")
248 project.output.makefile.add_linker_flag(
"-ldl")
249 project.output.makefile.add_linker_flag(
"-pthread")
253 project.output.makefile.d[
"MLIR_SOURCES_GPU"] = f
"{filename_root}{dimensions}d.mlir"
254 project.output.makefile.d[
"MLIR_LL_FILE_GPU"] = f
"{filename_root}{dimensions}d_gpu.ll"
255 project.output.makefile.d[
"MLIR_OBJECT_GPU"] = f
"{filename_root}{dimensions}d_mlir_gpu.o"
257 if project.output.makefile.d[
"GPU_VENDOR"] ==
"NVIDIA":
258 project.output.makefile.d[
"MLIR_GPU_NVIDIA"] =
True
259 project.output.makefile.add_CXX_flag(
"-DMLIR_GPU_NVIDIA")
260 CUDA_HOME = os.path.dirname(subprocess.check_output(
"which nvcc", shell=
True).decode().strip())
261 project.output.makefile.add_cpp_file(
"MLIRbridgeCUDAfunctions.cpp")
262 project.output.makefile.add_linker_flag(
"-lcuda")
263 project.output.makefile.add_linker_flag(
"-lcudart")
264 project.output.makefile.add_linker_flag(
"-lmlir_cuda_runtime")
265 project.output.makefile.add_linker_flag(f
"-L{CUDA_HOME}/../targets/sbsa-linux/lib")
267 cuda_bridge_header_file = f
"{peano_dir}python/exahype2/dslhype/MLIRbridgeCUDAfunctions.h"
268 cuda_bridge_file = f
"{peano_dir}python/exahype2/dslhype/MLIRbridgeCUDAfunctions.cpp"
269 os.system(
"cp {} MLIRbridgeCUDAfunctions.h".format(cuda_bridge_header_file))
270 os.system(
"cp {} MLIRbridgeCUDAfunctions.cpp".format(cuda_bridge_file))
271 elif project.output.makefile.d[
"GPU_VENDOR"] ==
"AMD":
272 project.output.makefile.d[
"MLIR_GPU_AMD"] =
True
273 project.output.makefile.add_CXX_flag(
"-DMLIR_GPU_AMD")
274 ROCM_HOME = os.path.dirname(subprocess.check_output(
"which hipcc", shell=
True).decode().strip()) +
"/.."
275 os.environ[
"ROCM_HOME"] = ROCM_HOME
276 project.output.makefile.add_cpp_file(
"MLIRbridgeHIPfunctions.cpp")
277 project.output.makefile.add_CXX_flag(
"-D__HIP_PLATFORM_AMD__")
278 project.output.makefile.add_linker_flag(
"-lamdhip64")
279 project.output.makefile.add_CXX_flag(f
"-I{ROCM_HOME}/include")
280 project.output.makefile.add_linker_flag(
"-lmlir_rocm_runtime")
281 hip_bridge_header_file = f
"{peano_dir}python/exahype2/dslhype/MLIRbridgeHIPfunctions.h"
282 hip_bridge_file = f
"{peano_dir}python/exahype2/dslhype/MLIRbridgeHIPfunctions.cpp"
283 os.system(
"cp {} MLIRbridgeHIPfunctions.h".format(hip_bridge_header_file))
284 os.system(
"cp {} MLIRbridgeHIPfunctions.cpp".format(hip_bridge_file))
286 raise RuntimeError(
"Unknown GPU vendor, please set it when configuring Peano with --with-gpu-vendor. Also set the GPU architecture with --with-gpu-arch.")
288 project.output.makefile.d[
"MLIR_ENABLED"] =
True
289 project.output.makefile.d[
"MLIR_PHYSICS_FILE"] = f
"{physics_file}"
290 project.output.makefile.d[
"MLIR_SOURCES"] = f
"{filename_root}{dimensions}d.mlir"
291 project.output.makefile.d[
"MLIR_LL_FILE"] = f
"{filename_root}{dimensions}d.ll"
292 project.output.makefile.d[
"MLIR_OBJECT"] = f
"{filename_root}{dimensions}d_mlir.o"
293 project.output.makefile.d[
"MLIR_SOURCES_OMP"] = f
"{filename_root}{dimensions}d_omp.mlir"
294 project.output.makefile.d[
"MLIR_LL_FILE_OMP"] = f
"{filename_root}{dimensions}d_omp.ll"
295 project.output.makefile.d[
"MLIR_OBJECT_OMP"] = f
"{filename_root}{dimensions}d_mlir_omp.o"