Kernel Translation#
The Kernel Creation Context#
- class pystencils.backend.kernelcreation.KernelCreationContext(default_dtype=PsIeeeFloatType(width=64, const=False), index_dtype=PsIntegerType(width=64, signed=True, const=False))#
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.
- Parameters:
default_dtype (PsNumericType)
index_dtype (PsIntegerType)
- property default_dtype: PsNumericType#
Data type used by default for numerical expressions
- property index_dtype: PsIntegerType#
Data type used by default for index expressions
- resolve_dynamic_type(dtype)#
Selects the appropriate data type for
DynamicType
instances, and returns all other types as they are.- Return type:
- Parameters:
dtype (DynamicType | PsType)
- get_symbol(name, dtype=None)#
Retrieve the symbol with the given name and data type from the symbol table.
If no symbol named
name
exists, a new symbol with the given data type is created.If a symbol with the given
name
already exists anddtype
is notNone
, the given data type will be applied to it, and it is returned. If the symbol already has a different data type, an error will be raised.If the symbol already exists and
dtype
isNone
, the existing symbol is returned without checking or altering its data type.
- get_new_symbol(name, dtype=None)#
Always create a new symbol, deduplicating its name if another symbol with the same name already exists.
- find_symbol(name)#
Find a symbol with the given name in the symbol table, if it exists.
- add_symbol(symbol)#
Add an existing symbol to the symbol table.
If a symbol with the same name already exists, an error will be raised.
- Parameters:
symbol (PsSymbol)
- replace_symbol(old, new)#
Replace one symbol by another.
The two symbols
old
andnew
must have the same name, but may have different data types.
- duplicate_symbol(symb, new_dtype=None)#
Canonically duplicates the given symbol.
A new symbol with the new name
symb.name + "__<counter>"
and optionally a different data type is created, added to the symbol table, and returned. Thecounter
reflects the number of previously created duplicates of this symbol.
- basename(symb)#
Returns the original name a symbol had before duplication.
- property fields: FieldsInKernel#
Collection of fields that occured during the current kernel translation.
- add_field(field)#
Add the given field to the context’s fields collection.
This method adds the passed
field
to the context’s field collection, which is accesible through thefield
member, and creates the underlying buffer for the field which is retrievable throughget_buffer
. Before adding the field to the collection, various sanity and constraint checks are applied.- Parameters:
field (Field)
- get_buffer(field)#
Retrieve the underlying array for a given field.
If the given field was not previously registered using
add_field
, this method internally callsadd_field
to check the field for consistency.
- set_iteration_space(ispace)#
Set the iteration space used for the current kernel.
- Parameters:
ispace (IterationSpace)
Analysis and Constraints Checks#
- class pystencils.backend.kernelcreation.KernelAnalysis(ctx, check_access_independence=True, check_double_writes=True)#
General analysis pass over a kernel expressed using the SymPy frontend.
The kernel analysis fulfills two tasks. It checks the SymPy input for consistency, and populates the context with required knowledge about the kernel.
A
KernelAnalysis
object may be called at most once.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 indexi
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
- The following knowledge is collected into the context:
The set of fields accessed in the kernel
- Parameters:
ctx (KernelCreationContext)
check_access_independence (bool)
check_double_writes (bool)
SymPy Parsing and IR Construction#
- class pystencils.backend.kernelcreation.AstFactory(ctx)#
Factory providing a convenient interface for building syntax trees.
The
AstFactory
uses the defaults provided by the givenKernelCreationContext
to quickly create AST nodes. Depending on context (numerical, loop indexing, etc.), symbols and constants receive eitherctx.default_dtype
orctx.index_dtype
.- Parameters:
ctx (
KernelCreationContext
) – The kernel creation context
- parse_sympy(sp_obj)#
Parse a SymPy expression or assignment through
FreezeExpressions
andTypifier
.The expression or assignment will be typified in a numerical context, using the kernel creation context’s
default_dtype
.- Parameters:
sp_obj (
Expr
|Tuple
|Relational
|BooleanFunction
|AssignmentBase
) – A SymPy expression or assignment- Return type:
- parse_index(idx)#
Parse the given object as an expression with data type
ctx.index_dtype
.- Parameters:
idx (PsExpression | PsSymbol | PsConstant | Expr | int | integer)
- parse_slice(iter_slice, normalize_to=None)#
Parse a slice to obtain start, stop and step expressions for a loop or iteration space dimension.
The slice entries may be instances of
PsExpression
,PsSymbol
orPsConstant
, in which case they must typify with the kernel creation context’sindex_dtype
. They may also be sympy expressions or integer constants, in which case they are parsed to AST objects and must also typify with the kernel creation context’sindex_dtype
.The
step
member of the slice, if it is constant, must be positive.The slice may optionally be normalized with respect to an upper iteration limit. If
normalize_to
is specified, negative integers initer_slice.start
anditer_slice.stop
will be added to that normalization limit.- Parameters:
iter_slice (
PsExpression
|PsSymbol
|PsConstant
|Expr
|int
|integer
|slice
) – The iteration slicenormalize_to (
Union
[PsExpression
,PsSymbol
,PsConstant
,Expr
,int
,integer
,None
]) – The upper iteration limit with respect to which the slice should be normalized
- Return type:
- loop(ctr_name, iteration_slice, body)#
Create a loop from a slice.
- Parameters:
ctr_name (
str
) – Name of the loop counteriteration_slice (
slice
) – The iteration region as a slice; seeparse_slice
.body (
PsBlock
) – The loop body
- loop_nest(counters, slices, body)#
Create a loop nest from a sequence of slices.
Example: This snippet creates a 3D loop nest with ten iterations in each dimension:
>>> from pystencils import make_slice >>> ctx = KernelCreationContext() >>> factory = AstFactory(ctx) >>> loop = factory.loop_nest(("i", "j", "k"), make_slice[:10,:10,:10], PsBlock([]))
- loops_from_ispace(ispace, body, loop_order=None)#
Create a loop nest from a dense iteration space.
- class pystencils.backend.kernelcreation.FreezeExpressions(ctx)#
Convert expressions and kernels expressed in the SymPy language to the code generator’s internal representation.
This class accepts a subset of the SymPy symbolic algebra language complemented with the extensions implemented in
pystencils.sympyextensions
, and converts it to the abstract syntax tree representation of the pystencils code generator. It is invoked early during the code generation process.TODO: Document the full set of supported SymPy features, with restrictions and caveats TODO: Properly document the SymPy extensions provided by pystencils
- Parameters:
ctx (KernelCreationContext)
- map_Function(func)#
Map SymPy function calls by mapping sympy function classes to backend-supported function symbols.
If applicable, functions are mapped to binary operators, e.g.
PsBitwiseXor
. Other SymPy functions are frozen to an instance ofPsFunction
.- Return type:
- Parameters:
func (Function)
Type Checking and Inference#
- class pystencils.backend.kernelcreation.typification.TypeContext(target_type=None)#
Typing context, with support for type inference and checking.
Instances of this class are used to propagate and check data types across expression subtrees of the AST. Each type context has a target type
target_type
, which shall be applied to all expressions it covers.Just like the types of expressions, the context’s target type must never be
const
. This is ensured by this class, which removes const-qualification from the target type when it is set.- Parameters:
target_type (PsType | None)
- add_hook(hook)#
Adds a resolution hook to this context.
The hook will be called with the context’s target type as soon as it becomes known, which might be immediately.
- apply_dtype(dtype, expr=None)#
Applies the given
dtype
to this type context, and optionally to the given expression.If the context’s target_type is already known, it must be compatible with the given dtype. If the target type is still unknown, target_type is set to dtype and retroactively applied to all deferred expressions.
If an expression is specified, it will be covered by the type context. If the expression already has a data type set, it must be compatible with the target type and will be replaced by it.
- Parameters:
dtype (PsType)
expr (PsExpression | None)
- infer_dtype(expr)#
Infer the data type for the given expression.
If the target_type of this context is already known, it will be applied to the given expression. Otherwise, the expression is deferred, and a type will be applied to it as soon as
apply_dtype
is called on this context.If the expression already has a data type set, it must be compatible with the target type and will be replaced by it.
- Parameters:
expr (PsExpression)
- class pystencils.backend.kernelcreation.Typifier(ctx)#
Apply data types to expressions.
Contextual Typing
The Typifier will traverse the AST and apply a contextual typing scheme to figure out the data types of all encountered expressions. To this end, it covers each expression tree with a set of disjoint typing contexts. All nodes covered by the same typing context must have the same type.
Starting from an expression’s root, a typing context is implicitly expanded through the recursive descent into a node’s children. In particular, a child is typified within the same context as its parent if the node’s semantics require parent and child to have the same type (e.g. at arithmetic operators, mathematical functions, etc.). If a node’s child is required to have a different type, a new context is opened.
For each typing context, its target type is prescribed by the first node encountered during traversal whose type is fixed according to its typing rules. All other nodes covered by the context must share that type.
The types of arithmetic operators, mathematical functions, and untyped constants are inferred from their context’s target type. If one of these is encountered while no target type is set yet in the context, the expression is deferred by storing it in the context, and will be assigned a type as soon as the target type is fixed.
Typing Rules
The following general rules apply:
The context’s
default_dtype
is applied to all untyped symbols encountered inside a right-hand side expressionIf an untyped symbol is encountered on an assignment’s left-hand side, it will first be attempted to infer its type from the right-hand side. If that fails, the context’s
default_dtype
will be applied.It is an error if an untyped symbol occurs in the same type context as a typed symbol or constant with a non-default data type.
By default, all expressions receive a
const
type unless they occur on a (non-declaration) assignment’s left-hand side
Typing of symbol expressions
Some expressions (
PsSymbolExpr
,PsBufferAcc
) encapsulate symbols and inherit their data types.- Parameters:
ctx (KernelCreationContext)
- visit(node)#
Recursive processing of structural nodes
- visit_expr(expr, tc)#
Recursive processing of expression nodes.
This method opens, expands, and closes typing contexts according to the respective expression’s typing rules. It may add or check restrictions only when opening or closing a type context.
The actual type inference and checking during context expansion are performed by the methods of
TypeContext
.visit_expr
tells the typing context how to handle an expression by calling eitherapply_dtype
orinfer_dtype
.- Return type:
- Parameters:
expr (PsExpression)
tc (TypeContext)