# Tensor Operator Set Architecture (TOSA) Dialect

[TOC]

## Rationale

The MLIR TOSA dialect implements the [TOSA
specification](https://www.mlplatform.org/tosa/tosa_spec.html). This document
describes the decision process for how TOSA expresses operators in
high level dialects.

TOSA was developed after parallel efforts to rationalize the top-down picture
from multiple high-level frameworks, as well as a bottom-up view of different
hardware target concerns (CPU, GPU and NPU), and reflects a set of choices
that attempt to manage both sets of requirements.

## TOSA and Tensor Level Expressiveness

TOSA endeavors to provide an operator set that tries to fulfil the following
expressiveness goals at the *tensor level of abstraction* :

### Complete

This is driven by the top-down perspective, needing to express as much of
multiple high level frameworks fully in TOSA, as possible. This was originally
done from an operator frequency analysis done upon dozens of high level
networks in different frameworks, to select the most frequently occurring ones
and establish a common set of tensor-level operators that could express them.

TOSA categorizes its operator set into classes and attempts to address major
functional operations at the tensor level, including compute, reduction,
elementwise transformations, comparison and control flow.

### Minimal

This takes the bottom-up approach - keep the TOSA operator set minimal in
order to bound the design of hardware, operator kernels, code generation
strategies and associated considerations that effect the executability of TOSA
content.

In this regard TOSA seeks to avoid creating compound operators, instead
leaving it to compiler backend to fuse multiple TOSA ops if required. This
choice also benefits the numerical precision goal, since it is easier to fuse the
numerical functionality of successive operators, than to split the numerical
functionality of a compound operator.

### Numerical Precision

TOSA began as a means to address operator-level numerical precision for
code generation and hardware development. It therefore incorporates precision
detail into the operator set.

In this regard, TOSA operators are best understood as a combination of the visible
quantization information embedded within an operation, together with the
functional information about how that information is used, as described in the
specification of the operation.

## TOSA Operator Rationale

The general basis of selection of the operator set that constitutes TOSA is
described in the TOSA specification document  under Section 1.3 Operator
Selection. Explanation of the thinking behind some operators is listed here:

### COND\_IF and WHILE\_LOOP

Several neural networks express conditional control flow at the tensor level.
A survey of multiple high level frameworks indicated that conditional if and
a loop construct are common in all major frameworks, with some variation.
Since TOSA endeavors to be complete in expressing tensor level functionality
including control flow, it implements these constructs.

The COND\_IF and WHILE\_LOOP operators implement such structured control
flow forms and should be lowerable to corresponding ops in the scf dialect.
Since the dialect seeks to remain isomorphic with an external, serialized form,
the decision was to keep these ops in the dialect (as opposed to deferring
completely to scf), and this may be re-evaluated if this turns out to not yield
the expected value.

## Using TOSA In A Compiler

The TOSA specification describes each operator in functional detail. It is
expected that compilers that use TOSA will use its builders to construct the
operators so that the quantization information for the operator is correctly
generated.

The functional steps described in the pseudocode of the specification enables
the construction of code generation for that operation, or decisions on the
design of underlying hardware. The functional pseudocode also describes
how the quantization parameters are utilized within the operation.

### Quantization Parameters in Ops vs Tensors

TOSA uses the quantization parameters embedded in the input and output
tensors to construct the quantization attributes that sit within the operator.
Once these attributes are constructed, the quantization information within
the tensors are no longer necessary for code generation.

This enables the tensors to be subsequently interpreted simply as contiguous
buffers containing raw data, with no 'meta information' in the form of the
quantization_type. Precision related manipulation of the input or output are
instead described by the operator itself which describes, for example, when
the zero point is applied, or when the scale multiplication is done.

However, TOSA does *not* eliminate the existing MLIR QuantOps quantization
type information within the tensors; this leaves the choice of how to handle
quantization information, to later backend code generation steps.

Maintaining the ability to overlap these different representations of
quantization parameters (i.e. tensor-carried vs op-carried) is an important
capability when considering progressive lowering between uses that expect one
scheme vs the other.

## Operation definitions

[include "Dialects/TosaOps.md"]

### Operation purity
Some TOSA operations may exhibit undefined behaviour. In the TOSA specification
this is indicated by a `REQUIRE` condition in the operation pesudo-code. An
implementation is not required to detect unpredictable behaviour, see
[Section 4.3](https://www.mlplatform.org/tosa/tosa_spec_1_0_0.html#_operator_validation_helpers).

If an operation can exhibit undefined behaviour, speculating or reordering it
may change program behaviour. For example, `INTDIV` may exhibit undefined
behaviour if the divisor is zero. If such an operation were speculated it could
be executed in situations where the original program would not have executed
it.

Therefore, operations that may exhibit undefined behaviour must not declare
the `AlwaysSpeculatable` trait and should not be treated as `Pure`.

Conversely, most TOSA operations are functional tensor computations and do not
mutate external system resources. These operations therefore typically declare
the `NoMemoryEffect` trait. Variable operations are an example of an exception
to this rule.
