From 24b61fcfe1aed4f87fc77262ad98fffbd1036b96 Mon Sep 17 00:00:00 2001 From: Frederik Hennig <frederik.hennig@fau.de> Date: Tue, 12 Mar 2024 10:44:52 +0100 Subject: [PATCH] extended backend documentation --- docs/source/backend/index.rst | 102 +++++++++++++++++- docs/source/backend/iteration_space.rst | 6 ++ docs/source/backend/kernelcreation.rst | 7 -- docs/source/backend/platforms.rst | 6 ++ docs/source/backend/translation.rst | 15 +++ .../backend/kernelcreation/__init__.py | 99 ----------------- .../backend/kernelcreation/analysis.py | 18 ++-- .../backend/kernelcreation/context.py | 22 ++-- .../backend/kernelcreation/iteration_space.py | 8 ++ 9 files changed, 154 insertions(+), 129 deletions(-) create mode 100644 docs/source/backend/iteration_space.rst delete mode 100644 docs/source/backend/kernelcreation.rst create mode 100644 docs/source/backend/platforms.rst create mode 100644 docs/source/backend/translation.rst diff --git a/docs/source/backend/index.rst b/docs/source/backend/index.rst index 24567e6ff..e9ac5237b 100644 --- a/docs/source/backend/index.rst +++ b/docs/source/backend/index.rst @@ -3,12 +3,110 @@ Developer's Reference: Code Generation Backend ############################################## These pages provide a detailed overview of the pystencils code generation backend -as a reference for current and future developers of pystencils. +as a reference for current and future developers of pystencils, as well as users +who wish to customize or extend the behaviour of the code generator in their applications. .. toctree:: :maxdepth: 1 symbols ast - kernelcreation + iteration_space + translation + platforms jit + +Internal Representation +----------------------- + +The code generator translates the kernel from the SymPy frontend's symbolic language to an internal +representation (IR), which is then emitted as code in the required dialect of C. +All names of classes associated with the internal kernel representation are prefixed `Ps...` +to distinguis them from identically named front-end and SymPy classes. +The IR comprises *symbols*, *constants*, *arrays*, the *iteration space* and the *abstract syntax tree*: + +* `PsSymbol` represents a single symbol in the kernel, annotated with a type. Other than in the frontend, + uniqueness of symbols is enforced by the backend: of each symbol, at most one instance may exist. +* `PsConstant` provides a type-safe representation of constants. +* `PsLinearizedArray` is the backend counterpart to the ubiquitous `Field`, representing a contiguous + n-dimensional array. + These arrays do not occur directly in the IR, but are represented through their *associated symbols*, + which are base pointers, shapes, and strides. +* The iteration space (`IterationSpace`) represents the kernel's iteration domain. + Currently, dense iteration spaces (`FullIterationSpace`) and an index list-based + sparse iteration spaces (`SparseIterationSpace`) are available. +* The *Abstract Syntax Tree* (AST) is implemented in the `pystencils.backend.ast` module. + It represents a subset of standard C syntax, as required for pystencils kernels. + + +Kernel Creation +--------------- + +Translating a kernel's symbolic representation to compilable code takes various analysis, transformation, and +optimization passes. These are implemented modularily, each represented by its own class. +They are tied together in the kernel translation *driver* and communicate with each other through the +`KernelCreationContext`, which assembles all relevant information. +The primary translation driver implemented in pystencils is the ubiquitous `create_kernel`. +However, the backend is designed to make it easy for users and developers to implement custom translation +drivers if necessary. + +The various functional components of the kernel translator are best explained in the order they are invoked +by `create_kernel`. + +Analysis and Constraint Checks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The `KernelAnalysis` pass parses the SymPy assignment list and checks it for the consistency requirements +of the code generator, including the absence of loop-carried dependencies and the static single-assignment form. +Furthermore, it populates the `KernelCreationContext` with information about all fields encountered in the kernel. + +Creation of the Iteration Space +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Before the actual translation can begin, the kernel's iteration space must be defined. +The `pystencils.backend.kernelcreation.iteration_space` module provides various means of creating iteration spaces, +which are used by *create_kernel* according to its input configuration. +To communicate the presence of an iteration space to other components, it must be set in the context using +`KernelCreationContext.set_iteration_space`. +It will be used during the *freeze* pass, and later be materialized to a loop nest or GPU index translation. + +Freeze and Typification +^^^^^^^^^^^^^^^^^^^^^^^ + +The transformation of the SymPy expressions to the backend's AST is handled by `FreezeExpressions`. +This class instantiates field accesses according to the iteration space, maps SymPy operators and functions to their +backend instances, and raises an exception if asked to translate something the backend can't handle. + +Constants and untyped symbols in the frozen expressions now need to be assigned a data type, and expression types +need to be checked against the C typing rules. This is the task of the `Typifier`. It assigns a default type to +every untyped symbol, attempts to infer the type of constants from their context in the expression, +and checks expression types using a stricter subset of the C typing rules, +allowing for no implicit type casts even between closely related types. +After the typification pass, the code generator either has a fully and correctly typed kernel body in hand, +or it has raised an exception. + +Platform Selection and Materialization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The various hardware platforms supported by pystencils are implemented in the `pystencils.backend.platforms` module. +Each implements a target-specific materialization of generic backend components, including: + +- The iteration space, which is materialized to a specific index source. This might be a loop nest for CPU kernels, or + a thread index translation for GPU kernels +- Mathematical functions, which might have to be mapped to concrete library functions +- Vector data types and operations, which are mapped to intrinsics on vector CPU architectures + +Transformations +^^^^^^^^^^^^^^^ + +TODO + +Target-Specific Optimization +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +TODO + +Finalization +^^^^^^^^^^^^ + +TODO diff --git a/docs/source/backend/iteration_space.rst b/docs/source/backend/iteration_space.rst new file mode 100644 index 000000000..b1444eadb --- /dev/null +++ b/docs/source/backend/iteration_space.rst @@ -0,0 +1,6 @@ +**************** +Iteration Spaces +**************** + +.. automodule:: pystencils.backend.kernelcreation.iteration_space + :members: \ No newline at end of file diff --git a/docs/source/backend/kernelcreation.rst b/docs/source/backend/kernelcreation.rst deleted file mode 100644 index 2451b8a8c..000000000 --- a/docs/source/backend/kernelcreation.rst +++ /dev/null @@ -1,7 +0,0 @@ -*************** -Kernel Creation -*************** - -.. automodule:: pystencils.kernelcreation - :members: - diff --git a/docs/source/backend/platforms.rst b/docs/source/backend/platforms.rst new file mode 100644 index 000000000..68b74504c --- /dev/null +++ b/docs/source/backend/platforms.rst @@ -0,0 +1,6 @@ +********* +Platforms +********* + +.. automodule:: pystencils.backend.platforms + :members: \ No newline at end of file diff --git a/docs/source/backend/translation.rst b/docs/source/backend/translation.rst new file mode 100644 index 000000000..157675980 --- /dev/null +++ b/docs/source/backend/translation.rst @@ -0,0 +1,15 @@ +****************** +Kernel Translation +****************** + +.. autoclass:: pystencils.backend.kernelcreation.KernelCreationContext + :members: + +.. autoclass:: pystencils.backend.kernelcreation.KernelAnalysis + :members: + +.. autoclass:: pystencils.backend.kernelcreation.FreezeExpressions + :members: + +.. autoclass:: pystencils.backend.kernelcreation.Typifier + :members: diff --git a/src/pystencils/backend/kernelcreation/__init__.py b/src/pystencils/backend/kernelcreation/__init__.py index dea2db232..978616769 100644 --- a/src/pystencils/backend/kernelcreation/__init__.py +++ b/src/pystencils/backend/kernelcreation/__init__.py @@ -1,102 +1,3 @@ -""" -The `kernelcreation` module contains the actual translation logic of the pystencils code generator. -It provides a number of classes and submodules providing the various parts and passes of the code -generation process: - - - Parameterization of the translation process - - Knowledge collection and management - - Kernel analysis and constraints checks - - Expression parsing and AST construction - - Platform-specific code materialization - - General and platform-specific optimizations - -These components are designed to be combined and composed in a variety of ways, depending -on the actual code generation flow required. -The ``nbackend`` currently provides one native code generation driver: -`create_kernel` takes an `AssignmentCollection` and translates it to a simple loop kernel. -The code generator's components are perhaps most easily introduced in the context of that particular driver. - -Exemplary Code Generation Driver: `create_kernel` -------------------------------------------------- - -Generator Arguments -^^^^^^^^^^^^^^^^^^^ - -The driver accepts two parameters: an `AssignmentCollection` whose assignments represent the code of a single -kernel iteration without recurrences or other loop-carried dependencies; and a `CreateKernelConfig` which configures -the translation process. - -Context Creation -^^^^^^^^^^^^^^^^ - -The primary object that stores all information and knowledge required during the translation process is the -`KernelCreationContext`. It is created in the beginning from the configuration parameter. -It will be responsible for managing all fields and arrays encountered during translation, -the kernel's iteration space, -and any parameter constraints introduced by later transformation passes. - -Analysis Passes -^^^^^^^^^^^^^^^ - -Before the actual translation of the SymPy-based assignment collection to the backend's AST begins, -the kernel's assignments are checked for consistency with the translator's prequesites. -In this case, the `KernelAnalysis` pass -checks the static single assignment-form (SSA) requirement and the absence of loop-carried dependencies. -At the same time, it collects the set of all fields used in the assignments. - -Iteration Space Creation -^^^^^^^^^^^^^^^^^^^^^^^^ - -The kernel's `IterationSpace` is inferred from a combination of configuration parameters and the set of field accesses -encountered in the kernel. Two kinds of iteration spaces are available: A sparse iteration space -(`SparseIterationSpace`) encompasses singular points in the cartesian coordinate space, provided by an index list. -A full iteration space (`FullIterationSpace`), on the other hand, represents a full cuboid cartesian coordinate space, -which may optionally be sliced. - -The iteration space is used during the following translation passes to translate field accesses with respect to -the current iteration. It will only be instantiated in the form of a loop nest or GPU index calculation much later. - -Freeze and Typification -^^^^^^^^^^^^^^^^^^^^^^^ - -The transformation of the SymPy-expressions to the backend's expression trees is handled by `FreezeExpressions`. -This class instantiates field accesses according to the iteration space, maps SymPy operators and functions to their -backend instances if supported, and raises an exception if asked to translate something the backend can't handle. - -Constants and untyped symbols in the frozen expressions now need to be assigned a data type, and expression types -need to be checked against the C typing rules. This is the task of the `Typifier`. It assigns a default type to -every untyped symbol, attempts to infer the type of constants from their context in the expression, -and checks expression types using a much stricter -subset of the C typing rules, allowing for no implicit type casts even between closely related types. -After the typification pass, the code generator either has a fully and correctly typed kernel body in hand, -or it has raised an exception. - -Platform-Specific Iteration Space Materialization -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -At this point, most remaining transformations are specific to the target platform. Hardware platforms are modelled -using subclasses of the `Platform` class, which implement all platform-specific transformations. -The platform for the current code generation flow is instantiated from the target specification passed -by the user in `CreateKernelConfig`. -Then, the platform is asked to materialize the iteration space (e.g. by turning it into a loop nest -for CPU code) and to materialize any functions for which it provides specific implementations. - -Platform-Specific Optimizations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Technically, the kernel is now complete, but it may still be optimized. -This is also the task of the platform instance. Potential optimizations include the inclusion of OpenMP, -loop splitting, slicing and blocking on CPUs, -and vectorization on CPU platforms with vector capabilities. - -Finalization -^^^^^^^^^^^^ - -At last, the kernel is packed up as a `KernelFunction`. -It is furthermore annotated with constraints collected during the translation, and returned to the user. - -""" - from .context import KernelCreationContext from .analysis import KernelAnalysis from .freeze import FreezeExpressions diff --git a/src/pystencils/backend/kernelcreation/analysis.py b/src/pystencils/backend/kernelcreation/analysis.py index c43452cc4..a72191b5b 100644 --- a/src/pystencils/backend/kernelcreation/analysis.py +++ b/src/pystencils/backend/kernelcreation/analysis.py @@ -22,21 +22,19 @@ class KernelAnalysis: A `KernelAnalysis` object may be called at most once. - Consistency and Constraints - --------------------------- + **Consistency and Constraints** The following checks are performed: - - **SSA Form:** The given assignments must be in single-assignment form; each symbol must be written at most once. - - **Independence of Accesses:** To avoid loop-carried dependencies, each field may be written at most once at - each index, and if a field is written at some location with index `i`, it may only be read with index `i` in - the same location. - - **Independence of Writes:** A weaker requirement than access independence; each field may only be written once - at each index. + - **SSA Form:** The given assignments must be in single-assignment form; each symbol must be written at most once. + - **Independence of Accesses:** To avoid loop-carried dependencies, each field may be written at most once at + each index, and if a field is written at some location with index `i`, it may only be read with index `i` in + the same location. + - **Independence of Writes:** A weaker requirement than access independence; each field may only be written once + at each index. - **Dimension of index fields:** Index fields occuring in the kernel must have exactly one spatial dimension. - Knowledge Collection - -------------------- + **Knowledge Collection** The following knowledge is collected into the context: - The set of fields accessed in the kernel diff --git a/src/pystencils/backend/kernelcreation/context.py b/src/pystencils/backend/kernelcreation/context.py index 7bf75f69b..5ce373797 100644 --- a/src/pystencils/backend/kernelcreation/context.py +++ b/src/pystencils/backend/kernelcreation/context.py @@ -43,17 +43,17 @@ class KernelCreationContext: """Manages the translation process from the SymPy frontend to the backend AST, and collects all necessary information for the translation: - - *Data Types*: The kernel creation context manages the default data types for loop limits - and counters, index calculations, and the typifier. - - *Symbols*: The context maintains a symbol table, keeping track of all symbols encountered - during kernel translation together with their types. - - *Fields and Arrays*: The context collects all fields encountered during code generation, - applies a few consistency checks to them, and manages their associated arrays. - - *Iteration Space*: The context manages the iteration space of the kernel currently being - translated. - - *Constraints*: The context collects all kernel parameter constraints introduced during the - translation process. - - *Required Headers*: The context collects all header files required for the kernel to run. + - *Data Types*: The kernel creation context manages the default data types for loop limits + and counters, index calculations, and the typifier. + - *Symbols*: The context maintains a symbol table, keeping track of all symbols encountered + during kernel translation together with their types. + - *Fields and Arrays*: The context collects all fields encountered during code generation, + applies a few consistency checks to them, and manages their associated arrays. + - *Iteration Space*: The context manages the iteration space of the kernel currently being + translated. + - *Constraints*: The context collects all kernel parameter constraints introduced during the + translation process. + - *Required Headers*: The context collects all header files required for the kernel to run. """ diff --git a/src/pystencils/backend/kernelcreation/iteration_space.py b/src/pystencils/backend/kernelcreation/iteration_space.py index 3a7143bc2..7d6404380 100644 --- a/src/pystencils/backend/kernelcreation/iteration_space.py +++ b/src/pystencils/backend/kernelcreation/iteration_space.py @@ -233,6 +233,8 @@ class FullIterationSpace(IterationSpace): class SparseIterationSpace(IterationSpace): + """Represents a sparse iteration space defined by an index list.""" + def __init__( self, spatial_indices: Sequence[PsSymbol], @@ -264,6 +266,12 @@ def get_archetype_field( check_same_layouts: bool = True, check_same_dimensions: bool = True, ): + """Retrieve an archetype field from a collection of fields, which represents their common properties. + + Raises: + KernelConstrainsError: If any two fields with conflicting properties are encountered. + """ + shapes = set(f.spatial_shape for f in fields) fixed_shapes = set(f.spatial_shape for f in fields if f.has_fixed_shape) layouts = set(f.layout for f in fields) -- GitLab