Reference Guide  2.5.0
psyclone.psyir.backend.opencl.OpenCLWriter Class Reference
Inheritance diagram for psyclone.psyir.backend.opencl.OpenCLWriter:
Collaboration diagram for psyclone.psyir.backend.opencl.OpenCLWriter:

Public Member Functions

def __init__ (self, skip_nodes=False, indent_string=" ", initial_indent_depth=0, kernels_local_size=1)
 
def gen_id_variable (self, symbol, dimension_index)
 
def gen_declaration (self, symbol)
 
def gen_array_length_variables (self, symbol, symtab=None)
 
def kernelschedule_node (self, node)
 
- Public Member Functions inherited from psyclone.psyir.backend.c.CWriter
def gen_indices (self, indices, var_name=None)
 
def gen_local_variable (self, symbol)
 
def assignment_node (self, node)
 
def literal_node (self, node)
 
def ifblock_node (self, node)
 
def unaryoperation_node (self, node)
 
def binaryoperation_node (self, node)
 
def intrinsiccall_node (self, node)
 
def return_node (self, _)
 
def codeblock_node (self, _)
 
def loop_node (self, node)
 
def regiondirective_node (self, node)
 
def standalonedirective_node (self, node)
 
def filecontainer_node (self, node)
 
- Public Member Functions inherited from psyclone.psyir.backend.language_writer.LanguageWriter
def __init__ (self, array_parenthesis, structure_character, skip_nodes=False, indent_string=" ", initial_indent_depth=0, check_global_constraints=True)
 
def array_parenthesis (self)
 
def structure_character (self)
 
def arrayreference_node (self, node)
 
def structurereference_node (self, node)
 
def member_node (self, node)
 
def arrayofstructuresreference_node (self, node)
 
def clause_node (self, node)
 
- Public Member Functions inherited from psyclone.psyir.backend.visitor.PSyIRVisitor
def reference_node (self, node)
 
def __call__ (self, node)
 

Detailed Description

Implements a PSyIR-to-OpenCL back-end for the PSyIR AST. This writer
produces OpenCL code conforming to Version 1.2 of the specification
(https://www.khronos.org/registry/OpenCL/specs/opencl-1.2.pdf).

:param bool skip_nodes: if skip_nodes is False then an exception \
is raised if a visitor method for a PSyIR node has not been \
implemented, otherwise the visitor silently continues. This is an \
optional argument which defaults to False.
:param str indent_string: specifies what to use for indentation. This \
is an optional argument that defaults to two spaces.
:param int initial_indent_depth: specifies how much indentation to \
start with. This is an optional argument that defaults to 0.
:param int kernel_local_size: uses the given local_size when generating \
OpenCL kernels.

:raises TypeError: if kernel_local_size is not an integer.
:raises ValueError: if kernel_local_size is not positive.

Definition at line 48 of file opencl.py.

Member Function Documentation

◆ gen_array_length_variables()

def psyclone.psyir.backend.opencl.OpenCLWriter.gen_array_length_variables (   self,
  symbol,
  symtab = None 
)
Generate length variable declaration and initialisation for each array
dimension of the given symbol. By convention they are named:
<name>LEN<DIM>, and initialised using the function:
`size_t get_global_size(uint dimindx)`.


:param symbol: The symbol instance.
:type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
:param symtab: The symbol table from the given symbol context to \
    check for name clashes.
:type symtab: :py:class:`psyclone.psyir.symbols.SymbolTable`

:return: OpenCL declaration and initialisation of length variables.
:rtype: str

:raises VisitorError: if the array length variable name clashes \
    with another symbol name.

Definition at line 150 of file opencl.py.

150  def gen_array_length_variables(self, symbol, symtab=None):
151  '''
152  Generate length variable declaration and initialisation for each array
153  dimension of the given symbol. By convention they are named:
154  <name>LEN<DIM>, and initialised using the function:
155  `size_t get_global_size(uint dimindx)`.
156 
157 
158  :param symbol: The symbol instance.
159  :type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
160  :param symtab: The symbol table from the given symbol context to \
161  check for name clashes.
162  :type symtab: :py:class:`psyclone.psyir.symbols.SymbolTable`
163 
164  :return: OpenCL declaration and initialisation of length variables.
165  :rtype: str
166 
167  :raises VisitorError: if the array length variable name clashes \
168  with another symbol name.
169  '''
170 
171  code = ""
172  dimensions = len(symbol.shape)
173  for dim in range(1, dimensions + 1):
174  code += self._nindent + "int "
175  varname = symbol.name + "LEN" + str(dim)
176 
177  # Check there is no clash with other variables
178  if symtab and varname in symtab:
179  raise VisitorError(
180  f"Unable to declare the variable '{varname}' to store the "
181  f"length of '{symbol.name}' because the Symbol Table "
182  f"already contains a symbol with the same name.")
183 
184  code += varname + " = get_global_size("
185  code += str(dim - 1) + ");\n"
186  return code
187 

References psyclone.psyir.backend.visitor.PSyIRVisitor._nindent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ gen_declaration()

def psyclone.psyir.backend.opencl.OpenCLWriter.gen_declaration (   self,
  symbol 
)
Generate the declaration of an OpenCL variable. This can be either
a local variable or a routine argument, so no indention or punctuation
is generated by this method.

Memory buffers reside in specific levels of the memory hierarchy,
and pointers are annotated with the region qualifiers __global,
__local, __constant, and __private, reflecting this.
At the moment all memory buffers (PSyIR arrays) are allocated at
the global address space.

:param symbol: The symbol instance.
:type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`

:returns: The OpenCL declaration of the given of the symbol.
:rtype: str

:raises VisitorError: if an array is encountered that does not have \
                      a lower bound of 1 for all of its dimensions.

Reimplemented from psyclone.psyir.backend.c.CWriter.

Definition at line 113 of file opencl.py.

113  def gen_declaration(self, symbol):
114  '''
115  Generate the declaration of an OpenCL variable. This can be either
116  a local variable or a routine argument, so no indention or punctuation
117  is generated by this method.
118 
119  Memory buffers reside in specific levels of the memory hierarchy,
120  and pointers are annotated with the region qualifiers __global,
121  __local, __constant, and __private, reflecting this.
122  At the moment all memory buffers (PSyIR arrays) are allocated at
123  the global address space.
124 
125  :param symbol: The symbol instance.
126  :type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
127 
128  :returns: The OpenCL declaration of the given of the symbol.
129  :rtype: str
130 
131  :raises VisitorError: if an array is encountered that does not have \
132  a lower bound of 1 for all of its dimensions.
133  '''
134  prefix = ""
135  if symbol.shape:
136  for dim in symbol.shape:
137  if not isinstance(dim, ArrayType.ArrayBounds):
138  continue
139  if (not isinstance(dim.lower, Literal) or
140  dim.lower.value != "1"):
141  raise VisitorError(
142  f"The OpenCL backend only supports arrays with a lower"
143  f" bound of 1 in each dimension. However, array "
144  f"'{symbol.name}' has a lower bound of "
145  f"'{self._visit(dim.lower)}' for dimension "
146  f"{symbol.shape.index(dim)}")
147  prefix += "__global "
148  return prefix + super(OpenCLWriter, self).gen_declaration(symbol)
149 
Here is the caller graph for this function:

◆ gen_id_variable()

def psyclone.psyir.backend.opencl.OpenCLWriter.gen_id_variable (   self,
  symbol,
  dimension_index 
)
Generate the declaration and initialisation of a variable identifying
an OpenCL work-item. IDs are initialised by the OpenCL function:
`size_t get_global_id(uint dimindx)`

:param symbol: The symbol instance.
:type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
:param int dimension_index: Dimension which the given symbol will \
    iterate on.

:returns: OpenCL declaration of an OpenCL id variable.
:rtype: str

:raises VisitorError: if symbol is not a scalar integer

Definition at line 86 of file opencl.py.

86  def gen_id_variable(self, symbol, dimension_index):
87  '''
88  Generate the declaration and initialisation of a variable identifying
89  an OpenCL work-item. IDs are initialised by the OpenCL function:
90  `size_t get_global_id(uint dimindx)`
91 
92  :param symbol: The symbol instance.
93  :type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
94  :param int dimension_index: Dimension which the given symbol will \
95  iterate on.
96 
97  :returns: OpenCL declaration of an OpenCL id variable.
98  :rtype: str
99 
100  :raises VisitorError: if symbol is not a scalar integer
101  '''
102  if (not isinstance(symbol.datatype, ScalarType) or
103  symbol.datatype.intrinsic != ScalarType.Intrinsic.INTEGER):
104  raise VisitorError(
105  f"OpenCL work-item identifiers must be scalar integer symbols "
106  f"but found {symbol}.")
107 
108  code = ""
109  code += self._nindent + "int " + symbol.name
110  code += " = get_global_id(" + str(dimension_index) + ");\n"
111  return code
112 

References psyclone.psyir.backend.visitor.PSyIRVisitor._nindent().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ kernelschedule_node()

def psyclone.psyir.backend.opencl.OpenCLWriter.kernelschedule_node (   self,
  node 
)
This method is called when a KernelSchedule instance is found in
the PSyIR tree.

:param node: A KernelSchedule PSyIR node.
:type node: :py:class:`psyclone.psyir.nodes.KernelSchedule`

:returns: The OpenCL code as a string.
:rtype: str

:raises VisitorError: if a non-precision symbol is found with a \
                      UnresolvedInterface.

Definition at line 188 of file opencl.py.

188  def kernelschedule_node(self, node):
189  '''This method is called when a KernelSchedule instance is found in
190  the PSyIR tree.
191 
192  :param node: A KernelSchedule PSyIR node.
193  :type node: :py:class:`psyclone.psyir.nodes.KernelSchedule`
194 
195  :returns: The OpenCL code as a string.
196  :rtype: str
197 
198  :raises VisitorError: if a non-precision symbol is found with a \
199  UnresolvedInterface.
200  '''
201  # OpenCL implementation assumptions:
202  # - All array have the same size and it is given by the
203  # global_work_size argument to clEnqueueNDRangeKernel.
204  # - Assumes no dependencies among kernels called concurrently.
205  # - All real variables are 64-bit
206 
207  # TODO: At the moment, the method caller is responsible to ensure
208  # these assumptions. KernelSchedule access to the kernel
209  # meta-arguments could be used to check them and also improve the
210  # generated code. (Issue #288)
211 
212  symtab = node.symbol_table
213  data_args = symtab.data_arguments
214 
215  # Check that we know where everything in the symbol table
216  # comes from. TODO #592 ultimately precision symbols should
217  # be included in this check too as we will need to be able to
218  # map from them to the equivalent OpenCL type.
219  unresolved_datasymbols = list(set(symtab.unresolved_datasymbols) -
220  set(symtab.precision_datasymbols))
221  if unresolved_datasymbols:
222  symbols_txt = ", ".join(
223  [f"'{sym.name}'" for sym in unresolved_datasymbols])
224  raise VisitorError(
225  f"Cannot generate OpenCL because the symbol table contains "
226  f"unresolved data entries (i.e. that have no defined "
227  f"Interface) which are not used purely to define the "
228  f"precision of other symbols: {symbols_txt}")
229 
230  # Start OpenCL kernel definition
231  code = self._nindent
232  if self._kernels_local_size != 1:
233  code += f"__attribute__((reqd_work_group_size("\
234  f"{self._kernels_local_size}, 1, 1)))\n"
235  code += "__kernel void " + node.name + "(\n"
236  self._depth += 1
237  arguments = []
238 
239  # Declare kernel arguments
240  for symbol in data_args:
241  arguments.append(self._nindent + self.gen_declaration(symbol))
242  code += ",\n".join(arguments) + "\n"
243  code += self._nindent + "){\n"
244 
245  # Declare local variables.
246  for symbol in symtab.automatic_datasymbols:
247  code += self.gen_local_variable(symbol)
248 
249  # Declare array length
250  for symbol in data_args:
251  code += self.gen_array_length_variables(symbol, symtab)
252 
253  # Declare iteration indices
254  for index, symbol in enumerate(symtab.iteration_indices):
255  code += self.gen_id_variable(symbol, index)
256 
257  # Generate kernel body
258  for child in node.children:
259  code += self._visit(child)
260 
261  # Close kernel definition
262  self._depth -= 1
263  code += self._nindent + "}\n\n"
264 
265  return code

References psyclone.psyir.backend.visitor.PSyIRVisitor._depth, psyclone.psyir.backend.opencl.OpenCLWriter._kernels_local_size, psyclone.psyir.backend.visitor.PSyIRVisitor._nindent(), psyclone.psyir.backend.visitor.PSyIRVisitor._visit(), psyclone.psyir.backend.opencl.OpenCLWriter.gen_array_length_variables(), psyclone.psyir.backend.c.CWriter.gen_declaration(), psyclone.psyir.backend.opencl.OpenCLWriter.gen_declaration(), psyclone.psyir.backend.opencl.OpenCLWriter.gen_id_variable(), and psyclone.psyir.backend.c.CWriter.gen_local_variable().

Here is the call graph for this function:

The documentation for this class was generated from the following file: