blob: 92d89230b12b2d01e64b2c4ec117ba94fdc104c6 [file] [edit]
// Copyright (c) Facebook, Inc. and its affiliates.
// All rights reserved.
//
// Copyright 2019 Google LLC
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "include/xnnpack.h"
#include "src/xnnpack/common.h"
#include "src/xnnpack/compute.h"
#include "src/xnnpack/indirection.h"
#include "src/xnnpack/log.h"
#include "src/xnnpack/math.h"
#include "src/xnnpack/microfnptr.h"
#include "src/xnnpack/microkernel-type.h"
#include "src/xnnpack/microparams.h"
#include "src/xnnpack/operator-type.h"
#include "src/xnnpack/operator-utils.h"
#include "src/xnnpack/operator.h"
#include "src/xnnpack/packq.h"
#include "src/xnnpack/quantization.h"
#include <pthreadpool.h>
#if XNN_MAX_UARCH_TYPES > 1
#include "src/xnnpack/config-types.h"
#include "src/xnnpack/microparams-init.h"
#endif // XNN_MAX_UARCH_TYPES > 1
void xnn_compute_transposec_2d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t tile_i,
size_t tile_j)
{
const size_t ld_input = context->input_stride[1];
const size_t ld_output = context->output_stride[0];
context->const_size_ukernel(
(const void*) ((uintptr_t) context->x + i * context->input_stride[0] + j * context->input_stride[1]),
(void*) ((uintptr_t) context->y + j * context->output_stride[1] + i * context->output_stride[0]),
ld_input,
ld_output,
tile_i,
tile_j);
}
void xnn_compute_transposec_3d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t tile_j,
size_t tile_k)
{
const size_t ld_input = context->input_stride[2];
const size_t ld_output = context->output_stride[1];
const void* x = (const void*) ((uintptr_t) context->x +
i * context->input_stride[0] + j * context->input_stride[1] + k * context->input_stride[2]);
void* y = (void*) ((uintptr_t) context->y + i * context->output_stride[0] + j * context->output_stride[1] +
k * context->output_stride[2]);
context->const_size_ukernel(
x,
y,
ld_input,
ld_output,
tile_j,
tile_k);
}
void xnn_compute_transposec_4d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t l,
size_t tile_k,
size_t tile_l)
{
const size_t ld_input = context->input_stride[3];
const size_t ld_output = context->output_stride[2];
const void* x = (const void*) ((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2] + l * context->input_stride[3]);
void* y = (void*) ((uintptr_t)context->y + i * context->output_stride[0] + j * context->output_stride[1] +
k * context->output_stride[2] + l * context->output_stride[3]);
context->const_size_ukernel(
x,
y,
ld_input,
ld_output,
tile_k,
tile_l);
}
void xnn_compute_transposec_5d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t l,
size_t m,
size_t tile_l,
size_t tile_m)
{
const size_t ld_input = context->input_stride[4];
const size_t ld_output = context->output_stride[3];
const void* x = (const void*)((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2] + l * context->input_stride[3] + m * context->input_stride[4]);
void* y = (void*)((uintptr_t)context->y + i * context->output_stride[0] + j * context->output_stride[1] +
k * context->output_stride[2] + l * context->output_stride[3] + m * context->output_stride[4]);
context->const_size_ukernel(
x,
y,
ld_input,
ld_output,
tile_l,
tile_m);
}
void xnn_compute_transposec_6d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t l,
size_t m,
size_t n,
size_t tile_m,
size_t tile_n)
{
const size_t ld_input = context->input_stride[5];
const size_t ld_output = context->output_stride[4];
const void* x = (const void*)((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2] + l * context->input_stride[3] +
m * context->input_stride[4] + n * context->input_stride[5]);
void* y = (void*)((uintptr_t)context->y + i * context->output_stride[0] + j * context->output_stride[1] +
k * context->output_stride[2] + l * context->output_stride[3] + m * context->output_stride[4] +
n * context->output_stride[5]);
context->const_size_ukernel(
x,
y,
ld_input,
ld_output,
tile_m,
tile_n);
}
void xnn_compute_transposev_2d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t tile_i,
size_t tile_j)
{
const size_t element_size = context->output_stride[1];
const size_t ld_input = context->input_stride[1];
const size_t ld_output = context->output_stride[0];
const void* x = (const void*) ((uintptr_t) context->x +
i * context->input_stride[0] + j * context->input_stride[1]);
void* y = (void*) ((uintptr_t) context->y + context->output_stride[1] * j + i * context->output_stride[0]);
context->variable_size_ukernel(
x,
y,
ld_input,
ld_output,
context->input_stride[0],
context->output_stride[1],
element_size,
tile_i,
tile_j);
}
void xnn_compute_transposev_3d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t tile_j,
size_t tile_k)
{
const size_t element_size = context->output_stride[2];
const size_t ld_input = context->input_stride[2];
const size_t ld_output = context->output_stride[1];
const void* x = (const void*)((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2]);
void* y = (void*)((uintptr_t)context->y + i * context->output_stride[0] + j * context->output_stride[1] +
k * context->output_stride[2]);
context->variable_size_ukernel(
x,
y,
ld_input,
ld_output,
context->input_stride[1],
context->output_stride[2],
element_size,
tile_j,
tile_k);
}
void xnn_compute_transposev_4d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t l,
size_t tile_k,
size_t tile_l)
{
const size_t element_size = context->output_stride[3];
const size_t ld_input = context->input_stride[3];
const size_t ld_output = context->output_stride[2];
const void* x = (const void*)((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2] + l * context->input_stride[3]);
void* y = (void*)((uintptr_t)context->y + context->output_stride[3] * l + i * context->output_stride[0] +
j * context->output_stride[1] + k * context->output_stride[2]);
context->variable_size_ukernel(
x,
y,
ld_input,
ld_output,
context->input_stride[2],
context->output_stride[3],
element_size,
tile_k,
tile_l);
}
void xnn_compute_transposev_5d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t l,
size_t m,
size_t tile_l,
size_t tile_m)
{
const size_t element_size = context->output_stride[4];
const size_t ld_input = context->input_stride[4];
const size_t ld_output = context->output_stride[3];
const void* x = (const void*)((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2] + l * context->input_stride[3] + m * context->input_stride[4]);
void* y = (void*)((uintptr_t)context->y + context->output_stride[4] * m + i * context->output_stride[0] +
j * context->output_stride[1] + k * context->output_stride[2] + l * context->output_stride[3]);
context->variable_size_ukernel(
x,
y,
ld_input,
ld_output,
context->input_stride[3],
context->output_stride[4],
element_size,
tile_l,
tile_m);
}
void xnn_compute_transposev_6d(
const struct transpose_context* context,
size_t i,
size_t j,
size_t k,
size_t l,
size_t m,
size_t n,
size_t tile_m,
size_t tile_n)
{
const size_t element_size = context->output_stride[5];
const size_t ld_input = context->input_stride[5];
const size_t ld_output = context->output_stride[4];
const void* x = (const void*)((uintptr_t)context->x + i * context->input_stride[0] + j * context->input_stride[1] +
k * context->input_stride[2] + l * context->input_stride[3] +
m * context->input_stride[4] + n * context->input_stride[5]);
void* y = (void*)((uintptr_t)context->y + context->output_stride[5] * n + i * context->output_stride[0] +
j * context->output_stride[1] + k * context->output_stride[2] + l * context->output_stride[3] +
m * context->output_stride[4]);
context->variable_size_ukernel(
x,
y,
ld_input,
ld_output,
context->input_stride[4],
context->output_stride[5],
element_size,
tile_m,
tile_n);
}
void xnn_compute_batched_packw_gemm_gio(
const struct packw_gemm_gio_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index, size_t n_block_start, size_t n_block_size) {
while (n_block_size > 0) {
const size_t n_step = min(n_block_size, context->nr);
const void* kernel = (const void*)((uintptr_t)context->kernel +
n_block_start * context->n_stride +
batch_index * context->gk_stride);
const void* bias = context->bias;
if (bias != NULL) {
bias = (const void*)((uintptr_t)bias + n_block_start * context->b_stride +
batch_index * context->gb_stride);
}
void* packed_weights = (void*)((uintptr_t)context->packed_weights +
n_block_start * context->w_stride +
batch_index * context->gc_stride);
if (context->pack_weights_and_biases) {
context->pack_weights_and_biases(
/*flags=*/XNN_FLAG_TRANSPOSE_WEIGHTS, context->gemm_config,
context->kc, n_step,
/*groups=*/1, /*block_size=*/0, /*k_stride=*/0,
/*accumulator_init=*/bias, kernel,
/*init_extra_data0_fn=*/NULL,
/*extra_data0=*/NULL, /*extra_data0_element_size=*/0,
/*init_extra_data1_fn=*/NULL, /*extra_data1=*/NULL,
/*extra_data1_element_size=*/0, packed_weights, /*params=*/NULL);
} else {
context->packw_gemm_gio(
/*groups=*/1, n_step, context->kc, context->nr, context->kr,
context->sr, context->k_stride_elements, kernel, bias, /*scale=*/NULL,
packed_weights, /*extra_bytes=*/0, /*params=*/NULL);
}
n_block_size -= n_step;
n_block_start += n_step;
}
}
void xnn_compute_packw_gemm_gio(
const struct packw_gemm_gio_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t n_block_start,
size_t n_block_size)
{
xnn_compute_batched_packw_gemm_gio(context, /*batch_index=*/0, n_block_start,
n_block_size);
}
void xnn_compute_batched_packw_gemm_goi(
const struct packw_gemm_goi_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index, size_t n_block_start, size_t n_block_size) {
while (n_block_size > 0) {
const size_t n_step = min(n_block_size, context->nr);
const void* kernel = (const void*)((uintptr_t)context->kernel +
context->k_stride * n_block_start +
batch_index * context->gk_stride);
const void* bias = context->bias;
if (bias != NULL) {
bias = (const void*)((uintptr_t)bias + n_block_start * context->b_stride +
batch_index * context->gb_stride);
}
void* packed_weights = (void*)((uintptr_t)context->packed_weights +
context->w_stride * n_block_start +
batch_index * context->gc_stride);
if (context->pack_weights_and_biases) {
context->pack_weights_and_biases(
/*flags=*/0, context->gemm_config, context->kc, n_step,
/*groups=*/1, /*block_size=*/0, /*k_stride=*/context->k_stride,
/*accumulator_init=*/bias, kernel,
/*init_extra_data0_fn=*/NULL,
/*extra_data0=*/NULL, /*extra_data0_element_size=*/0,
/*init_extra_data1_fn=*/NULL, /*extra_data1=*/NULL,
/*extra_data1_element_size=*/0, packed_weights, /*params=*/NULL);
} else {
context->packw_gemm_goi(
/*groups=*/1, n_step, context->kc, context->nr, context->kr,
context->sr, kernel, bias, /*scale=*/NULL, packed_weights,
/*extra_bytes=*/0, /*params=*/NULL);
}
n_block_size -= n_step;
n_block_start += n_step;
}
}
void xnn_compute_packw_gemm_goi(
const struct packw_gemm_goi_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t n_block_start,
size_t n_block_size)
{
xnn_compute_batched_packw_gemm_goi(context, /*batch_index=*/0, n_block_start,
n_block_size);
}
void xnn_compute_hmp_grouped_gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t group_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t k_scaled = context->k_scaled;
const size_t a_stride = context->a_stride;
const size_t cm_stride = context->cm_stride;
const size_t num_batch_dims = context->num_batch_dims;
const size_t group_index_c = group_index;
// Compute the group index offsets into A and B.
size_t group_index_a = 0;
size_t group_index_b = 0;
for (int k = 0; k < num_batch_dims; k++) {
// Extract the kth batch index from the group_index.
const size_t index = group_index / context->batch_strides_c[k];
group_index %= context->batch_strides_c[k];
// Compute the corresponding kth group index offsets into A and B.
group_index_a = (index % context->batch_dims_a[k]) +
context->batch_dims_a[k] * group_index_a;
group_index_b = (index % context->batch_dims_b[k]) +
context->batch_dims_b[k] * group_index_b;
}
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
if (context->quantization_params != NULL) {
// If the effective `mr_block_size` is smaller than the kernel's `mr`,
// create a padded copy of the dynamic quantization params.
const struct xnn_qd8_quantization_params* quantization_params =
&context->quantization_params[group_index_a * context->gq_stride +
mr_block_start];
struct xnn_qd8_quantization_params padded_quantization_params[XNN_MAX_MR];
if (mr_step < context->mr) {
for (size_t i = 0; i < mr_step; i++) {
padded_quantization_params[i] = quantization_params[i];
}
for (size_t i = mr_step; i < context->mr; i++) {
padded_quantization_params[i] =
padded_quantization_params[mr_step - 1];
}
quantization_params = padded_quantization_params;
};
context->dq_ukernel.function[uarch_index](
mr_step, nr_block_size, k_scaled,
(const void*)((uintptr_t)context->a + mr_block_start * a_stride +
group_index_a * context->ga_stride),
a_stride,
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index_b * context->gw_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize) +
group_index_c * context->gc_stride),
cm_stride, context->cn_stride, &context->params, quantization_params);
} else {
context->ukernel.function[uarch_index](
mr_step, nr_block_size, k_scaled,
(const void*)((uintptr_t)context->a + mr_block_start * a_stride +
group_index_a * context->ga_stride),
a_stride,
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index_b * context->gw_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize) +
group_index_c * context->gc_stride),
cm_stride, context->cn_stride, &context->params);
}
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_grouped_gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t group_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
xnn_compute_hmp_grouped_gemm(context, XNN_UARCH_DEFAULT, group_index,
nr_block_start, mr_block_start, nr_block_size,
mr_block_size);
}
void xnn_compute_gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
const size_t a_stride = context->a_stride;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->k_scaled,
(const void*)((uintptr_t)context->a + mr_block_start * a_stride),
a_stride,
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->fused_params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_dqgemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
const size_t a_stride = context->a_stride;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->k_scaled,
(const void*)((uintptr_t)context->a + mr_block_start * a_stride),
a_stride,
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->fused_params,
&context->quantization_params[mr_block_start]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_grouped_qp8gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t group_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t cm_stride = context->cm_stride;
const size_t num_batch_dims = context->num_batch_dims;
// Compute the group index offsets into A and B.
const size_t group_index_c = group_index;
size_t group_index_a = 0;
size_t group_index_b = 0;
for (int k = 0; k < num_batch_dims; k++) {
// Extract the kth batch index from the group_index.
const size_t index = group_index / context->batch_strides_c[k];
group_index %= context->batch_strides_c[k];
// Compute the corresponding kth group index offsets into A and B.
group_index_a = (index % context->batch_dims_a[k]) +
context->batch_dims_a[k] * group_index_a;
group_index_b = (index % context->batch_dims_b[k]) +
context->batch_dims_b[k] * group_index_b;
}
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
const size_t a_offset = context->packed_lh_offset_fn(
mr_block_start, context->kc, context->mr, context->kr, context->sr);
context->qp8_ukernel.function[uarch_index](
mr_step, nr_block_size, context->k_scaled,
(const void*)((uintptr_t)context->a +
group_index_a * context->ga_stride + a_offset),
(const void*)((uintptr_t)context->packed_w +
group_index_b * context->gw_stride +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + group_index_c * context->gc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride,
/*dst_stride_col=*/sizeof(float), context->fused_params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_grouped_qp8gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t group_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
xnn_compute_hmp_grouped_qp8gemm(context, XNN_UARCH_DEFAULT, group_index,
nr_block_start, mr_block_start, nr_block_size,
mr_block_size);
}
XNN_INLINE static void compute_hmp_qp8gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
const size_t a_offset = context->packed_lh_offset_fn(
mr_block_start, context->kc, context->mr, context->kr, context->sr);
context->qp8_ukernel.function[uarch_index](
mr_step, nr_block_size, context->k_scaled,
(const void*)((uintptr_t)context->a + a_offset),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride,
/*dst_stride_col=*/sizeof(float), context->fused_params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_qp8gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
compute_hmp_qp8gemm(context, uarch_index, nr_block_start, mr_block_start,
nr_block_size, mr_block_size);
}
void xnn_compute_qp8gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
compute_hmp_qp8gemm(context, XNN_UARCH_DEFAULT, nr_block_start,
mr_block_start, nr_block_size, mr_block_size);
}
void xnn_compute_spmm(
const struct spmm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t mr_block_start,
size_t mr_block_size)
{
context->ukernel(
mr_block_size,
context->n,
(const void*) ((uintptr_t) context->input + batch_index * context->batched_input_stride + mr_block_start),
context->nonzero_weights,
context->input_increments,
context->output_channel_nonzeros,
(void*) ((uintptr_t) context->output + batch_index * context->batched_output_stride + mr_block_start),
context->scaled_m,
&context->params);
}
void xnn_compute_grouped_batch_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index, size_t group_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
batch_index * context->bc_stride + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride +
batch_index * context->ba_stride,
context->zero, &context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_dq_zero_buffer_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index) {
memset(context->zero_buffers[batch_index],
context->quantization_params[batch_index].zero_point,
context->zero_size);
}
void xnn_compute_dq_zero_buffer_subconv(
const struct subconv_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index) {
memset(context->zero_buffers[batch_index],
context->quantization_params[batch_index].zero_point,
context->zero_size);
}
void xnn_compute_grouped_batch_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index, size_t group_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
batch_index * context->bc_stride + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride +
batch_index * context->ba_stride,
context->zero, context->zero_buffers[batch_index], &context->params,
&context->quantization_params[batch_index]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_grouped_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t group_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride, context->zero,
&context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_grouped_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t group_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride, context->zero,
context->zero_buffers[0], &context->params,
context->quantization_params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_batch_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + batch_index * context->bc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + batch_index * context->ba_stride, context->zero,
&context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_batch_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + batch_index * context->bc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + batch_index * context->ba_stride, context->zero,
context->zero_buffers[batch_index], &context->params,
&context->quantization_params[batch_index]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->a_offset, context->zero,
&context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->a_offset, context->zero,
context->zero_buffers[0], &context->params,
&context->quantization_params[/*mr_block_start=*/0]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
// `output_tile_start` should be a multiple of igemm.mr (tile size).
void xnn_compute_conv2d_igemm_indirection(
const struct conv2d_igemm_indirection_init_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t output_tile_start,
size_t output_tile_size)
{
xnn_indirection_init_conv2d(
output_tile_size,
output_tile_start,
output_tile_start + output_tile_size,
context->indirection_buffer,
context->input,
context->zero_buffer,
context->input_pixel_stride,
context->input_height, context->input_width,
context->output_height, context->output_width,
context->kernel_height, context->kernel_width,
context->stride_height, context->stride_width,
context->dilation_height, context->dilation_width,
context->input_padding_top, context->input_padding_left);
}
void xnn_compute_grouped_subgemm2d(
const struct subgemm_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t group_index,
size_t subkernel_index,
size_t slice_y,
size_t slice_x_start,
size_t nc_block_start,
size_t slice_x_max,
size_t nc_block_size)
{
const struct subconvolution_params* subconvolution_params = &context->subconvolution_params[subkernel_index];
if XNN_UNLIKELY(slice_y >= subconvolution_params->slice_height) {
return;
}
const size_t slice_width = subconvolution_params->slice_width;
if XNN_UNLIKELY(slice_x_start >= slice_width) {
return;
}
const size_t slice_x_size = min(slice_x_max, slice_width - slice_x_start);
const size_t ax_stride = context->ax_stride;
const size_t cx_stride = context->cx_stride;
context->ukernel.function[XNN_UARCH_DEFAULT](
slice_x_size,
nc_block_size,
context->kc,
(const void*) ((uintptr_t) context->a + group_index * context->ga_stride + slice_y * context->ay_stride + slice_x_start * ax_stride + batch_index * context->ba_stride),
ax_stride,
(const void*) ((uintptr_t) subconvolution_params->weights + nc_block_start * subconvolution_params->w_stride + group_index * context->gw_stride),
(void*) ((uintptr_t) subconvolution_params->output + group_index * context->gc_stride + slice_y * context->cy_stride + slice_x_start * cx_stride + batch_index * context->bc_stride + (nc_block_start << context->log2_csize)),
cx_stride,
context->cn_stride,
&context->params);
}
void xnn_compute_grouped_subconv2d(
const struct subconv_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t group_index,
size_t subkernel_index,
size_t slice_y,
size_t slice_x_start,
size_t nc_block_start,
size_t slice_x_max,
size_t nc_block_size)
{
const struct subconvolution_params* subconvolution_params = &context->subconvolution_params[subkernel_index];
if XNN_UNLIKELY(slice_y >= subconvolution_params->slice_height) {
return;
}
const size_t slice_width = subconvolution_params->slice_width;
if XNN_UNLIKELY(slice_x_start >= slice_width) {
return;
}
const size_t slice_x_size = min(slice_x_max, slice_width - slice_x_start);
const size_t cx_stride = context->cx_stride;
context->ukernel.function[XNN_UARCH_DEFAULT](
slice_x_size,
nc_block_size,
context->kc,
subconvolution_params->scaled_kernel_size,
(const void**) ((uintptr_t) subconvolution_params->indirection_buffer + slice_y * subconvolution_params->indirection_y_stride + slice_x_start * subconvolution_params->indirection_x_stride),
(const void*) ((uintptr_t) subconvolution_params->weights + nc_block_start * subconvolution_params->w_stride + group_index * context->gw_stride),
(void*) ((uintptr_t) subconvolution_params->output + group_index * context->gc_stride + slice_y * context->cy_stride + slice_x_start * cx_stride + batch_index * context->bc_stride + (nc_block_start << context->log2_csize)),
cx_stride,
context->cn_stride,
context->a_offset + group_index * context->ga_stride + batch_index * context->ba_stride,
context->zero,
&context->params);
}
void xnn_compute_grouped_dqsubconv2d(
const struct subconv_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t group_index,
size_t subkernel_index,
size_t slice_y,
size_t slice_x_start,
size_t nc_block_start,
size_t slice_x_max,
size_t nc_block_size)
{
const struct subconvolution_params* subconvolution_params = &context->subconvolution_params[subkernel_index];
if XNN_UNLIKELY(slice_y >= subconvolution_params->slice_height) {
return;
}
const size_t slice_width = subconvolution_params->slice_width;
if XNN_UNLIKELY(slice_x_start >= slice_width) {
return;
}
const size_t slice_x_size = min(slice_x_max, slice_width - slice_x_start);
const size_t cx_stride = context->cx_stride;
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
slice_x_size,
nc_block_size,
context->kc,
subconvolution_params->scaled_kernel_size,
(const void**) ((uintptr_t) subconvolution_params->indirection_buffer + slice_y * subconvolution_params->indirection_y_stride + slice_x_start * subconvolution_params->indirection_x_stride),
(const void*) ((uintptr_t) subconvolution_params->weights + nc_block_start * subconvolution_params->w_stride + group_index * context->gw_stride),
(void*) ((uintptr_t) subconvolution_params->output + group_index * context->gc_stride + slice_y * context->cy_stride + slice_x_start * cx_stride + batch_index * context->bc_stride + (nc_block_start << context->log2_csize)),
cx_stride,
context->cn_stride,
context->a_offset + group_index * context->ga_stride + batch_index * context->ba_stride,
context->zero,
context->zero_buffers[batch_index],
&context->params,
&context->quantization_params[batch_index]);
}
void xnn_compute_subconv2d(
const struct subconv_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t subkernel_index,
size_t slice_y,
size_t slice_x_start,
size_t nc_block_start,
size_t slice_x_max,
size_t nc_block_size)
{
const struct subconvolution_params* subconvolution_params = &context->subconvolution_params[subkernel_index];
if XNN_UNLIKELY(slice_y >= subconvolution_params->slice_height) {
return;
}
const size_t slice_width = subconvolution_params->slice_width;
if XNN_UNLIKELY(slice_x_start >= slice_width) {
return;
}
const size_t slice_x_size = min(slice_x_max, slice_width - slice_x_start);
const size_t cx_stride = context->cx_stride;
context->ukernel.function[XNN_UARCH_DEFAULT](
slice_x_size,
nc_block_size,
context->kc,
subconvolution_params->scaled_kernel_size,
(const void**) ((uintptr_t) subconvolution_params->indirection_buffer + slice_y * subconvolution_params->indirection_y_stride + slice_x_start * subconvolution_params->indirection_x_stride),
(const void*) ((uintptr_t) subconvolution_params->weights + nc_block_start * subconvolution_params->w_stride),
(void*) ((uintptr_t) subconvolution_params->output + slice_y * context->cy_stride + slice_x_start * cx_stride + batch_index * context->bc_stride + (nc_block_start << context->log2_csize)),
cx_stride,
context->cn_stride,
context->a_offset + batch_index * context->ba_stride,
context->zero,
&context->params);
}
void xnn_compute_dqsubconv2d(
const struct subconv_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t subkernel_index,
size_t slice_y,
size_t slice_x_start,
size_t nc_block_start,
size_t slice_x_max,
size_t nc_block_size)
{
const struct subconvolution_params* subconvolution_params = &context->subconvolution_params[subkernel_index];
if XNN_UNLIKELY(slice_y >= subconvolution_params->slice_height) {
return;
}
const size_t slice_width = subconvolution_params->slice_width;
if XNN_UNLIKELY(slice_x_start >= slice_width) {
return;
}
const size_t slice_x_size = min(slice_x_max, slice_width - slice_x_start);
const size_t cx_stride = context->cx_stride;
context->dq_ukernel.function[XNN_UARCH_DEFAULT](
slice_x_size,
nc_block_size,
context->kc,
subconvolution_params->scaled_kernel_size,
(const void**) ((uintptr_t) subconvolution_params->indirection_buffer + slice_y * subconvolution_params->indirection_y_stride + slice_x_start * subconvolution_params->indirection_x_stride),
(const void*) ((uintptr_t) subconvolution_params->weights + nc_block_start * subconvolution_params->w_stride),
(void*) ((uintptr_t) subconvolution_params->output + slice_y * context->cy_stride + slice_x_start * cx_stride + batch_index * context->bc_stride + (nc_block_start << context->log2_csize)),
cx_stride,
context->cn_stride,
context->a_offset + batch_index * context->ba_stride,
context->zero,
context->zero_buffers[batch_index],
&context->params,
&context->quantization_params[batch_index]);
}
void xnn_compute_conv2d_hwc2chw(
const struct conv2d_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t output_y_start,
size_t output_y_slice)
{
context->hwc2chw_ukernel(
context->input_height,
context->input_width,
output_y_start,
output_y_start + output_y_slice,
(const void*) ((uintptr_t) context->input + batch_index * context->input_batch_stride),
context->zero,
context->packed_weights,
(void*) ((uintptr_t) context->output + batch_index * context->output_batch_stride),
context->input_padding_top,
context->output_channels,
context->output_height_stride,
context->output_channel_stride,
&context->params);
}
void xnn_compute_dwconv_indirection(
const struct dwconv_indirection_init_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t output_y_start,
size_t output_y_tile)
{
xnn_indirection_init_dwconv2d(
output_y_start,
output_y_start + output_y_tile,
context->indirection_buffer,
context->input,
context->input_pixel_stride,
context->zero_buffer,
context->input_height, context->input_width,
context->output_height, context->output_width,
context->kernel_height, context->kernel_width,
context->stride_height, context->stride_width,
context->dilation_height, context->dilation_width,
context->input_padding_top, context->input_padding_left,
context->step_height, context->step_width, context->tile_size);
}
void xnn_compute_dwconv_unipass(
const struct dwconv_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t output_y,
size_t output_c_start,
size_t output_c_tile)
{
const void** indirect_input =
(const void**) ((uintptr_t) context->indirect_input + output_y * context->indirect_input_height_stride);
const size_t input_offset = context->input_offset + batch_index * context->input_batch_stride + output_c_start * context->input_channel_stride;
void* output = (void*) ((uintptr_t) context->output +
batch_index * context->output_batch_stride + output_y * context->output_height_stride + output_c_start * context->output_channel_stride);
void* weights = (void*) ((uintptr_t) context->packed_weights + output_c_start * context->weights_channel_stride);
const size_t output_increment = context->output_pixel_stride - output_c_tile * context->output_channel_stride;
context->ukernel(
output_c_tile, context->output_width,
indirect_input, weights, output,
context->indirect_input_width_stride, output_increment,
input_offset, /*input_pixel_stride=*/0, context->zero,
&context->params);
}
void xnn_compute_dwconv2d_chw(
const struct dwconv2d_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t channel)
{
context->chw_ukernel(
context->input_height,
context->input_width,
(const void*) ((uintptr_t) context->input + channel * context->input_channel_stride + batch_index * context->input_batch_stride),
(const void*) ((uintptr_t) context->packed_weights + channel * context->weights_channel_stride),
context->zero,
(void*) ((uintptr_t) context->output + channel * context->output_channel_stride + batch_index * context->output_batch_stride),
context->input_padding_top,
&context->params);
}
void xnn_compute_argmax_pooling(
const struct argmax_pooling_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t output_y)
{
const void** indirect_input = (const void**) ((uintptr_t) context->indirect_input +
output_y * context->indirect_input_height_stride);
const size_t input_offset = context->input_offset + batch_index * context->input_batch_stride;
void* output = (void*) ((uintptr_t) context->output +
batch_index * context->output_batch_stride + output_y * context->output_height_stride);
uint32_t* index = (uint32_t*) ((uintptr_t) context->index +
batch_index * context->index_batch_stride + output_y * context->index_height_stride);
context->ukernel(
context->output_width, context->pooling_size, context->channels,
indirect_input, input_offset, /*input_pixel_stride=*/0, output, index,
context->input_increment, context->output_increment, context->index_increment);
}
void xnn_compute_max_pooling(
const struct max_pooling_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t output_y)
{
const void** indirect_input = (const void**) ((uintptr_t) context->indirect_input +
output_y * context->indirect_input_height_stride);
const size_t input_offset = context->input_offset + batch_index * context->input_batch_stride;
void* output = (void*) ((uintptr_t) context->output +
batch_index * context->output_batch_stride + output_y * context->output_height_stride);
context->ukernel(
context->output_width, context->pooling_size, context->channels,
indirect_input, input_offset, /*input_pixel_stride=*/0, output,
context->input_increment, context->output_increment,
&context->params);
}
void xnn_compute_unpooling(
const struct unpooling_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t input_y,
size_t input_x)
{
const void* input = (const void*) ((uintptr_t) context->input +
input_y * context->input_height_stride + input_x * context->input_width_stride);
const uint32_t* index = (const uint32_t*) ((uintptr_t) context->index +
input_y * context->index_height_stride + input_x * context->index_width_stride);
void** indirect_output =
(void**) ((uintptr_t) context->indirect_output +
input_y * context->indirect_output_height_stride + input_x * context->indirect_output_width_stride);
context->ukernel(
context->pooling_size,
context->channels,
context->fill_value,
input, index, indirect_output);
}
void xnn_compute_average_pooling(
const struct average_pooling_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t output_y)
{
// Refer to xnn_compute_average_pooling for documentation on these terms.
const size_t indirect_y = min(output_y, context->indirect_top_height) + doz(output_y + 1, context->indirect_bot_start);
const void** indirect_input = (void*) ((uintptr_t) context->indirect_input + indirect_y * context->indirect_input_height_stride);
const size_t input_offset_for_compressed_section =
(output_y - indirect_y) * (output_y < context->indirect_bot_start) * context->input_y_stride;
const size_t input_offset = context->input_offset + batch_index * context->input_batch_stride + input_offset_for_compressed_section;
const void* pixelwise_buffer = context->pixelwise_buffer
? (const void*) ((uintptr_t) context->pixelwise_buffer + output_y * context->pixelwise_buffer_height_stride)
: NULL;
void* output = (void*) ((uintptr_t) context->output +
batch_index * context->output_batch_stride + output_y * context->output_height_stride);
context->ukernel(
context->output_width, context->pooling_size, context->channels,
indirect_input, input_offset, /*input_pixel_stride=*/0, context->zero,
pixelwise_buffer, output, context->input_increment, context->output_increment,
&context->params);
}
void xnn_compute_resize_bilinear_indirection(
const struct resize_bilinear_nhwc_indirection_init_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t output_y_start,
size_t output_y_tile)
{
void* buffer = context->buffer;
context->indirection_init(
output_y_start,
output_y_start + output_y_tile,
context->input_pixel_stride,
context->input_height, context->input_width,
context->output_height, context->output_width,
context->input,
/*indirection_buffer==*/(const void**) ((uintptr_t) buffer + context->indirect_input_offset),
/*packed_weights=*/(void*) buffer,
context->align_corners, context->tensorflow_legacy_mode);
}
void xnn_compute_resize_bilinear(
const struct resize_bilinear_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t pixel_start,
size_t pixel_range)
{
void* output =
(void*) ((uintptr_t) context->output + pixel_start * context->output_pixel_stride + batch_index * context->output_batch_stride);
context->ukernel(
pixel_range,
context->scaled_channels,
context->indirect_input + pixel_start * 4,
context->input_offset + batch_index * context->input_batch_stride,
(const void*) ((uintptr_t) context->packed_weights + (pixel_start << context->log2_wsize)),
output,
context->output_pixel_stride - context->scaled_channels);
}
void xnn_compute_resize_bilinear_chw(
const struct resize_bilinear_chw_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t channel_start,
size_t channel_range)
{
void* output =
(void*) ((uintptr_t) context->output + channel_start * context->output_channel_stride + batch_index * context->output_batch_stride);
const size_t input_offset = context->input_offset + batch_index * context->input_batch_stride + channel_start * context->input_channel_stride;
context->ukernel(
context->output_pixels,
channel_range,
context->indirect_input,
input_offset,
context->packed_weights,
output,
context->input_channel_stride);
}
void xnn_compute_pad_5d(
const struct pad_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j, size_t k, size_t l, size_t m)
{
const void* input = (const void*) ((uintptr_t) context->input +
i * context->input_stride[4] + j * context->input_stride[3] + k * context->input_stride[2] + l * context->input_stride[1] + m * context->input_stride[0]);
void* output = (void*) ((uintptr_t) context->output +
i * context->output_stride[4] + j * context->output_stride[3] + k * context->output_stride[2] + l * context->output_stride[1] + m * context->output_stride[0]);
const size_t i_padding = context->pre_paddings[5];
const size_t j_padding = context->pre_paddings[4];
const size_t k_padding = context->pre_paddings[3];
const size_t l_padding = context->pre_paddings[2];
const size_t m_padding = context->pre_paddings[1];
const size_t i_size = context->input_size[5];
const size_t j_size = context->input_size[4];
const size_t k_size = context->input_size[3];
const size_t l_size = context->input_size[2];
const size_t m_size = context->input_size[1];
if XNN_LIKELY(i - i_padding < i_size && j - j_padding < j_size && k - k_padding < k_size &&
l - l_padding < l_size && m - m_padding < m_size)
{
context->pad_ukernel(
1 /* rows */,
context->input_size[0], context->pre_paddings[0], context->post_paddings[0],
input, 0 /* input stride */, output, 0 /* output stride */,
context->padding_value);
} else {
context->fill_ukernel(1 /* rows */, context->output_size[0], output, 0 /* output stride */, context->padding_value);
}
}
void xnn_compute_slice_1d(
const struct slice_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i)
{
const void* input = (const void*) ((uintptr_t) context->input + i * context->input_stride[0]);
void* output = (void*) ((uintptr_t) context->output + i * context->output_stride[0]);
context->ukernel(context->contiguous_size, input, output, NULL);
}
void xnn_compute_slice_2d(
const struct slice_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j)
{
const void* input =
(const void*) ((uintptr_t) context->input +
i * context->input_stride[1] +
j * context->input_stride[0]);
void* output =
(void*) ((uintptr_t) context->output + i * context->output_stride[1] + j * context->output_stride[0]);
context->ukernel(context->contiguous_size, input, output, NULL);
}
void xnn_compute_slice_3d(
const struct slice_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j, size_t k)
{
const void* input =
(const void*) ((uintptr_t) context->input +
i * context->input_stride[2] +
j * context->input_stride[1] +
k * context->input_stride[0]);
void* output =
(void*) ((uintptr_t) context->output + i * context->output_stride[2] +
j * context->output_stride[1] + k * context->output_stride[0]);
context->ukernel(context->contiguous_size, input, output, NULL);
}
void xnn_compute_slice_4d(
const struct slice_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j, size_t k, size_t l)
{
const void* input =
(const void*) ((uintptr_t) context->input +
i * context->input_stride[3] +
j * context->input_stride[2] +
k * context->input_stride[1] +
l * context->input_stride[0]);
void* output =
(void*) ((uintptr_t) context->output + i * context->output_stride[3] +
j * context->output_stride[2] + k * context->output_stride[1] + l * context->output_stride[0]);
context->ukernel(context->contiguous_size, input, output, NULL);
}
void xnn_compute_slice_5d(
const struct slice_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j, size_t k, size_t l, size_t m)
{
const void* input =
(const void* ) ((uintptr_t) context->input +
i * context->input_stride[4] +
j * context->input_stride[3] +
k * context->input_stride[2] +
l * context->input_stride[1] +
m * context->input_stride[0]);
void* output =
(void*) ((uintptr_t) context->output + i * context->output_stride[4] +
j * context->output_stride[3] + k * context->output_stride[2] +
l * context->output_stride[1] + m * context->output_stride[0]);
context->ukernel(context->contiguous_size, input, output, NULL);
}
void xnn_compute_elementwise_binary_1d_tile(
const struct elementwise_binary_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t offset,
size_t size)
{
size_t a_offset = ((context->a_stride[4] == 0 ? 0 : offset));
size_t b_offset = ((context->b_stride[4] == 0 ? 0 : offset));
const void* a = (const void*) ((uintptr_t) context->a + a_offset);
const void* b = (const void*) ((uintptr_t) context->b + b_offset);
void* y = (void*) ((uintptr_t) context->y + offset);
context->ukernel(size, a, b, y, &context->params);
}
void xnn_compute_elementwise_binary_1d(
const struct elementwise_binary_context
context[restrict XNN_MIN_ELEMENTS(1)],
size_t offset, size_t count) {
for (size_t i = offset; i < offset + count; i++) {
const void* a =
(const void*)((uintptr_t)context->a + i * context->a_stride[4]);
const void* b =
(const void*)((uintptr_t)context->b + i * context->b_stride[4]);
void* y = (void*)((uintptr_t)context->y + i * context->y_stride[4]);
context->ukernel(context->elements, a, b, y, &context->params);
}
}
void xnn_compute_elementwise_binary_2d(
const struct elementwise_binary_context
context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t offset, size_t count) {
uintptr_t a = (uintptr_t)context->a + i * context->a_stride[3];
uintptr_t b = (uintptr_t)context->b + i * context->b_stride[3];
uintptr_t y = (uintptr_t)context->y + i * context->y_stride[3];
for (size_t j = offset; j < offset + count; j++) {
context->ukernel(context->elements,
(const void*)(a + j * context->a_stride[4]),
(const void*)(b + j * context->b_stride[4]),
(void*)(y + j * context->y_stride[4]), &context->params);
}
}
void xnn_compute_elementwise_binary_3d(
const struct elementwise_binary_context
context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t offset_j, size_t offset_k, size_t count_j,
size_t count_k) {
uintptr_t a = (uintptr_t)context->a + i * context->a_stride[2];
uintptr_t b = (uintptr_t)context->b + i * context->b_stride[2];
uintptr_t y = (uintptr_t)context->y + i * context->y_stride[2];
for (size_t j = offset_j; j < offset_j + count_j; j++) {
for (size_t k = offset_k; k < offset_k + count_k; k++) {
context->ukernel(
context->elements,
(const void*)(a + j * context->a_stride[3] +
k * context->a_stride[4]),
(const void*)(b + j * context->b_stride[3] +
k * context->b_stride[4]),
(void*)(y + j * context->y_stride[3] + k * context->y_stride[4]),
&context->params);
}
}
}
void xnn_compute_elementwise_binary_4d(
const struct elementwise_binary_context
context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j, size_t offset_k, size_t offset_l, size_t count_k,
size_t count_l) {
uintptr_t a = (uintptr_t)context->a + +i * context->a_stride[1] +
j * context->a_stride[2];
uintptr_t b = (uintptr_t)context->b + i * context->b_stride[1] +
j * context->b_stride[2];
uintptr_t y = (uintptr_t)context->y + i * context->y_stride[1] +
j * context->y_stride[2];
for (size_t k = offset_k; k < offset_k + count_k; k++) {
for (size_t l = offset_l; l < offset_l + count_l; l++) {
context->ukernel(
context->elements,
(const void*)(a + k * context->a_stride[3] +
l * context->a_stride[4]),
(const void*)(b + k * context->b_stride[3] +
l * context->b_stride[4]),
(void*)(y + k * context->y_stride[3] + l * context->y_stride[4]),
&context->params);
}
}
}
void xnn_compute_elementwise_binary_5d(
const struct elementwise_binary_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t i, size_t j, size_t k, size_t l, size_t m)
{
const void* a = (const void*) ((uintptr_t) context->a +
i * context->a_stride[0] + j * context->a_stride[1] + k * context->a_stride[2] + l * context->a_stride[3] + m * context->a_stride[4]);
const void* b = (const void*) ((uintptr_t) context->b +
i * context->b_stride[0] + j * context->b_stride[1] + k * context->b_stride[2] + l * context->b_stride[3] + m * context->b_stride[4]);
void* y = (void*) ((uintptr_t) context->y +
i * context->y_stride[0] + j * context->y_stride[1] + k * context->y_stride[2] + l * context->y_stride[3] + m * context->y_stride[4]);
context->ukernel(context->elements, a, b, y, &context->params);
}
void xnn_compute_lut_strided(
const struct lut_strided_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_offset, size_t batch_range) {
for (size_t batch_index = batch_offset;
batch_index < batch_offset + batch_range; batch_index++) {
const void* x =
(const void*)((uintptr_t)context->x + context->x_stride * batch_index);
void* y = (void*)((uintptr_t)context->y + context->y_stride * batch_index);
context->ukernel(context->n, x, y, context->t);
}
}
void xnn_compute_lut_contiguous(
const struct lut_contiguous_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t offset,
size_t size)
{
const void* x = (const void*) ((uintptr_t) context->x + offset);
void* y = (void*) ((uintptr_t) context->y + offset);
context->ukernel(size, x, y, context->t);
}
void xnn_compute_univector_strided(
const struct univector_strided_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t batch_range)
{
const size_t x_stride = context->x_stride;
const size_t y_stride = context->y_stride;
const void* x = (const void*) ((uintptr_t) context->x + x_stride * batch_index);
void* y = (void*) ((uintptr_t) context->y + y_stride * batch_index);
do {
context->ukernel(context->n, x, y, &context->params);
x = (const void*) ((uintptr_t) x + x_stride);
y = (void*) ((uintptr_t) y + y_stride);
} while (--batch_range != 0);
}
void xnn_compute_univector_contiguous(
const struct univector_contiguous_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t offset,
size_t size)
{
const uint32_t log2_xsize = context->log2_xsize;
const uint32_t log2_ysize = context->log2_ysize;
const void* x = (const void*) ((uintptr_t) context->x + offset);
void* y = (void*) ((uintptr_t) context->y + ((offset >> log2_xsize) << log2_ysize));
context->ukernel(size, x, y, &context->params);
}
void xnn_compute_contiguous_reduce(
const struct reduce_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t output_idx0,
size_t output_idx1,
size_t output_idx2,
size_t output1_block_size,
size_t output2_block_size)
{
assert(output1_block_size == 1);
const size_t* input_stride = context->input_stride;
const size_t* output_stride = context->output_stride;
// input dimensions 1, 3 & 5 are reduced so the entirety of these dimensions
// are processed so their indices are always 0.
size_t input_offset = input_stride[0] * output_idx0 + input_stride[2] * output_idx1
+ input_stride[4] * output_idx2;
size_t output_offset = (output_stride[0] * output_idx0 + output_stride[1] * output_idx1
+ output_stride[2] * output_idx2) * context->output_element_size;
size_t workspace_offset = (output_stride[0] * output_idx0 + output_stride[1] * output_idx1
+ output_stride[2] * output_idx2) * context->accumulation_element_size;
int input_shape1 = context->input_shape[1];
int input_shape3 = context->input_shape[3];
void* output_ptr = NULL;
if (context->workspace) {
output_ptr = context->workspace;
} else {
output_ptr = context->output;
}
void* output = (void*) ((uintptr_t) output_ptr + workspace_offset);
// Reduce microkernels accumulate into the output buffer.
if (context->identity_value == 0) {
memset(output, 0, context->accumulation_element_size * output2_block_size);
} else {
context->fill_ukernel(
1, context->accumulation_element_size * output2_block_size, output,
context->accumulation_element_size, context->identity_value);
}
// Input dimension 1 is reduced.
for (size_t i = 0; i < input_shape1; ++i) {
const void* input = (const void*) ((uintptr_t) context->input + input_offset);
// Input dimension 3 is reduced.
for (size_t j = 0; j < input_shape3; ++j) {
const void* input_row = input;
// output2_block_size output elements are written.
for (size_t k = 0; k < output2_block_size; ++k) {
// The microkernel reduces input dimension 5.
context->ukernel.contiguous_reduce(context->channels, input_row, output,
&context->params);
// input_stride[4] is the number of bytes of input which have been
// processed by the microkernel call.
input_row = (const void*) ((uintptr_t) input_row + input_stride[4]);
// Increment output pointer by the number of output bytes which have
// been written.
output = (void*) ((uintptr_t) output + context->accumulation_element_size);
}
// Reset the output pointer.
output = (void*) ((uintptr_t) output_ptr + workspace_offset);
// Iterating over input_shape[3].
input = (const void*) ((uintptr_t) input + input_stride[3]);
}
// Iterating over input_shape[1].
input_offset += input_stride[1];
}
// Convert to output datatype if accumulation type != output type.
if (context->workspace) {
void* workspace_ptr = (void*) ((uintptr_t) context->workspace + workspace_offset);
output_ptr = (void*) ((uintptr_t) context->output + output_offset);
context->cvt_ukernel(context->accumulation_element_size * output2_block_size, workspace_ptr, output_ptr, &context->cvt_params);
}
}
void xnn_compute_discontiguous_reduce(
const struct reduce_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t output_idx0,
size_t output_idx1,
size_t output_idx2,
size_t output1_block_size,
size_t output2_block_size)
{
assert(output1_block_size == 1);
const size_t* input_stride = context->input_stride;
const size_t* output_stride = context->output_stride;
// input dimensions 0, 2 & 4 are reduced so the entirety of these dimensions
// are processed so their indices are always 0.
size_t input_offset = input_stride[1] * output_idx0 + input_stride[3] * output_idx1 + input_stride[5] * output_idx2;
size_t output_offset = (output_stride[0] * output_idx0 + output_stride[1] * output_idx1
+ output_stride[2] * output_idx2) * context->output_element_size;
size_t workspace_offset = (output_stride[0] * output_idx0 + output_stride[1] * output_idx1
+ output_stride[2] * output_idx2) * context->accumulation_element_size;
int input_shape0 = context->input_shape[0];
int input_shape2 = context->input_shape[2];
void* output_ptr = NULL;
if (context->workspace) {
output_ptr = context->workspace;
} else {
output_ptr = context->output;
}
void* output = (void*) ((uintptr_t) output_ptr + workspace_offset);
// Discontiguous reduce microkernels accumulate into the output buffer.
if (context->identity_value == 0) {
memset(output, 0, context->accumulation_element_size * output2_block_size);
} else {
context->fill_ukernel(
1, context->accumulation_element_size * output2_block_size, output,
context->accumulation_element_size, context->identity_value);
}
// Input dimension 0 is reduced.
for (size_t i = 0; i < input_shape0; ++i) {
const void* input = (const void*) ((uintptr_t) context->input + input_offset);
// Input dimension 2 is reduced.
for (size_t j = 0; j < input_shape2; ++j) {
const void* input_row = input;
// The microkernel reduces input dimension 4 and iterates over output_block_size elements of dimension 5.
context->ukernel.discontiguous_reduce(
context->channels, output2_block_size, input_row, input_stride[4],
context->zero, output, &context->params);
// input_stride[4] is the number of bytes of input which have been
// processed by the microkernel call.
input_row = (const void*) ((uintptr_t) input_row + input_stride[4]);
// Reset the output pointer.
output = (void*) ((uintptr_t) output_ptr + workspace_offset);
// Iterating over input_shape[2].
input = (const void*) ((uintptr_t) input + input_stride[2]);
}
// Iterating over input_shape[0].
input_offset += input_stride[0];
}
// Convert to output datatype if accumulation type != output type.
if (context->workspace) {
void* workspace_ptr = (void*) ((uintptr_t) context->workspace + workspace_offset);
output_ptr = (void*) ((uintptr_t) context->output + output_offset);
context->cvt_ukernel(context->accumulation_element_size * output2_block_size, workspace_ptr, output_ptr, &context->cvt_params);
}
}
void xnn_compute_pad_qd8_params(
const struct f32_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index)
{
const size_t batch_size = context->batch_size;
for (size_t i = 0; i < XNN_EXTRA_QUANTIZATION_PARAMS; ++i) {
context->quantization_params[batch_size + i].zero_point = context->quantization_params[batch_size - 1].zero_point;
context->quantization_params[batch_size + i].inv_scale = context->quantization_params[batch_size - 1].inv_scale;
}
}
typedef struct xnn_qd8_quantization_params(f16_quantization_params_fn)(xnn_float16 min, xnn_float16 max, xnn_float16* f32_scale);
typedef struct xnn_qd8_quantization_params(f32_quantization_params_fn)(float min, float max, float* f32_scale);
void xnn_compute_f16_qx8_convert(
const struct f16_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
f16_quantization_params_fn quantization_params_function,
size_t batch_index)
{
const size_t x_stride = context->x_stride;
const size_t y_stride = context->y_stride;
const size_t n = context->n;
const void* input = (const void*) ((uintptr_t) context->x + x_stride * batch_index);
void* output = (void*) ((uintptr_t) context->y + y_stride * batch_index);
xnn_float16 minmax[2] = {xnn_float16_from_bits(UINT16_C(0x7c00)), xnn_float16_from_bits(UINT16_C(0xfc00))};
context->rminmax_ukernel(n, input, minmax, &context->params);
xnn_float16 f16_scale;
context->quantization_params[batch_index] = quantization_params_function(minmax[0], minmax[1], &f16_scale);
struct xnn_f16_qs8_cvt_params params;
params.scalar.scale = f16_scale;
params.scalar.output_zero_point = context->quantization_params[batch_index].zero_point;
context->convert_ukernel(n, input, output, (union xnn_unary_uparams*) &params);
}
void xnn_compute_f16_qd8_convert(
const struct f16_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_offset, size_t batch_range) {
for (size_t batch_index = batch_offset;
batch_index < batch_offset + batch_range; batch_index++) {
xnn_compute_f16_qx8_convert(
context, xnn_f16_qd8_asymmetric_quantization_params, batch_index);
}
}
void xnn_compute_f16_qdu8_convert(
const struct f16_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_offset, size_t batch_range) {
for (size_t batch_index = batch_offset;
batch_index < batch_offset + batch_range; batch_index++) {
xnn_compute_f16_qx8_convert(
context, xnn_f16_qdu8_asymmetric_quantization_params, batch_index);
}
}
void xnn_compute_f32_qx8_convert(
const struct f32_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
f32_quantization_params_fn quantization_params_function,
size_t batch_index)
{
const size_t x_stride = context->x_stride;
const size_t y_stride = context->y_stride;
const size_t n = context->n;
const void* input = (const void*) ((uintptr_t) context->x + x_stride * batch_index);
void* output = (void*) ((uintptr_t) context->y + y_stride * batch_index);
float minmax[2] = {INFINITY, -INFINITY};
context->rminmax_ukernel(n, input, minmax, &context->params);
float scale;
context->quantization_params[batch_index] = quantization_params_function(minmax[0], minmax[1], &scale);
struct xnn_f32_qs8_cvt_params params;
params.scalar.scale = scale;
params.scalar.output_zero_point = context->quantization_params[batch_index].zero_point;
context->convert_ukernel(n, input, output, (union xnn_unary_uparams*) &params);
}
void xnn_compute_f32_qd8_convert(
const struct f32_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_offset, size_t batch_range) {
for (size_t batch_index = batch_offset;
batch_index < batch_offset + batch_range; batch_index++) {
xnn_compute_f32_qx8_convert(
context, xnn_f32_qd8_asymmetric_quantization_params, batch_index);
}
}
void xnn_compute_f32_qdu8_convert(
const struct f32_qd8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_offset, size_t batch_range) {
for (size_t batch_index = batch_offset;
batch_index < batch_offset + batch_range; batch_index++) {
xnn_compute_f32_qx8_convert(
context, xnn_f32_qdu8_asymmetric_quantization_params, batch_index);
}
}
void xnn_compute_pack_lh(
const struct pack_lh_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t group_idx, size_t m_idx_start, size_t tile) {
const void* lhs =
(const void*)((uintptr_t)context->lhs + group_idx * context->gi_stride +
m_idx_start * context->lhs_stride);
const size_t offset = context->packed_offset_fn(
m_idx_start, context->k, context->mr, context->kr, context->sr);
void* lhs_packed = (void*)((uintptr_t)context->lhs_packed +
group_idx * context->gp_stride + offset);
context->pack_lh_ukernel(/*m=*/tile, context->k, context->mr, context->kr,
context->sr, /*m_idx_start=*/0, lhs,
context->lhs_stride, lhs_packed);
}
void xnn_compute_f32_qp8_convert(
const struct f32_qp8_convert_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t group_idx, size_t m_idx_start, size_t m_tile) {
const size_t m_end = m_idx_start + m_tile;
while (m_idx_start < m_end) {
const size_t m_step = min(context->mr, m_end - m_idx_start);
const float* lhs = (const float*)((const char*)context->lhs +
(group_idx * context->m + m_idx_start) *
context->lhs_stride);
int8_t* lhs_packed = (int8_t*)((uintptr_t)context->lhs_packed +
group_idx * context->group_stride +
xnn_x8_packq_f32qp8_packed_offset(
m_idx_start, context->k, context->mr,
context->kr, context->sr));
context->packq_ukernel(/*m=*/m_step, context->k, context->mr, context->kr,
context->sr, m_idx_start, lhs, context->lhs_stride,
lhs_packed);
m_idx_start += m_step;
}
}
void xnn_compute_u8_softmax(
const struct u8_softmax_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index)
{
const uint8_t* x = (const uint8_t*) ((uintptr_t) context->x + context->x_stride * batch_index);
uint8_t* y = (uint8_t*) ((uintptr_t) context->y + context->y_stride * batch_index);
const size_t n = context->n;
uint8_t x_max = 0;
context->rmax_ukernel(n, x, &x_max, /*params=*/NULL);
const size_t adjustment = x_max ^ 255;
const uint32_t* t = (const uint32_t*) context->t + adjustment;
context->lut_norm_ukernel(n, x, t, y);
}
void xnn_compute_floating_point_softmax(
const struct floating_point_softmax_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index)
{
const void* x = (const void*) ((uintptr_t) context->x + context->x_stride * batch_index);
void* y = (void*) ((uintptr_t) context->y + context->y_stride * batch_index);
const size_t n = context->n;
// First pass: reduce-max
union {
float as_float;
xnn_float16 as_half;
} x_max;
memcpy(&x_max, &context->rmax_init, sizeof(x_max));
context->rmax_ukernel(n, x, &x_max, &context->rmax_params);
// Second pass: reduce-add & store exp(x-x_max)
union {
float as_float;
xnn_float16 as_half;
} y_sum;
context->raddstoreexpminusmax_ukernel(n, x, &x_max, y, &y_sum, &context->expminus_params);
// Third pass: scale y
union {
float as_float;
xnn_float16 as_half;
} y_scale;
context->compute_reciprocal(&y_sum, &y_scale);
context->vmulc_ukernel(n, y, &y_scale, y, &context->minmax_params);
}
void xnn_compute_vmulcaddc(
const struct vmulcaddc_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_start,
size_t batch_size)
{
const size_t x_stride = context->x_stride;
const size_t y_stride = context->y_stride;
const void* x = (const void*) ((uintptr_t) context->x + x_stride * batch_start);
void* y = (void*) ((uintptr_t) context->y + y_stride * batch_start);
context->ukernel(
batch_size,
context->n,
x, x_stride,
context->w,
y, y_stride,
&context->params);
}
void xnn_compute_rope(
const struct rope_context context[restrict XNN_MIN_ELEMENTS(1)],
size_t batch_index,
size_t head_index,
size_t sequence_index)
{
const size_t scaled_channels = context->scaled_channels;
const size_t offset = batch_index * context->batch_stride + head_index * context->head_stride + sequence_index * context->sequence_stride;
const void* input = (const void*) ((uintptr_t) context->input + offset);
const void* weights = (const void*) ((uintptr_t) context->weights + sequence_index * (scaled_channels + scaled_channels));
void* output = (void*) ((uintptr_t) context->output + offset);
context->vcmul(
scaled_channels,
input, weights, output,
NULL);
}
#if XNN_MAX_UARCH_TYPES > 1
void xnn_compute_hmp_gemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t a_stride = context->a_stride;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[uarch_index](
mr_step, nr_block_size, context->k_scaled,
(const void*)((uintptr_t)context->a + mr_block_start * a_stride),
a_stride,
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->fused_params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_dqgemm(
const struct gemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t a_stride = context->a_stride;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[uarch_index](
mr_step, nr_block_size, context->k_scaled,
(const void*)((uintptr_t)context->a + mr_block_start * a_stride),
a_stride,
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->fused_params,
&context->quantization_params[mr_block_start]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_grouped_batch_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t batch_index, size_t group_index,
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
batch_index * context->bc_stride + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride +
batch_index * context->ba_stride,
context->zero, &context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_grouped_batch_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t batch_index, size_t group_index,
size_t nr_block_start, size_t mr_block_start, size_t nr_block_size,
size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
batch_index * context->bc_stride + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride +
batch_index * context->ba_stride,
context->zero, context->zero_buffers[batch_index], &context->params,
&context->quantization_params[batch_index]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_grouped_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t group_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride, context->zero,
&context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_grouped_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t group_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride +
group_index * context->gw_stride),
(void*)((uintptr_t)context->c + group_index * context->gc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + group_index * context->ga_stride, context->zero,
context->zero_buffers[0], &context->params,
(const void*)((uintptr_t)context->quantization_params));
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_batch_hmp_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t batch_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + batch_index * context->bc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + batch_index * context->ba_stride, context->zero,
&context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_batch_hmp_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t batch_index, size_t nr_block_start,
size_t mr_block_start, size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + batch_index * context->bc_stride +
mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride,
context->a_offset + batch_index * context->ba_stride, context->zero,
context->zero_buffers[batch_index], &context->params,
&context->quantization_params[batch_index]);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_igemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->a_offset, context->zero,
&context->params);
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
void xnn_compute_hmp_dqigemm(
const struct igemm_context context[restrict XNN_MIN_ELEMENTS(1)],
uint32_t uarch_index, size_t nr_block_start, size_t mr_block_start,
size_t nr_block_size, size_t mr_block_size) {
const size_t ks = context->ks;
const size_t cm_stride = context->cm_stride;
while (mr_block_size > 0) {
const size_t mr_step = min(mr_block_size, context->mr);
context->dq_ukernel.function[uarch_index](
mr_step, nr_block_size, context->kc, context->ks_scaled,
(const void**)((uintptr_t)context->indirect_a +
mr_block_start * ks * sizeof(void*)),
(const void*)((uintptr_t)context->packed_w +
nr_block_start * context->w_stride),
(void*)((uintptr_t)context->c + mr_block_start * cm_stride +
(nr_block_start << context->log2_csize)),
cm_stride, context->cn_stride, context->a_offset, context->zero,
context->zero_buffers[0], &context->params,
(const void*)((uintptr_t)context->quantization_params));
mr_block_size -= mr_step;
mr_block_start += mr_step;
}
}
#endif // XNN_MAX_UARCH_TYPES > 1
enum xnn_status xnn_run_operator(xnn_operator_t op, pthreadpool_t threadpool)
{
return xnn_run_operator_with_index(op, 0, 0, threadpool);
}
enum xnn_status xnn_run_operator_with_index(
xnn_operator_t op,
size_t opdata_index,
size_t operator_object_index,
pthreadpool_t threadpool)
{
switch (op->state) {
case xnn_run_state_invalid:
xnn_log_error("failed to run operator: operator was not successfully setup");
return xnn_status_invalid_state;
case xnn_run_state_ready:
xnn_log_debug("running operator %zu:%zu (%s %s)", opdata_index,
operator_object_index, xnn_operator_type_to_string_v2(op),
xnn_microkernel_type_to_string(op->ukernel.type));
break;
case xnn_run_state_skip:
xnn_log_debug("skip running operator %zu:%zu (%s %s)", opdata_index,
operator_object_index, xnn_operator_type_to_string_v2(op),
xnn_microkernel_type_to_string(op->ukernel.type));
return xnn_status_success;
case xnn_run_state_needs_setup:
xnn_log_error(
"failed to run operator %zu:%zu (%s %s): operator has been reshaped "
"but not yet setup",
opdata_index, operator_object_index,
xnn_operator_type_to_string_v2(op),
xnn_microkernel_type_to_string(op->ukernel.type));
return xnn_status_invalid_state;
}
uint32_t flags = PTHREADPOOL_FLAG_DISABLE_DENORMALS;
if (op->flags & XNN_FLAG_YIELD_WORKERS) {
flags |= PTHREADPOOL_FLAG_YIELD_WORKERS;
}
for (size_t i = 0; i < XNN_MAX_COMPUTE_INVOCATIONS; i++) {
switch (op->compute[i].type) {
case xnn_parallelization_type_invalid:
break;
case xnn_parallelization_type_1d:
assert(op->compute[i].range[0] != 0);
pthreadpool_parallelize_1d(
threadpool,
op->compute[i].task_1d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0],
flags);
break;
case xnn_parallelization_type_1d_with_thread:
assert(op->compute[i].range[0] != 0);
pthreadpool_parallelize_1d_with_thread(
threadpool,
op->compute[i].task_1d_with_thread,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0],
flags);
break;
case xnn_parallelization_type_1d_tile_1d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_1d_tile_1d(
threadpool,
op->compute[i].task_1d_tile_1d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_1d_tile_1d_dynamic:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_1d_tile_1d_dynamic(
threadpool, op->compute[i].task_1d_tile_1d_dynamic,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].tile[0], flags);
break;
case xnn_parallelization_type_2d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
pthreadpool_parallelize_2d(
threadpool,
op->compute[i].task_2d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
flags);
break;
case xnn_parallelization_type_2d_with_thread:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
pthreadpool_parallelize_2d_with_thread(
threadpool,
op->compute[i].task_2d_with_thread,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
flags);
break;
case xnn_parallelization_type_2d_tile_1d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_2d_tile_1d(
threadpool,
op->compute[i].task_2d_tile_1d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_2d_tile_2d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_2d_tile_2d(
threadpool,
op->compute[i].task_2d_tile_2d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_2d_tile_1d_dynamic:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_2d_tile_1d_dynamic(
threadpool, op->compute[i].task_2d_tile_1d_dynamic,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0], flags);
break;
case xnn_parallelization_type_2d_tile_2d_dynamic:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_2d_tile_2d_dynamic(
threadpool, op->compute[i].task_2d_tile_2d_dynamic,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0], op->compute[i].tile[1], flags);
break;
case xnn_parallelization_type_3d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
pthreadpool_parallelize_3d(
threadpool,
op->compute[i].task_3d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
flags);
break;
case xnn_parallelization_type_3d_tile_1d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_3d_tile_1d(
threadpool,
op->compute[i].task_3d_tile_1d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_3d_tile_1d_with_thread:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_3d_tile_1d_with_thread(
threadpool,
op->compute[i].task_3d_tile_1d_with_thread,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_3d_tile_2d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_3d_tile_2d(
threadpool,
op->compute[i].task_3d_tile_2d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_3d_tile_2d_dynamic:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_3d_tile_2d_dynamic(
threadpool, op->compute[i].task_3d_tile_2d_dynamic,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].range[2], op->compute[i].tile[0],
op->compute[i].tile[1], flags);
break;
case xnn_parallelization_type_4d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
pthreadpool_parallelize_4d(
threadpool,
op->compute[i].task_4d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2], op->compute[i].range[3],
flags);
break;
case xnn_parallelization_type_4d_tile_2d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_4d_tile_2d(
threadpool,
op->compute[i].task_4d_tile_2d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_4d_tile_2d_dynamic:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_4d_tile_2d_dynamic(
threadpool, op->compute[i].task_4d_tile_2d_dynamic,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].tile[0], op->compute[i].tile[1], flags);
break;
case xnn_parallelization_type_5d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].range[4] != 0);
pthreadpool_parallelize_5d(
threadpool,
op->compute[i].task_5d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].range[4],
flags);
break;
case xnn_parallelization_type_5d_tile_2d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].range[4] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_5d_tile_2d(
threadpool,
op->compute[i].task_5d_tile_2d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].range[4],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_6d_tile_2d:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].range[4] != 0);
assert(op->compute[i].range[5] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_6d_tile_2d(
threadpool,
op->compute[i].task_6d_tile_2d,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].range[4], op->compute[i].range[5],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
#if XNN_MAX_UARCH_TYPES > 1
case xnn_parallelization_type_2d_tile_1d_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_2d_tile_1d_with_uarch(
threadpool,
op->compute[i].task_2d_tile_1d_with_id,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_2d_tile_2d_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_2d_tile_2d_with_uarch(
threadpool,
op->compute[i].task_2d_tile_2d_with_id,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_2d_tile_2d_dynamic_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_2d_tile_2d_dynamic_with_uarch(
threadpool, op->compute[i].task_2d_tile_2d_dynamic_with_id,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
/*default_uarch_index=*/0, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].tile[0], op->compute[i].tile[1], flags);
break;
case xnn_parallelization_type_3d_tile_1d_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_3d_tile_1d_with_uarch(
threadpool,
op->compute[i].task_3d_tile_1d_with_id,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_3d_tile_1d_with_uarch_with_thread:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
pthreadpool_parallelize_3d_tile_1d_with_uarch_with_thread(
threadpool,
op->compute[i].task_3d_tile_1d_with_id_with_thread,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
op->compute[i].tile[0],
flags);
break;
case xnn_parallelization_type_3d_tile_2d_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_3d_tile_2d_with_uarch(
threadpool,
op->compute[i].task_3d_tile_2d_with_id,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_3d_tile_2d_dynamic_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_3d_tile_2d_dynamic_with_uarch(
threadpool, op->compute[i].task_3d_tile_2d_dynamic_with_id,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
/*default_uarch_index=*/0, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].range[2], op->compute[i].tile[0],
op->compute[i].tile[1], flags);
break;
case xnn_parallelization_type_4d_tile_2d_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_4d_tile_2d_with_uarch(
threadpool,
op->compute[i].task_4d_tile_2d_with_id,
(void*) ((uintptr_t) &op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1], op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].tile[0], op->compute[i].tile[1],
flags);
break;
case xnn_parallelization_type_4d_tile_2d_dynamic_with_uarch:
assert(op->compute[i].range[0] != 0);
assert(op->compute[i].range[1] != 0);
assert(op->compute[i].range[2] != 0);
assert(op->compute[i].range[3] != 0);
assert(op->compute[i].tile[0] != 0);
assert(op->compute[i].tile[1] != 0);
pthreadpool_parallelize_4d_tile_2d_dynamic_with_uarch(
threadpool, op->compute[i].task_4d_tile_2d_dynamic_with_id,
(void*)((uintptr_t)&op->context + op->compute[i].context_offset),
0 /* default uarch index */, XNN_MAX_UARCH_TYPES - 1,
op->compute[i].range[0], op->compute[i].range[1],
op->compute[i].range[2], op->compute[i].range[3],
op->compute[i].tile[0], op->compute[i].tile[1], flags);
break;
#endif // XNN_MAX_UARCH_TYPES > 1
default:
XNN_UNREACHABLE;
}
}
return xnn_status_success;
}