#include "padding_riscv.h"
#if __riscv_vector
#include <riscv_vector.h>
#endif
#include "riscv_usability.h"
namespace ncnn {
#if __riscv_vector
#include "padding_packn.h"
#endif
Padding_riscv::Padding_riscv()
{
#if __riscv_vector
support_packing = true;
#if __riscv_zfh
support_fp16_storage = true;
#endif
#endif
#if NCNN_BF16
support_bf16_storage = true;
#endif
}
int Padding_riscv::create_pipeline(const Option& opt)
{
#if __riscv_vector && __riscv_zfh
if (opt.use_fp16_storage)
{
ncnn::cast_float32_to_float16(per_channel_pad_data, per_channel_pad_data_fp16, opt);
}
#endif
#if NCNN_BF16
if (opt.use_bf16_storage)
{
value_bf16 = float32_to_bfloat16(value);
ncnn::cast_float32_to_bfloat16(per_channel_pad_data, per_channel_pad_data_bf16, opt);
}
#endif
return 0;
}
int Padding_riscv::destroy_pipeline(const Option& )
{
return 0;
}
int Padding_riscv::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
{
if (top == 0 && bottom == 0 && left == 0 && right == 0 && front == 0 && behind == 0)
{
top_blob = bottom_blob;
return 0;
}
int elembits = bottom_blob.elembits();
if (elembits == 8)
return forward_int8(bottom_blob, top_blob, opt);
#if __riscv_vector && __riscv_zfh
if (opt.use_fp16_storage && elembits == 16)
return forward_bf16s_fp16s(bottom_blob, top_blob, opt);
#endif
#if NCNN_BF16
if (opt.use_bf16_storage && elembits == 16)
return forward_bf16s_fp16s(bottom_blob, top_blob, opt);
#endif
#if __riscv_vector
const int packn = csrr_vlenb() / 4;
const size_t vl = vsetvl_e32m1(packn);
#endif
int w = bottom_blob.w;
int h = bottom_blob.h;
int d = bottom_blob.d;
int channels = bottom_blob.c;
int dims = bottom_blob.dims;
size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;
#if __riscv_vector
if (elempack == packn)
{
if (dims == 1)
{
int outw = w * elempack + left + right;
int out_elempack = outw % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (left % packn == 0 && out_elempack == packn && type == 0)
{
top_blob.create(outw / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
vfloat32m1_t pad_value = vfmv_v_f_f32m1(value, vl);
padding_constant_packn_float32_rvv(bottom_blob, top_blob, 0, 0, left / packn, right / packn, pad_value);
return 0;
}
}
if (dims == 2)
{
int outw = w + left + right;
int outh = h * elempack + top + bottom;
int out_elempack = outh % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (top % packn == 0 && out_elempack == packn && type == 0)
{
top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
vfloat32m1_t pad_value = vfmv_v_f_f32m1(value, vl);
padding_constant_packn_float32_rvv(bottom_blob, top_blob, top / packn, bottom / packn, left, right, pad_value);
return 0;
}
}
if (dims == 3)
{
int outw = w + left + right;
int outh = h + top + bottom;
int outc = channels * elempack + front + behind;
int out_elempack = outc % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (front % packn == 0 && out_elempack == packn && !(outc != channels * elempack && type != 0))
{
top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
int front_ = front / elempack;
#pragma omp parallel for num_threads(opt.num_threads)
for (int q = 0; q < outc / out_elempack; q++)
{
Mat borderm = top_blob.channel(q);
vfloat32m1_t pad_value = per_channel_pad_data_size ? vle32_v_f32m1((const float*)per_channel_pad_data + q * packn, vl) : vfmv_v_f_f32m1(value, vl);
if ((q - front_) < 0 || (q - front_) >= channels)
{
borderm.fill(pad_value);
}
else
{
const Mat m = bottom_blob.channel(q - front_);
if (type == 0)
padding_constant_packn_float32_rvv(m, borderm, top, bottom, left, right, pad_value);
if (type == 1)
padding_replicate_packn_float32_rvv(m, borderm, top, bottom, left, right);
if (type == 2)
padding_reflect_packn_float32_rvv(m, borderm, top, bottom, left, right);
}
}
return 0;
}
}
if (dims == 4)
{
int outw = w + left + right;
int outh = h + top + bottom;
int outd = d + front + behind;
if (type == 0)
{
top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
#pragma omp parallel for num_threads(opt.num_threads)
for (int q = 0; q < channels; q++)
{
vfloat32m1_t pad_value = per_channel_pad_data_size ? vle32_v_f32m1((const float*)per_channel_pad_data + q * packn, vl) : vfmv_v_f_f32m1(value, vl);
for (int z = 0; z < outd; z++)
{
Mat borderm = top_blob.channel(q).depth(z);
if ((z - front) < 0 || (z - front) >= d)
{
borderm.fill(pad_value);
}
else
{
const Mat m = bottom_blob.channel(q).depth(z - front);
padding_constant_packn_float32_rvv(m, borderm, top, bottom, left, right, pad_value);
}
}
}
return 0;
}
}
}
#endif
Mat bottom_blob_unpacked = bottom_blob;
if (elempack != 1)
{
Option opt_pack1 = opt;
opt_pack1.blob_allocator = opt.workspace_allocator;
convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1);
}
Mat top_blob_unpacked;
int ret = Padding::forward(bottom_blob_unpacked, top_blob_unpacked, opt);
if (ret != 0)
return ret;
int out_elempack = 1;
#if __riscv_vector
if (opt.use_packing_layout)
{
out_elempack = top_blob_unpacked.c % packn == 0 ? packn : 1;
}
#endif
convert_packing(top_blob_unpacked, top_blob, out_elempack, opt);
return 0;
}
int Padding_riscv::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
{
#if __riscv_vector
const int packn = csrr_vlenb() / 2;
const size_t vl = vsetvl_e16m1(packn);
#endif
int w = bottom_blob.w;
int h = bottom_blob.h;
int d = bottom_blob.d;
int channels = bottom_blob.c;
int dims = bottom_blob.dims;
size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;
#if __riscv_vector
if (elempack == packn)
{
if (dims == 1)
{
int outw = w * elempack + left + right;
int out_elempack = outw % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (left % packn == 0 && out_elempack == packn && type == 0)
{
top_blob.create(outw / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
vuint16m1_t pad_value;
#if __riscv_zfh
if (opt.use_fp16_storage)
{
pad_value = vreinterpret_v_f16m1_u16m1(vfmv_v_f_f16m1((__fp16)value, vl));
}
else
#endif
#if NCNN_BF16
if (opt.use_bf16_storage)
{
pad_value = vmv_v_x_u16m1(value_bf16, vl);
}
else
#endif
{
}
padding_constant_packn_uint16_rvv(bottom_blob, top_blob, 0, 0, left / packn, right / packn, pad_value);
return 0;
}
}
if (dims == 2)
{
int outw = w + left + right;
int outh = h * elempack + top + bottom;
int out_elempack = outh % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (top % packn == 0 && out_elempack == packn && type == 0)
{
top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
vuint16m1_t pad_value;
#if __riscv_zfh
if (opt.use_fp16_storage)
{
pad_value = vreinterpret_v_f16m1_u16m1(vfmv_v_f_f16m1((__fp16)value, vl));
}
else
#endif
#if NCNN_BF16
if (opt.use_bf16_storage)
{
pad_value = vmv_v_x_u16m1(value_bf16, vl);
}
else
#endif
{
}
padding_constant_packn_uint16_rvv(bottom_blob, top_blob, top / packn, bottom / packn, left, right, pad_value);
return 0;
}
}
if (dims == 3)
{
int outw = w + left + right;
int outh = h + top + bottom;
int outc = channels * elempack + front + behind;
int out_elempack = outc % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (front % packn == 0 && out_elempack == packn && !(outc != channels * elempack && type != 0))
{
top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
int front_ = front / elempack;
#pragma omp parallel for num_threads(opt.num_threads)
for (int q = 0; q < outc / out_elempack; q++)
{
Mat borderm = top_blob.channel(q);
vuint16m1_t pad_value;
#if __riscv_zfh
if (opt.use_fp16_storage)
{
pad_value = per_channel_pad_data_size ? vreinterpret_v_f16m1_u16m1(vle16_v_f16m1((const __fp16*)per_channel_pad_data_fp16 + q * packn, vl)) : vreinterpret_v_f16m1_u16m1(vfmv_v_f_f16m1((__fp16)value, vl));
}
else
#endif
#if NCNN_BF16
if (opt.use_bf16_storage)
{
pad_value = per_channel_pad_data_size ? vle16_v_u16m1((const unsigned short*)per_channel_pad_data_bf16 + q * packn, vl) : vmv_v_x_u16m1(value_bf16, vl);
}
else
#endif
{
}
if ((q - front_) < 0 || (q - front_) >= channels)
{
borderm.fill(pad_value);
}
else
{
const Mat m = bottom_blob.channel(q - front_);
if (type == 0)
padding_constant_packn_uint16_rvv(m, borderm, top, bottom, left, right, pad_value);
if (type == 1)
padding_replicate_packn_uint16_rvv(m, borderm, top, bottom, left, right);
if (type == 2)
padding_reflect_packn_uint16_rvv(m, borderm, top, bottom, left, right);
}
}
return 0;
}
}
if (dims == 4)
{
int outw = w + left + right;
int outh = h + top + bottom;
int outd = d + front + behind;
if (type == 0)
{
top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
#pragma omp parallel for num_threads(opt.num_threads)
for (int q = 0; q < channels; q++)
{
vuint16m1_t pad_value;
#if __riscv_zfh
if (opt.use_fp16_storage)
{
pad_value = per_channel_pad_data_size ? vreinterpret_v_f16m1_u16m1(vle16_v_f16m1((const __fp16*)per_channel_pad_data_fp16 + q * packn, vl)) : vreinterpret_v_f16m1_u16m1(vfmv_v_f_f16m1((__fp16)value, vl));
}
else
#endif
#if NCNN_BF16
if (opt.use_bf16_storage)
{
pad_value = per_channel_pad_data_size ? vle16_v_u16m1((const unsigned short*)per_channel_pad_data_bf16 + q * packn, vl) : vmv_v_x_u16m1(value_bf16, vl);
}
else
#endif
{
}
for (int z = 0; z < outd; z++)
{
Mat borderm = top_blob.channel(q).depth(z);
if ((z - front) < 0 || (z - front) >= d)
{
borderm.fill(pad_value);
}
else
{
const Mat m = bottom_blob.channel(q).depth(z - front);
padding_constant_packn_uint16_rvv(m, borderm, top, bottom, left, right, pad_value);
}
}
}
return 0;
}
}
}
#endif
Mat bottom_blob_unpacked = bottom_blob;
if (elempack != 1)
{
Option opt_pack1 = opt;
opt_pack1.blob_allocator = opt.workspace_allocator;
convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1);
}
Mat top_blob_unpacked;
int ret = Padding::forward(bottom_blob_unpacked, top_blob_unpacked, opt);
if (ret != 0)
return ret;
int out_elempack = 1;
#if __riscv_vector
if (opt.use_packing_layout)
{
out_elempack = top_blob_unpacked.c % packn == 0 ? packn : 1;
}
#endif
convert_packing(top_blob_unpacked, top_blob, out_elempack, opt);
return 0;
}
int Padding_riscv::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
{
#if __riscv_vector
const int packn = csrr_vlenb() / 1;
const size_t vl = vsetvl_e8m1(packn);
#endif
int w = bottom_blob.w;
int h = bottom_blob.h;
int d = bottom_blob.d;
int channels = bottom_blob.c;
int dims = bottom_blob.dims;
size_t elemsize = bottom_blob.elemsize;
int elempack = bottom_blob.elempack;
#if __riscv_vector
if (elempack == packn)
{
if (dims == 1)
{
int outw = w * elempack + left + right;
int out_elempack = outw % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (left % packn == 0 && out_elempack == packn && type == 0)
{
top_blob.create(outw / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
vint8m1_t pad_value = vmv_v_x_i8m1((signed char)value, vl);
padding_constant_packn_int8_rvv(bottom_blob, top_blob, 0, 0, left / packn, right / packn, pad_value);
return 0;
}
}
if (dims == 2)
{
int outw = w + left + right;
int outh = h * elempack + top + bottom;
int out_elempack = outh % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (top % packn == 0 && out_elempack == packn && type == 0)
{
top_blob.create(outw, outh / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
vint8m1_t pad_value = vmv_v_x_i8m1((signed char)value, vl);
padding_constant_packn_int8_rvv(bottom_blob, top_blob, top / packn, bottom / packn, left, right, pad_value);
return 0;
}
}
if (dims == 3)
{
int outw = w + left + right;
int outh = h + top + bottom;
int outc = channels * elempack + front + behind;
int out_elempack = outc % packn == 0 ? packn : 1;
size_t out_elemsize = elemsize / elempack * out_elempack;
if (front % packn == 0 && out_elempack == packn && !(outc != channels * elempack && type != 0))
{
top_blob.create(outw, outh, outc / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
int front_ = front / elempack;
#pragma omp parallel for num_threads(opt.num_threads)
for (int q = 0; q < outc / out_elempack; q++)
{
Mat borderm = top_blob.channel(q);
vint8m1_t pad_value = vmv_v_x_i8m1((signed char)value, vl);
if ((q - front_) < 0 || (q - front_) >= channels)
{
borderm.fill(pad_value);
}
else
{
const Mat m = bottom_blob.channel(q - front_);
if (type == 0)
padding_constant_packn_int8_rvv(m, borderm, top, bottom, left, right, pad_value);
if (type == 1)
padding_replicate_packn_int8_rvv(m, borderm, top, bottom, left, right);
if (type == 2)
padding_reflect_packn_int8_rvv(m, borderm, top, bottom, left, right);
}
}
return 0;
}
}
if (dims == 4)
{
int outw = w + left + right;
int outh = h + top + bottom;
int outd = d + front + behind;
if (type == 0)
{
top_blob.create(outw, outh, outd, channels, elemsize, elempack, opt.blob_allocator);
if (top_blob.empty())
return -100;
#pragma omp parallel for num_threads(opt.num_threads)
for (int q = 0; q < channels; q++)
{
vint8m1_t pad_value = vmv_v_x_i8m1((signed char)value, vl);
for (int z = 0; z < outd; z++)
{
Mat borderm = top_blob.channel(q).depth(z);
if ((z - front) < 0 || (z - front) >= d)
{
borderm.fill(pad_value);
}
else
{
const Mat m = bottom_blob.channel(q).depth(z - front);
padding_constant_packn_int8_rvv(m, borderm, top, bottom, left, right, pad_value);
}
}
}
return 0;
}
}
}
#endif
Mat bottom_blob_unpacked = bottom_blob;
if (elempack != 1)
{
Option opt_pack1 = opt;
opt_pack1.blob_allocator = opt.workspace_allocator;
convert_packing(bottom_blob, bottom_blob_unpacked, 1, opt_pack1);
}
Mat top_blob_unpacked;
int ret = Padding::forward(bottom_blob_unpacked, top_blob_unpacked, opt);
if (ret != 0)
return ret;
int out_elempack = 1;
#if __riscv_vector
if (opt.use_packing_layout)
{
out_elempack = top_blob_unpacked.c % packn == 0 ? packn : 1;
}
#endif
convert_packing(top_blob_unpacked, top_blob, out_elempack, opt);
return 0;
}
}