Repository: opencv
Issue: OE xx: Modify universal intrinsics for size-less architectures
Labels: optimization,category: core,evolution

This is a draft evolution proposal,  we are going to working on RISC-V Vector acceleration by modifying universal intrinsics and we'd like to make sure that the proposed design is compatible with other  size-less architectures. 

## OE xx: Modify universal intrinsics for size-less architectures

- Author: Liutong HAN, Vadim Pisarevsky
- Link: TBD
- Status: Draft
- Platforms: All vector architectures (RISC-V Vector, ARM SVE2, etc.)
- Complexity: TBD. Maybe a few man-months

## Introduction and Rationale
Currently, OpenCV includes [universal intrinsics](https://docs.opencv.org/master/df/d91/group__core__hal__intrin.html) that cover different SIMD extensions on different platforms, such as `SSE, AVX2, AVX512` on IA, `NEON` on ARM and  `VSX` on PPC64. All the above arch is designed with fixed register size. Nowadays, there are also some vector ISA extensions is designed with size-less instruction, such as RISC-V Vector (aka. RVV) and ARM SVE/SVE2. Taking RVV as an example, different devices that support the RVV extension may have different vector register sizes, any size powered of 2 && between 128 bits and 65536 bits is legally for a RVV application processor. Conversely, any AVX2 devices have a set of vector registers with 256 bits fixed-size.

There is also a RISC-V Vector backend in universal intrinsic, but the performance is very poor and only supported fixed vector size with 128 bit. The reason for the performance issue is speculated to be redundant instructions introduced by the wrapper class. And the fundamental problem is that the current design of Universal Intrinsic may not suitable for size-less architecture.

So it would be nice to modify the API and implementation of universal intrinsics for size-less architectures. Also, the modifications may affect existing code written in the universal intrinsics, but we hope the modifications to be minor.

## Proposed solution
The main modification is to directly use the vector built-in type (e.g. `vfloat32m1_t` in RVV intrinsic) as a universal intrinsic type (e.g. v_float32 ) in the backend of the size-less architecture and introduce the `VectorTraits` class to handle the class member (`nlanes` and `lane_type`) in the current wrapper classes.

An example project is in https://github.com/hanliutong/rvv-ui, particularly in `intrin_rvv_new.hpp`.

## Impact on existing code, compatibility
- Vector type: As size-less intrinsic, we will use `v_float32` etc. as vector type. And currently vector  type such as `v_float32x4` or `v_float32x8` can be renamed to `v_float32`
- intrinsic functions: Since there is no wrapper class for the vector type, we can not overload operators anymore. So we may need to introduce new universal intrinsic functions instead of overloaded operators. And `v0 + v1` should be rewritten by `v_add(v0, v1)`
- Scalars-to-vector constructors: The current Universal Intrinsic class uses scalars-to-vector constructors to build a SIMD vector like: `v_float32x4(float v0, float v1, float v2, float v3)`. But for a scalable vector, we do not know the number of scalars in the vector and there is no wrapper class then no constructors. So we may need to also introduce a universal intrinsic function overload, such as `v_load(std::initializer_list<float> nScalars)`
- Member function: Again, no class, so a new universal intrinsic function like `v_get0(v1)` instead of `v1.get0()` can be introduced.
- lane_type:  `VTraits<v_float32>::lane_type` instead of `v_float32::lane_type`
- nlanes: `VTraits<v_float32>::nlanes`  instead of `v_float32::nlanes`. Another modification related to `nlanes` is that since the new nlanes will be a static variable rather than a constant, the current use of `nlanes` in array declaration or initialization like `float foo[v_float32::nlanes]` can not be used anymore in size-less universal intrinsic.

## Possible alternatives
Write ~a specific~ the fixed-size universal intrinsic for each possible vector size by using template, and treat minimum vector size as the baseline. In this case, the same instruction set (e.g. RVV) will have different binary (RVV128, RVV256, etc.).

## References
1. [universal intrinsics](https://docs.opencv.org/master/df/d91/group__core__hal__intrin.html)
2. [OE-27. Wide-Universal-Intrinsics](https://github.com/opencv/opencv/wiki/OE-27.-Wide-Universal-Intrinsics#introduction-and-rationale)
3. [Iusse: About the performance of opencv of the sizeless instruction](https://github.com/opencv/opencv/issues/21780)