1from abc
import ABC, abstractmethod
5from operator
import itemgetter
47 return self.
_mlir.pop()
76 use_accelerator =
False
77 use_memory_manager =
False
82 target_variable_name =
None
83 mlir_symbol_table = {}
84 mlir_memref_types = {}
88 type_map.update({
'void':
'void'})
89 type_map.update({
'int':
'i64'})
90 type_map.update({
'double':
'f64'})
91 type_map.update({
'double*':
'memref<?xf64>'})
92 type_map.update({
'tarch::la::Vector<2, double>':
'memref<?xi64>'})
93 type_map.update({
'tarch::la::Vector<3, double>':
'memref<?xi64>'})
94 type_map.update({
'CellData<double, double>&':
'!llvm.ptr'})
95 type_map.update({
'const FluxFunctor&':
'(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()'})
96 type_map.update({
'const SourceFunctor&':
'(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, !llvm.ptr) -> ()'})
97 type_map.update({
'const NonconservativeProductFunctor&':
'(!llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()'})
98 type_map.update({
'const MaxEigenvalueFunctorInPlace&':
'(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()'})
99 type_map.update({
'const MaxEigenvalueFunctor&':
'(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()'})
100 type_map.update({
'peano4::utils::LoopPlacement':
'i32'})
104 type_map.update({
'flux':
'(memref<?xf64>, !llvm.ptr, !llvm.ptr, f64, f64, i32, memref<?xf64>) -> ()'})
105 type_map.update({
'nonconservativeProduct':
'(memref<?xf64>, memref<?xf64>, !llvm.ptr, !llvm.ptr, f64, f64, i32, memref<?xf64>) -> ()'})
106 type_map.update({
'sourceTerm':
'(memref<?xf64>, !llvm.ptr, !llvm.ptr, f64, f64, memref<?xf64>) -> ()'})
107 type_map.update({
'volumetricSource':
'(memref<?xf64>, !llvm.ptr, f64, memref<?xf64>) -> ()'})
108 type_map.update({
'maxEigenvalue':
'(memref<?xf64>, !llvm.ptr, !llvm.ptr, f64, f64, i32, memref<?xf64>) -> ()'})
111 type_map.update({
'source':
'memref<?xmemref<?xf64>>'})
112 type_map.update({
'maxEigenvaluesX':
'memref<?xmemref<?xf64>>'})
113 type_map.update({
'maxEigenvaluesY':
'memref<?xmemref<?xf64>>'})
114 type_map.update({
'maxEigenvaluesZ':
'memref<?xmemref<?xf64>>'})
115 type_map.update({
'maxEigenvaluesX2':
'memref<?xmemref<?xf64>>'})
116 type_map.update({
'maxEigenvaluesY2':
'memref<?xmemref<?xf64>>'})
117 type_map.update({
'maxEigenvaluesZ2':
'memref<?xmemref<?xf64>>'})
118 type_map.update({
'maxEigenvaluesXY':
'memref<?xmemref<?xf64>>'})
119 type_map.update({
'maxEigenvaluesPerVolume':
'memref<?xmemref<?xf64>>'})
123 type_map.update({
'lambdaLeft':
'memref<?xmemref<?xf64>>'})
124 type_map.update({
'lambdaRight':
'memref<?xmemref<?xf64>>'})
125 type_map.update({
'lambdaBottom':
'memref<?xmemref<?xf64>>'})
126 type_map.update({
'lambdaTop':
'memref<?xmemref<?xf64>>'})
127 type_map.update({
'lambdaNear':
'memref<?xmemref<?xf64>>'})
128 type_map.update({
'lambdaFar':
'memref<?xmemref<?xf64>>'})
129 type_map.update({
'fluxLeft':
'memref<?xmemref<?xf64>>'})
130 type_map.update({
'fluxRight':
'memref<?xmemref<?xf64>>'})
131 type_map.update({
'fluxBottom':
'memref<?xmemref<?xf64>>'})
132 type_map.update({
'fluxTop':
'memref<?xmemref<?xf64>>'})
133 type_map.update({
'fluxNear':
'memref<?xmemref<?xf64>>'})
134 type_map.update({
'fluxFar':
'memref<?xmemref<?xf64>>'})
139 type_map.update({
'flux_x':
'memref<?xmemref<?xf64>>'})
140 type_map.update({
'flux_y':
'memref<?xmemref<?xf64>>'})
141 type_map.update({
'flux_z':
'memref<?xmemref<?xf64>>'})
142 type_map.update({
'average_x':
'memref<?xmemref<?xf64>>'})
143 type_map.update({
'average_y':
'memref<?xmemref<?xf64>>'})
144 type_map.update({
'average_z':
'memref<?xmemref<?xf64>>'})
145 type_map.update({
'delta_x':
'memref<?xmemref<?xf64>>'})
146 type_map.update({
'delta_y':
'memref<?xmemref<?xf64>>'})
147 type_map.update({
'delta_z':
'memref<?xmemref<?xf64>>'})
148 type_map.update({
'nonconservative_x':
'memref<?xmemref<?xf64>>'})
149 type_map.update({
'nonconservative_y':
'memref<?xmemref<?xf64>>'})
150 type_map.update({
'nonconservative_z':
'memref<?xmemref<?xf64>>'})
153 type_map.update({
'memref<?xf64>':
'void*'})
154 type_map.update({
'!llvm.ptr':
'void*'})
155 type_map.update({
'f64':
'double'})
156 type_map.update({
'i32':
'int'})
157 type_map.update({
'i64':
'long'})
158 type_map.update({
'i1':
'bool'})
161 descriptor2DType =
"!llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>"
162 descriptor1DType =
"!llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>"
165 patchTypes = [descriptor2DType, descriptor2DType, descriptor1DType, descriptor1DType,
166 descriptor1DType, descriptor1DType, descriptor1DType,
'i64',
'i64',
'i64',
'ptr',
'ptr']
168 struct_map.update({
'patchData': [
169 (
'QIn' , f
"{descriptor2DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
170 (
'QOut' , f
"{descriptor2DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
171 (
'cellCentre' , f
"{descriptor1DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
172 (
'cellSize' , f
"{descriptor1DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
173 (
't' , f
"{descriptor1DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
174 (
'dt' , f
"{descriptor1DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
175 (
'id' , f
"{descriptor1DType}|||!llvm.struct<({', '.join(patchTypes)})>"),
176 (
'numberOfCells' , f
"i64|||!llvm.struct<({', '.join(patchTypes)})>"),
177 (
'memoryLocation' , f
"i64|||!llvm.struct<({', '.join(patchTypes)})>"),
178 (
'targetDevice' , f
"i64|||!llvm.struct<({', '.join(patchTypes)})>"),
179 (
'QOut_legacy' , f
"!llvm.ptr|||!llvm.struct<({', '.join(patchTypes)})>"),
180 (
'maxEigenvalue' , f
"memref<?xf64>|||!llvm.struct<({', '.join(patchTypes)})>")]})
184 for struct_name, fields
in struct_map.items():
185 for field_name, field_info
in fields:
186 target_type = field_info.split(
'|||')[0]
188 if target_type == descriptor2DType:
189 type_map.update({field_name:
'memref<?x?xf64>'})
190 elif target_type == descriptor1DType:
194 if field_name
in [
'cellCentre',
'cellSize',
'h',
'x']:
195 type_map.update({field_name:
'memref<?xi64>'})
197 type_map.update({field_name:
'memref<?xf64>'})
198 elif target_type ==
'i64':
199 type_map.update({field_name:
'i64'})
200 elif target_type ==
'!llvm.ptr':
202 type_map.update({field_name:
'!llvm.ptr'})
205 type_map.update({field_name: target_type})
214 if parent
is not None:
241 if isinstance(type_string, str):
242 if type_string ==
"int":
244 elif type_string ==
"double":
246 elif type_string ==
"bool":
252 indent =
' ' * indent_level * Node.spaces_per_tab
257 inner_memref_id = f
"%{Node.get_mlir_id()}"
258 mlir_code += indent + f
"{inner_memref_id} = memref.load {memref_mlir}[{row_index}] {{name = \"{memref_mlir.strip('%')}\"}} : memref<?xmemref<?xf64>>\n"
261 ptr_idx_id = f
"%{Node.get_mlir_id()}"
262 mlir_code += indent + f
"{ptr_idx_id} = memref.extract_aligned_pointer_as_index {inner_memref_id} : memref<?xf64> -> index {{name = \"{memref_mlir.strip('%')}\"}}\n"
265 element_size_bytes = f
"%{Node.get_mlir_id()}"
266 mlir_code += indent + f
"{element_size_bytes} = arith.constant 8 : index\n"
268 offset_bytes_id = f
"%{Node.get_mlir_id()}"
269 mlir_code += indent + f
"{offset_bytes_id} = arith.muli {col_index}, {element_size_bytes} : index\n"
272 ptr_with_offset = f
"%{Node.get_mlir_id()}"
273 mlir_code += indent + f
"{ptr_with_offset} = arith.addi {ptr_idx_id}, {offset_bytes_id} : index\n"
276 ptr_i64 = f
"%{Node.get_mlir_id()}"
277 mlir_code += indent + f
"{ptr_i64} = arith.index_cast {ptr_with_offset} : index to i64\n"
279 result_ptr = f
"%{Node.get_mlir_id()}"
280 mlir_code += indent + f
"{result_ptr} = llvm.inttoptr {ptr_i64} : i64 to !llvm.ptr\n"
283 col_width_id = f
"%{Node.get_mlir_id()}"
284 one_const = f
"%{Node.get_mlir_id()}"
285 mlir_code += indent + f
"{one_const} = arith.constant 1 : index\n"
286 mlir_code += indent + f
"{col_width_id} = memref.dim {memref_mlir}, {one_const} : memref<?x?xf64>\n"
289 row_offset = f
"%{Node.get_mlir_id()}"
290 mlir_code += indent + f
"{row_offset} = arith.muli {row_index}, {col_width_id} : index\n"
293 elem_offset = f
"%{Node.get_mlir_id()}"
294 mlir_code += indent + f
"{elem_offset} = arith.addi {row_offset}, {col_index} : index\n"
297 element_size_bytes = f
"%{Node.get_mlir_id()}"
298 mlir_code += indent + f
"{element_size_bytes} = arith.constant 8 : index\n"
300 offset_bytes_id = f
"%{Node.get_mlir_id()}"
301 mlir_code += indent + f
"{offset_bytes_id} = arith.muli {elem_offset}, {element_size_bytes} : index\n"
304 base_ptr_idx = f
"%{Node.get_mlir_id()}"
305 mlir_code += indent + f
"{base_ptr_idx} = memref.extract_aligned_pointer_as_index {memref_mlir} : memref<?x?xf64> -> index {{name = \"{memref_mlir.strip('%')}\"}}\n"
308 ptr_with_offset = f
"%{Node.get_mlir_id()}"
309 mlir_code += indent + f
"{ptr_with_offset} = arith.addi {base_ptr_idx}, {offset_bytes_id} : index\n"
312 ptr_i64 = f
"%{Node.get_mlir_id()}"
313 mlir_code += indent + f
"{ptr_i64} = arith.index_cast {ptr_with_offset} : index to i64\n"
315 result_ptr = f
"%{Node.get_mlir_id()}"
316 mlir_code += indent + f
"{result_ptr} = llvm.inttoptr {ptr_i64} {{name = \"{memref_mlir.strip('%')}\"}} : i64 to !llvm.ptr\n"
318 return mlir_code, result_ptr
325 desc_id = f
"%{cls.get_mlir_id()}"
326 desc_0_id = f
"%{cls.get_mlir_id()}"
327 desc_1_id = f
"%{cls.get_mlir_id()}"
328 desc_2_id = f
"%{cls.get_mlir_id()}"
329 desc_3_id = f
"%{cls.get_mlir_id()}"
330 desc_4_id = f
"%{cls.get_mlir_id()}"
334 memref_id = target_var_name
336 memref_id = f
"%{cls.get_mlir_id()}"
339 c0_i64_id = f
"%{cls.get_mlir_id()}"
340 c1_i64_id = f
"%{cls.get_mlir_id()}"
344 if target_type.startswith(
'memref<?x?'):
346 struct_type =
'!llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>'
350 struct_type =
'!llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>'
354 if target_type.startswith(
'memref<?xmemref')
or size_hint == 1:
356 elif target_type.startswith(
'memref<?xi64>')
and size_hint == 2:
358 elif target_type.startswith(
'memref<?xi64>'):
366 mlir_str += indent + f
"{c0_i64_id} = arith.constant 0 : i64\n"
367 mlir_str += indent + f
"{c1_i64_id} = arith.constant 1 : i64\n"
371 size_id = f
"%{cls.get_mlir_id()}"
372 size_i64_id = f
"%{cls.get_mlir_id()}"
373 mlir_str += indent + f
"{size_id} = arith.constant {size_val} : index\n"
374 mlir_str += indent + f
"{size_i64_id} = arith.index_cast {size_id} : index to i64\n"
375 size_ref = size_i64_id
380 mlir_str += indent + f
"{desc_id} = llvm.mlir.undef : {struct_type}\n"
381 mlir_str += indent + f
"{desc_0_id} = llvm.insertvalue {ptr_id}, {desc_id}[0] : {struct_type}\n"
382 mlir_str += indent + f
"{desc_1_id} = llvm.insertvalue {ptr_id}, {desc_0_id}[1] : {struct_type}\n"
383 mlir_str += indent + f
"{desc_2_id} = llvm.insertvalue {c0_i64_id}, {desc_1_id}[2] : {struct_type}\n"
384 mlir_str += indent + f
"{desc_3_id} = llvm.insertvalue {size_ref}, {desc_2_id}[3, 0] : {struct_type}\n"
385 if num_dimensions == 2:
387 desc_3_1_id = f
"%{cls.get_mlir_id()}"
388 mlir_str += indent + f
"{desc_3_1_id} = llvm.insertvalue {size_ref}, {desc_3_id}[3, 1] : {struct_type}\n"
389 mlir_str += indent + f
"{desc_4_id} = llvm.insertvalue {c1_i64_id}, {desc_3_1_id}[4, 0] : {struct_type}\n"
390 desc_final_id = f
"%{cls.get_mlir_id()}"
391 mlir_str += indent + f
"{desc_final_id} = llvm.insertvalue {c1_i64_id}, {desc_4_id}[4, 1] : {struct_type}\n"
394 mlir_str += indent + f
"{desc_4_id} = llvm.insertvalue {c1_i64_id}, {desc_3_id}[4, 0] : {struct_type}\n"
395 desc_final_id = desc_4_id
396 mlir_str += indent + f
"{memref_id} = builtin.unrealized_conversion_cast {desc_final_id} : {struct_type} to {target_type} {{name = \"{memref_id.strip('%')}\"}}\n"
398 return mlir_str, memref_id
401 def create_memref_from_extracted_descriptor(cls, alloc_ptr_id, aligned_ptr_id, offset_id, sizes_0_id, sizes_1_id, strides_0_id, strides_1_id, target_type, struct_type, indent_level=0, target_var_name=None, is_2d=False):
406 memref_id = target_var_name
408 memref_id = f
"%{cls.get_mlir_id()}"
411 desc_id = f
"%{cls.get_mlir_id()}"
412 desc_0_id = f
"%{cls.get_mlir_id()}"
413 desc_1_id = f
"%{cls.get_mlir_id()}"
414 desc_2_id = f
"%{cls.get_mlir_id()}"
415 desc_3_id = f
"%{cls.get_mlir_id()}"
416 desc_4_id = f
"%{cls.get_mlir_id()}"
418 c1_i64_id = f
"%{cls.get_mlir_id()}"
423 mlir_str += indent + f
"{c1_i64_id} = arith.constant 1 : i64\n"
427 mlir_str += indent + f
"{desc_id} = llvm.mlir.undef : {struct_type}\n"
428 mlir_str += indent + f
"{desc_0_id} = llvm.insertvalue {alloc_ptr_id}, {desc_id}[0] : {struct_type}\n"
429 mlir_str += indent + f
"{desc_1_id} = llvm.insertvalue {aligned_ptr_id}, {desc_0_id}[1] : {struct_type}\n"
430 mlir_str += indent + f
"{desc_2_id} = llvm.insertvalue {offset_id}, {desc_1_id}[2] : {struct_type}\n"
431 mlir_str += indent + f
"{desc_3_id} = llvm.insertvalue {sizes_0_id}, {desc_2_id}[3, 0] : {struct_type}\n"
436 desc_3_1_id = f
"%{cls.get_mlir_id()}"
437 mlir_str += indent + f
"{desc_3_1_id} = llvm.insertvalue {sizes_1_id}, {desc_3_id}[3, 1] : {struct_type}\n"
438 mlir_str += indent + f
"{desc_4_id} = llvm.insertvalue {strides_0_id}, {desc_3_1_id}[4, 0] : {struct_type}\n"
439 desc_final_id = f
"%{cls.get_mlir_id()}"
440 mlir_str += indent + f
"{desc_final_id} = llvm.insertvalue {strides_1_id}, {desc_4_id}[4, 1] : {struct_type}\n"
443 mlir_str += indent + f
"{desc_4_id} = llvm.insertvalue {strides_0_id}, {desc_3_id}[4, 0] : {struct_type}\n"
444 desc_final_id = desc_4_id
446 mlir_str += indent + f
"{memref_id} = builtin.unrealized_conversion_cast {desc_final_id} : {struct_type} to {target_type} {{name = \"{memref_id.strip('%')}\"}}\n"
448 return mlir_str, memref_id
470class Statement(Node):
504 return ' ' * indent_level * Node.spaces_per_tab +
'void'
507 return ' ' * indent_level * Node.spaces_per_tab +
'void'
510 return ' ' * indent_level * Node.spaces_per_tab +
'void'
513 return ' ' * indent_level * Node.spaces_per_tab +
'void'
521 def __init__(self, id, argument_type: Type, namespace =
None, is_function =
False):
528 if Node.use_accelerator ==
True:
529 if type(self.
_type)
is TCustom
and self.
_type._type.find(
"CellData") != -1:
530 index = self.
_type._type.find(
"CellData")
531 self.
_type._type = self.
_type._type[0:index] +
"CopyCellDataGPU" + self.
_type._type[index + 8:]
544 return f
"%{self.id} : {self._type.print_mlir(0)}"
547 return ' ' * indent_level * Node.spaces_per_tab + f
"Argument: {self.id}"
554 def __init__(self, id, return_type: Type, template =
None, namespaces = [], stateless =
False, top_level =
False):
563 FunctionDefinition._stateless = stateless
572 if statement
is not None:
573 self.
_body.append(statement)
580 Node.type_map.update({argument.id: argument._namespace})
581 if Node.type_map.get(argument._type.print_cpp())
is None:
582 Node.type_map.update({argument._type.print_cpp(): argument._namespace})
585 namespace_header = f
"""namespace {"::".join(self._namespaces)} {{"""
586 namespace_footer =
"}"
589 template_strings = [argument.print_cpp()
for argument
in self.
_template]
590 template_string =
"template <" +
",".join(template_strings) +
">\n"
592 current_indent = indent_level + 1
593 argument_prints = [argument.print_cpp()
for argument
in self.
_arguments]
595 return f
"""{namespace_header}
596{template_string}{' ' * current_indent * Node.spaces_per_tab}{self._return_type.print_cpp()} {self.id}({', '.join(argument_prints)});
601 namespace_header = f
"""namespace {"::".join(self._namespaces)} {{"""
602 namespace_footer =
"}"
605 template_strings = [argument.print_cpp()
for argument
in self.
_template]
606 template_string =
"template <" +
",".join(template_strings) +
">\n"
608 current_indent = indent_level + 1
609 statement_prints = [statement.print_cpp(current_indent + 1)
for statement
in self.
_body]
610 argument_prints = [argument.print_cpp()
for argument
in self.
_arguments]
612 return f
"""{namespace_header}
613{template_string}{' ' * current_indent * Node.spaces_per_tab}{self._return_type.print_cpp()} {self.id}({', '.join(argument_prints)}) {{
614{os.linesep.join(statement_prints)}
615{' ' * current_indent * Node.spaces_per_tab}}}
620 namespace_header = f
"""namespace {"::".join(self._namespaces)} {{"""
621 namespace_footer =
"}"
624 template_strings = [argument.print_omp()
for argument
in self.
_template]
625 template_string =
"template <" +
",".join(template_strings) +
">\n"
627 current_indent = indent_level + 1
628 statement_prints = [statement.print_omp(current_indent + 1)
for statement
in self.
_body]
629 argument_prints = [argument.print_omp()
for argument
in self.
_arguments]
631 return f
"""{namespace_header}
632{template_string}{' ' * current_indent * Node.spaces_per_tab}{self._return_type.print_omp()} {self.id}({', '.join(argument_prints)}) {{
633{os.linesep.join(statement_prints)}
634{' ' * current_indent * Node.spaces_per_tab}}}
639 namespace_header = f
"""namespace {"::".join(self._namespaces)} {{"""
640 namespace_footer =
"}"
643 template_strings = [argument.print_sycl()
for argument
in self.
_template]
644 template_string =
"template <" +
",".join(template_strings) +
">\n"
646 current_indent = indent_level + 1
647 statement_prints = [statement.print_sycl(current_indent + 1)
for statement
in self.
_body]
648 argument_prints = [argument.print_sycl()
for argument
in self.
_arguments]
649 statement_prints.insert(0,
"::sycl::queue& queue = tarch::accelerator::getSYCLQueue(targetDevice);")
650 statement_prints.insert(1,
"size_t range0, range1, range2;")
652 data_copy_prints = []
653 for dataBlockCreation
in FunctionDefinition._syclDataToCopy:
654 if len(dataBlockCreation._dataBlock._iteration_range) > 1:
656 for d
in dataBlockCreation._dataBlock._iteration_range[0:-1]:
657 step_size = step_size * (d[1] - d[0])
658 size = step_size * (dataBlockCreation._dataBlock._iteration_range[-1][1] - dataBlockCreation._dataBlock._iteration_range[-1][0])
660 return f
"""{namespace_header}
661{template_string}{' ' * current_indent * Node.spaces_per_tab}{self._return_type.print_sycl()} {self.id}({', '.join(argument_prints)}) {{
662{os.linesep.join(statement_prints)}
663{os.linesep.join(data_copy_prints)}
664{' ' * current_indent * Node.spaces_per_tab}}}
672 Node.reset_mlir_ids()
681 mlir_signature = argument._namespace
684 if argument._is_function:
687 func_decl = f
"func.func private @{argument.id}_bridge{mlir_signature}"
688 globals_mlir.append(
' ' * (indent_level) * Node.spaces_per_tab + func_decl)
694 "MLIR code generation requires template parameters to determine bridge function signatures. "
695 "Ensure the function has template parameters that specify the required functors."
699 function_global_loads = []
703 new_id = Node.get_mlir_id()
704 globals_mlir.append(
' ' * (indent_level) * Node.spaces_per_tab +f
"llvm.mlir.global external @{argument.id}() : {argument._type.print_mlir(0)}")
705 function_global_loads.append(
' ' * (indent_level + 1) * Node.spaces_per_tab + f
"%{new_id} = llvm.mlir.addressof @{argument.id} : !llvm.ptr")
708 arg_mlir_type = argument._type.print_mlir(0)
711 if arg_mlir_type
and arg_mlir_type.strip() !=
'' and len(arg_mlir_type.strip()) > 0:
712 function_global_loads.append(
' ' * (indent_level + 1) * Node.spaces_per_tab + f
"%{argument.id} = llvm.load %{new_id} {{name = \"{argument.id.strip('%')}\"}} : !llvm.ptr -> {arg_mlir_type}")
715 function_global_loads.append(
' ' * (indent_level + 1) * Node.spaces_per_tab + f
"// Skipping load for {argument.id} (empty type: '{arg_mlir_type}')")
719 Node.context.push_block()
720 argument_prints = [argument.print_mlir(indent_level).strip(
'')
for argument
in self.
_arguments]
721 Node.context.push_block()
723 statement_prints = [statement.print_mlir(indent_level + 1)
for statement
in self.
_body]
724 statements = Node.context.pop_block().get_mlir()
725 statements += statement_prints
728 return_type_str = f
" -> ({return_type})" if return_type !=
'void' else ''
732{os.linesep.join(globals_mlir)}
733 func.func @{self.id + "_omp" if Node.use_mlir_omp else self.id}({', '.join(argument_prints)}){return_type_str} {{
734{os.linesep.join(function_global_loads)}
735{os.linesep.join(statements)}
741 Node.context.push_block()
742 argument_prints = [argument.print_mlir(indent_level)
for argument
in self.
_arguments]
743 Node.context.push_block()
744 statement_prints = [statement.print_mlir(indent_level + 1)
for statement
in self.
_body]
745 statements = Node.context.pop_block().get_mlir()
746 statements += statement_prints
748 return_type_str = f
" -> ({return_type})" if return_type !=
'void' else ''
750 func.func @{self.id}({', '.join(argument_prints)}){return_type_str} {{
751{os.linesep.join(statements)}
757 statement_prints = [statement.print_tree(indent_level + 1)
for statement
in self.
_body]
758 argument_prints = [argument.print_tree(indent_level + 1)
for argument
in self.
_arguments]
760FunctionDefinition: {self.id}:
761{os.linesep.join(argument_prints)}
762{os.linesep.join(statement_prints)}"""
765 namespace_header = f
"""namespace {"::".join(self._namespaces)} {{"""
766 namespace_footer =
"}"
768 function_call_string = self.
id
770 template_strings = [argument.print_cpp()
for argument
in self.
_template]
771 template_string =
"template <" +
",".join(template_strings) +
">\n"
772 function_call_string +=
"<" +
",".join([template.split(
' ')[1]
for template
in template_strings]) +
">"
775 arguments.append(
Argument(
"measurement",
TCustom(
"tarch::timing::Measurement&")))
777 current_indent = indent_level + 1
778 argument_prints = [argument.print_cpp()
for argument
in arguments]
780 return f
"""{namespace_header}
781{template_string}{' ' * current_indent * Node.spaces_per_tab}{self._return_type.print_cpp()} {self.id}({', '.join(argument_prints)}) {{
782tarch::timing::Watch watch("{"::".join(self._namespaces)}", "{self.id}", false, true);
783{function_call_string}({",".join([argument.print_cpp().split(' ')[-1] for argument in self._arguments])});
785measurement.setValue(watch.getCalendarTime());
786{' ' * current_indent * Node.spaces_per_tab}}}
791 namespace_header = f
"""namespace {"::".join(self._namespaces)} {{"""
792 namespace_footer =
"}"
795 template_strings = [argument.print_cpp()
for argument
in self.
_template]
796 template_string =
"template <" +
",".join(template_strings) +
">\n"
799 arguments.append(
Argument(
"measurement",
TCustom(
"tarch::timing::Measurement&")))
801 current_indent = indent_level + 1
802 argument_prints = [argument.print_cpp()
for argument
in arguments]
804 return f
"""{namespace_header}
805{template_string}{' ' * current_indent * Node.spaces_per_tab}{self._return_type.print_cpp()} {self.id}({', '.join(argument_prints)});
815 return f
"""{self._output.print_cpp()} << {self._statement.print_cpp()};"""
818 return f
"""{self._output.print_omp()} << {self._statement.print_omp()};"""
821 return f
"""{self._output.print_sycl()} << {self._statement.print_sycl()};"""
838 if self.
type is None:
840 self.
type._parent = self
849 return Name.variables[self.
id].
index(i)
852 return Name.variables[self.
id].
index(i, j)
870 if type(rhs)
is Name:
871 return (Name.variables[self.
id] > Name.variables[rhs.id])
872 return (Name.variables[self.
id] > rhs)
875 if type(rhs)
is Name:
876 if rhs.id
in Name.variables
and self.
id in Name.variables:
877 return (self.
_value == Name.variables[rhs.id])
881 if self.
id in Name.variables:
882 return (Name.variables[self.
id] == rhs)
890 return ' ' * indent_level * Node.spaces_per_tab + self.
id
893 return ' ' * indent_level * Node.spaces_per_tab + self.
id
896 return ' ' * indent_level * Node.spaces_per_tab + self.
id
903 return ' ' * indent_level * Node.spaces_per_tab +
"Name:" + self.
id
908class Integer(Expression):
917 if type(rhs)
is Integer:
923 if type(rhs)
is Integer:
925 if type(rhs)
is UnaryOperation
and rhs._operation ==
"-":
928 if type(rhs)
is Integer:
945 if type(rhs)
is Name:
946 if rhs.id
in Name.variables:
947 return (self.
_value < Name.variables[rhs.id])
950 return (self.
_value < rhs)
953 if type(rhs)
is Name:
954 if rhs.id
in Name.variables:
955 return (self.
_value > Name.variables[rhs.id])
958 return (self.
_value > rhs)
961 if type(rhs)
is Integer:
962 return (self.
_value == rhs._value)
970 struct, field = self.
_string.split(
'.')
971 if struct
in Node.struct_map:
972 struct_list = Node.struct_map[struct]
974 for item
in struct_list:
978 target_type = mlir_type.split(
'|||')[0]
if '|||' in mlir_type
else mlir_type
980 if target_type ==
'i64':
983 elif target_type ==
'i32':
985 elif target_type ==
'f64':
992 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
994 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_string)
998 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1000 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_string)
1004 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1006 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_string)
1009 indent =
' ' * indent_level * Node.spaces_per_tab
1014 self.
mlir_id(Node.get_mlir_id())
1015 mlir_str =
"".join(Node.context.get_block().pop_mlir())
1016 mlir_str += indent + f
"%{self.mlir_id()} = arith.constant {self._value} : {self.get_type().print_mlir(0)}\n"
1017 Node.context.push_block()
1018 Node.context.get_block().mlir_append(mlir_str)
1019 id = f
"%{self.mlir_id()}"
1029 struct, field = x.split(
'.')
1030 if struct
in Node.struct_map:
1031 struct_list = Node.struct_map[struct]
1032 idx = [item[0]
for item
in struct_list].index(field)
1033 mlir_type = struct_list[idx][1]
1035 mlir_type_struct = mlir_type.split(
'|||')[1]
if '|||' in mlir_type
else mlir_type
1037 mlir_str = f
"llvm.getelementptr %{struct}[0, {idx}] : (!llvm.ptr) -> !llvm.ptr, {mlir_type_struct}"
1043 return ' ' * indent_level * Node.spaces_per_tab +
"Integer: " + str(self.
_value)
1045 return ' ' * indent_level * Node.spaces_per_tab +
"Integer: " + str(self.
_string)
1060 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1063 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1066 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1073 return ' ' * indent_level * Node.spaces_per_tab +
"Boolean: " + str(self.
_value)
1087 return ' ' * indent_level * Node.spaces_per_tab + self.
_value
1090 return ' ' * indent_level * Node.spaces_per_tab + self.
_value
1093 return ' ' * indent_level * Node.spaces_per_tab + self.
_value
1096 indent =
' ' * indent_level * Node.spaces_per_tab
1100 struct, field = x.split(
'.')
1101 if struct
in Node.struct_map:
1102 struct_list = Node.struct_map[struct]
1103 idx = [item[0]
for item
in struct_list].index(field)
1104 mlir_type_target, mlir_type_struct = struct_list[idx][1].split(
'|||')
1107 struct_val_id = f
"%{Node.get_mlir_id()}"
1110 if field ==
"maxEigenvalue":
1111 field_id = f
"%{field}s"
1113 field_id = f
"%{Node.get_mlir_id()}"
1116 mlir_str = indent + f
"{struct_val_id} = llvm.load %{struct} {{name = \"{struct.strip('%')}\"}}: !llvm.ptr -> {mlir_type_struct}\n"
1120 if not mlir_type_target.startswith(
"!llvm.struct<"):
1122 ptr_field_id = f
"%{field}{'_ptr' if field != 'maxEigenvalue' else '_ptr'}"
1123 mlir_str += indent + f
"{ptr_field_id} = llvm.extractvalue {struct_val_id}[{idx}] : {mlir_type_struct}\n"
1124 field_id = ptr_field_id
1127 mlir_str += indent + f
"{field_id} = llvm.extractvalue {struct_val_id}[{idx}] : {mlir_type_struct}\n"
1132 if mlir_type_target.startswith(
"!llvm.struct<"):
1134 ptr_getelementptr_id = f
"%{Node.get_mlir_id()}"
1135 ptr_load_id = f
"%{Node.get_mlir_id()}"
1136 mlir_str += indent + f
"{ptr_getelementptr_id} = llvm.getelementptr %{struct}[0, {idx}] : (!llvm.ptr) -> !llvm.ptr, {mlir_type_struct}\n"
1137 mlir_str += indent + f
"{ptr_load_id} = llvm.load {ptr_getelementptr_id} {{name = \"{struct.strip('%')}\"}}: !llvm.ptr -> {mlir_type_target}\n"
1140 alloc_ptr_id = f
"%{Node.get_mlir_id()}"
1141 aligned_ptr_id = f
"%{Node.get_mlir_id()}"
1142 offset_id = f
"%{Node.get_mlir_id()}"
1143 sizes_0_id = f
"%{Node.get_mlir_id()}"
1144 strides_0_id = f
"%{Node.get_mlir_id()}"
1146 mlir_str += indent + f
"{alloc_ptr_id} = llvm.extractvalue {ptr_load_id}[0] : {mlir_type_target}\n"
1147 mlir_str += indent + f
"{aligned_ptr_id} = llvm.extractvalue {ptr_load_id}[1] : {mlir_type_target}\n"
1148 mlir_str += indent + f
"{offset_id} = llvm.extractvalue {ptr_load_id}[2] : {mlir_type_target}\n"
1149 mlir_str += indent + f
"{sizes_0_id} = llvm.extractvalue {ptr_load_id}[3, 0] : {mlir_type_target}\n"
1150 mlir_str += indent + f
"{strides_0_id} = llvm.extractvalue {ptr_load_id}[4, 0] : {mlir_type_target}\n"
1153 is_2d =
"array<2 x i64>" in mlir_type_target
1160 sizes_1_id = f
"%{Node.get_mlir_id()}"
1161 strides_1_id = f
"%{Node.get_mlir_id()}"
1162 mlir_str += indent + f
"{sizes_1_id} = llvm.extractvalue {ptr_load_id}[3, 1] : {mlir_type_target}\n"
1163 mlir_str += indent + f
"{strides_1_id} = llvm.extractvalue {ptr_load_id}[4, 1] : {mlir_type_target}\n"
1167 if field
in Node.type_map:
1168 type_entry = Node.type_map[field]
1170 if isinstance(type_entry, str):
1171 target_memref_type = type_entry
1174 target_memref_type = type_entry.print_mlir(0).strip()
1179 target_memref_type =
"memref<?x?xf64>"
1182 target_memref_type =
"memref<?xf64>"
1185 conversion_mlir, memref_id = Node.create_memref_from_extracted_descriptor(
1196 target_var_name=Node.target_variable_name,
1198 mlir_str += conversion_mlir
1199 final_id = memref_id
1200 elif 'memref' in mlir_type_target
or mlir_type_target ==
'!llvm.ptr':
1203 clean_target_type = mlir_type_target.strip(
'()')
1205 conversion_mlir, memref_id = Node.create_memref_from_ptr(
1209 target_var_name=Node.target_variable_name)
1210 mlir_str += conversion_mlir
1211 final_id = memref_id
1214 Node.context.get_block().mlir_append(mlir_str)
1219 return ' ' * indent_level * Node.spaces_per_tab +
"String: " + self.
_value
1223 def __init__(self, value, string = None, reference = False):
1238 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1240 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_string)
1244 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1246 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_string)
1250 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_value)
1252 return ' ' * indent_level * Node.spaces_per_tab + str(self.
_string)
1255 indent =
' ' * indent_level * Node.spaces_per_tab
1260 self.
mlir_id(Node.get_mlir_id())
1261 mlir_str =
"".join(Node.context.get_block().pop_mlir())
1262 mlir_str += indent + f
"%{self.mlir_id()} = arith.constant {self._value} : {self.get_type().print_mlir(0)}\n"
1263 Node.context.push_block()
1264 Node.context.get_block().mlir_append(mlir_str)
1265 id = f
"%{self.mlir_id()}"
1272 return ' ' * indent_level * Node.spaces_per_tab +
"Float: " + str(self.
_value)
1276 def __init__(self, iteration_range, internal, requires_memory_allocation, id = None, underlying_type = String(
"double")):
1293 for i
in range(len(offset)):
1294 if type(offset[i])
is list:
1295 if offset[i][0]
is None:
1297 if offset[i][1]
is None:
1301 output._iteration_range[i][1] = offset[i][1]
1302 output._iteration_range[i][0] = offset[i][0]
1304 raise Exception(
"Invalid index")
1306 for i
in range(len(output._offset), len(output._iteration_range)):
1307 output._offset.append(
Integer(0))
1313 for i
in range(0, len(dimensions) - 1):
1315 if Node.use_accelerator ==
False and type(self)
is not FaceDataBlock:
1316 index_list = indices[0:-1]
1318 index_list = indices
1320 if type(dimensions[-len(index_list)][1] - dimensions[-len(index_list)][0])
is Integer
and (dimensions[-len(index_list)][1] - dimensions[-len(index_list)][0])._value == 1:
1321 index = self.
_offset[offset_start_index]
1323 if type(self.
_offset[offset_start_index + 0].
get_type())
is TDataBlock:
1326 index = index_list[0] + self.
_offset[offset_start_index + 0]
1328 index = factors[-len(index_list)] * index
1329 for i
in range(1, len(index_list)):
1330 if type(self.
_offset[offset_start_index + i].
get_type())
is TDataBlock:
1333 temp = index_list[i] + self.
_offset[offset_start_index + i]
1334 index = index + factors[-len(index_list) + i] * temp
1341 if Node.use_accelerator ==
False:
1354 return ' ' * indent_level * Node.spaces_per_tab + self.
id
1360 return ' ' * indent_level * Node.spaces_per_tab + self.
id
1366 return ' ' * indent_level * Node.spaces_per_tab + self.
id
1373 return "%" + self.
id
1377 return ' ' * indent_level * Node.spaces_per_tab + f
"""DataBlock:
1378{self._internal.print_tree(indent_level + 1)}"""
1380 return ' ' * indent_level * Node.spaces_per_tab +
"DataBlock: " + self.
id
1383FaceDataBlock distinguishes itself from normal DataBlocks by the fact that its internal array is always 1d.
1386 def __init__(self, iteration_range, internal, requires_memory_allocation, id = None, underlying_type = String(
"double")):
1387 super().
__init__(iteration_range, internal, requires_memory_allocation, id, underlying_type)
1393 for i
in range(len(offset)):
1394 if type(offset[i])
is list:
1395 if offset[i][0]
is None:
1397 if offset[i][1]
is None:
1401 output._iteration_range[i][1] = offset[i][1]
1402 output._iteration_range[i][0] = offset[i][0]
1404 raise Exception(
"Invalid index")
1406 for i
in range(len(output._offset), len(output._iteration_range)):
1407 output._offset.append(
Integer(0))
1425 for i
in range(len(self.
_dataBlock._memory_range) - 2, -1, -1):
1428 for i
in range(len(self.
_dataBlock._memory_range) - 1, -1, -1):
1429 index.append(loops[i].get_iteration_variable())
1433 for i
in range(0, len(loops) - 1):
1434 loops[i].add_statement(loops[i + 1])
1437 for i
in range(0, len(self.
_dataBlock._memory_range) - 2):
1440 for loop
in loops[::-1]:
1445 return f
"""log.open("{self._filename.print_cpp()}");
1446{self._loop.print_cpp()}
1463 def __init__(self, value: Expression, index: Expression):
1472 return isinstance(self.
_value, Subscript)
1478 return ' ' * indent_level * Node.spaces_per_tab + f
"{self._value.print_cpp()}[{self._index.print_cpp()}]"
1481 return ' ' * indent_level * Node.spaces_per_tab + f
"{self._value.print_omp()}[{self._index.print_omp()}]"
1484 return ' ' * indent_level * Node.spaces_per_tab + f
"{self._value.print_sycl()}[{self._index.print_sycl()}]"
1487 indent =
' ' * indent_level * Node.spaces_per_tab
1490 while isinstance(tmp, Subscript):
1496 type_str = value_type.print_cpp().strip()
1498 mlir_type = Node.type_map.get(type_str)
1499 if mlir_type
is None:
1501 mlir_type =
'' + value_type.print_mlir(0)
1503 mlir_str =
"".join(Node.context.get_block().pop_mlir())
1507 mlir_str +=
"".join(Node.context.get_block().pop_mlir())
1509 if not getattr(self.
_index,
'_index_type',
False):
1510 new_index = f
"%{Node.get_mlir_id()}"
1513 mlir_type_cast = index_expr_type.print_mlir(0).strip()
1514 mlir_str += indent + new_index + f
" = arith.index_cast {index.strip(' ')}: {mlir_type_cast} to index\n"
1520 if isinstance(self.
_value, String):
1526 if isinstance(base_type, TDataBlock):
1527 memref_type = base_type.print_mlir(0).strip()
1530 if "x?x" in memref_type:
1533 result_id = f
"%{Node.get_mlir_id()}"
1534 mlir_str += indent + f
"{result_id} = memref.load {base_mlir}[%0, {self._new_index}] {{name = \"{base_mlir.strip('%')}\"}} : {memref_type}\n"
1535 Node.context.push_block()
1536 Node.context.get_block().mlir_append(mlir_str)
1540 result_id = f
"%{Node.get_mlir_id()}"
1541 mlir_str += indent + f
"{result_id} = memref.load {base_mlir}[{self._new_index}] {{name = \"{base_mlir.strip('%')}\"}} : {memref_type}\n"
1542 Node.context.push_block()
1543 Node.context.get_block().mlir_append(mlir_str)
1549 Node.context.push_block()
1550 Node.context.get_block().mlir_append(mlir_str)
1557 result_id = f
"%{Node.get_mlir_id()}"
1560 outer_base = base_expr.print_mlir(indent_level)
1563 if outer_base
in Node.mlir_memref_types:
1564 actual_memref_type = Node.mlir_memref_types[outer_base]
1567 base_expr_type = base_expr.get_type()
1568 if isinstance(base_expr_type, TDataBlock):
1569 actual_memref_type = base_expr_type.print_mlir(0).strip()
1571 actual_memref_type =
"memref<?x?xf64>"
1575 if isinstance(base_expr, Name):
1576 base_name = base_expr.id
1577 elif hasattr(base_expr,
'id'):
1579 base_name = base_expr.id
1581 if base_name
and base_name
in Node.type_map
and _is_nested_memref(Node.type_map[base_name]):
1582 actual_memref_type = Node.type_map[base_name]
1587 while isinstance(current, Subscript):
1588 indices.insert(0, current._new_index)
1589 current = current._value
1592 indices_str =
", ".join(indices)
1593 mlir_str =
"".join(Node.context.get_block().pop_mlir())
1597 if isinstance(actual_memref_type, str):
1598 is_nested = actual_memref_type.count(
"memref<") > 1
1599 actual_memref_type_str = actual_memref_type
1602 is_nested = actual_memref_type.is_nested_memref()
1603 actual_memref_type_str = actual_memref_type.print_mlir(0).strip()
1605 if is_nested
and len(indices) >= 2:
1608 inner_memref_id = f
"%{Node.get_mlir_id()}"
1610 if actual_memref_type_str.startswith(
"memref<?x")
and actual_memref_type_str.endswith(
">>"):
1611 inner_type = actual_memref_type_str[9:-1]
1613 inner_type =
"memref<?xf64>"
1615 mlir_str += indent + f
"{inner_memref_id} = memref.load {outer_base}[{indices[0]}] {{name = \"{outer_base.strip('%')}\"}} : {actual_memref_type_str}\n"
1617 remaining_indices =
", ".join(indices[1:])
1618 mlir_str += indent + f
"{result_id} = memref.load {inner_memref_id}[{remaining_indices}] {{name = \"{outer_base.strip('%')}\"}} : {inner_type}\n"
1621 mlir_str += indent + f
"{result_id} = memref.load {outer_base}[{indices_str}] {{name = \"{outer_base.strip('%')}\"}} : {actual_memref_type_str}\n"
1623 Node.context.push_block()
1624 Node.context.get_block().mlir_append(mlir_str)
1632 return f
"""Subscript:
1633{self._value.print_tree(indent_level + 1)}
1634{self._index.print_tree(indent_level + 1)}"""
1655 indent =
' ' * indent_level * Node.spaces_per_tab
1656 mlir_str =
"".join(Node.context.get_block().pop_mlir())
1665 base_expr.hoist(
True)
1666 base_mlir = base_expr.print_mlir(indent_level)
1668 mlir_str +=
"".join(Node.context.get_block().pop_mlir())
1672 index_expr.hoist(
True)
1673 index_mlir = index_expr.print_mlir(indent_level)
1674 mlir_str +=
"".join(Node.context.get_block().pop_mlir())
1677 new_index = f
"%{Node.get_mlir_id()}"
1678 mlir_type = (
'index' if hasattr(index_expr,
'_index_type')
and index_expr._index_type
else 'i32')
1679 mlir_str += indent + new_index + f
" = arith.index_cast {index_mlir.strip(' ')}: {mlir_type} to index\n"
1685 base_type = base_expr.get_type()
1686 if isinstance(base_type, TDataBlock):
1687 result_id = f
"%{Node.get_mlir_id()}"
1690 if isinstance(base_expr, Subscript):
1693 if isinstance(base_expr._value, Subscript):
1694 result_id = base_mlir
1697 base_mlir_name = base_mlir.lstrip(
'%')
1698 is_nested_memref =
False
1699 if base_mlir_name
in Node.type_map
and _is_nested_memref(Node.type_map[base_mlir_name]):
1700 is_nested_memref =
True
1702 outer_index = base_expr._new_index
1705 ptr_code, result_id = Node.generate_pointer_to_2d_element(
1706 base_mlir, outer_index, new_index, is_nested_memref, indent_level
1709 mlir_str += ptr_code
1711 element_type =
"f64"
1712 mlir_str += indent + f
"{result_id} = memref.subview {base_mlir}[{new_index}][1][1] : memref<?x{element_type}> to memref<?x{element_type}>\n"
1715 Node.context.push_block()
1716 Node.context.get_block().mlir_append(mlir_str)
1723 return ' ' * indent_level * Node.spaces_per_tab + f
"""Reference:
1724{self._expression.print_tree(indent_level + 1)}"""
1728 def __init__(self, elements, element_type, string = None):
1735 element_prints = [element.print_cpp()
for element
in self.
_elements]
1736 return ' ' * indent_level * Node.spaces_per_tab + f
"""tarch::la::Vector<{len(self._elements)}, {self._type.print_cpp()}>{{{", ".join(element_prints)}}}"""
1740 element_prints = [element.print_cpp()
for element
in self.
_elements]
1741 return ' ' * indent_level * Node.spaces_per_tab + f
"""tarch::la::Vector<{len(self._elements)}, {self._type.print_cpp()}>{{{", ".join(element_prints)}}}"""
1744 element_prints = [element.print_cpp()
for element
in self.
_elements]
1745 return ' ' * indent_level * Node.spaces_per_tab + f
"""tarch::la::Vector<{len(self._elements)}, {self._type.print_cpp()}>{{{", ".join(element_prints)}}}"""
1756 return TCustom(f
"tarch::la::Vector<{len(self._elements)}, {self._type.print_cpp()}>")
1767 diagonal_index = index[1]
1769 for i
in range(2, len(index) - 1):
1770 factor = factor * (dimensions[i - 1][1] - dimensions[i - 1][0])
1771 diagonal_index = diagonal_index + factor * index[i]
1775 if self.
_id is not None:
1781 if self.
_id is not None:
1793 return ' ' * indent_level * Node.spaces_per_tab +
"DiagonalMatrix"
1800 def __init__(self, dimensions, internal, index_dimensions):
1806 def index(self, row_index, column_index):
1810 if self.
_id is not None:
1816 if self.
_id is not None:
1828 return ' ' * indent_level * Node.spaces_per_tab +
"Matrix"
1837 if type(matrix)
is Name:
1844 lhs_matrix = self.
_matrix._internal._arguments[0]
1845 if type(lhs_matrix)
is Name:
1846 lhs_matrix = Name.variables[lhs_matrix.id]
1848 rhs_matrix = self.
_matrix._internal._arguments[1]
1849 if type(rhs_matrix)
is Name:
1850 rhs_matrix = Name.variables[rhs_matrix.id]
1853 internal_loop =
For([
Integer(0), rhs_matrix._width])
1854 index = self.
_assignment.get_iteration_variable() * rhs_matrix._width + internal_loop.get_iteration_variable()
1856 if type(lhs_matrix._internal)
is Float
or type(lhs_matrix._internal)
is Integer:
1857 lhs_index = lhs_matrix._internal
1858 rhs_index =
Subscript(rhs_matrix, internal_loop.get_iteration_variable())
1859 if type(rhs_matrix._internal)
is Float
or type(rhs_matrix._internal)
is Integer:
1860 rhs_index = rhs_matrix._internal
1863 internal_loop.close_scope()
1867 return f
"""{self._memory_allocation.print_cpp(indent_level)}
1868{self._assignment.print_cpp(indent_level)}"""
1871 return f
"""{self._memory_allocation.print_omp(indent_level)}
1872{self._assignment.print_omp(indent_level)}"""
1881 return ' ' * indent_level * Node.spaces_per_tab +
"DiagonalKroneckerProduct"
1890 if type(matrix)
is Name:
1902 return f
"""{self._memory_allocation.print_cpp(indent_level)}
1903{self._assignment.print_cpp(indent_level)}"""
1906 return f
"""{self._memory_allocation.print_omp(indent_level)}
1907{self._assignment.print_omp(indent_level)}"""
1916 return ' ' * indent_level * Node.spaces_per_tab +
"DiagonalKroneckerProduct"
1925 if type(matrix)
is Name:
1936 lhs_matrix = self.
_matrix._internal._arguments[0]
1937 if type(lhs_matrix)
is Name:
1938 lhs_matrix = Name.variables[lhs_matrix.id]
1940 rhs_matrix = self.
_matrix._internal._arguments[1]
1941 if type(rhs_matrix)
is Name:
1942 rhs_matrix = Name.variables[rhs_matrix.id]
1944 if type(lhs_matrix.get_type())
is TMatrix:
1945 lhs_dimensions = lhs_matrix._dimensions
1947 lhs_dimensions = [lhs_matrix._width, lhs_matrix._width]
1949 if type(rhs_matrix.get_type())
is TMatrix:
1950 rhs_dimensions = rhs_matrix._dimensions
1952 rhs_dimensions = [rhs_matrix._width, rhs_matrix._width]
1955 if type(lhs_matrix.get_type())
is TMatrix:
1956 loops.append(
For([
Integer(0), lhs_matrix._dimensions[0]]))
1957 loops.append(
For([
Integer(0), lhs_matrix._dimensions[1]]))
1958 lhs_index = loops[0].get_iteration_variable() * lhs_dimensions[1] + loops[1].get_iteration_variable()
1959 startIndex = loops[0].get_iteration_variable() * lhs_dimensions[1] * rhs_dimensions[1] * rhs_dimensions[0] + loops[1].get_iteration_variable() * rhs_dimensions[1]
1961 loops.append(
For([
Integer(0), lhs_matrix._width]))
1962 lhs_index = loops[0].get_iteration_variable()
1963 startIndex = loops[0].get_iteration_variable() * lhs_dimensions[1] * rhs_dimensions[1] * rhs_dimensions[0] + loops[0].get_iteration_variable() * rhs_dimensions[1]
1965 if type(rhs_matrix.get_type())
is TMatrix:
1966 loops.append(
For([
Integer(0), rhs_matrix._dimensions[0]]))
1967 loops.append(
For([
Integer(0), rhs_matrix._dimensions[1]]))
1968 rhs_index = loops[-2].get_iteration_variable() * rhs_dimensions[1] + loops[-1].get_iteration_variable()
1969 index = startIndex + loops[-1].get_iteration_variable() + loops[-2].get_iteration_variable() * lhs_dimensions[1] * rhs_dimensions[1]
1971 loops.append(
For([
Integer(0), rhs_matrix._width]))
1972 rhs_index = loops[-1].get_iteration_variable()
1973 index = startIndex + loops[-1].get_iteration_variable() + loops[-1].get_iteration_variable() * lhs_dimensions[1] * rhs_dimensions[1]
1975 lhs_subscript =
Subscript(lhs_matrix, lhs_index)
1976 if type(lhs_matrix._internal)
is Float
or type(lhs_matrix._internal)
is Integer:
1977 lhs_subscript = lhs_matrix._internal
1978 rhs_subscript =
Subscript(rhs_matrix, rhs_index)
1979 if type(rhs_matrix._internal)
is Float
or type(rhs_matrix._internal)
is Integer:
1980 rhs_subscript = rhs_matrix._internal
1984 for i
in range(len(loops) - 1):
1985 loops[i].add_statement(loops[i + 1])
1986 loops[i].close_scope()
1987 loops[-1].close_scope()
1991 return f
"""{self._memory_allocation.print_cpp(indent_level)}
1992{self._initialisation.print_cpp(indent_level)}
1993{self._assignment.print_cpp(indent_level)}"""
1996 return f
"""{self._memory_allocation.print_omp(indent_level)}
1997{self._initialisation.print_omp(indent_level)}
1998{self._assignment.print_omp(indent_level)}"""
2007 return ' ' * indent_level * Node.spaces_per_tab +
"KroneckerProduct"
2014 def __init__(self, value: Expression, index: Expression):
2023 return ' ' * indent_level * Node.spaces_per_tab + f
"{self._value.print_cpp()}({self._index.print_cpp()})"
2026 return ' ' * indent_level * Node.spaces_per_tab + f
"{self._value.print_omp()}({self._index.print_omp()})"
2029 return ' ' * indent_level * Node.spaces_per_tab + f
"{self._value.print_sycl()}({self._index.print_sycl()})"
2032 indent =
' ' * indent_level * Node.spaces_per_tab
2035 if isinstance(self.
_value, Subscript):
2036 array_base = self.
_value._value
2037 array_index = self.
_value._index
2038 array_base_mlir = array_base.print_mlir(indent_level)
2039 array_index_mlir = array_index.print_mlir(indent_level)
2041 if not getattr(array_index,
'_index_type',
False):
2042 array_index_cast = f
"%{Node.get_mlir_id()}"
2043 array_index_type = array_index.get_type()
2044 array_index_mlir_type = array_index_type.print_mlir(0).strip()
2045 mlir_str += indent + f
"{array_index_cast} = arith.index_cast {array_index_mlir} : {array_index_mlir_type} to index\n"
2047 array_index_cast = array_index_mlir
2049 raw_ptr = f
"%{Node.get_mlir_id()}"
2050 mlir_str += indent + f
"{raw_ptr} = memref.load {array_base_mlir}[{array_index_cast}] {{name = \"{array_base_mlir.strip('%')}\"}} : memref<?xi64>\n"
2052 vec_ptr = f
"%{Node.get_mlir_id()}"
2053 mlir_str += indent + f
"{vec_ptr} = llvm.inttoptr {raw_ptr} {{name = \"{array_base_mlir.strip('%')}\"}} : i64 to !llvm.ptr\n"
2057 if isinstance(self.
_index, Integer):
2058 func_param_i32 = f
"%{Node.get_mlir_id()}"
2059 mlir_str += indent + f
"{func_param_i32} = arith.constant {int(self._index._value)} : i32\n"
2060 elif not getattr(self.
_index,
'_index_type',
False):
2061 func_param_i32 = f
"%{Node.get_mlir_id()}"
2062 mlir_str += indent + f
"{func_param_i32} = arith.index_cast {func_param_mlir} : index to i32\n"
2064 func_param_i32 = func_param_mlir
2066 result = f
"%{Node.get_mlir_id()}"
2068 func_param_i64 = f
"%{Node.get_mlir_id()}"
2069 mlir_str += indent + f
"{func_param_i64} = arith.extsi {func_param_i32} : i32 to i64\n"
2071 velem_ptr = f
"%{Node.get_mlir_id()}"
2072 mlir_str += indent + f
"{velem_ptr} = llvm.getelementptr {vec_ptr}[{func_param_i64}] {{name = \"{array_base_mlir.strip('%')}\"}} : (!llvm.ptr, i64) -> !llvm.ptr, f64\n"
2074 mlir_str += indent + f
"{result} = llvm.load {velem_ptr} {{name = \"{array_base_mlir.strip('%')}\"}} : !llvm.ptr -> f64\n"
2075 Node.context.get_block().mlir_append(mlir_str)
2083{self._value.print_tree(indent_level + 1)}
2084{self._index.print_tree(indent_level + 1)}"""
2097 return ' ' * indent_level * Node.spaces_per_tab + f
"({self._lhs.print_cpp()} {self._operation} {self._rhs.print_cpp()})"
2100 return ' ' * indent_level * Node.spaces_per_tab + f
"({self._lhs.print_omp()} {self._operation} {self._rhs.print_omp()})"
2103 return ' ' * indent_level * Node.spaces_per_tab + f
"({self._lhs.print_sycl()} {self._operation} {self._rhs.print_sycl()})"
2107 if op_type_class
is TFloat:
2109 "<":
"arith.cmpf olt",
2110 ">":
"arith.cmpf ogt",
2111 "<=":
"arith.cmpf ole",
2112 ">=":
"arith.cmpf oge",
2113 "==":
"arith.cmpf oeq",
2114 "!=":
"arith.cmpf one"
2118 "<":
"arith.cmpi slt",
2119 ">":
"arith.cmpi sgt",
2120 "<=":
"arith.cmpi sle",
2121 ">=":
"arith.cmpi sge",
2122 "==":
"arith.cmpi eq",
2123 "!=":
"arith.cmpi ne"
2125 return op_map.get(operation,
None)
2128 op_type_class = TDataBlock.get_mlir_type_for_operation(self.
_lhs, self.
_rhs)
2130 mlir_operation = Comparison.get_mlir_comparison_op(self.
_operation, op_type_class)
2133 if mlir_operation
is None:
2134 raise ValueError(f
"Unsupported comparison operation: {self._operation}")
2136 const_zero_id =
None
2139 if TDataBlock.needs_memref_load(self.
_lhs):
2140 const_zero_id = TDataBlock.ensure_const_zero(const_zero_id, indent_level)
2141 lhs_mlir = TDataBlock.generate_memref_load(self.
_lhs, lhs_mlir, const_zero_id, indent_level)
2144 if TDataBlock.needs_memref_load(self.
_rhs):
2145 const_zero_id = TDataBlock.ensure_const_zero(const_zero_id, indent_level)
2146 rhs_mlir = TDataBlock.generate_memref_load(self.
_rhs, rhs_mlir, const_zero_id, indent_level)
2148 return ' ' * indent_level * Node.spaces_per_tab + f
"""{mlir_operation} {lhs_mlir}, {rhs_mlir} : {result_type}"""
2152Comparison {self._operation}:
2153{self._lhs.print_tree(indent_level + 1)}
2154{self._rhs.print_tree(indent_level + 1)}"""
2163 if type(self.
_lhs)
is BinaryOperation:
2164 if self.
_lhs._operation ==
"+":
2169 elif self.
_lhs._operation ==
"-":
2172 elif self.
_lhs._operation ==
"*":
2178 if type(self.
_rhs)
is BinaryOperation:
2179 if self.
_rhs._operation ==
"+":
2184 elif self.
_rhs._operation ==
"-":
2187 elif self.
_rhs._operation ==
"*":
2193 if self.
_operation ==
"-" and type(self.
_rhs)
is UnaryOperation
and self.
_rhs._operation ==
"-":
2196 if self.
_operation ==
"+" and type(self.
_rhs)
is UnaryOperation
and self.
_rhs._operation ==
"-":
2221 op_type_class = TDataBlock.get_mlir_type_for_operation(self.
_lhs, self.
_rhs)
2222 return op_type_class()
2225 return ' ' * indent_level * Node.spaces_per_tab + f
"({self._lhs.print_cpp()} {self._operation} {self._rhs.print_cpp()})"
2228 return ' ' * indent_level * Node.spaces_per_tab + f
"({self._lhs.print_omp()} {self._operation} {self._rhs.print_omp()})"
2231 return ' ' * indent_level * Node.spaces_per_tab + f
"({self._lhs.print_sycl()} {self._operation} {self._rhs.print_sycl()})"
2235 if op_type_class
is TFloat:
2249 return op_map.get(operation,
None)
2253 indent =
' ' * indent_level * Node.spaces_per_tab
2254 operand_type = operand.get_type()
2256 if type(operand_type)
is TDataBlock:
2257 operand_type = operand_type.get_element_type()
2259 if isinstance(operand_type, TInteger)
and result_type == TFloat:
2260 new_op = f
"%{Node.get_mlir_id()}"
2261 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.sitofp {operand_mlir.strip(' ')} : i32 to f64\n")
2263 elif isinstance(operand_type, TLong)
and result_type == TFloat:
2264 new_op = f
"%{Node.get_mlir_id()}"
2265 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.sitofp {operand_mlir.strip(' ')} : i64 to f64\n")
2267 elif isinstance(operand_type, TFloat)
and result_type == TInteger:
2268 new_op = f
"%{Node.get_mlir_id()}"
2269 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.fptosi {operand_mlir.strip(' ')} : f64 to i32\n")
2271 elif isinstance(operand_type, TFloat)
and result_type == TLong:
2272 new_op = f
"%{Node.get_mlir_id()}"
2273 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.fptosi {operand_mlir.strip(' ')} : f64 to i64\n")
2275 elif isinstance(operand_type, TInteger)
and result_type == TLong:
2276 new_op = f
"%{Node.get_mlir_id()}"
2277 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.extsi {operand_mlir.strip(' ')} : i32 to i64\n")
2279 elif isinstance(operand_type, TLong)
and result_type == TInteger:
2280 new_op = f
"%{Node.get_mlir_id()}"
2281 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.trunci {operand_mlir.strip(' ')} : i64 to i32\n")
2283 elif operand._index_type
and result_type == TFloat:
2284 new_op = f
"%{Node.get_mlir_id()}"
2285 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.index_cast {operand_mlir.strip(' ')} : index to f64\n")
2287 elif operand._index_type
and result_type == TInteger:
2288 new_op = f
"%{Node.get_mlir_id()}"
2289 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.index_cast {operand_mlir.strip(' ')} : index to i32\n")
2291 elif operand._index_type
and result_type == TLong:
2292 new_op = f
"%{Node.get_mlir_id()}"
2293 Node.context.get_block().mlir_append(indent + f
"{new_op} = arith.index_cast {operand_mlir.strip(' ')} : index to i64\n")
2299 op_type_class = TDataBlock.get_mlir_type_for_operation(self.
_lhs, self.
_rhs)
2300 return BinaryOperation.get_mlir_arithmetic_op(self.
_operation, op_type_class)
2303 indent =
' ' * indent_level * Node.spaces_per_tab
2307 op_type_class = TDataBlock.get_mlir_type_for_operation(self.
_lhs, self.
_rhs)
2308 result_type = op_type_class.print_mlir(0)
2310 op_type_class = TDataBlock.get_mlir_type_for_operation(self.
_lhs, self.
_rhs)
2313 const_zero_id =
None
2318 if TDataBlock.needs_memref_load(self.
_lhs):
2319 const_zero_id = TDataBlock.ensure_const_zero(const_zero_id, indent_level)
2320 lhs = TDataBlock.generate_memref_load(self.
_lhs, lhs, const_zero_id, indent_level)
2322 lhs = BinaryOperation.cast_operand(lhs, self.
_lhs, op_type_class, indent_level)
2327 if TDataBlock.needs_memref_load(self.
_rhs):
2328 const_zero_id = TDataBlock.ensure_const_zero(const_zero_id, indent_level)
2329 rhs = TDataBlock.generate_memref_load(self.
_rhs, rhs, const_zero_id, indent_level)
2331 rhs = BinaryOperation.cast_operand(rhs, self.
_rhs, op_type_class, indent_level)
2334 for mlir
in Node.context.pop_block().get_mlir():
2335 mlir_str += indent + mlir.strip(
' ')
2337 self.
mlir_id(f
"%{Node.get_mlir_id()}")
2339 mlir_str += indent + f
"""{self.mlir_id()} = {self.get_mlir_op()} {lhs}, {rhs} : {result_type}\n"""
2340 Node.context.push_block()
2341 Node.context.get_block().mlir_append(mlir_str)
2347BinaryOperation {self._operation}:
2348{self._lhs.print_tree(indent_level + 1)}
2349{self._rhs.print_tree(indent_level + 1)}"""
2377 return f
"({self._operation} {self._operand.print_cpp()})"
2380 return f
"({self._operation} {self._operand.print_omp()})"
2383 return f
"({self._operation} {self._operand.print_sycl()})"
2386 indent =
' ' * indent_level * Node.spaces_per_tab
2390 if isinstance(operand_type, TDataBlock):
2391 element_type_class = operand_type.get_element_type()
2392 operand_type = element_type_class()
if element_type_class
else operand_type
2394 if isinstance(operand_type, TFloat):
2400 mlir_str =
"".join(Node.context.get_block().pop_mlir())
2401 neg_one_id = f
"%{Node.get_mlir_id()}"
2402 mlir_str += indent + f
"{neg_one_id} = arith.constant -1.0 : f64\n"
2404 self.
mlir_id(f
"%{Node.get_mlir_id()}")
2405 mlir_str += indent + f
"{self.mlir_id()} = arith.mulf {op_mlir}, {neg_one_id} : f64\n"
2406 Node.context.push_block()
2407 Node.context.get_block().mlir_append(mlir_str)
2415 mlir_str =
"".join(Node.context.get_block().pop_mlir())
2416 neg_one_id = f
"%{Node.get_mlir_id()}"
2417 mlir_str += indent + f
"{neg_one_id} = arith.constant -1 : i32\n"
2419 self.
mlir_id(f
"%{Node.get_mlir_id()}")
2420 mlir_str += indent + f
"{self.mlir_id()} = arith.muli {op_mlir}, {neg_one_id} : i32\n"
2421 Node.context.push_block()
2422 Node.context.get_block().mlir_append(mlir_str)
2427UnaryOperation {self._operation}:
2428{self._operand.print_tree(indent_level + 1)}"""
2433 if type(dataBlock)
is Name:
2467class DataBlockComparison(Expression):
2469 if type(lhs)
is Name
and type(lhs.get_type())
is TDataBlock:
2474 if type(rhs)
is Name
and type(rhs.get_type())
is TDataBlock:
2490 if type(self.
_rhs._memory_range[0])
is not BinaryOperation
and type(self.
_memory_range[0])
is not BinaryOperation
and self.
_rhs._memory_range[0][1] > self.
_memory_range[0][1]:
2527 def __init__(self, operation, lhs, rhs, useFunctionSyntax=False):
2529 if type(lhs)
is Name
and type(lhs.get_type())
is TDataBlock:
2534 if type(rhs)
is Name
and type(rhs.get_type())
is TDataBlock:
2548 elif type(self.
_rhs._iteration_range[0][1])
is not BinaryOperation
and type(self.
_iteration_range[0][1])
is not BinaryOperation
and self.
_rhs._iteration_range[0][1] > self.
_iteration_range[0][1]:
2584 lhs_is_double =
False
2585 rhs_is_double =
False
2587 lhs_is_double = (str(self.
_lhs.
get_type().get_single()) ==
"double")
2589 lhs_is_double = (str(self.
_lhs.
get_type()) ==
"double")
2592 rhs_is_double = (str(self.
_rhs.
get_type().get_single()) ==
"double")
2594 rhs_is_double = (str(self.
_rhs.
get_type()) ==
"double")
2596 if (lhs_is_double
or rhs_is_double):
2626 if type(dataBlock)
is Name
and type(dataBlock.get_type())
is TDataBlock:
2665 if type(dataBlock)
is Name:
2675 for i
in range(len(self.
_dataBlock._iteration_range) - 2, -1, -1):
2679 for loop
in self.
_loops[::-1]:
2680 index.append(loop.get_iteration_variable())
2692 if Node.use_accelerator:
2693 return f
"""{' ' * indent_level * Node.spaces_per_tab}omp_target_memset(maxEigenvalues, 0, N * sizeof(double), targetDevice);
2694{' ' * indent_level * Node.spaces_per_tab}for (int {self._loop._iteration_variable.print_cpp()} = {self._loop._iteration_range[0].print_cpp()}; {self._loop._iteration_variable.print_cpp()} < {self._loop._iteration_range[1].print_cpp()}; {self._loop._iteration_variable.print_cpp()}++) {{
2695{' ' * (indent_level + 1) * Node.spaces_per_tab}#pragma omp target teams loop collapse(Dimensions) reduction(max:{self._outputVariable.multidimensional_index([self._loop.get_iteration_variable()]).print_omp()})
2696{self._loop._statements[1].print_omp(indent_level + 1)}
2697{' ' * indent_level * Node.spaces_per_tab}}}
2703 ranges = [f
"range{i} = {loop.get_interval_size().print_sycl()};" for i, loop
in enumerate(self.
_loops[0:3])]
2704 indexing = [f
"int {loop.get_iteration_variable().print_sycl()} = index[{i}];" for i, loop
in enumerate(self.
_loops[0:3])]
2705 statement_prints = [statement.print_sycl(indent_level + 1)
for statement
in self.
_loops[2]._statements]
2706 return os.linesep.join(ranges) +
"\n" +
' ' * indent_level * Node.spaces_per_tab + f
"""queue.submit([&](::sycl::handler& handler) {{handler.memset({self._outputVariable.print_sycl()}, 0, sizeof(double) * {self._loop.get_interval_size().print_sycl()}); }}).wait();
2707{' ' * indent_level * Node.spaces_per_tab}queue.submit([&](::sycl::handler& handler) {{
2708{' ' * indent_level * Node.spaces_per_tab}handler.parallel_for(::sycl::range<3>{{range0, range1, range2}}, [=](::sycl::item<3> index) {{
2709{os.linesep.join(indexing)}
2710{self._loops[3].print_sycl(indent_level + 1)}
2711{' ' * (indent_level + 1) * Node.spaces_per_tab}}});
2712{' ' * indent_level * Node.spaces_per_tab}}}).wait();"""
2718 return f
"""DataBlockUnaryMax:
2719{self._dataBlock.print_tree(indent_level + 1)}"""
2753 return ' ' * indent_level * Node.spaces_per_tab + self.
_type
2756 return ' ' * indent_level * Node.spaces_per_tab + self.
_type
2759 return ' ' * indent_level * Node.spaces_per_tab + self.
_type
2762 mlir_type = Node.get_mlir_type(self.
_type)
2763 if mlir_type
is not None:
2764 return ' ' * indent_level * Node.spaces_per_tab + mlir_type
2767 type_entry = Node.type_map[f
"{self._type}"]
2768 if isinstance(type_entry, str):
2769 return ' ' * indent_level * Node.spaces_per_tab + type_entry
2772 return ' ' * indent_level * Node.spaces_per_tab + type_entry.print_mlir(0)
2775 return ' ' * indent_level * Node.spaces_per_tab +
"TCustom: " + self.
_type
2779 return isinstance(self.
_type, str)
and (
'xmemref<' in self.
_type or self.
_type.count(
'memref<') > 1)
2786 return ' ' * indent_level * Node.spaces_per_tab +
"int"
2789 return ' ' * indent_level * Node.spaces_per_tab +
"int"
2792 return ' ' * indent_level * Node.spaces_per_tab +
"int"
2795 return ' ' * indent_level * Node.spaces_per_tab +
"i32"
2798 return ' ' * indent_level * Node.spaces_per_tab +
"TInteger"
2802 """Type for 64-bit integers (long) used in MLIRCellData struct fields"""
2804 return ' ' * indent_level * Node.spaces_per_tab +
"long"
2807 return ' ' * indent_level * Node.spaces_per_tab +
"long"
2810 return ' ' * indent_level * Node.spaces_per_tab +
"long"
2813 return ' ' * indent_level * Node.spaces_per_tab +
"i64"
2816 return ' ' * indent_level * Node.spaces_per_tab +
"TLong"
2821 return ' ' * indent_level * Node.spaces_per_tab +
"bool"
2824 return ' ' * indent_level * Node.spaces_per_tab +
"bool"
2827 return ' ' * indent_level * Node.spaces_per_tab +
"bool"
2830 return ' ' * indent_level * Node.spaces_per_tab +
"i1"
2833 return ' ' * indent_level * Node.spaces_per_tab +
"TBoolean"
2840 return ' ' * indent_level * Node.spaces_per_tab +
"double" + (
"&" if self.
_reference else "")
2843 return ' ' * indent_level * Node.spaces_per_tab +
"double" + (
"&" if self.
_reference else "")
2846 return ' ' * indent_level * Node.spaces_per_tab +
"double" + (
"&" if self.
_reference else "")
2849 return ' ' * indent_level * Node.spaces_per_tab +
"f64"
2852 return ' ' * indent_level * Node.spaces_per_tab +
"TFloat"
2857 return ' ' * indent_level * Node.spaces_per_tab +
"const char*"
2860 return ' ' * indent_level * Node.spaces_per_tab +
"const char*"
2863 return ' ' * indent_level * Node.spaces_per_tab +
"const char*"
2869 return ' ' * indent_level * Node.spaces_per_tab +
"TString"
2878 return ' ' * indent_level * Node.spaces_per_tab + f
'double**'
2881 return ' ' * indent_level * Node.spaces_per_tab + f
'memref<?xmemref<?x{self._element_type.print_mlir(0).strip()}>>'
2884 return ' ' * indent_level * Node.spaces_per_tab + f
'double**'
2887 return ' ' * indent_level * Node.spaces_per_tab + f
'double**'
2903 return ' ' * indent_level * Node.spaces_per_tab +
'void*'
2906 return ' ' * indent_level * Node.spaces_per_tab + self.
_signature
2909 return ' ' * indent_level * Node.spaces_per_tab +
'void*'
2912 return ' ' * indent_level * Node.spaces_per_tab +
'void*'
2916 def __init__(self, element_type=TFloat(), dimensions=1):
2922 return ' ' * indent_level * Node.spaces_per_tab +
'void*'
2927 return ' ' * indent_level * Node.spaces_per_tab + f
'memref<{dims}x{self._element_type.print_mlir(0).strip()}>'
2930 return ' ' * indent_level * Node.spaces_per_tab +
'void*'
2933 return ' ' * indent_level * Node.spaces_per_tab +
'void*'
2946 if isinstance(operand, VectorIndex):
2949 operand_type = operand.get_type()
2950 if isinstance(operand_type, TDataBlock):
2951 if (isinstance(operand_type._dimensions, int)
and operand_type._dimensions == 1)
or \
2952 (isinstance(operand_type._dimensions, list)
and len(operand_type._dimensions) == 1):
2955 if isinstance(operand, Subscript)
and operand.is_nested_subscript():
2962 indent =
' ' * indent_level * Node.spaces_per_tab
2963 load_id = f
"%{Node.get_mlir_id()}"
2964 operand_type = operand.get_type()
2966 if isinstance(operand_type, TDataBlock):
2968 if isinstance(operand, Subscript)
and operand.is_nested_subscript():
2971 element_type_class = operand_type.get_element_type()
2972 if element_type_class
is not None:
2973 element_type = element_type_class().
print_mlir(0)
2975 element_type =
"f64"
2977 load_str = indent + f
"{load_id} = memref.load {operand_mlir}[{const_zero_id}] {{name = \"{operand_mlir.strip('%')}\"}} : memref<?x{element_type}>\n"
2978 Node.context.get_block().mlir_append(load_str)
2985 if const_zero_id
is None:
2986 const_zero_id = f
"%{Node.get_mlir_id()}"
2987 indent =
' ' * indent_level * Node.spaces_per_tab
2988 Node.context.get_block().mlir_append(indent + f
"{const_zero_id} = arith.constant 0 : index\n")
2989 return const_zero_id
3007 lhs_operand_type = lhs.get_type()
3008 if type(lhs_operand_type)
is TDataBlock:
3009 lhs_type = lhs_operand_type.get_element_type()
3011 lhs_type = type(lhs_operand_type)
3013 rhs_operand_type = rhs.get_type()
3014 if type(rhs_operand_type)
is TDataBlock:
3015 rhs_type = rhs_operand_type.get_element_type()
3017 rhs_type = type(rhs_operand_type)
3020 if lhs_type
is TFloat
or rhs_type
is TFloat:
3022 elif lhs_type
is TLong
or rhs_type
is TLong:
3024 elif lhs_type
is TInteger
and rhs_type
is TInteger:
3026 elif lhs_type
is TBoolean
and rhs_type
is TBoolean:
3044 mlir_element_type =
"i64"
3046 mlir_element_type = element_type_class().
print_mlir(0)
3048 return element_type_class
or TFloat, is_vector, mlir_element_type
3069 dims.append(str(dim))
3071 dims.append(dim.print_mlir(indent_level))
3073 Node.context.push_block()
3075 op.print_mlir(indent_level)
3076 dims.append(
''.join(Node.context.pop_block().get_mlir()))
3085 if type_name
is None:
3087 type_name = Node.type_map[f
"{self._underlying_type}"]
3091 if isinstance(type_name, str)
and type_name.startswith(
"memref<"):
3092 return ' ' * indent_level * Node.spaces_per_tab + type_name
3115 dimension_list = [
"?"] * actual_dims
3116 memref_dims =
"x".join(dimension_list)
3118 return ' ' * indent_level * Node.spaces_per_tab + f
"""memref<{memref_dims}x{type_name}>"""
3121 return ' ' * indent_level * Node.spaces_per_tab +
"TDataBlock"
3125 if isinstance(type_map_entry, str):
3127 return 'xmemref<' in type_map_entry
3128 elif hasattr(type_map_entry,
'is_nested_memref'):
3130 return type_map_entry.is_nested_memref()
3149 return ' ' * indent_level * Node.spaces_per_tab +
"TMatrix"
3166 return ' ' * indent_level * Node.spaces_per_tab +
"TDiagonalMatrix"
3183 return ' ' * indent_level * Node.spaces_per_tab +
"TVector"
3194 if statement
is not None:
3198 statement_prints = [statement.print_cpp(indent_level + 1)
for statement
in self.
_statements]
3199 return ' ' * indent_level * Node.spaces_per_tab + f
"""if constexpr ({self._boolean.print_cpp()}) {{
3200{os.linesep.join(statement_prints)}
3201""" +
' ' * indent_level * Node.spaces_per_tab +
"}"
3204 statement_prints = [statement.print_omp(indent_level + 1)
for statement
in self.
_statements]
3205 return ' ' * indent_level * Node.spaces_per_tab + f
"""if constexpr ({self._boolean.print_omp()}) {{
3206{os.linesep.join(statement_prints)}
3207""" +
' ' * indent_level * Node.spaces_per_tab +
"}"
3210 statement_prints = [statement.print_sycl(indent_level + 1)
for statement
in self.
_statements]
3211 return ' ' * indent_level * Node.spaces_per_tab + f
"""if constexpr ({self._boolean.print_sycl()}) {{
3212{os.linesep.join(statement_prints)}
3213""" +
' ' * indent_level * Node.spaces_per_tab +
"}"
3216 indent =
' ' * indent_level * Node.spaces_per_tab
3217 Node.context.push_block()
3218 statement_prints = [statement.print_mlir(indent_level + 1)
for statement
in self.
_statements]
3219 body_statements =
''.join(Node.context.pop_block().get_mlir())
3220 body_statements +=
''.join(statement_prints)
3221 return indent + f
"""scf.if {self._boolean.print_mlir(indent_level)} {{
3222{body_statements}""" + indent +
"}"
3226 statement_prints = [statement.print_tree(indent_level + 1)
for statement
in self.
_statements]
3227 return ' ' * indent_level * Node.spaces_per_tab + f
"""If:
3228{os.linesep.join(statement_prints)}"""
3231 _inuse_iteration_variables = set()
3232 _iteration_variable_names = [
'i',
'j',
'k',
'l',
'n',
'm',
'a',
'b',
'c',
'd']
3234 def __init__(self, iteration_range, iteration_variable_name = None, use_scheduler = False):
3240 if iteration_variable_name ==
None:
3241 for variable_name
in For._iteration_variable_names:
3242 if variable_name
not in For._inuse_iteration_variables:
3245 For._inuse_iteration_variables.add(variable_name)
3249 For._inuse_iteration_variables.update({iteration_variable_name : self.
_iteration_variable})
3264 statement_prints = [statement.print_cpp(indent_level + 1)
for statement
in self.
_statements]
3266 return ' ' * indent_level * Node.spaces_per_tab + f
"""parallelForWithSchedulerInstructions({self._iteration_variable.print_cpp()}, {self._iteration_range[1].print_cpp()}, loopParallelism) {{
3267{os.linesep.join(statement_prints)}
3268{' ' * indent_level * Node.spaces_per_tab}}}
3271 return ' ' * indent_level * Node.spaces_per_tab + f"""for (int {self._iteration_variable.print_cpp()} = {self._iteration_range[0].print_cpp()}; {self._iteration_variable.print_cpp()} < {self._iteration_range[1].print_cpp()}; {self._iteration_variable.print_cpp()}++) {{
3272{os.linesep.join(statement_prints)}
3273""" + ' ' * indent_level * Node.spaces_per_tab + "}"
3276 def print_omp(self, indent_level = 0):
3277 statement_prints = [statement.print_omp(indent_level + 1) for statement in self._statements]
3278 return ' ' * indent_level * Node.spaces_per_tab + f"""for (int {self._iteration_variable.print_omp()} = {self._iteration_range[0].print_omp()}; {self._iteration_variable.print_omp()} < {self._iteration_range[1].print_omp()}; {self._iteration_variable.print_omp()}++) {{
3279{os.linesep.join(statement_prints)}
3280""" + ' ' * indent_level * Node.spaces_per_tab + "}"
3282 def print_sycl(self, indent_level = 0):
3283 statement_prints = [statement.print_sycl(indent_level + 1) for statement in self._statements]
3284 return ' ' * indent_level * Node.spaces_per_tab + f"""for (int {self._iteration_variable.print_sycl()} = {self._iteration_range[0].print_sycl()}; {self._iteration_variable.print_sycl()} < {self._iteration_range[1].print_sycl()}; {self._iteration_variable.print_sycl()}++) {{
3285{os.linesep.join(statement_prints)}
3286""" + ' ' * indent_level * Node.spaces_per_tab + "}"
3288 def print_mlir(self, indent_level=0):
3289 indent = ' ' * indent_level * Node.spaces_per_tab
3292 if isinstance(self._iteration_range[0], list) or isinstance(self._iteration_range[0], tuple):
3293 dims = len(self._iteration_range)
3298 for d in range(dims):
3299 var = For._iteration_variable_names[d]
3300 iter_vars.append(f"%{var}")
3301 self._iteration_range[d][0].hoist(True)
3302 self._iteration_range[d][1].hoist(True)
3303 if isinstance(self._iteration_range[d][0], Integer):
3304 mlir_id = f"%{Node.get_mlir_id()}"
3305 bounds_casting += indent + f"{mlir_id} = arith.constant {self._iteration_range[d][0].print_mlir(indent_level)} : index\n"
3308 lwb = self._iteration_range[d][0].print_mlir(indent_level).strip()
3309 if isinstance(self._iteration_range[d][1], Integer):
3310 mlir_id = f"%{Node.get_mlir_id()}"
3311 bounds_casting += indent + f"{mlir_id} = arith.constant {self._iteration_range[d][1].print_mlir(indent_level)} : index\n"
3314 upb = self._iteration_range[d][1].print_mlir(indent_level).strip()
3317 mlir_id = f"%{Node.get_mlir_id()}"
3318 bounds_casting += indent + f"{mlir_id} = arith.constant 1 : index\n"
3319 steps.append(mlir_id)
3321 self._iteration_range[0].hoist(True)
3322 self._iteration_range[1].hoist(True)
3323 if not self._iteration_variable._index_type:
3324 self._iteration_variable.hoist(True)
3325 mlir_str = self._iteration_variable.print_mlir(indent_level).strip()
3326 mlir_id = f"%{Node.get_mlir_id()}"
3327 bounds_casting += ''.join(Node.context.pop_block().get_mlir())
3328 Node.context.push_block()
3329 bounds_casting += indent + f"{mlir_id} = arith.index_cast {mlir_str} : {self._iteration_variable.get_type().print_mlir(0)} to index\n"
3330 iter_vars = [mlir_id]
3332 iter_vars = [self._iteration_variable.print_mlir(indent_level).strip()]
3334 if not self._iteration_range[0]._index_type:
3335 self._iteration_range[0].hoist(True)
3336 mlir_str = self._iteration_range[0].print_mlir(indent_level).strip()
3337 mlir_id = f"%{Node.get_mlir_id()}"
3338 bounds_casting += ''.join(Node.context.pop_block().get_mlir())
3339 Node.context.push_block()
3340 bounds_casting += indent + f"{mlir_id} = arith.index_cast {mlir_str} : {self._iteration_range[0].get_type().print_mlir(indent_level).strip()} to index\n"
3343 lwbs += [self._iteration_range[0].print_mlir(indent_level).strip()]
3345 if not self._iteration_range[1]._index_type:
3346 self._iteration_range[1].hoist(True)
3347 mlir_str = self._iteration_range[1].print_mlir(indent_level).strip()
3348 mlir_id = f"%{Node.get_mlir_id()}"
3349 bounds_casting += ''.join(Node.context.pop_block().get_mlir())
3350 Node.context.push_block()
3351 bounds_casting += indent + f"{mlir_id} = arith.index_cast {mlir_str} : {self._iteration_range[1].get_type().print_mlir(indent_level).strip()} to index\n"
3354 upbs += [self._iteration_range[1].print_mlir(indent_level).strip()]
3356 bounds_casting += ''.join(Node.context.pop_block().get_mlir())
3357 mlir_id = f"%{Node.get_mlir_id()}"
3358 bounds_casting += indent + f"{mlir_id} = arith.constant 1 : index\n"
3362 Node.context.push_block()
3363 statement_prints = [statement.print_mlir(indent_level + 1) for statement in self._statements]
3364 statements = ''.join(Node.context.pop_block().get_mlir())
3365 statements += ''.join(statement_prints)
3367 # Check if loop contains memory allocation (nested memref allocation must be sequential)
3368 # Use scf.for for allocation loops, scf.parallel for computation loops
3369 has_allocation = any(isinstance(stmt, MemoryAllocation) for stmt in self._statements)
3372 # Use sequential scf.for for memory allocation (cannot parallelize)
3374 f"{indent}scf.for {', '.join(iter_vars)} = "
3375 f"{', '.join(lwbs)} to {', '.join(upbs)} step {', '.join(steps)} {{\n"
3378 # Use scf.parallel for computation loops (safe to parallelize)
3380 f"{indent}scf.parallel ({', '.join(iter_vars)}) = "
3381 f"({', '.join(lwbs)}) to ({', '.join(upbs)}) step ({', '.join(steps)}) {{\n"
3383 loop_footer = "\n" + indent + "}\n"
3385 return bounds_casting + loop_header + statements + loop_footer
3387 def print_tree(self, indent_level = 0):
3388 statement_prints = [statement.print_tree(indent_level + 1) for statement in self._statements]
3389 return ' ' * indent_level * Node.spaces_per_tab + f"""For:
3390{os.linesep.join(statement_prints)}"""
3393class Comment(Statement):
3394 def __init__(self, comment):
3396 self._comment = comment
3401 def print_cpp(self, indent_level = 0):
3402 return ' ' * indent_level * Node.spaces_per_tab + "//" + self._comment[1:]
3404 def print_omp(self, indent_level = 0):
3405 return ' ' * indent_level * Node.spaces_per_tab + "//" + self._comment[1:]
3407 def print_sycl(self, indent_level = 0):
3408 return ' ' * indent_level * Node.spaces_per_tab + "//" + self._comment[1:]
3410 def print_mlir(self, indent_level = 0):
3411 return ' ' * indent_level * Node.spaces_per_tab + "//" + self._comment[1:]
3413 def print_tree(self, indent_level=0):
3414 return ' ' * indent_level * Node.spaces_per_tab + "Comment"
3417class FunctionCall(Statement):
3418 def __init__(self, id, arguments, is_offloadable = False):
3420 self._arguments = arguments
3421 self._is_offloadable = is_offloadable
3423 def add_argument(self, argument: Expression):
3424 self._arguments.append(argument)
3426 def print_cpp(self, indent_level=0):
3427 argument_prints = [argument.print_cpp() for argument in self._arguments]
3428 return ' ' * indent_level * Node.spaces_per_tab + f"""{self.id}({", ".join(argument_prints)});"""
3430 def print_omp(self, indent_level=0):
3431 argument_prints = [argument.print_omp() for argument in self._arguments]
3432 return ' ' * indent_level * Node.spaces_per_tab + f"""{self.id}({", ".join(argument_prints)});"""
3434 def print_sycl(self, indent_level=0):
3435 argument_prints = [argument.print_sycl() for argument in self._arguments]
3436 return ' ' * indent_level * Node.spaces_per_tab + f"""{self.id}({", ".join(argument_prints)});"""
3438 def print_mlir(self, indent_level=0):
3439 indent = ' ' * indent_level * Node.spaces_per_tab
3440 Node.context.push_block()
3442 # Detect if this is a bridge function call
3443 is_bridge_call = self.id in ['sourceTerm', 'flux', 'nonconservativeProduct']
3445 # Process arguments and handle array subscripts
3446 argument_prints = []
3447 for i, argument in enumerate(self._arguments):
3448 argument.hoist(True)
3450 # Check if this is a Reference to a 2D subscript for a bridge call
3451 is_reference_to_2d_subscript = (
3453 isinstance(argument, Reference) and
3454 isinstance(argument._expression, Subscript) and
3455 isinstance(argument._expression._value, Subscript)
3458 if is_reference_to_2d_subscript:
3459 # This is Reference(Subscript[Subscript[2D_memref]])
3460 # Extract the nested structure
3461 outer_subscript = argument._expression # Subscript[Subscript[...], col_index]
3462 inner_subscript = outer_subscript._value # Subscript[2D_memref, row_index]
3463 memref_2d = inner_subscript._value
3465 outer_subscript.hoist(True)
3466 outer_mlir = outer_subscript.print_mlir(indent_level)
3467 mlir_str_from_outer = "".join(Node.context.get_block().pop_mlir())
3468 Node.context.get_block().mlir_append(mlir_str_from_outer)
3470 # Get MLIR representations
3471 memref_2d.hoist(True)
3472 memref_2d_mlir = memref_2d.print_mlir(indent_level).strip(' ')
3474 # Get the base memref variable name (strip % prefix)
3475 base_mlir_name = memref_2d_mlir.lstrip('%')
3476 is_nested_base = False
3477 if base_mlir_name in Node.type_map and _is_nested_memref(Node.type_map[base_mlir_name]):
3478 is_nested_base = True
3480 # Use unified method from Node to generate pointer arithmetic
3481 ptr_code, final_ptr = Node.generate_pointer_to_2d_element(
3482 memref_2d_mlir, inner_subscript._new_index, outer_subscript._new_index, is_nested_base, indent_level
3484 Node.context.get_block().mlir_append(ptr_code)
3485 arg_mlir = final_ptr
3487 # Not a 2D subscript for bridge call - use standard approach
3488 arg_mlir = argument.print_mlir(indent_level).strip(' ')
3490 # Regular subscript (array indexing) that needs loading
3491 if not is_reference_to_2d_subscript and isinstance(argument, Subscript):
3492 # Get the base array and index
3493 base_value = arg_mlir # This is the array reference
3494 index = argument._new_index # This is the converted index
3495 base_type = argument._value.get_type()
3497 if isinstance(base_type, TDataBlock):
3498 # Check if this is a multi-dimensional (2D+) DataBlock
3499 if isinstance(base_type._dimensions, int) and base_type._dimensions >= 2:
3500 # This is a flat multi-dimensional memref (like memref<?x?xf64>)
3501 # When passed to a function expecting memref<?xf64>, just pass it as-is
3502 arg_mlir = f"{base_value}[{index}]"
3504 # Single-dimensional DataBlock
3505 element_type_class, is_vector, mlir_element_type = base_type.get_array_element_info()
3508 # This is an array of vectors - generate a load to get the vector pointer as i64, then cast to !llvm.ptr
3509 result_id = f"%{Node.get_mlir_id()}"
3510 load_op = indent + f"{result_id} = memref.load {base_value}[{index}] {{name = \"{base_value.strip('%')}\"}} : memref<?x{mlir_element_type}>\n"
3511 Node.context.get_block().mlir_append(load_op)
3512 # Now cast the i64 to !llvm.ptr
3513 ptr_id = f"%{Node.get_mlir_id()}"
3514 cast_op = indent + f"{ptr_id} = llvm.inttoptr {result_id} : {mlir_element_type} to !llvm.ptr\n"
3515 Node.context.get_block().mlir_append(cast_op)
3518 # Regular array of scalars - generate a load to get the scalar value
3519 result_id = f"%{Node.get_mlir_id()}"
3520 load_op = indent + f"{result_id} = memref.load {base_value}[{index}] {{name = \"{base_value.strip('%')}\"}} : memref<?x{mlir_element_type}>\n"
3521 Node.context.get_block().mlir_append(load_op)
3522 arg_mlir = result_id
3524 # Handle non-TDataBlock types (like nested memrefs)
3525 if str(base_type).startswith("memref<?xmemref<?xf64>>"):
3526 # This is an array of vectors (stored as memref of memrefs)
3527 result_id = f"%{Node.get_mlir_id()}"
3528 load_op = indent + f"{result_id} = memref.load {base_value}[{index}] {{name = \"{base_value.strip('%')}\"}} : memref<?xmemref<?xf64>>\n"
3529 Node.context.get_block().mlir_append(load_op)
3530 arg_mlir = result_id
3532 # For other types, just pass the reference
3533 arg_mlir = f"{base_value}[{index}]"
3535 argument_prints.append(arg_mlir)
3537 argument_block = Node.context.pop_block().get_mlir()
3538 for op in argument_block:
3539 Node.context.get_block().mlir_append(' ' * indent_level * Node.spaces_per_tab + op.strip(' '))
3541 # NOTE: we lookup the function pointer name in type_map to get the type
3542 id = self.id[0].upper() + self.id[1:]
3543 type_entry = Node.type_map[self.id]
3544 # Handle both Type objects and strings
3545 if isinstance(type_entry, str):
3546 fn_type = type_entry
3548 fn_type = type_entry.print_mlir(0).strip()
3550 bridge_function_name = f"{self.id}_bridge"
3551 call_statement = f"""func.call @{bridge_function_name}({", ".join(argument_prints)}) : {fn_type.strip(' ')}"""
3553 Node.context.get_block().mlir_append(indent + call_statement)
3556 def print_tree(self, indent_level=0):
3557 argument_prints = [argument.print_tree() for argument in self._arguments]
3558 return ' ' * indent_level * Node.spaces_per_tab + f"""FunctionCall:
3559{' ' * (indent_level + 1) * Node.spaces_per_tab + ",".join(argument_prints)}"""
3562class Max(Statement):
3563 def __init__(self, lhs, rhs):
3568 def print_cpp(self, indent_level=0):
3569 return ' ' * indent_level * Node.spaces_per_tab + f"""std::max({self._lhs.print_cpp()}, {self._rhs.print_cpp()});"""
3571 def print_omp(self, indent_level=0):
3572 return ' ' * indent_level * Node.spaces_per_tab + f"""std::max({self._lhs.print_omp()}, {self._rhs.print_omp()});"""
3574 def print_sycl(self, indent_level=0):
3575 return ' ' * indent_level * Node.spaces_per_tab + f"""::sycl::max({self._lhs.print_sycl()}, {self._rhs.print_sycl()});"""
3577 def print_mlir(self, indent_level=0):
3578 indent = ' ' * indent_level * Node.spaces_per_tab
3580 def unpack_nested_memref_access(expr, indent_level):
3581 indent = ' ' * indent_level * Node.spaces_per_tab
3583 if not (isinstance(expr, Subscript) and isinstance(expr._value, Subscript)):
3584 return expr.print_mlir(indent_level).strip(' ')
3586 outer_subscript = expr._value
3588 if not hasattr(outer_subscript, '_new_index'):
3589 outer_subscript.print_mlir(indent_level)
3590 if not hasattr(expr, '_new_index'):
3591 expr.print_mlir(indent_level)
3593 outer_index = getattr(outer_subscript, '_new_index', outer_subscript._index.print_mlir(indent_level))
3594 inner_index = getattr(expr, '_new_index', expr._index.print_mlir(indent_level))
3596 inner_memref_id = f"%{Node.get_mlir_id()}"
3598 # Get the outer memref's MLIR variable name and check type_map
3599 outer_memref_var = outer_subscript._value.print_mlir(indent_level).strip(' ')
3601 # Try to determine the outer memref type
3602 # First, check if this variable is registered in type_map
3604 # Get the cpp name to check type_map
3605 outer_var_cpp = outer_subscript._value.print_cpp().strip()
3606 if outer_var_cpp in Node.type_map:
3607 type_entry = Node.type_map[outer_var_cpp]
3608 # Handle both Type objects and strings
3609 if isinstance(type_entry, str):
3610 outer_memref_type = type_entry
3612 # Type object - call print_mlir()
3613 outer_memref_type = type_entry.print_mlir(0).strip()
3615 # Fallback to default nested memref type
3616 outer_memref_type = "memref<?xmemref<?xf64>>"
3618 outer_memref_type = "memref<?xmemref<?xf64>>"
3620 mlir_str = indent + f"{inner_memref_id} = memref.load {outer_memref_var}[{outer_index}] {{name = \"{outer_memref_var.strip('%')}\"}} : {outer_memref_type}\n"
3621 value_id = f"%{Node.get_mlir_id()}"
3622 mlir_str += indent + f"{value_id} = memref.load {inner_memref_id}[{inner_index}] {{name = \"{outer_memref_var.strip('%')}\"}} : memref<?xf64>\n"
3623 Node.context.get_block().mlir_append(mlir_str)
3627 Node.context.push_block()
3629 if type(self._lhs.get_type()) is TDataBlock:
3630 self._lhs.hoist(True)
3631 if type(self._rhs.get_type()) is TDataBlock:
3632 self._rhs.hoist(True)
3634 const_zero_id = None
3635 if isinstance(self._lhs, Subscript) and isinstance(self._lhs._value, Subscript):
3636 lhs = unpack_nested_memref_access(self._lhs, indent_level)
3638 lhs = self._lhs.print_mlir(indent_level).strip(' ')
3639 if TDataBlock.needs_memref_load(self._lhs):
3640 const_zero_id = TDataBlock.ensure_const_zero(const_zero_id, indent_level)
3641 lhs = TDataBlock.generate_memref_load(self._lhs, lhs, const_zero_id, indent_level)
3643 if isinstance(self._rhs, Subscript) and isinstance(self._rhs._value, Subscript):
3644 rhs = unpack_nested_memref_access(self._rhs, indent_level)
3646 rhs = self._rhs.print_mlir(indent_level).strip(' ')
3647 if TDataBlock.needs_memref_load(self._rhs):
3648 const_zero_id = TDataBlock.ensure_const_zero(const_zero_id, indent_level)
3649 rhs = TDataBlock.generate_memref_load(self._rhs, rhs, const_zero_id, indent_level)
3651 argument_block = Node.context.pop_block().get_mlir()
3652 for op in argument_block:
3653 Node.context.get_block().mlir_append(op)
3655 # Use the unified type determination and operation mapping from TDataBlock
3656 op_type_class = TDataBlock.get_mlir_type_for_operation(self._lhs, self._rhs)
3657 result_type = op_type_class.print_mlir(0)
3659 if op_type_class is TInteger:
3660 mlir_op = "arith.maxsi"
3662 mlir_op = "arith.maximumf" # Default to float
3664 new_id = f"%{Node.get_mlir_id()}"
3665 mlir_str = indent + f"{new_id} = {mlir_op} {lhs}, {rhs} : {result_type}\n"
3666 Node.context.get_block().mlir_append(mlir_str)
3670 def print_tree(self, indent_level=0):
3671 return ' ' * indent_level * Node.spaces_per_tab + f"""Max:
3672{self._lhs.print_tree(indent_level + 1)}
3673{self._rhs.print_tree(indent_level + 1)}"""
3676class MemoryAllocation(Statement):
3677 memoryAllocated = []
3678 allocated_types = {} # Map from MLIR variable name to allocated memref type string
3680 def __init__(self, name: Name, object_type: Type, dimensions, specify_type = True, add_to_stack=True):
3682 self._type = object_type
3683 if type(dimensions[0]) is list:
3684 self._dimensions = [dimension[1] for dimension in dimensions]
3686 self._dimensions = dimensions
3688 self._specify_type = specify_type
3690 if add_to_stack == True:
3691 MemoryAllocation.memoryAllocated[-1].append(self)
3693 if len(self._dimensions) > 1:
3694 self._size = self._dimensions[-2]
3695 for i in range(len(self._dimensions) - 3, -1, -1):
3696 self._size = self._size * self._dimensions[i]
3698 self._loop = For([Integer(0), self._dimensions[-1]])
3699 self._loop.add_statement(MemoryAllocation(Subscript(self._name, self._loop.get_iteration_variable()), self._type, [self._size], False, False))
3700 self._loop.close_scope()
3702 def print_cpp(self, indent_level=0):
3703 if len(self._dimensions) == 1:
3704 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_cpp() + "* " if self._specify_type else ""}{self._name.print_cpp()} = new {self._type.print_cpp()}[{self._dimensions[0].print_cpp()}];"""
3706 if Node.use_accelerator == False and type(Name.variables[self._name.id]) is not FaceDataBlock:
3707 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_cpp()}** {self._name.print_cpp()} = new {self._type.print_cpp()}*[{self._dimensions[-1].print_cpp()}];
3708{self._loop.print_cpp(indent_level)}"""
3710 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_cpp()}* {self._name.print_cpp()} = new {self._type.print_cpp()}[{(self._size * self._dimensions[-1]).print_cpp()}];"""
3713 def print_omp(self, indent_level=0):
3714 if Node.use_accelerator == False:
3715 if len(self._dimensions) == 1:
3716 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_omp() + "* " if self._specify_type else ""}{self._name.print_omp()} = new {self._type.print_omp()}[{self._dimensions[0].print_omp()}];"""
3718 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_omp()}** {self._name.print_omp()} = new {self._type.print_omp()}*[{self._dimensions[-1].print_omp()}];
3719{self._loop.print_omp(indent_level)}"""
3721 if len(self._dimensions) == 1:
3722 if Node.use_memory_manager == True:
3723 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_omp() + "* " if self._specify_type else ""}{self._name.print_omp()} = tarch::accelerator::GPUMemoryManager::getInstance().allocate<{self._type.print_omp()}>({self._dimensions[0].print_omp()}, targetDevice);"""
3725 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_omp() + "* " if self._specify_type else ""}{self._name.print_omp()} = ({self._type.print_omp()}*)omp_target_alloc(sizeof({self._type.print_omp()}) * {self._dimensions[0].print_omp()}, targetDevice);"""
3727 if Node.use_memory_manager == True:
3728 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_omp()}* {self._name.print_omp()} = tarch::accelerator::GPUMemoryManager::getInstance().allocate<{self._type.print_omp()}>({(self._size * self._dimensions[-1]).print_omp()}, targetDevice);"""
3730 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_omp()}* {self._name.print_omp()} = ({self._type.print_omp()}*)omp_target_alloc(sizeof({self._type.print_omp()}) * {(self._size * self._dimensions[-1]).print_omp()}, targetDevice);"""
3732 def print_sycl(self, indent_level=0):
3733 if len(self._dimensions) == 1:
3734 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_sycl() + "* " if self._specify_type else ""}{self._name.print_sycl()} = new {self._type.print_sycl()}[{self._dimensions[0].print_sycl()}];"""
3736 return ' ' * indent_level * Node.spaces_per_tab + f"""{self._type.print_sycl()}** {self._name.print_sycl()} = new {self._type.print_sycl()}*[{self._dimensions[-1].print_sycl()}];
3737{self._loop.print_sycl(indent_level)}"""
3739 def print_mlir(self, indent_level=0):
3740 indent = ' ' * indent_level * Node.spaces_per_tab
3742 # Comprehensive tracing for MemoryAllocation
3743 name_mlir = self._name.print_mlir(0)
3744 name_type = self._name.get_type()
3745 is_datablock = isinstance(name_type, TDataBlock)
3746 var_name_for_map = self._name.print_cpp().strip()
3747 in_type_map = var_name_for_map in Node.type_map
3750 if len(self._dimensions) == 1:
3751 # Process the dimension expression first and collect any intermediate operations
3752 Node.context.push_block()
3753 index_val = self._dimensions[0].print_mlir(indent_level)
3754 intermediate_ops = Node.context.pop_block().get_mlir()
3756 # Now build the allocation operations
3757 index_id = f"%{Node.get_mlir_id()}"
3758 decl = ''.join(intermediate_ops)
3760 # Add the index cast and allocation with correct source type
3761 index_type = self._dimensions[0].get_type()
3762 index_mlir_type = index_type.print_mlir(0).strip()
3763 decl += indent + f"{index_id} = arith.index_cast {index_val} : {index_mlir_type} to index\n"
3764 new_id = f"%{Node.get_mlir_id()}"
3766 # For 1D allocation, we should always generate 1D memref type
3767 # Get the element type correctly
3768 name_type = self._name.get_type()
3769 if isinstance(name_type, TDataBlock):
3770 # Get the element type of the DataBlock
3771 element_type_class = name_type.get_element_type()
3772 element_type = element_type_class().print_mlir(0)
3773 mlir_type = f"memref<?x{element_type}>"
3775 mlir_type = name_type.print_mlir(0)
3777 decl += indent + f"{new_id} = memref.alloc({index_id}) {{name = \"{name_mlir.strip('%')}\"}} : {mlir_type}\n"
3778 # Track the allocated type for deallocation
3779 MemoryAllocation.allocated_types[new_id] = mlir_type
3781 # Check if this is an inner allocation that needs to be stored in an outer array
3782 # This happens when self._name is a Subscript (indicating arr[i] = allocated_inner_array)
3783 if isinstance(self._name, Subscript) and not self._specify_type:
3784 # This is an inner allocation for nested memref, add the store operation
3785 # Get the outer array name and index
3786 outer_array = self._name._value # This should be the outer array name
3787 outer_index = self._name._index
3789 # Process the outer array and index expressions to collect any additional operations
3790 Node.context.push_block()
3791 outer_array_mlir = outer_array.print_mlir(indent_level)
3792 outer_index_mlir = outer_index.print_mlir(indent_level)
3793 additional_ops = Node.context.pop_block().get_mlir()
3795 # Add any additional operations
3796 decl += ''.join(additional_ops)
3798 # When storing a memref into a nested memref array, we need to use memref<?xmemref<?xf64>>
3799 type_mlir = Node.get_mlir_type(self._type)
3800 if type_mlir is None:
3801 type_entry = Node.type_map[self._type.print_cpp()]
3802 # Handle both Type objects and strings
3803 if isinstance(type_entry, str):
3804 type_mlir = type_entry.strip(' ')
3806 # Type object - call print_mlir()
3807 type_mlir = type_entry.print_mlir(0).strip()
3808 outer_type = f"memref<?xmemref<?x{type_mlir}>>"
3810 # Add the store operation
3811 decl += indent + f"memref.store {new_id}, {outer_array_mlir}[{outer_index_mlir}] {{name = \"{outer_array_mlir.strip('%')}\"}} : {outer_type}"
3815 # For multi-dimensional arrays, check type_map first (ordering is important)
3816 # This allows overriding default DataBlock behavior for nested memref types
3817 var_name_for_type_check = self._name.print_cpp().strip()
3818 in_type_map = var_name_for_type_check in Node.type_map
3820 # Use nested memref if in type_map, otherwise check if DataBlock flat
3822 # Variable has explicit type specification - use nested memref path
3823 is_datablock = False # Force nested path
3824 actual_dims_calc = -1
3826 # For multi-dimensional arrays, check if this is a DataBlock
3827 # If so, use flat memref with the correct number of dimensions instead of nested memref
3828 is_datablock = isinstance(self._name.get_type(), TDataBlock)
3830 # Calculate actual_dims based on DataBlock iteration_range
3832 datablock_obj = self._name.get_type()
3834 if hasattr(datablock_obj, '_iteration_range'):
3835 actual_dims_calc = len(datablock_obj._iteration_range)
3836 elif isinstance(datablock_obj._dimensions, int):
3837 actual_dims_calc = 1 if datablock_obj._dimensions == 1 else 2
3838 elif isinstance(datablock_obj._dimensions, list):
3839 actual_dims_calc = len(datablock_obj._dimensions) if len(datablock_obj._dimensions) > 0 else 1
3841 actual_dims_calc = 1
3843 actual_dims_calc = -1 # Not a DataBlock
3845 if is_datablock and actual_dims_calc >= 2:
3846 # Multi-dimensional DataBlock case: allocate as flat N-D memref
3847 element_type_class = self._name.get_type().get_element_type()
3848 element_type = element_type_class().print_mlir(0)
3850 # We need actual_dims_calc dimensions from self._dimensions
3851 # For a 2D array: _dimensions might have 2, 3, or 4 elements (depends on iteration_range structure)
3852 # Take the first actual_dims_calc elements
3853 dim_exprs = self._dimensions[:actual_dims_calc]
3854 if len(dim_exprs) < actual_dims_calc:
3855 # Fallback: if we don't have enough dimensions, use what we have
3856 dim_exprs = self._dimensions
3858 intermediate_decl = ""
3861 for i, dim_expr in enumerate(dim_exprs):
3862 # Evaluate the dimension expression - this appends its operations to context
3863 dim_val = dim_expr.print_mlir(indent_level)
3864 dim_id = f"%{Node.get_mlir_id()}"
3865 dim_ids.append(dim_id)
3866 dim_type = dim_expr.get_type()
3867 dim_mlir_type = dim_type.print_mlir(0).strip()
3869 # Generate the index cast (will be appended after dimension expressions)
3870 intermediate_decl += indent + f"{dim_id} = arith.index_cast {dim_val} : {dim_mlir_type} to index\n"
3872 # These must come before the index_cast operations
3873 dim_expr_ops = Node.context.pop_block().get_mlir()
3874 intermediate_decl = ''.join(dim_expr_ops) + intermediate_decl
3876 # Re-push a new block for remaining operations
3877 Node.context.push_block()
3879 # Process name and allocate
3880 name_mlir = self._name.print_mlir(indent_level)
3882 # Build memref type: memref<?x?x...xf64> with actual_dims_calc '?'s
3883 dimension_list = ["?"] * actual_dims_calc
3884 memref_dims = "x".join(dimension_list)
3885 alloc_args = ", ".join(dim_ids)
3887 # Allocate as flat N-D memref
3888 alloc_line = indent + f"{name_mlir} = memref.alloc({alloc_args}) {{name = \"{name_mlir.strip('%')}\"}} : memref<{memref_dims}x{element_type}>\n"
3890 # Track the allocated memref type so it can be used in load/store operations
3891 memref_type_full = f"memref<{memref_dims}x{element_type}>"
3892 Node.mlir_memref_types[name_mlir] = memref_type_full
3893 MemoryAllocation.allocated_types[name_mlir] = memref_type_full
3895 return intermediate_decl + alloc_line
3897 # For non-DataBlock multi-dimensional arrays, use nested memref with loop
3898 # Use the existing loop structure created in the constructor
3899 size = self._dimensions[-2]
3900 for i in range(len(self._dimensions) - 3, -1, -1):
3901 size = size * self._dimensions[i]
3903 # Process the outer dimension expression first and collect any intermediate operations
3904 Node.context.push_block()
3905 outer_size_val = self._dimensions[-1].print_mlir(indent_level)
3906 intermediate_ops = Node.context.pop_block().get_mlir()
3908 # Build the allocation operations
3909 decl = ''.join(intermediate_ops)
3911 # Add the index cast and allocation with correct source type
3912 outer_size_id = f"%{Node.get_mlir_id()}"
3913 outer_size_type = self._dimensions[-1].get_type()
3914 outer_size_mlir_type = outer_size_type.print_mlir(0).strip()
3915 decl += indent + f"{outer_size_id} = arith.index_cast {outer_size_val} : {outer_size_mlir_type} to index\n"
3917 # Determine the correct type for the outer array
3918 # Check if this variable name is in type_map (e.g., maxEigenvaluesX, maxEigenvaluesY)
3919 var_name = self._name.print_cpp().strip()
3921 # NOTE: We need to check if the variable name is in type_map first
3922 if var_name in Node.type_map:
3923 # Use the explicitly registered type from type_map
3924 type_entry = Node.type_map[var_name]
3926 # Handle both Type objects and strings
3927 if isinstance(type_entry, str):
3928 outer_type = type_entry
3930 # Type object (e.g., TNestedMemref)
3931 outer_type = type_entry.print_mlir(0).strip()
3932 elif isinstance(self._name.get_type(), TDataBlock):
3933 # Get the element type correctly for the inner memref
3934 element_type_class = self._name.get_type().get_element_type()
3935 element_type = element_type_class().print_mlir(0)
3936 outer_type = f"memref<?xmemref<?x{element_type}>>"
3938 # Fallback for non-DataBlock types
3939 name_type_mlir = self._name.get_type().print_mlir(0)
3941 if name_type_mlir is None:
3942 type_entry = Node.type_map[self._name.get_type().print_cpp()]
3943 # Handle both Type objects and strings
3944 if isinstance(type_entry, str):
3945 name_type_mlir = type_entry.strip(' ')
3948 name_type_mlir = type_entry.print_mlir(0).strip()
3949 outer_type = f"memref<?x{name_type_mlir}>"
3951 # Process the name expression to collect any additional operations
3952 Node.context.push_block()
3953 name_mlir = self._name.print_mlir(indent_level)
3954 name_ops = Node.context.pop_block().get_mlir()
3956 # Add any name-related operations
3957 decl += ''.join(name_ops)
3958 decl += indent + f"{name_mlir} = memref.alloc({outer_size_id}) {{name = \"{name_mlir.strip('%')}\"}} : {outer_type}\n"
3959 # Track the allocated type for deallocation
3960 MemoryAllocation.allocated_types[name_mlir] = outer_type
3962 # Use the existing loop structure for inner allocations
3963 loop_mlir = self._loop.print_mlir(indent_level)
3965 return decl + loop_mlir
3967 def print_tree(self, indent_level=0):
3968 return ' ' * indent_level * Node.spaces_per_tab + f"""MemoryAllocation:
3969{self._name.print_tree(indent_level + 1)}"""
3972class MemoryDeallocation(Statement):
3973 def __init__(self, allocation: MemoryAllocation):
3975 self._dimensions = allocation._dimensions
3976 self._name = allocation._name
3977 self._allocated_type = None # Will store the MLIR type string when known
3979 if len(self._dimensions) > 1:
3980 size = self._dimensions[-2]
3981 for i in range(len(self._dimensions) - 3, -1, -1):
3982 size = size * self._dimensions[i]
3984 self._loop = For([Integer(0), self._dimensions[-1]])
3985 self._loop.add_statement(MemoryDeallocation(MemoryAllocation(Subscript(self._name, self._loop.get_iteration_variable()), None, [size], False, False)))
3986 self._loop.close_scope()
3988 def print_cpp(self, indent_level=0):
3989 if len(self._dimensions) == 1:
3990 return ' ' * indent_level * Node.spaces_per_tab + f"""delete[] {self._name.print_cpp()};"""
3992 if Node.use_accelerator == False and type(Name.variables[self._name.id]) is not FaceDataBlock:
3993 return f"""{self._loop.print_cpp(indent_level)}
3994{' ' * indent_level * Node.spaces_per_tab}delete[] {self._name.print_cpp()};"""
3996 return f"""{' ' * indent_level * Node.spaces_per_tab}delete[] {self._name.print_cpp()};"""
3998 def print_omp(self, indent_level=0):
3999 if Node.use_accelerator == False:
4000 if len(self._dimensions) == 1:
4001 return ' ' * indent_level * Node.spaces_per_tab + f"""delete[] {self._name.print_omp()};"""
4003 return f"""{self._loop.print_omp(indent_level)}
4004{' ' * indent_level * Node.spaces_per_tab}delete[] {self._name.print_omp()};"""
4006 if Node.use_memory_manager:
4007 return ' ' * indent_level * Node.spaces_per_tab + f"""tarch::accelerator::GPUMemoryManager::getInstance().free({self._name.print_omp()}, targetDevice);"""
4009 return ' ' * indent_level * Node.spaces_per_tab + f"""omp_target_free({self._name.print_omp()}, targetDevice);"""
4011 def print_sycl(self, indent_level=0):
4012 return ' ' * indent_level * Node.spaces_per_tab + f"""::sycl::free({self._name.print_sycl()}, queue);"""
4014 # return f"""{' ' * indent_level * Node.spaces_per_tab}::sycl::free({self._name.print_sycl()}, queue);"""
4015# return f"""{self._loop.print_sycl(indent_level)}
4016#{' ' * indent_level * Node.spaces_per_tab}::sycl::free({self._name.print_sycl()}, queue);"""
4018 def print_mlir(self, indent_level=0):
4019 indent = ' ' * indent_level * Node.spaces_per_tab
4021 # Get the MLIR variable name
4022 name_mlir = self._name.print_mlir(indent_level)
4024 # Use the stored allocated type if available
4025 if name_mlir in MemoryAllocation.allocated_types:
4026 name_type_mlir = MemoryAllocation.allocated_types[name_mlir]
4027 elif self._allocated_type is not None:
4028 # Use the allocated type if it was set explicitly
4029 name_type_mlir = self._allocated_type
4031 # Fallback: try to reconstruct the type from the allocation dimensions
4032 # For nested memrefs (multi-dimensional arrays), we need memref<?xmemref<?xf64>>
4033 # For 1D arrays, we need memref<?xf64>
4034 name_element_type = self._name.get_type()
4035 element_type = name_element_type.print_mlir(0).strip()
4037 if len(self._dimensions) == 1:
4038 name_type_mlir = f"memref<?x{element_type}>"
4040 # For multidimensional, assume nested memref
4041 name_type_mlir = f"memref<?xmemref<?x{element_type}>>"
4043 return "\n" + indent + f"""memref.dealloc {name_mlir} : {name_type_mlir}\n"""
4045 def print_tree(self, indent_level=0):
4046 return ' ' * indent_level * Node.spaces_per_tab + f"""MemoryDeallocation:
4047{self._name.print_tree(indent_level + 1)}"""
4050class Construction(Statement):
4051 def __init__(self, name: Name, expression: Expression):
4054 self._name.on_left(True)
4055 self._expression = expression
4056 Name.variables.update({self._name.id: expression})
4058 def print_cpp(self, indent_level = 0):
4059 return ' ' * indent_level * Node.spaces_per_tab + f"{self._name.get_type().print_cpp()} {self._name.print_cpp()} = {self._expression.print_cpp()};"
4061 def print_omp(self, indent_level = 0):
4062 return ' ' * indent_level * Node.spaces_per_tab + f"{self._name.get_type().print_omp()} {self._name.print_omp()} = {self._expression.print_omp()};"
4064 def print_sycl(self, indent_level = 0):
4065 return ' ' * indent_level * Node.spaces_per_tab + f"{self._name.get_type().print_sycl()} {self._name.print_sycl()} = {self._expression.print_sycl()};"
4067 def print_mlir(self, indent_level = 0):
4068 indent = ' ' * indent_level * Node.spaces_per_tab
4070 if self._expression._string is None:
4071 expr_mlir = self._expression.print_mlir(indent_level)
4073 # Get any operations that were added to the context
4074 mlir_str = ''.join(Node.context.get_block().pop_mlir())
4075 mlir_str += indent + f"{self._name.print_mlir(indent_level)} = {expr_mlir} : {self._name.get_type().print_mlir(indent_level).strip(' ')}\n"
4077 # Get another variable id and load the pointer into that, then load the value into the actual variable (self)
4078 new_id = Node.get_mlir_id()
4079 mlir_str = indent + f"%{new_id} = {self._expression.print_mlir(indent_level)}\n"
4081 # Use the expression's type, not the name's type
4082 expr_type = self._expression.get_type().print_mlir(indent_level).strip(' ')
4083 mlir_str += indent + f"{self._name.print_mlir(indent_level)} = llvm.load %{new_id} {{name = \"{self._name.print_mlir(indent_level).strip('%')}\"}} : !llvm.ptr -> {expr_type}\n"
4085 Node.context.get_block().mlir_append(mlir_str)
4088 def print_tree(self, indent_level=0):
4091{self._name.print_tree(indent_level + 1)}
4092{self._expression.print_tree(indent_level + 1)}"""
4095class DataBlockConstructionFromExisting(Statement):
4096 def __init__(self, name: Name, dataBlock: DataBlock):
4099 self._dataBlock = dataBlock
4100 self._dataBlock.id = name.id
4101 Name.variables.update({self._name.id: self._dataBlock})
4102 FunctionDefinition._syclDataToCopy.append(self)
4104 def print_cpp(self, indent_level = 0):
4105 type_print = self._name.get_type().print_cpp()
4106 if len(self._dataBlock._iteration_range) > 1 and Node.use_accelerator == False and type(self._dataBlock) is not FaceDataBlock:
4108 return ' ' * indent_level * Node.spaces_per_tab + f"{type_print} {self._name.print_cpp()} = {self._dataBlock._internal.print_cpp()};"
4110 def print_omp(self, indent_level = 0):
4111 type_print = self._name.get_type().print_omp()
4112 if len(self._dataBlock._iteration_range) > 1 and Node.use_accelerator == False and type(self._dataBlock) is not FaceDataBlock:
4114 return ' ' * indent_level * Node.spaces_per_tab + f"{type_print} {self._name.print_omp()} = {self._dataBlock._internal.print_omp()};"
4116 def print_sycl(self, indent_level = 0):
4117 type_print = self._name.get_type().print_sycl()
4118 if len(self._dataBlock._iteration_range) > 1 and Node.use_accelerator == False and type(self._dataBlock) is not FaceDataBlock:
4120 return ' ' * indent_level * Node.spaces_per_tab + f"{type_print} {self._name.print_sycl()} = {self._dataBlock._internal.print_sycl()};"
4121# step_size = Integer(1)
4122# for d in self._dataBlock._iteration_range[0:-1]:
4123# step_size = step_size * (d[1] - d[0])
4124# size = step_size * (self._dataBlock._iteration_range[-1][1] - self._dataBlock._iteration_range[-1][0])
4125# return f"""{' ' * indent_level * Node.spaces_per_tab}auto {self._name.print_sycl()} = ::sycl::malloc_shared<double>({size.print_sycl()}, queue);
4126#{' ' * indent_level * Node.spaces_per_tab}for (int z = 0; z < {(self._dataBlock._iteration_range[-1][1]-self._dataBlock._iteration_range[-1][0]).print_sycl()}; z++){{
4127#""" + (f"""{' ' * (indent_level + 1) * Node.spaces_per_tab}queue.memcpy(&{self._name.print_sycl()}[{step_size.print_sycl()} * z], {self._dataBlock._internal.print_sycl()}[z], {step_size.print_sycl()} * sizeof({self._dataBlock._underlying_type.print_sycl()})).wait();""" if self._dataBlock._internal.print_sycl()[-4:] != "QOut" else """""") + f"""
4128#{' ' * indent_level * Node.spaces_per_tab}}}
4130# for d in self._dataBlock._iteration_range[0:-1]:
4131# size = size * (d[1] - d[0])
4132# return f"""{' ' * indent_level * Node.spaces_per_tab}auto {self._name.print_sycl()} = ::sycl::malloc_shared<double*>({(self._dataBlock._iteration_range[-1][1]-self._dataBlock._iteration_range[-1][0]).print_sycl()}, queue);
4133#{' ' * indent_level * Node.spaces_per_tab}for (int z = 0; z < {(self._dataBlock._iteration_range[-1][1]-self._dataBlock._iteration_range[-1][0]).print_sycl()}; z++){{
4134#{' ' * (indent_level + 1) * Node.spaces_per_tab}{self._name.print_sycl()}[z] = ::sycl::malloc_shared<double>({size.print_sycl()}, queue);
4135#""" + (f"""{' ' * (indent_level + 1) * Node.spaces_per_tab}queue.memcpy({self._name.print_sycl()}[z], {self._dataBlock._internal.print_sycl()}[z], {size.print_sycl()} * sizeof({self._dataBlock._underlying_type.print_sycl()})).wait();""" if self._dataBlock._internal.print_sycl()[-4:] != "QOut" else """""") + f"""
4136#{' ' * indent_level * Node.spaces_per_tab}}}
4138 return ' ' * indent_level * Node.spaces_per_tab + f"{type_print} {self._name.print_sycl()} = {self._dataBlock._internal.print_sycl()};"
4140 def print_mlir(self, indent_level = 0):
4141 indent = ' ' * indent_level * Node.spaces_per_tab
4142 type_print = self._name.get_type().print_mlir(indent_level)
4145 for i in range(len(self._dataBlock._iteration_range) - 3, -1, -1):
4146 dims.append(self._dataBlock._iteration_range[i])
4148 if len(self._dataBlock._iteration_range) > 1:
4149 type_print = "!llvm.ptr " #+ f"{self._dataBlock._underlying_type} dims: {dims})"
4151 # NOTE: We encode structs as Strings, so check here if they are a struct and generate accordingly
4152 # Set the target variable name so String.print_mlir() can use it
4153 target_var_name = self._name.print_mlir(indent_level)
4154 Node.target_variable_name = target_var_name
4156 # Store the mapping from DSL name to MLIR variable name for later use in assignments
4157 # TODO: This is clumsy - it is assuming the exact flow here...
4158 dsl_name = self._dataBlock._internal._value
4159 Node.mlir_symbol_table[dsl_name] = target_var_name
4161 # Generate the struct field access operations with the target variable name
4162 struct_mlir = self._dataBlock._internal.print_mlir(indent_level).strip(' ')
4163 mlir_str = ''.join(Node.context.pop_block().get_mlir())
4165 # Clear the target variable name - we've finished generating the MLIR for this Node
4166 Node.target_variable_name = None
4171 def print_tree(self, indent_level=0):
4173DataBlockConstructionFromExisting:
4174{self._name.print_tree(indent_level + 1)}
4175{self._dataBlock._internal.print_tree(indent_level + 1)}"""
4178class DataBlockConstructionFromOperation:
4179 def __init__(self, name: Name, dataBlockOperation):
4182 self._dataBlock = DataBlock(dataBlockOperation._iteration_range, None, False, self._name.id, underlying_type=dataBlockOperation.get_type().get_single())
4183 Name.variables.update({self._name.id: self._dataBlock})
4184 if type(dataBlockOperation) is DataBlockBinaryOperation or type(dataBlockOperation) is DataBlockUnaryOperation or type(dataBlockOperation) is DataBlockMax or type(dataBlockOperation) is DataBlockComparison or type(dataBlockOperation._internal) is String:
4185 self._operation = dataBlockOperation
4187 self._operation = dataBlockOperation._internal
4189 self.memoryAllocation = MemoryAllocation(self._name, self._dataBlock.get_type().get_single(), self._dataBlock._memory_range)
4190 self.assignment = DataBlockAssignment(self._name, self._operation)
4192 def print_cpp(self, indent_level = 0):
4193 return f"""{self.memoryAllocation.print_cpp(indent_level)}
4194{self.assignment.print_cpp(indent_level)}"""
4196 def print_omp(self, indent_level = 0):
4197 return f"""{self.memoryAllocation.print_omp(indent_level)}
4198{self.assignment.print_omp(indent_level)}"""
4200 def print_sycl(self, indent_level = 0):
4201 return f"""{self.memoryAllocation.print_sycl(indent_level)}
4202{self.assignment.print_sycl(indent_level)}"""
4204 def print_mlir(self, indent_level = 0):
4205 return f"""{self.memoryAllocation.print_mlir(indent_level)}
4206{self.assignment.print_mlir(indent_level)}"""
4208 def print_tree(self, indent_level = 0):
4209 return ' ' * indent_level * Node.spaces_per_tab + f"""DataBlockConstructionFromOperation:
4210{self._name.print_tree(indent_level + 1)}
4211{self._dataBlock.print_tree(indent_level + 1)}"""
4214class DataBlockConstructionFromMatrixVectorProduct:
4215 def __init__(self, name: Name, matrix, vector):
4217 if type(vector) is Name:
4218 self._vector = Name.variables[vector.id]
4220 self._vector = vector
4222 if type(matrix) is Name:
4223 self._matrix = Name.variables[matrix.id]
4225 self._matrix = matrix
4227 self._dataBlock = DataBlock(self._vector._iteration_range, None, False, self._name.id, underlying_type=vector.get_type().get_single())
4228 Name.variables.update({self._name.id: self._dataBlock})
4230 self.memoryAllocation = MemoryAllocation(self._name, self._dataBlock.get_type().get_single(), self._dataBlock._memory_range)
4232 element_width = self._vector._iteration_range[0][1] - self._vector._iteration_range[0][0]
4235 loops.append(For([Integer(0), self._dataBlock._iteration_range[-1][1] - self._dataBlock._iteration_range[-1][0]]))
4236 loops.append(For([Integer(0), self._matrix._dimensions[0]]))
4237 loops.append(For([Integer(0), self._dataBlock._iteration_range[0][1] - self._dataBlock._iteration_range[0][0]]))
4239 if Node.use_accelerator:
4241 for [a, b] in self._dataBlock._memory_range[0:-1]:
4242 size = size * (b - a)
4243 index = size * loops[0].get_iteration_variable() + (loops[1].get_iteration_variable() * element_width + loops[2].get_iteration_variable())
4244 loops[2].add_statement(Assignment(Subscript(self._dataBlock, index), Float(0.0)))
4246 loops[2].add_statement(Assignment(Subscript(Subscript(self._dataBlock, loops[0].get_iteration_variable()), loops[1].get_iteration_variable() * element_width + loops[2].get_iteration_variable()), Float(0.0)))
4248 loops.append(For([Integer(0), self._matrix._dimensions[1]]))
4250 if Node.use_accelerator:
4252 for [a, b] in self._dataBlock._memory_range[0:-1]:
4253 size = size * (b - a)
4254 index = size * loops[0].get_iteration_variable() + (loops[1].get_iteration_variable() * element_width + loops[2].get_iteration_variable())
4255 loops[3].add_statement(Assignment(Subscript(self._dataBlock, index), BinaryOperation("+", Subscript(self._dataBlock, index), BinaryOperation("*", matrix.index(loops[1].get_iteration_variable(), loops[3].get_iteration_variable()), Subscript(self._vector, loops[0].get_iteration_variable() * size + element_width * loops[3].get_iteration_variable() + loops[2].get_iteration_variable())))))
4257 loops[3].add_statement(Assignment(Subscript(Subscript(self._dataBlock, loops[0].get_iteration_variable()), loops[1].get_iteration_variable() * element_width + loops[2].get_iteration_variable()), BinaryOperation("+", Subscript(Subscript(self._dataBlock, loops[0].get_iteration_variable()), loops[1].get_iteration_variable() * element_width + loops[2].get_iteration_variable()), BinaryOperation("*", matrix.index(loops[1].get_iteration_variable(), loops[3].get_iteration_variable()), Subscript(Subscript(self._vector, loops[0].get_iteration_variable()), element_width * loops[3].get_iteration_variable() + loops[2].get_iteration_variable())))))
4261 loops[2].add_statement(loops[3])
4262 loops[1].add_statement(loops[2])
4263 loops[0].add_statement(loops[1])
4264 loops[3].close_scope()
4265 loops[2].close_scope()
4266 loops[1].close_scope()
4267 loops[0].close_scope()
4268 self.assignment = loops[0]
4270 def print_cpp(self, indent_level = 0):
4271 return f"""{self.memoryAllocation.print_cpp(indent_level)}
4272{self.assignment.print_cpp(indent_level)}"""
4274 def print_omp(self, indent_level = 0):
4275 return f"""{self.memoryAllocation.print_omp(indent_level)}
4276{self.assignment.print_omp(indent_level)}"""
4278 def print_sycl(self, indent_level = 0):
4279 return f"""{self.memoryAllocation.print_sycl(indent_level)}
4280{self.assignment.print_sycl(indent_level)}"""
4282 def print_mlir(self, indent_level = 0):
4283 return f"""{self.memoryAllocation.print_mlir(indent_level)}
4284{self.assignment.print_mlir(indent_level)}"""
4286 def print_tree(self, indent_level = 0):
4287 return ' ' * indent_level * Node.spaces_per_tab + f"""DataBlockConstructionFromOperation:
4288{self._name.print_tree(indent_level + 1)}
4289{self._dataBlock.print_tree(indent_level + 1)}"""
4292class DataBlockConstructionFromDotProduct:
4293 def __init__(self, name: Name, matrix, vector):
4295 if type(vector) is Name:
4296 self._vector = Name.variables[vector.id]
4298 self._vector = vector
4300 if type(matrix) is Name:
4301 self._matrix = Name.variables[matrix.id]
4303 self._matrix = matrix
4305 iteration_range = self._vector._iteration_range
4306 iteration_range[-1][1] = Integer(1)
4307 self._dataBlock = DataBlock(self._vector._iteration_range, None, False, self._name.id, underlying_type=vector.get_type().get_single())
4308 Name.variables.update({self._name.id: self._dataBlock})
4310 self.memoryAllocation = MemoryAllocation(self._name, self._dataBlock.get_type().get_single(), self._dataBlock._memory_range)
4314 for [a, b] in self._dataBlock._iteration_range[-1::-1]:
4315 loops.append(For([Integer(0), b - a]))
4317 for loop in loops[::-1]:
4318 index.append(loop.get_iteration_variable())
4320 loops[-1].add_statement(Assignment(self._dataBlock.multidimensional_index(index), Float(0.0)))
4321 for i in range(len(loops) - 1):
4322 loops[i].add_statement(loops[i + 1])
4324 loops.append(For([Integer(0), self._matrix._width]))
4325 rhs_index = index.copy()
4326 rhs_index[-1] = loops[-1].get_iteration_variable()
4327 loops[-1].add_statement(Assignment(self._dataBlock.multidimensional_index(index), BinaryOperation("+", self._dataBlock.multidimensional_index(index), BinaryOperation("*", Subscript(self._matrix, rhs_index[-1]), self._vector.multidimensional_index(rhs_index)))))
4328 loops[-2].add_statement(loops[-1])
4332 self.assignment = loops[0]
4334 def print_cpp(self, indent_level = 0):
4335 return f"""{self.memoryAllocation.print_cpp(indent_level)}
4336{self.assignment.print_cpp(indent_level)}"""
4338 def print_omp(self, indent_level = 0):
4339 return f"""{self.memoryAllocation.print_omp(indent_level)}
4340{self.assignment.print_omp(indent_level)}"""
4342 def print_sycl(self, indent_level = 0):
4343 return f"""{self.memoryAllocation.print_sycl(indent_level)}
4344{self.assignment.print_sycl(indent_level)}"""
4346 def print_mlir(self, indent_level = 0):
4347 return f"""{self.memoryAllocation.print_mlir(indent_level)}
4348{self.assignment.print_mlir(indent_level)}"""
4350 def print_tree(self, indent_level = 0):
4351 return ' ' * indent_level * Node.spaces_per_tab + f"""DataBlockConstructionFromOperation:
4352{self._name.print_tree(indent_level + 1)}
4353{self._dataBlock.print_tree(indent_level + 1)}"""
4356class DataBlockConstructionFromFunction(Statement):
4357 def __init__(self, name: Name, dataBlock: DataBlock):
4360 self._dataBlock = dataBlock
4361 self._dataBlock.id = name.id
4362 Name.variables.update({self._name.id: self._dataBlock})
4364 self.memoryAllocation = MemoryAllocation(self._name, self._dataBlock.get_type().get_single(), self._dataBlock._memory_range)
4365 self.initialisation = For(self._dataBlock._memory_range[-1])
4368 for i in range(len(self._dataBlock._iteration_range) - 2, 0, -1):
4369 loop_bound = self._dataBlock._memory_range[i][1] - self._dataBlock._memory_range[i][0]
4370 inner_loop = For([Integer(0), loop_bound])
4371 inner_loops.append(inner_loop)
4372 if type(self._dataBlock._internal) is not FunctionCall:
4373 inner_loop = For(self._dataBlock._memory_range[0])
4374 inner_loops.append(inner_loop)
4377 for i in range(len(inner_loops)):
4378 index.append(inner_loops[-(i + 1)].get_iteration_variable())
4379 index.append(self.initialisation.get_iteration_variable())
4381 output_offset = [Integer(0) for i in self._dataBlock._iteration_range[1:]]
4382 if type(self._dataBlock._internal._arguments[0]) is Index:
4383 input_offset = [0 for i in range(1, len(self._dataBlock._iteration_range))]
4385 input_offset = [self._dataBlock._iteration_range[i][0] - Name.variables[self._dataBlock._internal._arguments[0].id]._iteration_range[i][0] for i in range(1, len(self._dataBlock._iteration_range))]
4387 if type(self._dataBlock._internal) is FunctionCall:
4388 functionCall = FunctionCall(self._dataBlock._internal.id, [])
4389 functionCall._is_offloadable = self._dataBlock._internal._is_offloadable
4391 if type(self._dataBlock._internal._arguments[0]) is Index:
4392 functionCall.add_argument(Vector(index[0:-1], TInteger()))
4394 functionCall.add_argument(Reference(self._dataBlock._internal._arguments[0].multidimensional_index(index, 1)))
4396 for argument in self._dataBlock._internal._arguments[1:]:
4397 if type(argument.get_type()) is TDataBlock:
4398 offset = [i[0] for i in Name.variables[argument.id]._iteration_range[1:]]
4399 if len(Name.variables[argument.id]._iteration_range) == 1 or Name.variables[argument.id]._iteration_range[0][1] == Integer(1):
4400 functionCall.add_argument(Name.variables[argument.id].multidimensional_index(index, 1))
4402 functionCall.add_argument(Reference(Name.variables[argument.id].multidimensional_index(index, 1)))
4404 functionCall.add_argument(argument)
4406 functionCall.add_argument(Reference(self._dataBlock.multidimensional_index(index, 1)))
4407 if functionCall._is_offloadable:
4408 functionCall.add_argument(String("Solver::Offloadable::Yes"))
4410 functionCall = Assignment(self._dataBlock.multidimensional_index(index), self._dataBlock._internal)
4412 self.initialisation.add_statement(inner_loops[0])
4414 for i in range (0, len(inner_loops) - 1):
4415 inner_loops[i].add_statement(inner_loops[i + 1])
4416 inner_loops[-1].add_statement(functionCall)
4418 for i in range(len(inner_loops) - 1, -1, -1):
4419 inner_loops[i].close_scope()
4420 self.initialisation.close_scope()
4421 self._loops = inner_loops
4422 self._loops.insert(0, self.initialisation)
4424 def print_cpp(self, indent_level = 0):
4425 return f"""{self.memoryAllocation.print_cpp(indent_level)}
4426{self.initialisation.print_cpp(indent_level)}"""
4428 def print_omp(self, indent_level = 0):
4429 if Node.use_accelerator == True:
4430 omp_pragma = "#pragma omp target teams loop collapse(Dimensions + 1) device(targetDevice)"
4432 omp_pragma = "#pragma omp parallel for simd collapse(Dimensions + 1)"
4433 return f"""{self.memoryAllocation.print_omp(indent_level)}
4434{' ' * indent_level * Node.spaces_per_tab + omp_pragma}
4435{self.initialisation.print_omp(indent_level)}"""
4437 def print_sycl(self, indent_level = 0):
4438 ranges = [f"range{i} = {loop.get_interval_size().print_sycl()};" for i, loop in enumerate(self._loops[0:3])]
4439 indexing = [f"int {loop.get_iteration_variable().print_sycl()} = index[{i}];" for i, loop in enumerate(self._loops[0:3])]
4440 statement_prints = [statement.print_sycl(indent_level + 1) for statement in self._loops[2]._statements]
4441 return self.memoryAllocation.print_sycl(indent_level) + os.linesep.join(ranges) + "\n" + ' ' * indent_level * Node.spaces_per_tab + f"""queue.submit([&](::sycl::handler& handler) {{
4442{' ' * indent_level * Node.spaces_per_tab}handler.parallel_for(::sycl::range<3>{{range0, range1, range2}}, [=](::sycl::item<3> index) {{
4443{os.linesep.join(indexing)}
4444{os.linesep.join(statement_prints)}
4445{' ' * (indent_level + 1) * Node.spaces_per_tab}}});
4446{' ' * indent_level * Node.spaces_per_tab}}}).wait();"""
4449 def print_mlir(self, indent_level = 0):
4450 Node.context.push_block()
4451 mem_alloc = self.memoryAllocation.print_mlir(indent_level)
4452 init = self.initialisation.print_mlir(indent_level)
4453 alloc_block = Node.context.pop_block().get_mlir()
4454 for op in alloc_block:
4455 Node.context.get_block().mlir_append(op)
4457 return f"""{mem_alloc}
4460 def print_tree(self, indent_level = 0):
4461 return ' ' * indent_level * Node.spaces_per_tab + f"""DataBlockConstructionFromFunction:
4462{self._name.print_tree(indent_level + 1)}
4463{self._dataBlock.print_tree(indent_level + 1)}"""
4465class Assignment(Statement):
4466 def __init__(self, lhs: Expression, rhs: Expression):
4469 self._lhs.on_left(True)
4471 self._rhs.on_left(False) # Just to be sure...
4473 def print_cpp(self, indent_level = 0):
4474 return ' ' * indent_level * Node.spaces_per_tab + f"{self._lhs.print_cpp()} = {self._rhs.print_cpp()};"
4476 def print_omp(self, indent_level = 0):
4477 return ' ' * indent_level * Node.spaces_per_tab + f"{self._lhs.print_omp()} = {self._rhs.print_omp()};"
4479 def print_sycl(self, indent_level = 0):
4480 return ' ' * indent_level * Node.spaces_per_tab + f"{self._lhs.print_sycl()} = {self._rhs.print_sycl()};"
4482 def print_mlir(self, indent_level = 0):
4483 indent = ' ' * indent_level * Node.spaces_per_tab
4485 Node.context.push_block()
4486 rhs = self._rhs.print_mlir(indent_level)
4490 rhs_casting_mlir = ''
4492 if isinstance(self._rhs, Subscript):
4493 mlir_list = Node.context.get_block().get_mlir()
4494 for i in range(self._rhs._dimensions):
4495 rhs_dims.append('?')
4496 if len(mlir_list) > 0:
4497 rhs_indices.insert(0, self._rhs._new_index)
4498 rhs_casting_mlir += mlir_list.pop()
4500 mlir_str += ''.join(Node.context.pop_block().get_mlir())
4501 mlir_str += rhs_casting_mlir
4503 # Assume scalar here
4504 tmp = ''.join(Node.context.pop_block().get_mlir())
4507 Node.context.push_block()
4508 lhs = self._lhs.print_mlir(indent_level)
4512 lhs_casting_mlir = ''
4514 if isinstance(self._lhs, Subscript):
4515 mlir_list = Node.context.get_block().get_mlir()
4516 for i in range(self._lhs._dimensions):
4517 lhs_dims.append('?')
4518 if len(mlir_list) > 0:
4519 popped = mlir_list.pop()
4520 lhs_indices.insert(0, self._lhs._new_index)
4521 lhs_casting_mlir += popped
4523 mlir_str += ''.join(Node.context.pop_block().get_mlir())
4524 mlir_str += lhs_casting_mlir
4526 tmp = ''.join(Node.context.pop_block().get_mlir())
4529 # Check if LHS is a flat 2D memref (Subscript[Subscript] on String-based field)
4530 lhs_is_flat_2d = False
4531 lhs_memref_name = None
4532 all_lhs_indices = []
4534 if isinstance(self._lhs, Subscript) and isinstance(self._lhs._value, Subscript):
4535 # Check if the base is a String-based field
4536 base_base = self._lhs._value._value
4537 if isinstance(base_base, DataBlock) and isinstance(base_base._internal, String):
4538 # This is a String-based field which is now a flat 2D memref
4539 lhs_is_flat_2d = True
4540 dsl_name = base_base._internal._value
4541 lhs_memref_name = Node.mlir_symbol_table[dsl_name]
4543 outer_sub = self._lhs
4544 inner_sub = self._lhs._value
4546 if hasattr(inner_sub, '_new_index'):
4547 all_lhs_indices.append(inner_sub._new_index)
4548 if hasattr(outer_sub, '_new_index'):
4549 all_lhs_indices.append(outer_sub._new_index)
4554 lhs_index_str = '[' + ','.join(all_lhs_indices) + ']'
4555 lhs_type = f"memref<?x?xf64>"
4556 mlir_str += indent + f"memref.store {rhs_value}, {lhs_memref_name}{lhs_index_str} {{name = \"{lhs_memref_name.strip('%')}\"}} : {lhs_type}\n"
4557 elif isinstance(self._lhs, Subscript) and isinstance(self._lhs._value, Subscript):
4558 base_base = self._lhs._value._value
4560 # If base is not a String field, it's a true nested memref (e.g. lambdaLeft[i][j])
4561 if not (isinstance(base_base, DataBlock) and isinstance(base_base._internal, String)):
4562 # This is a nested memref store (e.g., lambdaLeft[i][j] = value)
4564 if isinstance(self._rhs, Float):
4565 const_id = f"%{Node.get_mlir_id()}"
4566 mlir_str += indent + f"{const_id} = arith.constant {self._rhs._value} : f64\n"
4567 rhs_value = const_id
4568 elif isinstance(self._rhs, Integer):
4569 const_id = f"%{Node.get_mlir_id()}"
4570 mlir_str += indent + f"{const_id} = arith.constant {self._rhs._value} : i32\n"
4571 rhs_value = const_id
4572 elif isinstance(self._rhs, Subscript):
4573 rhs_id = f"%{Node.get_mlir_id()}"
4574 rhs_index_str = '[' + ','.join(rhs_indices) + ']'
4575 rhs_type = "memref<?xf64>" if not rhs_dims else f"memref<{ 'x'.join(rhs_dims) }xf64>"
4576 mlir_str += indent + f"{rhs_id} = memref.load {rhs}{rhs_index_str} {{name = \"{rhs.strip('%')}\"}} : {rhs_type.strip(' ')}\n"
4579 # Extract indices from nested subscript chain
4580 # lhs._value is the inner subscript, lhs is the outer subscript
4581 outer_index = self._lhs._new_index
4582 inner_memref_var = self._lhs._value._value.print_mlir(indent_level) # Base memref name
4584 # Load the inner memref from the outer nested structure
4585 inner_memref_id = f"%{Node.get_mlir_id()}"
4586 # Get the actual outer memref type from type_map
4587 base_var = self._lhs._value._value
4588 type_entry = Node.type_map[base_var.id]
4590 if isinstance(type_entry, str):
4591 outer_memref_type = type_entry
4593 outer_memref_type = type_entry.print_mlir(0).strip()
4595 # Load inner memref with first index
4596 inner_sub_index = self._lhs._value._new_index
4597 mlir_str += indent + f"{inner_memref_id} = memref.load {inner_memref_var}[{inner_sub_index}] {{name = \"{inner_memref_var.strip('%')}\"}} : {outer_memref_type}\n"
4599 # Store directly into the inner memref with the second index
4600 inner_memref_type = "memref<?xf64>" # Default inner arrays are 1D
4601 mlir_str += indent + f"memref.store {rhs_value}, {inner_memref_id}[{outer_index}] {{name = \"{inner_memref_var.strip('%')}\"}} : {inner_memref_type}\n"
4603 # Handle regular flat memref assignment (non-nested)
4604 rhs_id = f"%{Node.get_mlir_id()}"
4606 lhs_index_str = '[' + ','.join(lhs_indices) + ']'
4607 # Ensure at least one dimension for memref type
4609 lhs_type = f"memref<{ 'x'.join(lhs_dims) }xf64>"
4611 lhs_type = "memref<?xf64>"
4612 rhs_index_str = '[' + ','.join(rhs_indices) + ']'
4614 rhs_type = f"memref<{ 'x'.join(rhs_dims) }x f64>"
4616 rhs_type = "memref<?xf64>"
4618 if isinstance(self._rhs, Subscript):
4619 mlir_str += indent + f"{rhs_id} = memref.load {rhs}{rhs_index_str} {{name = \"{rhs.strip('%')}\"}} : {rhs_type.strip(' ')}\n"
4624 if isinstance(self._rhs, Float):
4625 const_id = f"%{Node.get_mlir_id()}"
4626 mlir_str += indent + f"{const_id} = arith.constant {self._rhs._value} : f64\n"
4627 rhs_value = const_id
4628 elif isinstance(self._rhs, Integer):
4629 const_id = f"%{Node.get_mlir_id()}"
4630 mlir_str += indent + f"{const_id} = arith.constant {self._rhs._value} : i32\n"
4631 rhs_value = const_id
4633 if isinstance(self._lhs, Subscript):
4634 mlir_str += indent + f"memref.store {rhs_value}, {lhs}{lhs_index_str} {{name = \"{lhs.strip('%')}\"}} : {lhs_type.strip(' ')}\n"
4636 lhs_type_obj = self._lhs.get_type()
4637 lhs_mlir_type = lhs_type_obj.print_mlir(indent_level).strip(' ')
4638 mlir_str += indent + f"memref.store {rhs_value}, {lhs} {{name = \"{lhs.strip('%')}\"}} : {lhs_mlir_type}\n"
4642 def print_tree(self, indent_level = 0):
4643 return ' ' * indent_level * Node.spaces_per_tab + f"""Assignment:
4644{self._lhs.print_tree(indent_level + 1)}
4645{self._rhs.print_tree(indent_level + 1)}"""
4648class DataBlockAssignment(Statement):
4649 def __init__(self, lhs: Expression, rhs: Expression):
4651 if type(lhs) is Name:
4652 self._lhs = Name.variables[lhs.id]
4653 self._lhs._id = lhs.id
4657 if type(rhs) is Name:
4658 self._rhs = Name.variables[rhs.id]
4662 self._lhs.on_left(True)
4663 self._rhs.on_left(False) # Just to be sure...
4668 self._loops.append(For([Integer(0), self._lhs._iteration_range[-1][1] - self._lhs._iteration_range[-1][0]]))
4669 for i in range(len(self._lhs._memory_range) - 2, -1, -1):
4670 self._loops.append(For([Integer(0), self._lhs._iteration_range[i][1] - self._lhs._iteration_range[i][0]]))
4672 for i in range(len(self._lhs._memory_range) - 1, -1, -1):
4673 index.append(self._loops[i].get_iteration_variable())
4675 if type(self._rhs.get_type()) is TDataBlock:
4677 for i in range(len(self._lhs._iteration_range)):
4678 lhs_start = self._lhs._iteration_range[i][0]
4679 rhs_start = self._rhs._iteration_range[i][0]
4680 if type(rhs_start.get_type()) is TDataBlock:
4681 rhs_start = Subscript(rhs_start, lhs_start)
4682 rhs_offset.append(lhs_start - rhs_start)
4684 rhs_offset = [Integer(0) for i in self._lhs._iteration_range]
4686 lhs_offset = [Integer(0) for i in self._lhs._iteration_range]
4688 self._loops[-1].add_statement(Assignment(self._lhs.multidimensional_index(index, dimensions=self._lhs._memory_range), self._rhs.multidimensional_index(index, dimensions=self._lhs._memory_range)))
4689 for i in range(0, len(self._loops) - 1):
4690 self._loops[i].add_statement(self._loops[i + 1])
4692 for loop in self._loops[::-1]:
4694 self._loop = self._loops[0]
4695 self._numDimensions = len(self._loops)
4697 def print_cpp(self, indent_level = 0):
4698 return self._loop.print_cpp(indent_level)
4700 def print_omp(self, indent_level = 0):
4701 if Node.use_accelerator == True:
4702 omp_pragma = "#pragma omp target teams loop collapse(Dimensions + 1) device(targetDevice)"
4704 omp_pragma = "#pragma omp parallel for simd collapse(Dimensions + 1)"
4705 return ' ' * indent_level * Node.spaces_per_tab + omp_pragma + f"""
4706{self._loop.print_omp(indent_level)}"""
4708 def print_sycl(self, indent_level = 0):
4709 #return self._loop.print_sycl(indent_level)
4710 ranges = [f"range{i} = {loop.get_interval_size().print_sycl()};" for i, loop in enumerate(self._loops[0:3])]
4711 indexing = [f"int {loop.get_iteration_variable().print_sycl()} = index[{i}];" for i, loop in enumerate(self._loops[0:3])]
4712 statement_prints = [statement.print_sycl(indent_level + 1) for statement in self._loops[2]._statements]
4713 return os.linesep.join(ranges) + "\n" + ' ' * indent_level * Node.spaces_per_tab + f"""queue.submit([&](::sycl::handler& handler) {{
4714{' ' * indent_level * Node.spaces_per_tab}handler.parallel_for(::sycl::range<3>{{range0, range1, range2}}, [=](::sycl::item<3> index) {{
4715{os.linesep.join(indexing)}
4716{os.linesep.join(statement_prints)}
4717{' ' * (indent_level + 1) * Node.spaces_per_tab}}});
4718{' ' * indent_level * Node.spaces_per_tab}}}).wait();"""
4721 def print_mlir(self, indent_level = 0):
4722 return self._loop.print_mlir(indent_level)
4724 def print_tree(self, indent_level = 0):
4725 return ' ' * indent_level * Node.spaces_per_tab + f"""DataBlockAssignment:
4726{self._lhs.print_tree(indent_level + 1)}
4727{self._rhs.print_tree(indent_level + 1)}"""
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
__init__(self, id, Type argument_type, namespace=None, is_function=False)
print_tree(self, indent_level=0)
print_cpp(self, indent_level=0)
get_mlir_arithmetic_op(operation, op_type_class)
print_sycl(self, indent_level=0)
__init__(self, operation, lhs, rhs)
print_mlir(self, indent_level=0)
cast_operand(operand_mlir, operand, result_type, indent_level)
print_omp(self, indent_level=0)
multidimensional_index(self, index, start_index=0, dimensions=[])
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
get_mlir_comparison_op(operation, op_type_class)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
__init__(self, operation, lhs, rhs)
__init__(self, operation, lhs, rhs, useFunctionSyntax=False)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
requires_memory_allocation
print_cpp(self, indent_level=0)
multidimensional_index(self, index, start_index=0, dimensions=[])
print_sycl(self, indent_level=0)
print_sycl(self, indent_level=0)
requires_memory_allocation
print_omp(self, indent_level=0)
__init__(self, operation, lhs, rhs)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
multidimensional_index(self, index, start_index=0, dimensions=[])
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
__init__(self, dataBlock, index)
print_tree(self, indent_level=0)
multidimensional_index(self, index, start_index=0, dimensions=[])
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
multidimensional_index(self, index, start_index=0, dimensions=[])
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
__init__(self, dataBlock)
print_omp(self, indent_level=0)
set_output_variable(self, outputVariable)
print_sycl(self, indent_level=0)
requires_memory_allocation
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
__init__(self, operation, dataBlock)
multidimensional_index(self, index, start_index=0, dimensions=[])
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
multidimensional_index(self, index_list, start_index=0, dimensions=[])
linearise_index(self, indices, dimensions, offset_start_index=0)
__init__(self, iteration_range, internal, requires_memory_allocation, id=None, underlying_type=String("double"))
print_tree(self, indent_level=0)
requires_memory_allocation
print_cpp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
__init__(self, id, matrix)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
__init__(self, id, matrix)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
multidimensional_index(self, index, start_index=0, dimensions=[])
__init__(self, width, internal, index_dimensions)
print_sycl(self, indent_level=0)
multidimensional_index(self, index_list, start_index=0, dimensions=[])
__init__(self, iteration_range, internal, requires_memory_allocation, id=None, underlying_type=String("double"))
multidimensional_index(self, index_list, start_index=0, dimensions=[])
__init__(self, value, string=None, reference=False)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
add_statement(self, statement)
__init__(self, iteration_range, iteration_variable_name=None, use_scheduler=False)
get_iteration_variable(self)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
add_statement(self, Statement statement)
print_declaration_with_timer(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
top_level(self, top=None)
__init__(self, id, Type return_type, template=None, namespaces=[], stateless=False, top_level=False)
print_definition_with_timer(self, indent_level=0)
print_declaration(self, indent_level=0)
add_argument(self, Argument argument)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
add_statement(self, statement)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
__init__(self, value, string=None)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
print_omp(self, indent_level=0)
__init__(self, dataBlock, filename)
print_tree(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
__init__(self, statementToLog, outputStream)
print_sycl(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
__init__(self, id, matrix)
print_mlir(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_tree(self, indent_level=0)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_cpp(self, indent_level=0)
__init__(self, dimensions, internal, index_dimensions)
print_mlir(self, indent_level=0)
index(self, row_index, column_index)
print_tree(self, indent_level=0)
multidimensional_index(self, index_list, start_index=0, dimensions=[])
print_mlir(self, indent_level=0)
__init__(self, id, type=None)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
get_mlir_type(type_string)
print_tree(self, indent_level=0)
create_memref_from_ptr(cls, ptr_id, target_type, indent_level=0, size_hint=None, target_var_name=None)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
generate_pointer_to_2d_element(memref_mlir, row_index, col_index, is_nested, indent_level=0)
create_memref_from_extracted_descriptor(cls, alloc_ptr_id, aligned_ptr_id, offset_id, sizes_0_id, sizes_1_id, strides_0_id, strides_1_id, target_type, struct_type, indent_level=0, target_var_name=None, is_2d=False)
print_sycl(self, indent_level=0)
parent(self, parent=None)
print_cpp(self, indent_level=0)
__init__(self, Expression expression)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
__init__(self, Expression value, Expression index)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
is_nested_subscript(self)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
__init__(self, type_name)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
get_mlir_type_for_operation(lhs, rhs)
ensure_const_zero(const_zero_id, indent_level)
get_array_element_info(self)
print_cpp(self, indent_level=0)
generate_memref_load(operand, operand_mlir, const_zero_id, indent_level)
needs_memref_load(operand)
print_omp(self, indent_level=0)
print_tree(self, indent_level=0)
__init__(self, dimensions, underlying_type)
print_mlir(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
__init__(self, reference=False)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
__init__(self, signature_string)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
Type for 64-bit integers (long) used in MLIRCellData struct fields.
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
__init__(self, element_type=TFloat())
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
__init__(self, element_type=TFloat(), dimensions=1)
print_tree(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_omp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_tree(self, indent_level=0)
print_tree(self, indent_level=0)
print_omp(self, indent_level=0)
__init__(self, operation, operand)
print_mlir(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_tree(self, indent_level=0)
print_mlir(self, indent_level=0)
__init__(self, Expression value, Expression index)
print_omp(self, indent_level=0)
print_cpp(self, indent_level=0)
print_sycl(self, indent_level=0)
print_tree(self, indent_level=0)
__init__(self, elements, element_type, string=None)
print_cpp(self, indent_level=0)
print_mlir(self, indent_level=0)
print_sycl(self, indent_level=0)
print_omp(self, indent_level=0)
_is_nested_memref(type_map_entry)