blob: d415e24e958a18b06db6c3beab7c38e4a00b6291 [file] [log] [blame]
Eric Kunze3309a532020-10-01 18:50:46 -07001//
2// This confidential and proprietary software may be used only as
3// authorised by a licensing agreement from ARM Limited
Dominic Symesc386a052023-01-20 16:09:31 +00004// (C) COPYRIGHT 2020-2023 ARM Limited
Eric Kunze3309a532020-10-01 18:50:46 -07005// ALL RIGHTS RESERVED
6// The entire notice above must be reproduced on all authorised
7// copies and copies may only be made to the extent permitted
8// by a licensing agreement from ARM Limited.
9
10== Introduction
11
12=== Overview
13
Eric Kunzefa1b3242020-11-09 13:53:23 -080014Tensor Operator Set Architecture (TOSA) provides a set of whole-tensor
15operations commonly employed by Deep Neural Networks. The intent is to enable a
16variety of implementations running on a diverse range of processors, with the
17results at the TOSA level consistent across those implementations. Applications
18or frameworks which target TOSA can therefore be deployed on a wide range of
19different processors, such as SIMD CPUs, GPUs and custom hardware such as
20NPUs/TPUs, with defined accuracy and compatibility constraints. Most operators
21from the common ML frameworks (TensorFlow, PyTorch, etc.) should be expressible
22in TOSA. It is expected that there will be tools to lower from ML frameworks
23into TOSA.
24
25=== Goals
26
27The goals of TOSA include the following:
28
29* A minimal and stable set of tensor-level operators to which machine learning
30framework operators can be reduced.
31
32* Full support for both quantized integer and floating-point content.
33
34* Precise functional description of the behavior of every operator, including
35the treatment of their numerical behavior in the case of precision, saturation,
36scaling, and range as required by quantized datatypes.
37
38* Agnostic to any single high-level framework, compiler backend stack or
39particular target.
40
41* The detailed functional and numerical description enables precise code
42construction for a diverse range of targets – SIMD CPUs, GPUs and custom
43hardware such as NPUs/TPUs.
44
45=== Specification
46
47The TOSA Specification is written as AsciiDoc mark-up and developed in its raw
48mark-up form, managed through a git repository here:
Eric Kunzef9e5ba92022-05-26 16:38:40 -070049https://git.mlplatform.org/tosa/specification.git/.
50The specification is developed and versioned much like software.
51While the mark-up is legible and can be read fairly easily in its raw form, it is recommended to build or “render” the mark-up into PDF or HTML.
52To do this, please follow the instructions in the README.md in the root of the specification repository.
53
54=== Operator Selection Principles
55
56TOSA defines a set of primitive operators to which higher level operators can be lowered in a consistent way.
57To remain effective and efficient to implement, the set of operators must be constrained to a reasonably small set of primitive operations out of which others can be constructed.
58The following principles govern the selection of operators within TOSA.
59
60.Principles
61[cols="1,5,5"]
62|===
63|ID|Principle|Reason for this
64
65|P0
66|An operator shall be a primitive operation or building block that cannot be decomposed into simpler whole tensor operations.
67|If the operator can be broken down, then we should look at the component operators.
68
69|P1
70|An operator shall be a usable as a component out of which more complex operations can be constructed.
71|Single use operators have a high architectural cost and a more reusable version should be considered instead.
72
73|P2
74|Precision should be appropriate for the input and output data types.
75|Precision higher than that needed to calculate the result leads to extra implementation cost.
76
77|P3
78|Numerical definition of common sub-operations should be consistent between operators (for example: value scaling).
79|Consistent sub-operation definition reduces the operator implementation cost.
80
81|P4
Kevin Petit5333c252023-05-16 09:08:48 +010082|The valid input and output ranges for all arguments shall be specified.
Eric Kunzef9e5ba92022-05-26 16:38:40 -070083|Ranges are required to make consistent (numerically agreeing) implementations possible.
84
85|P5
86|Integer operators shall be implementable in a bit-exact form with good efficiency on CPU, GPU and hardware targets.
87|Reduces implementation cost and gives consistent inference results.
88|===
Eric Kunze3309a532020-10-01 18:50:46 -070089
90=== Profiles
91
Eric Kunzef9e5ba92022-05-26 16:38:40 -070092TOSA supports three profiles that enable efficient implementation on different classes of device.
93The Base Inference profile is intended for embedded integer/fixed-point designs performing inference only.
94The Main Inference profile is intended for general inference functionality including integer and floating-point data types.
95The Main Training profile adds training operators in addition to inference operators.
96This version of the specification covers the Base Inference and Main Inference profiles.
97Main Training profile is expected in a later version of the specification.
Eric Kunze3309a532020-10-01 18:50:46 -070098The following table summarizes the three profiles:
99
100.Profiles
101|===
102|Profile|Name|Integer Inference|Floating-point Inference|Training
103
104|Base Inference|TOSA-BI|Yes|No|No
105|Main Inference|TOSA-MI|Yes|Yes|No
106|Main Training|TOSA-MT|Yes|Yes|Yes
107|===
108
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000109=== Levels
110
Kevin Petit5333c252023-05-16 09:08:48 +0100111A TOSA level defines operator argument ranges that an implementation shall support.
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000112This is distinct from a profile that defines the operations and data-types supported.
113This version of the specification defines two TOSA levels:
114
Kevin Petit5333c252023-05-16 09:08:48 +0100115* No level : allows the full range of arguments specified by the operations according to the operation data types.
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000116* Level 8K : ranges are expected to be sufficient for applications with frame sizes up to 8K.
117
118Later versions of the specification may define additional levels.
119The following table defines the value ranges for Level 1.0.
120These ranges are checked using the LEVEL_CHECK() function with the operator descriptions.
121
122.Level maximums
Kevin Petit211c5f52023-04-26 16:25:52 +0100123include::{generated}/levels.adoc[]
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000124
Eric Kunze42229d02022-04-07 16:54:46 -0700125=== Status
126
127The TOSA specification is a work in progress.
128
129* The Base Inference profile should be considered to be near release quality, with conformance tests available.
130* The Main Inference profile has most of the expected operators in place, but is still subject to change.
131* The reference model and conformance tests do not yet support all of the floating point types that have been defined.
132* There is not currently a conformance test suite available for Main Inference.
133* Main Training profile is pre-alpha, significant work still needs to be done for the profile, and no conformance tests are available.
134
Dominic Symesca2a8542021-03-19 13:56:27 +0000135=== Compliance
136
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000137This section defines when a TOSA implementation is compliant to a given TOSA specification profile and level.
Dominic Symes5b936a32023-03-01 11:34:40 +0000138To be compliant an implementation must achieve the results and accuracy defined by this specification.
139TOSA also defines a set of conformance tests.
140A compliant implementation must pass the conformance tests.
141The conformance tests are not exhaustive, so an implementation that passes the conformance tests may not be compliant if there is a non-compliance that is undetected by the tests.
Dominic Symesca2a8542021-03-19 13:56:27 +0000142
Dominic Symesc386a052023-01-20 16:09:31 +0000143==== Base Inference Profile Compliance
Dominic Symesca2a8542021-03-19 13:56:27 +0000144
Eric Kunzea3eded02021-12-13 15:40:04 -0800145The <<Operator Graphs>> section of this specification defines a TOSA graph and the behavior defined for a TOSA graph.
146This behavior is captured in the pseudo-code function tosa_execute_graph().
Dominic Symesca2a8542021-03-19 13:56:27 +0000147For a given input graph (with attributes) and input tensors there are three possible tosa_graph_result values after executing the graph:
148
149* tosa_unpredictable: The result of the graph on the given inputs cannot be relied upon.
150* tosa_error: The graph does not meet the specification and is recognised as an illegal graph.
151* tosa_valid: The result is defined and predictable and the list of output tensors defines the result.
152
153An implementation is compliant to the TOSA Baseline Inference Profile if it matches the above results as follows:
154
155* For tosa_unpredictable, the implementation can return whatever result it chooses (including error)
156* For tosa_error, the implementation must return an error result (and there is no requirement on how much of the graph is executed, if any)
157* For tosa_valid, the implementation must execute the entire graph without error and return the result defined by this specification.
158
159In terms of psuedo-code, if *graph* is a TOSA graph consisting of Baseline Inference Profile operators and *input_list* is a list of input tensors then the following test must pass.
160
161[source,c++]
162----
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000163bool tosa_test_compliance(tosa_graph_t graph, tosa_list_t input_list, tosa_level_t level) {
Dominic Symesca2a8542021-03-19 13:56:27 +0000164 shape_list_t output_list_spec = tosa_allocate_list(tosa_output_shape(graph));
165 shape_list_t output_list_test = tosa_allocate_list(tosa_output_shape(graph));
Dominic Symes7b0f1c92023-07-20 14:26:38 +0100166 tosa_graph_result = tosa_valid; // result starts as valid
167 tosa_nesting_depth = 0; // if/while nesting level
Dominic Symese4d6a1b2022-11-04 18:00:03 +0000168 tosa_execute_graph(graph, input_list, output_list_spec, level);
Dominic Symesca2a8542021-03-19 13:56:27 +0000169 if (tosa_graph_result == tosa_unpredictable) {
170 return true; // No requirement to match an unpredictable result
171 }
172 result_test = execute_implementation_under_test(graph, input_list, output_list_test);
173 if (tosa_graph_result == tosa_error) {
174 return result_test == tosa_error; // result must be an error
175 }
176 if (exact_tensor_match(output_list_spec, output_list_test)) {
177 // Predictable bit-exact value match required
178 return true;
179 }
180 return false;
181}
182----
183
Dominic Symes5b936a32023-03-01 11:34:40 +0000184==== Main Inference Profile Compliance
Dominic Symesca2a8542021-03-19 13:56:27 +0000185
Dominic Symesc386a052023-01-20 16:09:31 +0000186A Main Inference compliant implementation must satisfy the following:
187
188* The implementation must meet <<Base Inference Profile Compliance>> for all Base inference complaint graphs
189* The implementation must support all Main Inference operations using the datatype fp32_t
190** The operations must meet the precision requirements of <<Main Inference precision requirements>>
191* The implementation must support all Main Inference operations using the datatype fp16_t
192** The operations must meet the precision requirements of <<Main Inference precision requirements>>
193** Note: These requirements allow fp16_t operations to be implemented using the fp32_t datatype
194* The implementation must support all Main Inference operations using the datatype bf16_t
195** The operations must meet the precision requirements of <<Main Inference precision requirements>>
196** Note: These requirements allow bf16_t operations to be implemented using the fp32_t datatype
197
198As with <<Base Inference Profile Compliance>> the pseudo-code function tosa_execute_graph() can return one of three possible results.
199A compliant implementation must satisfy the following:
Dominic Symesca2a8542021-03-19 13:56:27 +0000200
201* For a graph returning tosa_error the implementation must also return an error
202* For a graph returning tosa_valid the implementation must execute the entire graph without error
203* For a graph returning tosa_valid and consisting only of integer operators the results must match exactly
Dominic Symesca2a8542021-03-19 13:56:27 +0000204
Dominic Symesc386a052023-01-20 16:09:31 +0000205===== Main Inference precision requirements
206
207In a compliant implementation, individual-floating point operations within the graph must meet the following accuracy bounds
208listed in the table below. In the table _ulp_ means unit of the last place.
209
210NOTE: The error criteria in this section are at an early draft stage and are likely to change during conformance test development.
211
212The following criteria apply to all operations:
213
214* If any input is a NaN and the result is floating-point then the result must be a NaN
215* If any input is a NaN and the operation is a comparison (greater, greater-equal, equal) then the result must be false
216* if any input is a NaN and the operation is conversion to an integer or boolean then the result is unpredictable
217
218[cols="1,3"]
219|===
220| Operation | Accuracy bound
221
222| <<ARGMAX>>, <<MAX_POOL2D>>, <<CLAMP>>, <<MAXIMUM>>, <<MINIMUM>>, <<ABS>>, <<NEGATE>>, , <<CONST>>, <<IDENTITY>>
Dominic Symes5b936a32023-03-01 11:34:40 +0000223| Non NaN results must be exact.
Dominic Symesc386a052023-01-20 16:09:31 +0000224
225| <<EQUAL>>, <<GREATER>>, <<GREATER_EQUAL>>
226| The result must be exact with: +
227(1) The sign of the zero is ignored +
228(2) Infinities of the same sign compare as equal
229
230| <<CONV2D>>, <<CONV3D>>, <<DEPTHWISE_CONV2D>>, <<FULLY_CONNECTED>>, <<MATMUL>>, <<TRANSPOSE_CONV2D>>
231| Each output can be expressed as a dot product of two input vectors. +
232The dot product must meet the <<Dot product accuracy requirements>>
233
234| <<FFT2D>>, <<RFFT2D>>
Dominic Symes5b936a32023-03-01 11:34:40 +0000235| Each output can be expressed as a dot product of an input vector with a constant coefficient vector. +
Dominic Symesc386a052023-01-20 16:09:31 +0000236The dot product must meet the <<Dot product accuracy requirements>>
237
Dominic Symes5b936a32023-03-01 11:34:40 +0000238| <<ADD>>, <<MUL>>, <<SUB>>, <<CEIL>>, <<FLOOR>>
Dominic Symesc386a052023-01-20 16:09:31 +0000239| Floating-point result overflows must be set to infinity of the correct sign. +
240Floating-point result underflows must be set to zero of the correct sign. +
Dominic Symesc386a052023-01-20 16:09:31 +0000241Addition of infinites of different signs must produce a NaN. +
242Subtraction of infinities of the same sign must produce a NaN. +
243Multiplication of an infinity by a zero must produce a NaN. +
244Otherwise for fp32_t the result must be rounded to the nearest representable value using the round to nearest, ties to even rounding mode. +
245Otherwise for fp16_t and bf16_t the result must be within 0.5 ulp of the mathematical result.
246
Dominic Symes5b936a32023-03-01 11:34:40 +0000247| <<CAST>>
248| Floating-point result overflows must be set to infinity of the correct sign. +
249Floating-point result underflows must be set to zero of the correct sign. +
250Cast from floating-point to integer result overflows must be saturated. +
251Otherwise for fp32_t the result must be rounded to the nearest representable value using the round to nearest, ties to even rounding mode. +
252Otherwise for fp16_t and bf16_t the result must be within 0.5 ulp of the mathematical result.
253
Dominic Symesc386a052023-01-20 16:09:31 +0000254| <<RECIPROCAL>>
255| If the input is a zero or the result overlows the output must be an infinity of the same sign. +
256If the input is an infinty or the result underflows the output must be a zero of the same sign. +
257Otherwise:the result must be within 1 ulp of the mathematical result.
258
259| <<RSQRT>>
260| If the input is less than zero the result must be a NaN. +
261Otherwise if the input is a zero the output must be an infinity of the same sign. +
262Otherwise the result must be within 1 ulp of the mathematical result.
263
Eric Kunze52c89f42023-05-10 16:41:13 -0700264| <<SIGMOID>>, <<TANH>>, <<POW>>, <<EXP>>, <<LOG>>, <<ERF>>
Dominic Symesc386a052023-01-20 16:09:31 +0000265| If the input to LOG is less than zero then the result must be a NaN. +
266If the inputs to POW are both zero then the result must be a NaN. +
267If the first input to POW is less than zero and the second input is not an integer then the result must be a NaN. +
268If the result overflows the output must be an infinity of the correct sign. +
269If the result underflows the output must be a zero of the correct sign. +
270Otherwise the result must be within 5 ulp of the mathematical result.
271
272| <<REDUCE_SUM>>
273| Each output can be expressed as a dot product of an input vector with a vector of ones. +
274This dot product must meet the <<Dot product accuracy requirements>>
275
276| <<AVG_POOL2D>>
Dominic Symes5b936a32023-03-01 11:34:40 +0000277| Each output can be expressed as a dot product of an input vector with a vector with elements 1/KS where KS is the kernel size. +
Dominic Symesc386a052023-01-20 16:09:31 +0000278This dot product must meet the <<Dot product accuracy requirements>>
279
280| <<REDUCE_PRODUCT>>
281| Result overflows must be set to an infinity of the correct sign. +
282Result underflows must be set to a zero of the correct sign. +
283Othewise if the final product and all sub-products are within the normal range then the result `R` must have an absolute error of at most `E*abs\(R)`
284where `E = pow(1 + pow(2, -M-1), N) - 1`. In this expression M is the number of mantissa bit of the floating point format and N is the number of elements in the product.
285
286|===
287
288===== Dot product accuracy requirements
289
Dominic Symesb5b06782023-07-27 11:50:57 +0100290This section assumes an operation acting on tensors named 'input', 'weight' and optionally 'bias'.
291Each output tensor element can be expressed as a dot product of elements between the 'input' and 'weight' tensors with optional bias addition.
Dominic Symes5b936a32023-03-01 11:34:40 +0000292The dot product has length KS, the kernel size.
Dominic Symesb5b06782023-07-27 11:50:57 +0100293If the operation does not specify a bias then 'bias' is taken to be zero in this section.
Dominic Symes5b936a32023-03-01 11:34:40 +0000294Note: KS is defined for each relevant operator in the appendix section <<Main Inference operator test data>>.
Dominic Symesc386a052023-01-20 16:09:31 +0000295
Dominic Symesb5b06782023-07-27 11:50:57 +0100296In other words, each output element `out` can be expressed as a dot product between input elements `in[k]`, weight elements `w[k]`, bias `b`:
Dominic Symesc386a052023-01-20 16:09:31 +0000297
Dominic Symesb5b06782023-07-27 11:50:57 +0100298`out = in[0] * w[0] + in[1] * w[1] + ... + in[KS-1] * w[KS-1] + b`
Dominic Symesc386a052023-01-20 16:09:31 +0000299
Dominic Symesb5b06782023-07-27 11:50:57 +0100300The positions of `in[k]`, `w[k]`, `b` in the input, weight and bias tensors depends on the operation being performed.
301This may be, for example, a convolution.
Dominic Symesc386a052023-01-20 16:09:31 +0000302
Dominic Symes5b936a32023-03-01 11:34:40 +0000303This section defines the accuracy required for these operations.
Dominic Symesb5b06782023-07-27 11:50:57 +0100304In this section:
Dominic Symesc386a052023-01-20 16:09:31 +0000305
Dominic Symesb5b06782023-07-27 11:50:57 +0100306* "fp64 arithmetic" refers to double-precision floating-point arithmetic defined by IEEE 754 (<<Other publications>>[1])
307* `operation_fp64()` is an fp64 reference implementation of the operation
308* `operation_imp()` is the implementation under test
309* `local_bound` is defined as follows:
310** For operations with a local_bound attribute it is the value of the optional attribute, with default value of false
311** For operations that do not have a local_bound attribute the value is true
Dominic Symes5b936a32023-03-01 11:34:40 +0000312
Dominic Symesb5b06782023-07-27 11:50:57 +0100313The checks described in the following code must pass for the following data sets:
Dominic Symes5b936a32023-03-01 11:34:40 +0000314
Dominic Symesb5b06782023-07-27 11:50:57 +0100315* Data sets defined for the operation in Appendix A <<Main Inference operator test data>>.
316* Data sets that have at least MIN_DOT_PRODUCT different output values. For these data sets we take S=-1.
Dominic Symes5b936a32023-03-01 11:34:40 +0000317
318[source,c++]
319----
Dominic Symesb5b06782023-07-27 11:50:57 +0100320output_ref = operation_fp64(input, weight, bias);
321output_imp = operation_imp (input, weight, bias);
322input_abs = abs(input); // Element-wise absolute
323weight_abs = abs(weight); // Element-wise absolute
324bias_abs = abs(bias); // Element-wise absolute
325if (!local_bound) {
326 input_abs_max = max_value(input_abs); // maximum over all elements
327 for_each(index in shape(input_abs) {
328 input_abs[index] = input_abs_max; // set all entries to global maximum
329 }
330}
331output_bnd = operation_fp64(input_abs, weight_abs, bias_abs);
332
Dominic Symes5b936a32023-03-01 11:34:40 +0000333size_t T = tensor_size(output_shape) // number dot product results
Dominic Symesb5b06782023-07-27 11:50:57 +0100334size_t ksb = (max_value(bias_abs) > 0) ? (KS + 1) : KS; // kernel size and bias
Dominic Symes5b936a32023-03-01 11:34:40 +0000335fp64_t out_err_sum = 0.0;
336fp64_t out_err_sumsq = 0.0;
Dominic Symesb5b06782023-07-27 11:50:57 +0100337fp64_t acc_prec; // 1<<(M+1) where M is the number of mantissa bits
338fp64_t acc_min_normal; // accumulator minimum normal greater than zero
339fp64_t two_m63 = -1.0/(fp64)((int64_t)-1<<63); // pow(2, -63)
Dominic Symes5b936a32023-03-01 11:34:40 +0000340switch (acc_t) {
Eric Kunzefb0284e2023-07-18 15:20:53 -0700341 case fp32_t: acc_prec = static_cast<fp64_t>(1<<24); // pow(2, 24)
Dominic Symesb5b06782023-07-27 11:50:57 +0100342 acc_min_normal = two_m63 * two_m63; // pow(2, -126)
343 break;
Eric Kunzefb0284e2023-07-18 15:20:53 -0700344 case fp16_t: acc_prec = static_cast<fp64_t>(1<<11); // pow(2, 11)
345 acc_min_normal = 1.0/static_cast<fp64_t>(1<<14); // pow(2, -14)
Dominic Symesb5b06782023-07-27 11:50:57 +0100346 break;
347 default: ERROR_IF(true);
Dominic Symes5b936a32023-03-01 11:34:40 +0000348}
349for_each(index in output_shape) {
350 fp64_t out_bnd = tensor_read<fp64_t>(output_bnd, output_shape, index);
351 fp64_t out_ref = tensor_read<fp64_t>(output_ref, output_shape, index);
352 acc_t out_imp = tensor_read<acc_t> (output_imp, output_shape, index);
353 fp64_t out_err;
Dominic Symesb5b06782023-07-27 11:50:57 +0100354 if ((acc_t)out_bnd == infinity) {
355 // dot product can overflow and there is no accuracy limit
356 out_err = 0.0;
357 } else if (out_bnd == 0.0) {
Dominic Symes5b936a32023-03-01 11:34:40 +0000358 REQUIRE(out_ref == 0.0 && out_imp == 0.0);
359 out_err = 0.0;
Dominic Symesb5b06782023-07-27 11:50:57 +0100360 } else { // 0.0 < out_bnd < infinity
Dominic Symesb2035122023-09-01 11:41:08 +0100361 fp64_t out_err_bnd = max(out_bnd / acc_prec, acc_min_normal);
362 out_err = (static_cast<fp64_t>(out_imp) - out_ref) / out_err_bnd;
Dominic Symesb5b06782023-07-27 11:50:57 +0100363 REQUIRE(abs(out_err) <= ksb);
Dominic Symes5b936a32023-03-01 11:34:40 +0000364 }
365 out_err_sum += out_err;
366 out_err_sumsq += out_err * out_err;
367}
Dominic Symesb5b06782023-07-27 11:50:57 +0100368if (input and weights are data set S with 3 <= S <= 5) {
Dominic Symes5b936a32023-03-01 11:34:40 +0000369 // check output error bias magnitude for data sets S which are not positive biased
Dominic Symesb5b06782023-07-27 11:50:57 +0100370 REQUIRE(abs(out_err_sum) <= 2*sqrt(ksb*T));
Dominic Symes5b936a32023-03-01 11:34:40 +0000371}
372// check output error variance magnitude
Dominic Symesb5b06782023-07-27 11:50:57 +0100373REQUIRE(out_err_sumsq <= 0.4*ksb*T)
Dominic Symes5b936a32023-03-01 11:34:40 +0000374----
Dominic Symesca2a8542021-03-19 13:56:27 +0000375
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700376=== Tensor Definitions
Eric Kunze3309a532020-10-01 18:50:46 -0700377
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700378==== Tensors
Eric Kunze3309a532020-10-01 18:50:46 -0700379
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700380Tensors are multidimensional arrays of data.
381Tensors have metadata associated with them that describe characteristics of the tensor, including:
Eric Kunze3309a532020-10-01 18:50:46 -0700382
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700383* Data Type
384* Shape
Eric Kunze3309a532020-10-01 18:50:46 -0700385
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700386The number of dimensions in a shape is called the rank.
387A tensor with rank equal to zero is permitted.
Dominic Symes830b43b2023-05-09 10:14:49 +0100388In that case, the tensor has a single entry and is also known as a scalar.
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700389A tensor shape is an array of integers of size equal to the rank of the tensor.
390Each element in the tensor shape describes the number of elements in the dimension.
391The tensor shape in each dimension must be greater than or equal to 1.
392For tensor access information, see <<Tensor Access Helpers>>.
Dominic Symes830b43b2023-05-09 10:14:49 +0100393
394The shape of a tensor of non-zero rank is itself a tensor of rank 1 with elements of type shape_t.
395The single dimension has size which is the rank of the original tensor.
396In this specification a shape-tensor means a rank 1 tensor with elements of type shape_t.
397The components of a shape tensor are rank 0 tensors of type shape_t.
398
399Some operations can process rank 0 or rank 1 tensors of type shape_t.
400For these operations, shape_t is permitted as an input or output tensor data type.
401In this version of the specification, shape_t values must be resolvable to constants at backend compile time.
Eric Kunze3309a532020-10-01 18:50:46 -0700402
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700403==== Tensor size limit
Eric Kunze3309a532020-10-01 18:50:46 -0700404
Dominic Symesbc72ba82023-04-24 17:08:02 +0100405The tensor overall size is limited by the data type size_t.
406This type must be able to hold integers in the range 0 to (1++<<++(MAX_LOG2_SIZE+1)) - 1 where MAX_LOG2_SIZE is defined in <<Levels>>.
407For each tensor, the number of tensor elements multiplied by the element size in bytes (which is taken to be 1 for elements smaller than a 8-bit) must be less than or equal to (1<<(MAX_LOG2_SIZE+1)) - 1.
408
Kevin Petite0fee3d2023-04-18 10:39:32 +0100409The size of tensors along each of their dimensions is limited by the data type index_t.
Dominic Symesbc72ba82023-04-24 17:08:02 +0100410This type must be able to hold integers in the range 0 to (1++<<++MAX_LOG2_SIZE) - 1 where MAX_LOG2_SIZE is defined in <<Levels>>.
411This means that the maximum size of a tensor along each dimension is (1<<MAX_LOG2_SIZE) - 1 and therefore the maximum coordinate value is (1<<MAX_LOG2_SIZE) - 2.
Dominic Symes0205d992022-10-07 15:03:01 +0100412Indices used to access tensors must be non-negative.
Eric Kunze3309a532020-10-01 18:50:46 -0700413
Dominic Symes830b43b2023-05-09 10:14:49 +0100414The type shape_t, used in shape tensors, must be able to hold integers in the range -(1++<<++MAX_LOG2_SIZE) to (1++<<++MAX_LOG2_SIZE) - 1.
415
Eric Kunze3309a532020-10-01 18:50:46 -0700416==== Data Layouts
417
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700418The following data layouts are supported in TOSA.
419TOSA operations are defined in terms of a linear packed tensor layout.
420In a linear packed layout a rank r tensor has elements of dimension (r-1) consecutive.
421The next to increment is dimension (r-2) and so on.
422For a specification of this layout see the tensor read and write functions in section <<Tensor Access Helpers>>.
423
424An implementation of TOSA can choose a different tensor memory layout provided that the operation behavior is maintained.
Eric Kunze3309a532020-10-01 18:50:46 -0700425
426.Data Layouts
427[cols="1,4,4"]
428|===
429|Name|Description of dimensions|Usage
430
431|NHWC|Batch, Height, Width, Channels|Feature maps
432|NDHWC|Batch, Depth, Height, Width, Channels|Feature maps for 3D convolution
433|OHWI|Output channels, Filter Height, Filter Width, Input channels|Weights
434|HWIM|Filter Height, Filter Width, Input channels, Channel Multiplier|Weights for depthwise convolutions
435|DOHWI|Depth, Output Channels, Filter Height, Filter Width, Input Channels|Weights for 3D convolution
436|===
437
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700438==== Broadcasting
Eric Kunze3309a532020-10-01 18:50:46 -0700439
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700440In operations where broadcasting is supported, an input shape dimension can be broadcast to an output shape dimension if the input shape dimension is 1.
441TOSA broadcast requires the rank of both tensors to be the same.
442A RESHAPE can be done to create a compatible tensor with appropriate dimensions of size 1.
443To map indexes in an output tensor to that of an input tensor, see <<Broadcast Helper>>.
Eric Kunze3309a532020-10-01 18:50:46 -0700444
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700445==== Supported Number Formats
Eric Kunze3309a532020-10-01 18:50:46 -0700446
Eric Kunze1e9ba652021-02-17 19:23:39 -0800447The following number formats are defined in TOSA.
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700448The number formats supported by a given operator are listed in its table of supported types.
Eric Kunze3309a532020-10-01 18:50:46 -0700449
450.Number formats
Eric Kunze1e9ba652021-02-17 19:23:39 -0800451[cols="1,1,1,5"]
Eric Kunze3309a532020-10-01 18:50:46 -0700452|===
453|Format|Minimum|Maximum|Description
454
Eric Kunze1e9ba652021-02-17 19:23:39 -0800455|bool_t
Eric Kunze3309a532020-10-01 18:50:46 -0700456| -
457| -
Eric Kunze173fc162021-08-17 14:57:46 -0700458|Boolean value. Size implementation defined. The TOSA reference model implements this as int8_t with 0 for false and 1 for true. All non-zero values are accepted on input as true.
Eric Kunze3309a532020-10-01 18:50:46 -0700459
Eric Kunzefb0284e2023-07-18 15:20:53 -0700460|i4_t
461| -
462| -
463|Signless 4-bit integer type. Will be interpreted as int4_t by all operators
464
Eric Kunze1e9ba652021-02-17 19:23:39 -0800465|int4_t
Eric Kunze3309a532020-10-01 18:50:46 -0700466| -7
467| +7
Eric Kunzeeef012e2022-05-13 14:54:06 -0700468|Signed 4-bit two's-complement value. Excludes -8 to maintain a symmetric about zero range for weights.
Eric Kunze3309a532020-10-01 18:50:46 -0700469
Eric Kunzefb0284e2023-07-18 15:20:53 -0700470|i8_t
471| -
472| -
473|Signless 8-bit integer value. Will be interpreted as int8_t unless otherwise specified by an operator.
474
Eric Kunze1e9ba652021-02-17 19:23:39 -0800475|int8_t
Eric Kunze3309a532020-10-01 18:50:46 -0700476| -128
477| +127
Eric Kunzeeef012e2022-05-13 14:54:06 -0700478|Signed 8-bit two's-complement value.
Eric Kunze3309a532020-10-01 18:50:46 -0700479
Eric Kunze1e9ba652021-02-17 19:23:39 -0800480|uint8_t
Eric Kunze3309a532020-10-01 18:50:46 -0700481| 0
482| 255
Eric Kunzefb0284e2023-07-18 15:20:53 -0700483|Unsigned 8-bit integer value.
484
485|i16_t
486| -
487| -
488|Signless 16-bit integer type. Will be interpreted as int16_t unless otherwise specified by an operator.
Eric Kunze3309a532020-10-01 18:50:46 -0700489
Eric Kunze1e9ba652021-02-17 19:23:39 -0800490|int16_t
Eric Kunze3309a532020-10-01 18:50:46 -0700491| -32768
Eric Kunze2dce0d02021-01-12 16:19:50 -0800492| +32767
Eric Kunzeeef012e2022-05-13 14:54:06 -0700493|Signed 16-bit two's-complement value.
494
495|uint16_t
496| 0
497| 65535
498|Unsigned 16-bit value.
Eric Kunze3309a532020-10-01 18:50:46 -0700499
Eric Kunzefb0284e2023-07-18 15:20:53 -0700500|i32_t
501| -
502| -
503|Signless 32-bit integer value. Will be interpreted as int32_t by all operators.
504
Eric Kunze1e9ba652021-02-17 19:23:39 -0800505|int32_t
Eric Kunze3309a532020-10-01 18:50:46 -0700506| -(1<<31)
Eric Kunze2dce0d02021-01-12 16:19:50 -0800507| (1<<31)-1
Eric Kunze173fc162021-08-17 14:57:46 -0700508|Signed 32-bit two's-complement value.
Eric Kunze3309a532020-10-01 18:50:46 -0700509
Eric Kunzefb0284e2023-07-18 15:20:53 -0700510|i48_t
511| -
512| -
513|Signless 32-bit integer value. Will be interpreted as int48_t by all operators.
514
Eric Kunze1e9ba652021-02-17 19:23:39 -0800515|int48_t
Eric Kunze57e79c02020-11-03 11:23:09 -0800516| -(1<<47)
Eric Kunze2dce0d02021-01-12 16:19:50 -0800517| (1<<47)-1
Eric Kunze173fc162021-08-17 14:57:46 -0700518|Signed 48-bit two's-complement value.
Eric Kunze57e79c02020-11-03 11:23:09 -0800519
Eric Kunze42229d02022-04-07 16:54:46 -0700520|fp16_t
Eric Kunze3309a532020-10-01 18:50:46 -0700521| -infinity
522| +infinity
Dominic Symesc386a052023-01-20 16:09:31 +0000523| 16-bit half-precision floating-point defined by <<Other publications>>[1]. +
524Normal values must be supported. +
525Denormal values must either be supported or flushed to zero. +
526Positive and negative infinity must be supported. +
527At least one NaN encoding must be supported. +
528Signed zero must be supported.
Eric Kunze42229d02022-04-07 16:54:46 -0700529
530|bf16_t
531| -infinity
532| +infinity
Dominic Symesc386a052023-01-20 16:09:31 +0000533| 16-bit brain floating-point defined as bits [31:16] of the fp32_t format. +
534Normal values must be supported. +
535Denormal values must either be supported or flushed to zero. +
536Positive and negative infinity must be supported. +
537At least one NaN encoding must be supported. +
538Signed zero must be supported.
Eric Kunze42229d02022-04-07 16:54:46 -0700539
540|fp32_t
541| -infinity
542| +infinity
Eric Kunze277a4f12023-05-12 17:50:19 -0700543| 32-bit single-precision floating-point defined by <<Other publications>>[1]. +
544Normal values must be supported. +
545Denormal values must either be supported or flushed to zero. +
546Positive and negative infinity must be supported. +
547At least one NaN encoding must be supported. +
548Signed zero must be supported.
549
550|fp64_t
551| -infinity
552| + infinity
553| 64-bit double-precision floating-point defined by <<Other publications>>[1]. +
Dominic Symesc386a052023-01-20 16:09:31 +0000554Normal values must be supported. +
555Denormal values must either be supported or flushed to zero. +
556Positive and negative infinity must be supported. +
557At least one NaN encoding must be supported. +
558Signed zero must be supported.
Eric Kunze3309a532020-10-01 18:50:46 -0700559|===
560
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700561Note: In this specification minimum<type> and maximum<type> will denote the minimum and maximum values of the data as stored in memory (ignoring the zero point).
562The minimum and maximum values for each type is given in the preceeding table.
Eric Kunze3309a532020-10-01 18:50:46 -0700563
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700564Note: Integer number formats smaller than 8 bits may be used provided that the numerical result is the same as using a sequence of 8-bit TOSA operations.
565For example, a convolution with low precision data must equal that of running the convolution at 8 bits and then clipping the result to the peritted output range.
566This ensures that a Base Inference profile TOSA implementation can calculate the same result.
Eric Kunze3309a532020-10-01 18:50:46 -0700567
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700568=== Integer Behavior
Eric Kunze3309a532020-10-01 18:50:46 -0700569
Eric Kunzefb0284e2023-07-18 15:20:53 -0700570TOSA integer inputs and outputs are specified by signless values with the given number of bits.
571Unless otherwise specified, these values will be interpreted as signed twos-complement.
572The pseudocode will use int*_t to indicate use as a signed value and uint*_t to indicate use as an unsigned value.
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700573If overflow occurs doing integer calculation, the result is unpredictable, as indicated by the REQUIRE checks in the pseudocode for the operators.
Eric Kunze3309a532020-10-01 18:50:46 -0700574
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700575Unsigned 8 and 16-bit values are only allowed in the RESCALE operation, to allow for compatibility with networks which expect unsigned 8-bit or 16-bit tensors for input and output.
Eric Kunze3309a532020-10-01 18:50:46 -0700576
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700577==== Quantization
Eric Kunze3309a532020-10-01 18:50:46 -0700578
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700579Machine Learning frameworks may represent tensors with a quantized implementation, using integer values to represent the original floating-point numbers.
580TOSA integer operations do not perform any implicit scaling to represent quantized values.
581Required zero point values are passed to the operator as necessary, and will be processed according to the pseudocode for each operator.
Eric Kunzec949f8a2021-09-16 14:51:26 -0700582
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700583To convert a network containing quantized tensors to TOSA, generate explicit RESCALE operators for any change of quantization scaling.
584This reduces quantized operations to purely integer operations.
Eric Kunze839830a2021-03-11 15:38:22 -0800585
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700586As an example, an ADD between two quantized tensors requires the integer values represent the same range.
Kevin Petit5333c252023-05-16 09:08:48 +0100587The scale arguments for RESCALE can be calculated to ensure that the resulting tensors represent the same range.
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700588Then the ADD is performed, and a RESCALE can be used to ensure that the result is scaled properly.
Eric Kunze3309a532020-10-01 18:50:46 -0700589
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700590RESCALE provides support for per-tensor and per-channel scaling values to ensure compatibility with a range of possible quantization implementations.
Eric Kunze3309a532020-10-01 18:50:46 -0700591
Eric Kunzec949f8a2021-09-16 14:51:26 -0700592
Eric Kunze3309a532020-10-01 18:50:46 -0700593
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700594==== Precision scaling
Eric Kunze3309a532020-10-01 18:50:46 -0700595
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700596TOSA uses the RESCALE operation to scale between values with differing precision.
597The RESCALE operator is defined using an integer multiply, add, and shift.
598This guarantees that all TOSA implementations will return the same result for a RESCALE, including those with no support for floating-point numbers.
Eric Kunze3309a532020-10-01 18:50:46 -0700599
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700600This TOSA specification supports two precisions of multiplier: 16-bit and 32-bit.
601The 32-bit multiplier version supports two rounding modes to enable simpler lowering of existing frameworks that use two stage rounding.
602All arithmetic is designed so that it does not overflow a 64-bit accumulator and that the final result fits in 32 bits.
603In particular a 48-bit value can only be scaled with the 16-bit multiplier.
Eric Kunze3309a532020-10-01 18:50:46 -0700604
Dominic Symes3cb75352022-01-24 11:18:05 +0000605The apply_scale functions provide a scaling of approximately (multiplier * 2^-shift^).
606The shift and value range is limited to allow a variety of implementations.
607The limit of 62 on shift allows the shift to be decomposed as two right shifts of 31.
Eric Kunzece6e02c2022-03-11 15:12:38 -0800608The limit on value allows implementations that left shift the value before the multiply in the case of shifts of 32 or less.
Dominic Symes3cb75352022-01-24 11:18:05 +0000609For example, in the case shift=30 an implementation of the form ((value\<<2) * multiplier + round)>>32 can be used.
610A scaling range of 2^+12^ down to 2^-32^ is supported for both functions with a normalized multiplier.
611
612For example, in typical usage a scaling of m*2^-n^ where m is a fraction in the
613range 1.0 \<= m < 2.0 can be represented using multiplier=(1<<30)*m, shift=(30+n) for
614apply_scale_32() and multiplier=(1<<14)*m, shift=(14+n) for apply_scale_16().
615The values to achieve a scaling of 1.0 are shift=30, multiplier=1<<30 for apply_scale_32 and shift=14, multiplier=1<<14 for apply_scale_16.
Eric Kunze3309a532020-10-01 18:50:46 -0700616
Eric Kunze839830a2021-03-11 15:38:22 -0800617[source,c++]
618----
Kevin Petit98b3e332023-05-16 09:13:50 +0100619int32_t apply_scale_32(int32_t value, int32_t multiplier, int8_t shift, bool_t double_round=false) {
Eric Kunzea9101532021-06-17 18:01:09 -0700620 REQUIRE(multiplier >= 0);
621 REQUIRE(2 <= shift && shift <= 62);
Dominic Symes830b43b2023-05-09 10:14:49 +0100622 REQUIRE(value >= (-1 << (shift - 1)) && value < (1 << (shift - 1)));
Eric Kunze839830a2021-03-11 15:38:22 -0800623 int64_t round = 1 << (shift - 1);
624 if (double_round) {
625 if (shift > 31 && value >= 0) round += 1<<30;
626 if (shift > 31 && value < 0) round -= 1<<30;
627 }
Eric Kunzefb0284e2023-07-18 15:20:53 -0700628 int64_t result = static_cast<int64_t>(value) * multiplier + round;
Eric Kunze839830a2021-03-11 15:38:22 -0800629 result = result >> shift;
Dominic Symes3cb75352022-01-24 11:18:05 +0000630 // result will fit a 32-bit range due to the REQUIRE on value
Eric Kunzefb0284e2023-07-18 15:20:53 -0700631 return static_cast<int32_t>(result);
Eric Kunze3309a532020-10-01 18:50:46 -0700632}
633
Kevin Petit98b3e332023-05-16 09:13:50 +0100634int32_t apply_scale_16(int48_t value, int16_t multipler, int8_t shift) {
Eric Kunzea9101532021-06-17 18:01:09 -0700635 REQUIRE(multiplier >= 0);
636 REQUIRE(2 <= shift && shift <= 62);
Eric Kunze839830a2021-03-11 15:38:22 -0800637 int64_t round = (1 << (shift - 1));
Eric Kunzefb0284e2023-07-18 15:20:53 -0700638 int64_t result = static_cast<int64_t>(value) * multiplier + round;
Eric Kunze839830a2021-03-11 15:38:22 -0800639 result = result >> shift;
Eric Kunzea9101532021-06-17 18:01:09 -0700640 REQUIRE(result >= minimum<int32_t> && result <= maximum<int32_t>);
Eric Kunzefb0284e2023-07-18 15:20:53 -0700641 return static_cast<int32_t>(result);
Eric Kunze3309a532020-10-01 18:50:46 -0700642}
Eric Kunze839830a2021-03-11 15:38:22 -0800643----
Eric Kunze3309a532020-10-01 18:50:46 -0700644
645In some functions, the multiplier and shift are combined into a scale_t structure:
646
Eric Kunze839830a2021-03-11 15:38:22 -0800647[source,c++]
648----
Eric Kunze3309a532020-10-01 18:50:46 -0700649typedef struct {
Eric Kunze839830a2021-03-11 15:38:22 -0800650 int32_t multiplier;
Kevin Petit98b3e332023-05-16 09:13:50 +0100651 int8_t shift;
Eric Kunze3309a532020-10-01 18:50:46 -0700652} scale_t;
Eric Kunze839830a2021-03-11 15:38:22 -0800653----
Eric Kunze3309a532020-10-01 18:50:46 -0700654
655In places where a divide is required, we also use the function below to calculate an appropriate scaling value.
656
Eric Kunze839830a2021-03-11 15:38:22 -0800657[source,c++]
658----
Eric Kunze3309a532020-10-01 18:50:46 -0700659scale_t reciprocal_scale(uint32_t value) {
Eric Kunzea9101532021-06-17 18:01:09 -0700660 REQUIRE(value > 0);
Eric Kunze839830a2021-03-11 15:38:22 -0800661 scale_t scale;
Dominic Symescb6c6b32022-04-29 16:15:56 +0100662 int32_t k = 32 - count_leading_zeros(value - 1); // (1 << k) / 2 < value <= (1 << k)
Eric Kunze839830a2021-03-11 15:38:22 -0800663 int64_t numerator = ((1 << 30) + 1) << k;
664 scale.multiplier = numerator / value; // (1 << 30) <= multiplier < (1 << 31)
665 scale.shift = 30 + k;
666 return scale;
Eric Kunze3309a532020-10-01 18:50:46 -0700667}
Eric Kunze839830a2021-03-11 15:38:22 -0800668----
Eric Kunze3309a532020-10-01 18:50:46 -0700669
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700670==== Integer Convolutions
Eric Kunze1e9ba652021-02-17 19:23:39 -0800671
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700672For the convolution operators, the input is not required to be scaled.
673The integer versions of the convolution operators will subtract the zero point from the integer values as defined for each operator.
Eric Kunze1e9ba652021-02-17 19:23:39 -0800674The convolution produces an accumulator output of type int32_t or int48_t.
675This accumulator output is then scaled to the final output range using the RESCALE operator.
676The scale applied in the RESCALE operator should be set to multiplier and shift values such that: multiplier * 2^-shift^ = (input scale * weight scale) / output_scale.
677Here, input_scale, weight_scale and output_scale are the conversion factors from integer to floating-point for the input, weight and output tensor values respectively.
678If per-channel scaling is needed then the per-channel option of the RESCALE operation should be used.
679
Eric Kunzef9e5ba92022-05-26 16:38:40 -0700680==== Integer Elementwise Operators
Eric Kunze1e9ba652021-02-17 19:23:39 -0800681
682When two quantized tensors are used in an operation, they must represent the same numeric range for the result to be valid.
683In this case, TOSA expects that RESCALE operators will be used as necessary to generate 32-bit integer values in a common range.
684There are many valid choices for scale factors and options for the common range.
685TOSA does not impose a requirement on which scale factors and range should be used.
686Compilers generating TOSA sequences should choose a range that allows the operation to be computed without overflow, while allowing the highest possible accuracy of the output.
687
688==== General Unary Functions
689General unary functions such as sigmoid(), tanh(), exp() for integer inputs are expressed using a lookup table and interpolation to enable efficient implementation.
690This also allows for other operations with the addition of user-supplied tables (the TABLE operation).
691All table lookups are based on the following reference lookup function that takes as input a table of 513 entries of 16 bits each.
692
Eric Kunze839830a2021-03-11 15:38:22 -0800693[source,c++]
694----
Eric Kunzefb0284e2023-07-18 15:20:53 -0700695int32_t apply_lookup_s(int16_t *table, int32_t value)
Eric Kunze1e9ba652021-02-17 19:23:39 -0800696{
Eric Kunzefb0284e2023-07-18 15:20:53 -0700697 int16_t clipped_value = static_cast<int16_t>(apply_clip_s<int32_t>(value, -32768, +32767));
Eric Kunze1e9ba652021-02-17 19:23:39 -0800698 int32_t index = (clipped_value + 32768) >> 7;
699 int32_t fraction = clipped_value & 0x7f;
700 int16_t base = table[index];
701 int16_t next = table[index+1];
Dominic Symes2ff79fe2022-01-27 15:44:26 +0000702 int32_t slope = next - base;
703 REQUIRE(slope >= minimum<int16_t> && slope <= maximum<int16_t>)
704 int32_t return_value = (base << 7) + slope * fraction;
Eric Kunze1e9ba652021-02-17 19:23:39 -0800705 return return_value; // return interpolated value of 16 + 7 = 23 bits
706}
Eric Kunze839830a2021-03-11 15:38:22 -0800707----
Eric Kunze1e9ba652021-02-17 19:23:39 -0800708
709Note that although the table lookup defined here has 16-bit precision, for 8-bit only operations an 8-bit table can be derived by applying the reference function to each of the possible 256 input values.
710The following code constructs a 513-entry table based on a reference function.
711
Eric Kunze839830a2021-03-11 15:38:22 -0800712[source,c++]
713----
Eric Kunze1e9ba652021-02-17 19:23:39 -0800714void generate_lookup_table(int16_t *table, int32_t (*reference)(int32_t))
715{
716 for (int i = -256; i <= 256; i++) {
717 int32_t value = (*reference)(i);
Eric Kunzefb0284e2023-07-18 15:20:53 -0700718 table[i + 256] = static_cast<int16_t>(apply_clip<int32_t>(value, -32768, +32767));
Eric Kunze1e9ba652021-02-17 19:23:39 -0800719 }
720}
Eric Kunze839830a2021-03-11 15:38:22 -0800721----
Eric Kunze1e9ba652021-02-17 19:23:39 -0800722
Dominic Symesc386a052023-01-20 16:09:31 +0000723=== Other publications
Eric Kunze1e9ba652021-02-17 19:23:39 -0800724
Dominic Symesc386a052023-01-20 16:09:31 +0000725The following publications are referred to in this specification, or provide more information:
Eric Kunze1e9ba652021-02-17 19:23:39 -0800726
Kevin Petit98b3e332023-05-16 09:13:50 +0100727. IEEE Std 754-2008, _IEEE Standard for Floating-point Arithmetic_, August 2008.