From a7ac313a13f8f82b4b3ca9730bd746392f6600d9 Mon Sep 17 00:00:00 2001 From: Kevin Petit Date: Mon, 8 Jan 2024 15:27:25 +0000 Subject: Move operator pseudocode to separate files This makes it easier to process the pseudocode automatically. Change-Id: I84394192598e589de07d43a7af60b96788e14f86 Signed-off-by: Kevin Petit --- chapters/activation_funcs.adoc | 46 +------ chapters/comparison.adoc | 44 +------ chapters/control_flow.adoc | 42 +----- chapters/data_layout.adoc | 129 ++---------------- chapters/ewise_binary.adoc | 237 +++------------------------------ chapters/ewise_ternary.adoc | 19 +-- chapters/ewise_unary.adoc | 87 ++---------- chapters/image.adoc | 68 +--------- chapters/reduction.adoc | 105 +-------------- chapters/scatter_gather.adoc | 32 +---- chapters/tensor_ops.adoc | 293 ++--------------------------------------- chapters/type_conversion.adoc | 71 +--------- chapters/variable.adoc | 67 +--------- 13 files changed, 86 insertions(+), 1154 deletions(-) (limited to 'chapters') diff --git a/chapters/activation_funcs.adoc b/chapters/activation_funcs.adoc index 1acaf56..1be3168 100644 --- a/chapters/activation_funcs.adoc +++ b/chapters/activation_funcs.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2021 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -20,12 +20,7 @@ include::{generated}/operators/CLAMP.adoc[] [source,c++] ---- -ERROR_IF(max_val < min_val); -for_each(index in shape) { - in_out_t value = tensor_read(input, shape, index); - value = apply_clip(value, min_val, max_val); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/CLAMP.tosac[lines=10..-1] ---- ==== ERF @@ -43,13 +38,7 @@ The ERF table has 513 entries each of 16-bit precision and covering the input ra [source,c++] ---- -int16_t erf_reference(int16_t x) { // input x range is -256 to + 256 inclusive - F64 v = (double)x / (double)64; - v = erf(v); - return round_to_nearest_int(32768.0 * v); -} - -generate_lookup_table(&erf_table, &erf_reference); +include::{pseudocode}/operators/tables/ERF.tosac[lines=10..-1] ---- include::{generated}/operators/ERF.adoc[] @@ -72,24 +61,14 @@ This sigmoid table has 513 entries each of 16-bit precision and covering the inp .Code for generating 16-bit sigmoid table [source,c++] ---- -int16_t sigmoid_reference(int16_t x) { // input x range is -256 to + 256 inclusive - fp64_t v = (fp64_t)x / (fp64_t)16; - v = 1.0/(1.0 + exp(-v)); - return round_to_nearest_int(32768.0 * v); -} - -generate_lookup_table(&sigmoid_table, &sigmoid_reference); +include::{pseudocode}/operators/tables/SIGMOID.tosac[lines=10..-1] ---- include::{generated}/operators/SIGMOID.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input, shape, index); - value = sigmoid(value1); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/SIGMOID.tosac[lines=10..-1] ---- ==== TANH @@ -109,23 +88,12 @@ This tanh_table has 513 entries each of 16-bit precision and covering the input .Calculation of an example 16-bit tanh table [source,c++] ---- -int16_t tanh_reference(int16_t x) { // input x range is -256 to +256 inclusive - fp64_t v = (fp64_t)x/(fp64_t)32; - v = exp(-2.0*v); - v = (1.0-v)/(1.0+v); - return round_to_nearest_int(32768.0 * v); -} - -generate_lookup_table(&tanh_table, &tanh_reference); +include::{pseudocode}/operators/tables/TANH.tosac[lines=10..-1] ---- include::{generated}/operators/TANH.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input, shape, index); - value = tanh(value1); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/TANH.tosac[lines=10..-1] ---- diff --git a/chapters/comparison.adoc b/chapters/comparison.adoc index 4ef52d6..5535b40 100644 --- a/chapters/comparison.adoc +++ b/chapters/comparison.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2022 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -17,19 +17,7 @@ include::{generated}/operators/EQUAL.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_t value1 = tensor_read(input1, shape1, index1); - in_t value2 = tensor_read(input2, shape2, index2); - out_t result; - if (isNaN(value1) || isNaN(value2)) - result = False; - else - result = (value1 == value2) ? True : False; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/EQUAL.tosac[lines=10..-1] ---- ==== GREATER @@ -40,19 +28,7 @@ include::{generated}/operators/GREATER.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_t value1 = tensor_read(input1, shape1, index1); - in_t value2 = tensor_read(input2, shape2, index2); - out_t result; - if (isNaN(value1) || isNaN(value2)) - result = False; - else - result = (value1 > value2) ? True : False; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/GREATER.tosac[lines=10..-1] ---- ==== GREATER_EQUAL @@ -63,17 +39,5 @@ include::{generated}/operators/GREATER_EQUAL.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_t value1 = tensor_read(input1, shape1, index1); - in_t value2 = tensor_read(input2, shape2, index2); - out_t result; - if (isNaN(value1) || isNaN(value2)) - result = False; - else - result = (value1 >= value2) ? True : False; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/GREATER_EQUAL.tosac[lines=10..-1] ---- diff --git a/chapters/control_flow.adoc b/chapters/control_flow.adoc index 9de9c72..2da2424 100644 --- a/chapters/control_flow.adoc +++ b/chapters/control_flow.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2021 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -19,20 +19,7 @@ include::{generated}/operators/COND_IF.adoc[] [source,c++] ---- -ERROR_IF(tosa_nesting_depth >= MAX_NESTING); -ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(then_graph)); -ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(else_graph)); -ERROR_IF(tensor_list_shape(output_list) != tosa_output_shape(then_graph)); -ERROR_IF(tensor_list_shape(output_list) != tosa_output_shape(else_graph)); -ERROR_IF(tensor_size(shape) != 1); - -tosa_nesting_depth++; -if (condition[0]) { - tosa_execute_graph(then_graph, input_list, output_list); -} else { - tosa_execute_graph(else_graph, input_list, output_list); -} -tosa_nesting_depth--; +include::{pseudocode}/operators/COND_IF.tosac[lines=10..-1] ---- ==== WHILE_LOOP @@ -43,28 +30,5 @@ include::{generated}/operators/WHILE_LOOP.adoc[] [source,c++] ---- -ERROR_IF(tosa_nesting_depth >= MAX_NESTING); -ERROR_IF(tensor_list_shape(input_list) != tosa_list_shape(output_list)); -ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(cond_graph)); -ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(body_graph)); -ERROR_IF(tensor_list_shape(input_list) != tosa_output_shape(body_graph)); -// Condition graph output must be a single element tensor with a single bool value -ERROR_IF(tensor_size(tosa_output_shape(cond_graph)) != 1); -ERROR_IF(tosa_output_type(cond_graph) != bool_t); - -// The iteration number 'i' is included to give unique names to variables -// in each iteration of the loop and is not required by implementations -int32_t i=0; // iteration number -tensor_list_t list[]; // array of tensor lists indexed by iteration -bool_t *condition[]; // array of condition tensors indexed by iteration -list[i] = input_list; // copy input data as list[0] -tosa_nesting_depth++; -tosa_execute_graph(cond_graph, list[i], [ condition[i] ]); // initial condition -while (condition[i][0]) { - tosa_execute_graph(body_graph, list[i], list[i+1]); - i = i+1; - tosa_execute_graph(cond_graph, list[i], [ condition[i] ]); -} -tosa_nesting_depth--; -output_list = list[i]; +include::{pseudocode}/operators/WHILE_LOOP.tosac[lines=10..-1] ---- diff --git a/chapters/data_layout.adoc b/chapters/data_layout.adoc index 2d48eb1..1ce92be 100644 --- a/chapters/data_layout.adoc +++ b/chapters/data_layout.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -17,30 +17,7 @@ include::{generated}/operators/CONCAT.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= max(1,rank(shapes1[0]))); -ERROR_IF(shape[axis] != sum(shape_dim(shapes1[k], axis) for all k)) -ERROR_IF(in_out_t == shape_t && rank(shape) > 1); -// The following checks ensure all inputs are compatible for concatenation -for_each(input_shape in shapes1) { - ERROR_IF(rank(input_shape) != rank(shapes1[0])); - for_each(index in input_shape) { - ERROR_IF(index != axis && input_shape[index] != shapes1[0][index]); - } -} -for_each(index1 in shape) { - dim_t index2 = index1; - for (tensor t = 0; t < length(input1); t++) { - // Continue to concatenate along axis from each tensor - // For each output location, we are looking for the - // appropriate input tensor - if (index2[axis] >= 0 && index2[axis] < shape_dim(shapes1[t], axis)) { - in_out_t value = tensor_read(input1[t], shapes1[t], index2); - tensor_write(output, shape, index1, value); - } - index2[axis] = index2[axis] - shape_dim(shapes1[t], axis); - } -} - +include::{pseudocode}/operators/CONCAT.tosac[lines=10..-1] ---- ==== PAD @@ -53,24 +30,7 @@ include::{generated}/operators/PAD.adoc[] [source,c++] ---- -// Check output shape matches the padded input shape -ERROR_IF(rank(shape) != rank(shape1)); -for (i = 0; i < rank(shape); i++) { - ERROR_IF(padding[i,0] < 0 || padding[i,1] < 0); - ERROR_IF(shape[i] != padding[i, 0] + shape1[i] + padding[i, 1]); -} -for_each(index in shape) { - dim_t index1 = index; - bool_t is_pad = false; - for(i = 0; i < rank(shape); i++) { - index1[i] = index1[i] - padding[i,0]; - if (index1[i] < 0 || index[i] >= length(shape[i])) { - is_pad = true; - } - } - in_out_t value = is_pad ? pad_const : tensor_read(input1, shape1, index1); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/PAD.tosac[lines=10..-1] ---- ==== DIM @@ -81,8 +41,7 @@ include::{generated}/operators/DIM.adoc[] [source,c++] ---- -ERROR_IF(axis >= rank(shape)); -tensor_write(output, [], [], shape_dim(shape, axis)); +include::{pseudocode}/operators/DIM.tosac[lines=10..-1] ---- ==== RESHAPE @@ -93,18 +52,7 @@ include::{generated}/operators/RESHAPE.adoc[] [source,c++] ---- -ERROR_IF(tensor_size(shape1) != tensor_size(shape)); - -for_each(index in shape) { - // Calculate flattened index for the output location (index) - size_t offset = tensor_index_to_offset(shape, index); - // Now convert to the location in the input - dim_t tmp_index = tensor_offset_to_index(shape1, offset); - - // Now read/write the value - in_out_t val = tensor_read(input1, shape1, tmp_index); - tensor_write(output, shape, index, val); -} +include::{pseudocode}/operators/RESHAPE.tosac[lines=10..-1] ---- ==== REVERSE @@ -115,13 +63,7 @@ include::{generated}/operators/REVERSE.adoc[] [source,c++] ---- -ERROR_IF(axis < 0 || axis >= rank(shape)); -for_each(index in shape) { - dim_t tmp_index = index; - tmp_index[axis] = shape[axis] - 1 - index[axis]; - in_out_t value = tensor_read(input, shape, tmp_index); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/REVERSE.tosac[lines=10..-1] ---- ==== SLICE @@ -133,25 +75,7 @@ include::{generated}/operators/SLICE.adoc[] [source,c++] ---- -ERROR_IF(rank(shape1) != length(start) || rank(shape1) != length(size)); -ERROR_IF(rank(shape1) != rank(shape)); -// Sanity check the given coordinates, ensure start and end are -// within tensor bounds -for_each(index in rank(shape1)) { - ERROR_IF(start[index] < 0); - ERROR_IF(size[index] <= 0); //Output must be positive size - ERROR_IF(start[index] + size[index] > shape1[index]); - ERROR_IF(shape[index] != size[index]); -} - -for_each(index in shape) { - dim_t tmp_index = index; - for(i = 0; i < rank(shape); i++) { - tmp_index[i] = index[i] + start[i]; - } - in_out_t value = tensor_read(input1, shape1, tmp_index); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/SLICE.tosac[lines=10..-1] ---- ==== TILE @@ -162,17 +86,7 @@ include::{generated}/operators/TILE.adoc[] [source,c++] ---- -ERROR_IF(rank(shape1) != rank(shape)); - -for_each(index in shape) { - dim_t tmp_index = index; - for(i = 0; i < rank(shape); i++) { - ERROR_IF(shape1[i] * multiples[i] != shape[i]); - tmp_index[i] = index[i] % shape1[i]; - } - in_out_t value = tensor_read(input1, shape1, tmp_index); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/TILE.tosac[lines=10..-1] ---- ==== TRANSPOSE @@ -184,30 +98,5 @@ include::{generated}/operators/TRANSPOSE.adoc[] [source,c++] ---- -ERROR_IF(rank(shape1) != rank(shape)); -ERROR_IF(tensor_size(shape1) != tensor_size(shape)); - -for_each(index in perms) { - // Ensure each perms value is a valid value - ERROR_IF(index >= rank(shape1)); - ERROR_IF(index < 0); - // Ensure ranks aren't repeated - ERROR_IF(indexes_used[index] == true); - indexes_used[index] = true; -} - -// Ensure that the output shapes have the properly -// permuted shapes -for(i = 0; i < rank(shape); i++) { - ERROR_IF(shape1[perms[i]] != shape[i]) -} - -for_each(index in shape) { - dim_t tmp_index = index; - for(i = 0; i < rank(shape); i++) { - tmp_index[perms[i]] = index[i] - } - in_out_t value = tensor_read(input1, shape1, tmp_index); - tensor_write(output, shape, index, value); -} +include::{pseudocode}/operators/TRANSPOSE.tosac[lines=10..-1] ---- diff --git a/chapters/ewise_binary.adoc b/chapters/ewise_binary.adoc index 876ab4b..3cc2ecb 100644 --- a/chapters/ewise_binary.adoc +++ b/chapters/ewise_binary.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -18,23 +18,7 @@ include::{generated}/operators/ADD.adoc[] [source,c++] ---- -if (in_out_t == shape_t) { - ERROR_IF(rank(shape) != 0 || rank(shape1) != 0 || rank(shape2) != 0); - shape_t value1 = tensor_read(input1, [], []); - shape_t value2 = tensor_read(input2, [], []); - shape_t result = apply_add_s(value1, value2); - tensor_write(output, [], [], result); -} else { - ERROR_IF(shape != broadcast_shape(shape1, shape2)); - for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = apply_add_s(value1, value2); - tensor_write(output, shape, index, result); - } -} +include::{pseudocode}/operators/ADD.tosac[lines=10..-1] ---- ==== ARITHMETIC_RIGHT_SHIFT @@ -46,26 +30,7 @@ include::{generated}/operators/ARITHMETIC_RIGHT_SHIFT.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - - // Ensure that shift amount is appropriate for the data type - REQUIRE((in_out_t == i32_t && 0 <= value2 && value2 <= 31) || - (in_out_t == i16_t && 0 <= value2 && value2 <= 15) || - (in_out_t == i8_t && 0 <= value2 && value2 <= 7)); - - in_out_t result = apply_arith_rshift(value1, value2); - if (round == true && static_cast(value2) > 0 && - (apply_arith_rshift(value1, apply_sub_s(value2, 1)) & 1 != 0) { - result = result + 1; - } - result = apply_clip_s(result, minimum_s, maximum_s); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/ARITHMETIC_RIGHT_SHIFT.tosac[lines=10..-1] ---- ==== BITWISE_AND @@ -77,15 +42,7 @@ include::{generated}/operators/BITWISE_AND.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = value1 & value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/BITWISE_AND.tosac[lines=10..-1] ---- ==== BITWISE_OR @@ -97,15 +54,7 @@ include::{generated}/operators/BITWISE_OR.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = value1 | value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/BITWISE_OR.tosac[lines=10..-1] ---- ==== BITWISE_XOR @@ -117,15 +66,7 @@ include::{generated}/operators/BITWISE_XOR.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = value1 ^ value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/BITWISE_XOR.tosac[lines=10..-1] ---- ==== INTDIV @@ -140,28 +81,7 @@ include::{generated}/operators/INTDIV.adoc[] [source,c++] ---- -if (in_out_t == shape_t) { - ERROR_IF(rank(shape) != 0 || rank(shape1) != 0 || rank(shape2) != 0); - shape_t value1 = tensor_read(input1, [], []); - shape_t value2 = tensor_read(input2, [], []); - REQUIRE(value2 != 0); - shape_t result = value1 / value2; - tensor_write(output, [], [], result); -} else { - ERROR_IF(shape != broadcast_shape(shape1, shape2)); - for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - REQUIRE(value2 != 0); - // This catches the case where we divide minimum by -1 - // which is not representable in two's complement - REQUIRE(static_cast(value1) / static_cast(value2) <= maximum_s); - in_out_t result = apply_intdiv_s(value1, value2); - tensor_write(output, shape, index, result); - } -} +include::{pseudocode}/operators/INTDIV.tosac[lines=10..-1] ---- ==== LOGICAL_AND @@ -173,15 +93,7 @@ include::{generated}/operators/LOGICAL_AND.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = value1 && value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOGICAL_AND.tosac[lines=10..-1] ---- ==== LOGICAL_LEFT_SHIFT @@ -193,16 +105,7 @@ include::{generated}/operators/LOGICAL_LEFT_SHIFT.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - REQUIRE(0 <= value2 && value2 <= 31); - in_out_t result = value1 << value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOGICAL_LEFT_SHIFT.tosac[lines=10..-1] ---- ==== LOGICAL_RIGHT_SHIFT @@ -214,17 +117,7 @@ include::{generated}/operators/LOGICAL_RIGHT_SHIFT.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - REQUIRE(0 <= static_cast(value2) && static_cast(value2) <= 31); - // Logical shifts happen as unsigned types internally - in_out_t result = apply_logical_rshift(value1, value2); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOGICAL_RIGHT_SHIFT.tosac[lines=10..-1] ---- ==== LOGICAL_OR @@ -236,15 +129,7 @@ include::{generated}/operators/LOGICAL_OR.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = value1 || value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOGICAL_OR.tosac[lines=10..-1] ---- ==== LOGICAL_XOR @@ -256,15 +141,7 @@ include::{generated}/operators/LOGICAL_XOR.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = value1 != value2; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOGICAL_XOR.tosac[lines=10..-1] ---- ==== MAXIMUM @@ -276,15 +153,7 @@ include::{generated}/operators/MAXIMUM.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = apply_max_s(value1, value2); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/MAXIMUM.tosac[lines=10..-1] ---- ==== MINIMUM @@ -296,15 +165,7 @@ include::{generated}/operators/MINIMUM.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = apply_min_s(value1, value2); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/MINIMUM.tosac[lines=10..-1] ---- ==== MUL @@ -316,34 +177,7 @@ include::{generated}/operators/MUL.adoc[] [source,c++] ---- -if (in_out_t == shape_t) { - ERROR_IF(rank(shape) != 0 || rank(shape1) != 0 || rank(shape2) != 0); - shape_t value1 = tensor_read(input1, [], []); - shape_t value2 = tensor_read(input2, [], []); - shape_t result = value1 * value2; - tensor_write(output, [], [], result); -} else { - REQUIRE(0 <= shift && shift <= 63); - REQUIRE(in_t == int32_t || shift == 0); - ERROR_IF(shape != broadcast_shape(shape1, shape2)); - for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_t value1 = tensor_read(input1, shape1, index1); - in_t value2 = tensor_read(input2, shape2, index2); - out_t result; - if (in_t == i32_t && shift > 0) { - int64_t product = sign_extend(value1) * sign_extend(value2); - int64_t round = static_cast(1) << (shift - 1); - product = (product + round) >> shift; - REQUIRE(product >= minimum_s && product <= maximum_s) - result = product; - } else { - result = apply_mul_s(value1, value2); // low 32-bits of result for i32_t - } - tensor_write(output, shape, index, result); - } -} +include::{pseudocode}/operators/MUL.tosac[lines=10..-1] ---- ==== POW @@ -355,15 +189,7 @@ include::{generated}/operators/POW.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(shape1, shape2)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = apply_pow(value1, value2); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/POW.tosac[lines=10..-1] ---- ==== SUB @@ -375,23 +201,7 @@ include::{generated}/operators/SUB.adoc[] [source,c++] ---- -if (in_out_t == shape_t) { - ERROR_IF(rank(shape) != 0 || rank(shape1) != 0 || rank(shape2) != 0); - shape_t value1 = tensor_read(input1, [], []); - shape_t value2 = tensor_read(input2, [], []); - shape_t result = apply_sub(value1, value2); - tensor_write(output, [], [], result); -} else { - ERROR_IF(shape != broadcast_shape(shape1, shape2)); - for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - in_out_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t result = apply_sub_s(value1, value2); - tensor_write(output, shape, index, result); - } -} +include::{pseudocode}/operators/SUB.tosac[lines=10..-1] ---- ==== TABLE @@ -414,16 +224,5 @@ include::{generated}/operators/TABLE.adoc[] [source,c++] ---- -REQUIRE(length(table) == TABLE_SIZE); -for_each(index in shape) { - in_t value = tensor_read(input, shape, index); - out_t result; - if (in_t == i8_t) { - // value is a signed int, convert to a 0 based index - result = table[static_cast(value) + 128]; - } else { - result = apply_lookup_s(static_cast(table), static_cast(value)); - } - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/TABLE.tosac[lines=10..-1] ---- diff --git a/chapters/ewise_ternary.adoc b/chapters/ewise_ternary.adoc index 57cf599..d6ea453 100644 --- a/chapters/ewise_ternary.adoc +++ b/chapters/ewise_ternary.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2021 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -17,20 +17,5 @@ include::{generated}/operators/SELECT.adoc[] [source,c++] ---- -ERROR_IF(shape != broadcast_shape(broadcast_shape(shape1, shape2), shape3)); -for_each(index in shape) { - dim_t index1 = apply_broadcast(shape, shape1, index); - dim_t index2 = apply_broadcast(shape, shape2, index); - dim_t index3 = apply_broadcast(shape, shape3, index); - bool_t value1 = tensor_read(input1, shape1, index1); - in_out_t value2 = tensor_read(input2, shape2, index2); - in_out_t value3 = tensor_read(input3, shape3, index3); - in_out_t result; - if (value1) { - result = value2; - } else { - result = value3; - } - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/SELECT.tosac[lines=10..-1] ---- diff --git a/chapters/ewise_unary.adoc b/chapters/ewise_unary.adoc index d3eacc4..4b8cd4d 100644 --- a/chapters/ewise_unary.adoc +++ b/chapters/ewise_unary.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -24,16 +24,7 @@ include::{generated}/operators/ABS.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - if (is_floating_point(in_out_t) && value1 == -0.0) { - value1 = 0.0; - } - if (static_cast(value1) < 0.0) { - value1 = apply_sub_s(0, value1); - } - tensor_write(output, shape, index, value1); -} +include::{pseudocode}/operators/ABS.tosac[lines=10..-1] ---- ==== BITWISE_NOT @@ -44,11 +35,7 @@ include::{generated}/operators/BITWISE_NOT.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - in_out_t result = ~value1; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/BITWISE_NOT.tosac[lines=10..-1] ---- ==== CEIL @@ -66,11 +53,7 @@ include::{generated}/operators/CEIL.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - in_out_t result = apply_ceil(value1); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/CEIL.tosac[lines=10..-1] ---- ==== CLZ @@ -81,11 +64,7 @@ include::{generated}/operators/CLZ.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - in_out_t result = count_leading_zeros(value1); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/CLZ.tosac[lines=10..-1] ---- ==== EXP @@ -103,11 +82,7 @@ include::{generated}/operators/EXP.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - in_out_t result = apply_exp(value1); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/EXP.tosac[lines=10..-1] ---- ==== FLOOR @@ -125,11 +100,7 @@ include::{generated}/operators/FLOOR.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - in_out_t result = apply_floor(value1); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/FLOOR.tosac[lines=10..-1] ---- ==== LOG @@ -147,11 +118,7 @@ include::{generated}/operators/LOG.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - in_out_t result = apply_log(value1); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOG.tosac[lines=10..-1] ---- ==== LOGICAL_NOT @@ -162,11 +129,7 @@ include::{generated}/operators/LOGICAL_NOT.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape1, index); - in_out_t result = !value1; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/LOGICAL_NOT.tosac[lines=10..-1] ---- ==== NEGATE @@ -184,19 +147,7 @@ include::{generated}/operators/NEGATE.adoc[] [source,c++] ---- -ERROR_IF(in_out_t != i8_t && input1_zp != 0) // Zero point only for int8_t -ERROR_IF(in_out_t != i8_t && output_zp != 0) // Zero point only for int8_t -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape, index); - acc_t value = apply_sub_s(sign_extend(value1), - sign_extend(input1_zp)); - value = apply_sub_s(0, value); - value = apply_add_s(value, sign_extend(output_zp)); - in_out_t result = truncate(apply_clip_s(value, - minimum_s, - maximum_s)); - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/NEGATE.tosac[lines=10..-1] ---- ==== RECIPROCAL @@ -214,11 +165,7 @@ include::{generated}/operators/RECIPROCAL.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape1, index); - in_out_t result = 1.0 / value1; - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/RECIPROCAL.tosac[lines=10..-1] ---- ==== RSQRT @@ -236,15 +183,5 @@ include::{generated}/operators/RSQRT.adoc[] [source,c++] ---- -for_each(index in shape) { - in_out_t value1 = tensor_read(input1, shape1, index); - in_out_t result; - if (value1 < 0) { - result = NaN; - } - else { - result = 1.0 / apply_sqrt(value1); - } - tensor_write(output, shape, index, result); -} +include::{pseudocode}/operators/RSQRT.tosac[lines=10..-1] ---- diff --git a/chapters/image.adoc b/chapters/image.adoc index 59e5ddf..1d2a212 100644 --- a/chapters/image.adoc +++ b/chapters/image.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -61,69 +61,5 @@ include::{generated}/operators/RESIZE.adoc[] [source,c++] ---- -// Ensure the image size is supported by GPU APIs and that for integer -// implementations, position * stride does not overflow int32_t. -ERROR_IF(max(OH,OW,IH,IW) >= 16384); -ERROR_IF(scale_y_n <= 0 || scale_y_d <= 0 || scale_x_n <= 0 || scale_x_d <= 0); -// if in_t=int8_t ensure that an int32_t accumulator can be used -ERROR_IF(scale_y_n > (1 << 11) || scale_x_n > (1 << 11)); -// set a consistent lower limit of 1/16 downscale to simplify implementations -ERROR_IF(scale_y_d >= 16 * scale_y_n || scale_x_d >= 16 * scale_x_n); -ERROR_IF(offset_y < -scale_y_n || offset_y >= 16 * scale_y_n); -ERROR_IF(offset_x < -scale_x_n || offset_x >= 16 * scale_x_n); -ERROR_IF(border_y < -16 * scale_y_n || border_y >= scale_y_n); -ERROR_IF(border_x < -16 * scale_x_n || border_x >= scale_x_n); -ERROR_IF(OH != idiv_check((IH - 1) * scale_y_n - offset_y + border_y, scale_y_d) + 1); -ERROR_IF(OW != idiv_check((IW - 1) * scale_x_n - offset_x + border_x, scale_x_d) + 1); -for_each(0 <= n < N, 0 <= oy < OH, 0 <= ox < OW; 0 <= c < C) { - out_t acc; - resize_t dx, dy; - resize_t unit_x, unit_y; - - unit_x = (is_floating_point(resize_t)) ? 1.0 : scale_x_n; - unit_y = (is_floating_point(resize_t)) ? 1.0 : scale_y_n; - - int32_t y = oy * scale_y_d + offset_y; - int32_t x = ox * scale_x_d + offset_x; - int16_t iy = idiv_floor(y, scale_y_n); - int16_t ix = idiv_floor(x, scale_x_n); - int16_t ry = y - iy * scale_y_n; // (y % scale_y_n) - int16_t rx = x - ix * scale_x_n; // (x % scale_x_n) - - if (is_floating_point(resize_t)) { - dy = static_cast(ry) / static_cast(scale_y_n); - dx = static_cast(rx) / static_cast(scale_x_n); - } else { - dy = ry; - dx = rx; - } - // Note that -1 <= iy < IH and -1 <= ix < IW - int16_t iy0 = apply_max_s(iy, 0); - int16_t iy1 = apply_min_s(iy + 1, IH - 1); - int16_t ix0 = apply_max_s(ix, 0); - int16_t ix1 = apply_min_s(ix + 1, IW - 1); - if (mode==BILINEAR) { - using in_s_t = make_signed(in_t); // Use signed calculations for i8/i16 - in_s_t v00 = static_cast(tensor_read(input, [N,IH,IW,C], [n,iy0,ix0,c])); - in_s_t v01 = static_cast(tensor_read(input, [N,IH,IW,C], [n,iy0,ix1,c])); - in_s_t v10 = static_cast(tensor_read(input, [N,IH,IW,C], [n,iy1,ix0,c])); - in_s_t v11 = static_cast(tensor_read(input, [N,IH,IW,C], [n,iy1,ix1,c])); - acc = v00 * (unit_y - dy) * (unit_x - dx); - acc += v01 * (unit_y - dy) * dx; - acc += v10 * dy * (unit_x - dx); - acc += v11 * dy * dx; - tensor_write(output, [N,OH,OW,C], [n,oy,ox,c], acc); - } else if (mode==NEAREST) { - int32_t iy, ix; - if (is_floating_point(resize_t)) { - iy = (dy >= 0.5) ? iy1 : iy0; - ix = (dx >= 0.5) ? ix1 : ix0; - } else { - iy = (2 * dy >= scale_y_n) ? iy1 : iy0; - ix = (2 * dx >= scale_x_n) ? ix1 : ix0; - } - in_t v = tensor_read(input, [N,IH,IW,C], [n,iy,ix,c]); - tensor_write(output, [N,OH,OW,C], [n,oy,ox,c], v); - } -} +include::{pseudocode}/operators/RESIZE.tosac[lines=10..-1] ---- diff --git a/chapters/reduction.adoc b/chapters/reduction.adoc index 19ff4ed..e3692de 100644 --- a/chapters/reduction.adoc +++ b/chapters/reduction.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -17,22 +17,7 @@ include::{generated}/operators/REDUCE_ALL.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -ERROR_IF(shape[axis] != 1); -left_shape = (axis > 1) ? shape[0:axis-1] : []; -right_shape = (axis < rank(shape)-1) ? shape[axis+1:rank(shape)-1] : []; -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - in_out_t acc = true; - for (i = 0; i < shape1[axis]; i++) { - index = flatten(left_index, [i], right_index); - in_out_t value = tensor_read(input, shape1, index); - acc = acc && value; - } - out_index = flatten(left_index, [0], right_index); - tensor_write(output, shape, out_index, acc); - } -} +include::{pseudocode}/operators/REDUCE_ALL.tosac[lines=10..-1] ---- ==== REDUCE_ANY @@ -43,22 +28,7 @@ include::{generated}/operators/REDUCE_ANY.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -ERROR_IF(shape[axis] != 1); -left_shape = (axis > 1) ? shape[0:axis-1] : []; -right_shape = (axis < rank(shape)-1) ? shape[axis+1:rank(shape)-1] : []; -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - in_out_t acc = false; - for (i = 0; i < shape1[axis]; i++) { - index = flatten(left_index, [i], right_index); - in_out_t value = tensor_read(input, shape1, index); - acc = acc || value; - } - out_index = flatten(left_index, [0], right_index); - tensor_write(output, shape, out_index, acc); - } -} +include::{pseudocode}/operators/REDUCE_ANY.tosac[lines=10..-1] ---- ==== REDUCE_MAX @@ -69,22 +39,7 @@ include::{generated}/operators/REDUCE_MAX.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -ERROR_IF(shape[axis] != 1); -left_shape = (axis > 1) ? shape[0:axis-1] : []; -right_shape = (axis < rank(shape)-1) ? shape[axis+1:rank(shape)-1] : []; -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - in_out_t acc = minimum; - for (i = 0; i < shape1[axis]; i++) { - index = flatten(left_index, [i], right_index); - in_out_t value = tensor_read(input, shape1, index); - acc = apply_max_s(acc, value); - } - out_index = flatten(left_index, [0], right_index); - tensor_write(output, shape, out_index, acc); - } -} +include::{pseudocode}/operators/REDUCE_MAX.tosac[lines=10..-1] ---- ==== REDUCE_MIN @@ -95,22 +50,7 @@ include::{generated}/operators/REDUCE_MIN.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -ERROR_IF(shape[axis] != 1); -left_shape = (axis > 1) ? shape[0:axis-1] : []; -right_shape = (axis < rank(shape)-1) ? shape[axis+1:rank(shape)-1] : []; -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - in_out_t acc = maximum; - for (i = 0; i < shape1[axis]; i++) { - index = flatten(left_index, [i], right_index); - in_out_t value = tensor_read(input, shape1, index); - acc = apply_min_s(acc, value); - } - out_index = flatten(left_index, [0], right_index); - tensor_write(output, shape, out_index, out); - } -} +include::{pseudocode}/operators/REDUCE_MIN.tosac[lines=10..-1] ---- ==== REDUCE_PRODUCT @@ -121,22 +61,7 @@ include::{generated}/operators/REDUCE_PRODUCT.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -ERROR_IF(shape[axis] != 1); -left_shape = (axis > 1) ? shape[0:axis-1] : []; -right_shape = (axis < rank(shape)-1) ? shape[axis+1:rank(shape)-1] : []; -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - in_out_t acc = 1.0; - for (i = 0; i < shape1[axis]; i++) { - index = flatten(left_index, [i], right_index); - in_out_t value = tensor_read(input, shape1, index); - acc = apply_mul_s(acc, value); - } - out_index = flatten(left_index, [0], right_index); - tensor_write(output, shape, out_index, acc); - } -} +include::{pseudocode}/operators/REDUCE_PRODUCT.tosac[lines=10..-1] ---- ==== REDUCE_SUM @@ -147,21 +72,5 @@ include::{generated}/operators/REDUCE_SUM.adoc[] [source,c] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -ERROR_IF(shape[axis] != 1); -left_shape = (axis > 1) ? shape[0:axis-1] : []; -right_shape = (axis < rank(shape)-1) ? shape[axis+1:rank(shape)-1] : []; -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - acc_t acc = 0; - for (i = 0; i < shape1[axis]; i++) { - index = flatten(left_index, [i], right_index); - acc_t value = tensor_read(input, shape1, index); - acc = apply_add_s(acc, value); - } - out_index = flatten(left_index, [0], right_index); - in_out_t result = static_cast(acc); - tensor_write(output, shape, out_index, result); - } -} +include::{pseudocode}/operators/REDUCE_SUM.tosac[lines=10..-1] ---- diff --git a/chapters/scatter_gather.adoc b/chapters/scatter_gather.adoc index d694d39..4632e3a 100644 --- a/chapters/scatter_gather.adoc +++ b/chapters/scatter_gather.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2021 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -18,12 +18,7 @@ include::{generated}/operators/GATHER.adoc[] [source,c++] ---- -for_each(0 <= n < N, 0 <= w < W, 0 <= c < C) { - index_t k = tensor_read(indices, [N,W], [n,w]); - REQUIRE(0 <= k && k < K); - in_out_t value = tensor_read(values, [N,K,C], [n,k,c]); - tensor_write(output, [N,W,C], [n,w,c], value); -} +include::{pseudocode}/operators/GATHER.tosac[lines=10..-1] ---- ==== SCATTER @@ -38,26 +33,5 @@ include::{generated}/operators/SCATTER.adoc[] [source,c++] ---- - -// The following array is used to check compliance that an output position -// is modified at most once. -bool_t output_modified[N,K,C]; - -// Copy the values_in tensor to the values_out tensor. -// Values not written by the scatter operation are unchanged in the output. -for_each(0 <= n < N, 0 <= k < K, 0 <= c < C) { - in_out_t value = tensor_read(values_in, [N,K,C], [n,k,c]); - tensor_write(values_out, [N,K,C], [n, k, c], value); - output_modified[n,k,c]=false; -} - -// Now perform the SCATTER operation, modifying the positions from the indices tensor -for_each(0 <= n < N, 0 <= w < W, 0 <= c < C) { - index_t k = tensor_read(indices, [N,W], [n,w]); - REQUIRE(0 <= k && k < K); - REQUIRE(output_modified[n,k,c] == false); - in_out_t value = tensor_read(input, [N,W,C], [n,w,c]); - tensor_write(values_out, [N,K,C], [n, k, c], value); - output_modified[n,k,c] = true; -} +include::{pseudocode}/operators/SCATTER.tosac[lines=10..-1] ---- diff --git a/chapters/tensor_ops.adoc b/chapters/tensor_ops.adoc index b3de433..3de5150 100644 --- a/chapters/tensor_ops.adoc +++ b/chapters/tensor_ops.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -17,34 +17,7 @@ include::{generated}/operators/ARGMAX.adoc[] [source,c++] ---- -ERROR_IF(axis < 0 || axis >= rank(shape1)); -if (axis == 0) { - left_shape = []; -} else { - left_shape = shape1[0:axis - 1]; -} -if (axis == rank(shape1)-1) { - right_shape = []; -} else { - right_shape = shape1[axis+1:rank(shape1) - 1]; -} -ERROR_IF(flatten(left_shape, right_shape) != shape); -for_each(left_index in left_shape) { - for_each(right_index in right_shape) { - in_t max_value = minimum_s; - out_t max_index = 0; - for (i = 0; i < shape[axis]; i++) { - dim_t index = flatten(left_index, [i], right_index); - in_t value = tensor_read(input, shape1, index); - if (apply_max_s(value, max_value) != max_value) { - max_value = value; - max_index = i; - } - } - dim_t index = flatten(left_index, right_index); - tensor_write(output, shape, index, max_index); - } -} +include::{pseudocode}/operators/ARGMAX.tosac[lines=10..-1] ---- ==== AVG_POOL2D @@ -57,47 +30,7 @@ include::{generated}/operators/AVG_POOL2D.adoc[] [source,c++] ---- -ERROR_IF(in_out_t != i8_t && input_zp != 0); // Zero point only for int8_t -ERROR_IF(in_out_t != i8_t && output_zp != 0); // Zero point only for int8_t -ERROR_IF(kernel_y < 1 || kernel_x < 1); // kernel size must be >= 1 -ERROR_IF(stride_y < 1 || stride_x < 1); -ERROR_IF(pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0); -// Padding must be less than kernel size to avoid -// a divide-by-zero. -ERROR_IF(pad_right >= kernel_x || pad_left >= kernel_x); -ERROR_IF(pad_top >= kernel_y || pad_bottom >= kernel_y); -ERROR_IF(OH != idiv_check(IH + pad_top + pad_bottom - kernel_y, stride_y) + 1); -ERROR_IF(OW != idiv_check(IW + pad_left + pad_right - kernel_x, stride_x) + 1); - -for_each(0 <= n < N, 0 <= oy < OH, 0 <= ox < OW, 0 <= c < C ) { - in_out_t output_val; - acc_t acc = 0; - int count = 0; - index_t iy = oy * stride_y - pad_top; - index_t ix = ox * stride_x - pad_left; - for_each(0 <= ky < kernel_y, 0 <= kx < kernel_x) { - index_t y = iy + ky; - index_t x = ix + kx; - // Only values from the input tensor are used to calculate the - // average, padding does not count - if (0 <= y < IH and 0 <= x < IW) { - count++; - acc_t value = sign_extend(tensor_read(input, [N,IH,IW,C], [n,y,x,c])); - value = apply_sub_s(value, sign_extend(input_zp)); - acc = apply_add_s(acc, value); - } - } - if (is_float(in_out_t)) { - output_val = acc / static_cast(count); - } else { - scale_t scale = reciprocal_scale(count); - acc = apply_scale_32(acc, scale.multiplier, scale.shift, false); - acc = apply_add_s(acc, sign_extend(output_zp)); - acc = apply_clip_s(acc, minimum_s, maximum_s); - output_val = static_cast(acc); - } - tensor_write(output, [N,OH,OW,C], [n,oy,ox,c], output_val); -} +include::{pseudocode}/operators/AVG_POOL2D.tosac[lines=10..-1] ---- ==== CONV2D @@ -108,37 +41,7 @@ include::{generated}/operators/CONV2D.adoc[] [source,c++] ---- -ERROR_IF(in_t != i8_t && input_zp != 0); // Zero point only for int8_t -ERROR_IF(weight_t != int8_t && weight_zp != 0); -ERROR_IF(pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0); -ERROR_IF(stride_y < 1 || stride_x < 1); -ERROR_IF(dilation_y < 1 || dilation_x < 1); -ERROR_IF(OH != idiv_check(IH - 1 + pad_top + pad_bottom - (KH - 1) * dilation_y, stride_y) + 1); -ERROR_IF(OW != idiv_check(IW - 1 + pad_left + pad_right - (KW - 1) * dilation_x, stride_x) + 1); -ERROR_IF(BC != OC && BC != 1); - -for_each(0 <= n < N, 0 <= oy < OH, 0 <= ox < OW; 0 <= oc < OC) { - out_t acc = 0; - index_t iy = oy * stride_y - pad_top; - index_t ix = ox * stride_x - pad_left; - for_each(0 <= ky < KH, 0 <= kx < KW, 0 <= ic < IC) { - index_t y = iy + ky * dilation_y; - index_t x = ix + kx * dilation_x; - if (0 <= y < IH && 0 <= x < IW) { - out_t value = static_cast(tensor_read(input, - [N,IH,IW,IC], - [n,y,x,ic])); - out_t weight = static_cast(tensor_read(weight, - [OC,KH,KW,IC], - [oc,ky,kx,ic])); - value = apply_sub_s(value, static_cast(input_zp)); - weight = apply_sub_s(weight, static_cast(weight_zp)); - acc = apply_add_s(acc, apply_mul_s(value, weight)); - } - } - acc = apply_add_s(acc, bias[(BC == 1) ? 0 : oc]); - tensor_write(output, [N,OH,OW,OC], [n,oy,ox,oc], acc); -} +include::{pseudocode}/operators/CONV2D.tosac[lines=10..-1] ---- ==== CONV3D @@ -149,40 +52,7 @@ include::{generated}/operators/CONV3D.adoc[] [source,c++] ---- -ERROR_IF(in_t != i8_t && input_zp != 0); // Zero point only for int8_t -ERROR_IF(weight_t != i8_t && weight_zp != 0); -ERROR_IF(pad_d0 < 0 || pad_d1 < 0 || pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0); -ERROR_IF(stride_d < 1 || stride_y < 1 || stride_x < 1); -ERROR_IF(dilation_d < 1 || dilation_y < 1 || dilation_x < 1); -ERROR_IF(OD != idiv_check(ID - 1 + pad_d0 + pad_d1 - (KD - 1) * dilation_d, stride_d) + 1); -ERROR_IF(OH != idiv_check(IH - 1 + pad_top + pad_bottom - (KH - 1) * dilation_y, stride_y) + 1); -ERROR_IF(OW != idiv_check(IW - 1 + pad_left + pad_right - (KW - 1) * dilation_x, stride_x) + 1); -ERROR_IF(BC != OC && BC != 1); - -for_each(0 <= n < N, 0 <= od < OD, 0 <= oy < OH, 0 <= ox < OW; 0 <= oc < OC) { - out_t acc = 0; - index_t id = od * stride_d - pad_d0; - index_t iy = oy * stride_y - pad_top; - index_t ix = ox * stride_x - pad_left; - for_each(0 <= kd < KD, 0 <= ky < KH, 0 <= kx < KW, 0 <= ic < IC) { - index_t d = id + kd * dilation_d; - index_t y = iy + ky * dilation_y; - index_t x = ix + kx * dilation_x; - if (0 <= x < IW && 0 <= y < IH && 0 <= d < ID) { - out_t value = static_cast(tensor_read(input, - [N,ID,IH,IW,IC], - [n,d,y,x,ic])); - out_t weight = static_cast(tensor_read(weight, - [OC,KD,KH,KW,IC], - [oc,kd,ky,kx,ic])); - value = apply_sub_s(value, static_cast(input_zp)); - weight = apply_sub_s(weight, static_cast(weight_zp)); - acc = apply_add_s(acc, apply_mul_s(value, weight)); - } - } - acc = apply_add_s(acc, bias[(BC == 1) ? 0 : oc]); - tensor_write(output, [N,OD,OH,OW,OC], [n,od,oy,ox,oc], acc); -} +include::{pseudocode}/operators/CONV3D.tosac[lines=10..-1] ---- ==== DEPTHWISE_CONV2D @@ -193,37 +63,7 @@ include::{generated}/operators/DEPTHWISE_CONV2D.adoc[] [source,c++] ---- -ERROR_IF(in_t != i8_t && input_zp != 0); // Zero point only for int8_t -ERROR_IF(weight_t != i8_t && weight_zp != 0); -ERROR_IF(pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0); -ERROR_IF(stride_y < 1 || stride_x < 1); -ERROR_IF(dilation_y < 1 || dilation_x < 1); -ERROR_IF(OH != idiv_check(IH - 1 + pad_top + pad_bottom - (KH - 1) * dilation_y, stride_y) + 1); -ERROR_IF(OW != idiv_check(IW - 1 + pad_left + pad_right - (KW - 1) * dilation_x, stride_x) + 1); -ERROR_IF(BC != C*M && BC != 1); - -for_each(0 <= n < N, 0 <= oy < OH, 0 <= ox < OW; 0 <= c < C, 0 <= m < M) { - out_t acc = 0; - index_t iy = oy * stride_y - pad_top; - index_t ix = ox * stride_x - pad_left; - for_each(0 <= ky < KH, 0 <= kx < KW) { - index_t y = iy + ky * dilation_y; - index_t x = ix + kx * dilation_x; - if (0 <= y < IH && 0 <= x < IW) { - out_t value = static_cast(tensor_read(input, - [N,IH,IW,C], - [n,y,x,c])); - out_t weight = static_cast(tensor_read(weight, - [KH,KW,C,M], - [ky,kx,c,m])); - value = apply_sub_s(value, static_castinput_zp); - weight = apply_sub_s(weight, static_castweight_zp); - acc = apply_add_s(acc, apply_mul_s(value, weight)); - } - } - acc = apply_add_s(acc, bias[(BC == 1) ? 0 : (c * M) + m]); - tensor_write(output, [N,OH,OW,C * M], [n,oy,ox,c * M + m], acc); -} +include::{pseudocode}/operators/DEPTHWISE_CONV2D.tosac[lines=10..-1] ---- ==== FFT2D @@ -247,28 +87,7 @@ include::{generated}/operators/FFT2D.adoc[] [source,c++] ---- -ERROR_IF(!power_of_two(H)); -ERROR_IF(!power_of_two(W)); - -float sign_val = 1.0; - -if (inverse) { - sign_val = -1.0; -} - -for_each(0 <= n < N, 0 <= oy < H, 0 <= ox < W) { - in_out_t sum_real = 0.0; - in_out_t sum_imag = 0.0; - for_each(0 <= iy < H, 0 <= ix < W) { - in_out_t val_real = tensor_read(input_real, [N,H,W], [n,iy,ix]); - in_out_t val_imag = tensor_read(input_imag, [N,H,W], [n,iy,ix]); - float_t a = sign_val * 2 * pi() * ((iy * oy) / H + (ix * ox) / W); - sum_real += val_real * cos(a) + val_imag * sin(a); - sum_imag += -val_real * sin(a) + val_imag * cos(a); - } - tensor_write(output_real, [N,H,W], [n,oy,ox], sum_real); - tensor_write(output_imag, [N,H,W], [n,oy,ox], sum_imag); -} +include::{pseudocode}/operators/FFT2D.tosac[lines=10..-1] ---- ==== FULLY_CONNECTED @@ -279,22 +98,7 @@ include::{generated}/operators/FULLY_CONNECTED.adoc[] [source,c++] ---- -ERROR_IF(in_t != i8_t && input_zp != 0); // Zero point only for int8_t -ERROR_IF(weight_t != i8_t && weight_zp != 0); -ERROR_IF(BC != OC && BC != 1); - -for_each(0 <= n < N, 0 <= oc < OC) { - out_t acc = 0; - for_each(0 <= ic < IC) { - out_t value = static_cast(tensor_read(input, [N,IC], [n,ic])); - out_t weight = static_cast(tensor_read(weight, [OC,IC], [oc,ic])); - value = apply_sub_s(value, static_cast(input_zp)); - weight = apply_sub_s(weight, static_cast(weight_zp)); - acc = apply_add_s(acc, apply_mul_s(value, weight)); - } - acc = apply_add_s(acc, bias[(BC == 1) ? 0 : oc]); - tensor_write(output, [N,OC], [n,oc], acc); -} +include::{pseudocode}/operators/FULLY_CONNECTED.tosac[lines=10..-1] ---- ==== MATMUL @@ -305,18 +109,7 @@ include::{generated}/operators/MATMUL.adoc[] [source,c++] ---- -ERROR_IF(in_t != i8_t && (A_zp != 0 || B_zp != 0)); // Zero point only for int8_t -for_each(0 <= n < N, 0 <= h < H, 0 <= w < W) { - out_t acc = 0; - for_each(0 <= c < C) { - out_t value1 = static_cast(tensor_read(A, [N,H,C], [n,h,c])); - out_t value2 = static_cast(tensor_read(B, [N,C,W], [n,c,w])); - value1 = apply_sub_s(value1, static_cast(A_zp)); - value2 = apply_sub_s(value2, static_cast(B_zp)); - acc = apply_add_s(acc, apply_mul_s(value1 * value2)); - } - tensor_write(output, [N,H,W], [n,h,w], acc); -} +include::{pseudocode}/operators/MATMUL.tosac[lines=10..-1] ---- ==== MAX_POOL2D @@ -327,30 +120,7 @@ include::{generated}/operators/MAX_POOL2D.adoc[] [source,c++] ---- -ERROR_IF(kernel_y < 1 || kernel_x < 1); // kernel size must be >= 1 -ERROR_IF(stride_y < 1 || stride_x < 1); -ERROR_IF(pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0); -// Padding must be less than kernel size, otherwise no -// input values will be used. -ERROR_IF(pad_right >= kernel_x || pad_left >= kernel_x); -ERROR_IF(pad_top >= kernel_y || pad_bottom >= kernel_y); -ERROR_IF(OH != idiv_check(IH + pad_top + pad_bottom - kernel_y, stride_y) + 1); -ERROR_IF(OW != idiv_check(IW + pad_left + pad_right - kernel_x, stride_x) + 1); - -for_each(0 <= n < N, 0 <= oy < H, 0 <= ox < W, 0 <= c < C ) { - in_out_t acc = minimum_value; - index_t iy = oy * stride_y - pad_top; - index_t ix = ox * stride_x - pad_left; - for_each( 0 <= ky < kernel_y, 0 <= kx < kernel_x ) { - index_t y = iy + ky; - index_t x = ix + kx; - if (y >= 0 && y < IH && x >= 0 && x < IW) { - in_out_t value = tensor_read(input, [N,IH,IW,C], [n,y,x,c]); - acc = apply_max_s(acc, value); - } - } - tensor_write(output, [N,OH,OW,C], [n,oy,ox,c], acc); -} +include::{pseudocode}/operators/MAX_POOL2D.tosac[lines=10..-1] ---- ==== RFFT2D @@ -368,21 +138,7 @@ include::{generated}/operators/RFFT2D.adoc[] [source,c++] ---- -ERROR_IF(!power_of_two(H)); -ERROR_IF(!power_of_two(W)); - -for_each(0 <= n < N, 0 <= oy < H, 0 <= ox < W/2 + 1) { - in_out_t sum_real = 0.0; - in_out_t sum_imag = 0.0; - for_each(0 <= iy < H, 0 <= ix < W) { - in_out_t val_real = tensor_read(input_real, [N,H,W], [n,iy,ix]); - float_t a = 2 * pi() * ((iy * oy) / H + (ix * ox) / W); - sum_real += val_real * cos(a); - sum_imag += -val_real * sin(a); - } - tensor_write(output_real, [N,H,W], [n,oy,ox], sum_real); - tensor_write(output_imag, [N,H,W], [n,oy,ox], sum_imag); -} +include::{pseudocode}/operators/RFFT2D.tosac[lines=10..-1] ---- ==== TRANSPOSE_CONV2D @@ -393,30 +149,5 @@ include::{generated}/operators/TRANSPOSE_CONV2D.adoc[] [source,c++] ---- -ERROR_IF(in_t != i8_t && input_zp != 0); // Zero point only allowed for int8_t -ERROR_IF(weight_t != i8_t && weight_zp != 0); -ERROR_IF(out_pad_top <= -KH || out_pad_bottom <= -KH); -ERROR_IF(out_pad_left <= -KW || out_pad_right <= -KW); -ERROR_IF(stride_y < 1 || stride_x < 1); -ERROR_IF(OH != (IH - 1) * stride_y + out_pad_top + out_pad_bottom + KH); -ERROR_IF(OW != (IW - 1) * stride_x + out_pad_left + out_pad_right + KW); -ERROR_IF(BC != OC && BC != 1); - -for_each(index in [N, OH, OW, OC]) { - tensor_write(output, [N,OH,OW,OC], index, bias[(BC == 1) ? 0 : index[3]]) -} -for_each(0 <= n < N, 0 <= iy < IH, 0 <= ix < IW, 0 <= oc < OC, - 0 <= ic < IC, 0 <= ky < KH, 0 <= kx < KW) { - index_t oy = iy * stride_y + out_pad_top + ky; - index_t ox = ix * stride_x + out_pad_left + kx; - if (oy >= 0 && oy < OH && ox >= 0 && ox < OW) { - out_t acc = static_cast(tensor_read(output, [N,OH,OW,OC], [n,oy,ox,oc])); - out_t value = static_cast(tensor_read(input, [N,IH,IW,IC], [n,iy,ix,ic])); - out_t weight = static_cast(tensor_read(weight, [OC,KH,KW,IC], [oc,ky,kx,ic])); - value = apply_sub_s(value, static_cast(input_zp)); - weight = apply_sub_s(weight, static_cast(weight_zp)); - acc = apply_add_s(acc, apply_mul_s(value, weight)); - tensor_write(output, [N,OH,OW,OC], [n,oy,ox,oc], acc); - } -} +include::{pseudocode}/operators/TRANSPOSE_CONV2D.tosac[lines=10..-1] ---- diff --git a/chapters/type_conversion.adoc b/chapters/type_conversion.adoc index 90aca2d..71be3ac 100644 --- a/chapters/type_conversion.adoc +++ b/chapters/type_conversion.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2020-2023 ARM Limited +// (C) COPYRIGHT 2020-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -17,24 +17,7 @@ include::{generated}/operators/CAST.adoc[] [source,c++] ---- -for_each(index in shape) { - in_t in = tensor_read(input, shape, index); - out_t out; - if (out_t == bool_t) { - out = (in != 0) ? true : false; - } else if (in_t == bool_t) { - out = (in) ? 1 : 0; - } else if (out_t == fp16_t || out_t == bf16_t || out_t == fp32_t) { - out = round_to_nearest_float(in); - } else if (in_t == fp16_t || in_t == bf16_t || in_t == fp32_t) { - out = apply_clip(round_to_nearest_int(in), minimum, maximum); - } else if (sizeof(out_t) >= sizeof(in_t)) { - out = sign_extend(in); - } else { - out = truncate(in); - } - tensor_write(output, shape, index, out) -} +include::{pseudocode}/operators/CAST.tosac[lines=10..-1] ---- ==== RESCALE @@ -45,53 +28,5 @@ include::{generated}/operators/RESCALE.adoc[] [source,c++] ---- -for_each(index in shape) { - // uint16 values can have zero_point 0 or 32768 - // int8/uint8 can have zero point within their valid range - // No other types can have zero point != 0 - ERROR_IF(in_t != i8_t && - (in_t != i16_t || input_unsigned == False) && input_zp != 0); - ERROR_IF(out_t != i8_t && - (out_t != i16_t || output_unsigned == False) && output_zp != 0); - ERROR_IF(in_t == i16_t && input_unsigned == True && input_zp != 0 && input_zp != 32768); - ERROR_IF(out_t == i16_t && output_unsigned == True && output_zp != 0 && output_zp != 32768); - ERROR_IF(scale32 && in_t == i48_t); - ERROR_IF(!scale32 && double_round); - ERROR_IF(in_t == i16_t && out_t == i32_t && input_unsigned); - ERROR_IF(in_t == i32_t && out_t == i16_t && output_unsigned); - - in_t in_value = tensor_read(input, shape, index); - - int48_t value, extended_in_zp; - if (input_unsigned) { - value = zero_extend(in_value); - extended_in_zp = zero_extend(input_zp); - } - else { - value = sign_extend(value); - extended_in_zp = sign_extend(input_zp); - } - - value = value - extended_in_zp; - int c = (per_channel) ? index[rank(input) - 1] : 0; - int32_t result = (scale32) ? - apply_scale_32(value, multiplier[c], shift[c], double_round) : - apply_scale_16(value, multiplier[c], shift[c]); - - if (output_unsigned) { - int32_t extended_out_zp = zero_extend(output_zp); - result = apply_add_s(result, extended_out_zp); - out_t out = static_cast(apply_clip(result, - minimum_u, - maximum_u)); - } - else { - int32_t extended_out_zp = sign_extend(output_zp); - result = apply_add_s(result, extended_out_zp); - out_t out = static_cast(apply_clip(result, - minimum_s, - maximum_s)); - } - tensor_write(output, shape, index, out); -} +include::{pseudocode}/operators/RESCALE.tosac[lines=10..-1] ---- diff --git a/chapters/variable.adoc b/chapters/variable.adoc index 1f7da51..8522f5e 100644 --- a/chapters/variable.adoc +++ b/chapters/variable.adoc @@ -1,7 +1,7 @@ // // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited -// (C) COPYRIGHT 2023 ARM Limited +// (C) COPYRIGHT 2023-2024 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted @@ -21,31 +21,7 @@ include::{generated}/operators/VARIABLE.adoc[] [source,c++] ---- - -tensor_t var_tensor = variable_tensor_lookup(uid); - -// Invocation for the first time -if (var_tensor == NULL) { - // Allocate the persistent mutable memory for the variable tensor - tensor_t var_tensor = variable_tensor_allocate(var_shape, uid); - - if (initial_value != NULL) { - REQUIRE(var_t == in_t); - REQUIRE(var_shape == shape); - for_each (index in shape) { - // Copy data from initial_value to var_tensor - in_t value = tensor_read(initial_value, shape, index); - tensor_write(var_tensor.data, var_shape, index, value); - } - var_tensor.is_written = true; - } -} else { // Variable tensor has already been declared - // It's invalid to declare the second variable with the same uid in a single graph execution, - REQUIRE(!var_tensor.seen); -} - -var_tensor.seen = true; - +include::{pseudocode}/operators/VARIABLE.tosac[lines=10..-1] ---- ==== VARIABLE_WRITE @@ -56,26 +32,7 @@ include::{generated}/operators/VARIABLE_WRITE.adoc[] [source,c++] ---- - -tensor_t. variable_tensor = variable_tensor_lookup(uid); -// Check this variable tensor has been declared -REQUIRE(variable_tensor); -// The tensor has to be seen before to be written to -// The seen variable is cleared before each graph execution and set in declaration -REQUIRE(variable_tensor.seen); -// Input tensor's shape and variable_tensor's shape have to match -REQUIRE(variable_tensor.shape == shape); -// Input tensor's shape and variable_tensor's type have to match -REQUIRE(variable_tensor.type == in_t); - -for_each (index in shape) { - // Write data from the input to the pseudo-buffer resource - in_t value = tensor_read(input1, shape, index); - tensor_write(variable_tensor.data, variable_tensor.shape, index, value); -} - -variable_tensor.is_written = true; - +include::{pseudocode}/operators/VARIABLE_WRITE.tosac[lines=10..-1] ---- ==== VARIABLE_READ @@ -86,21 +43,5 @@ include::{generated}/operators/VARIABLE_READ.adoc[] [source,c++] ---- - -tensor_t variable_tensor = variable_tensor_lookup(uid); -// Check this variable tensor has been decalred -REQUIRE(variable_tensor != NULL); -// Check this variable tensor has been written -REQUIRE(variable_tensor.is_written); -// Output tensor's shape and variable_tensor's shape have to match -REQUIRE(variable_tensor.shape == shape); -// Output tensor's shape and variable_tensor's type have to match -REQUIRE(variable_tensor.type == out_t); - -for_each (index in shape) { - // Read data from pseudo-buffer resource to the output - out_t value = tensor_read(variable_tensor.data, variable_tensor.shape, index); - tensor_write(input1, shape, index, value); -} - +include::{pseudocode}/operators/VARIABLE_READ.tosac[lines=10..-1] ---- -- cgit v1.2.1