This Request for Comments (RFC) proposes an extension to the Clang’s ext_vector_type attribute that would make it possible to create the variables of the scalable vector data types.
Motivation and Background
The indented beneficiary of this extension is the LLVM’s libc library in which we wish to extend the existing set of the vectorized math routines. We would like these routines to process any kind of vector data types, including the ones with fixed and scalable vector sizes. Therefore we need a portable way of expressing these vector types which would be independent of any underlying architectural implementation. A generalized vector data type (covering both fixed and scalable vector lengths) would be our ideal.
Currently, the vector data types with fixed vector sizes are being created using the Clang’s ext_vector_type attribute, which takes the vector size as its only parameter. This attribute has been added to Clang in order to introduce the OpenCL vector types, but it can also be used in normal C/C++ code for specifying vector data types in an architectural-agnostic manner. For example, in case of Arm’s NEON, the types annotated with this attribute are compatible with the vector data types annotated with the neon_vector_type attribute and can be used by the intrinsics defined in the arm-neon.h header.
This attribute plays similar role as GCC’s vector_size attribute (see [1]), yet it is so neat that there were proposals to introduce it in there too (see [2]).
In LLVM’s libc, we can see an example of using this attribute in the simd.h header of the C++ support layer:
template <typename T, size_t N = internal::native_vector_size<T>>
using simd = T [[clang::ext_vector_type(N)]];
We would wish to extend this attribute with the ability to cover the vector-length agnostic scalable vectors (e.g., ARM SVE or RISCV RVV).
Proposed extensions
As can be seen in our PoC PR (see [3]), we were discussing two possibilities:
-
To encode scalable vector sizes as negative numbers;
-
To add an optional second parameter of the integer logic type to the
ext_vector_typeattribute which would denote whether the vector length is scalable or not.
We were also considering the addition of a new attribute (namely, ext_scalable_vector_type), but this would create a lot of overlap with the existing attribute, and would not lead to a more generalized solution.
Example of using the first possibility:
In a C piece of code:
#define SCALABLE_SIZE(N) (-1 * ((signed)(N)))
typedef float svfloat1 __attribute__((ext_vector_type(SCALABLE_SIZE(1U))));
typedef float svfloat4 __attribute__((ext_vector_type(SCALABLE_SIZE(4U))));
In a C++ piece of code:
namespace cpp {
template <size_t N>
constexpr signed scalable_size = -1 * static_cast<signed>(N);
template <typename T, auto N = internal::native_vector_size<T>>
using simd = T [[clang::ext_vector_type(N)]];
} // namespace cpp
cpp::simd<int, cpp::scalable_size<1U>> sv = cpp::iota<int, cpp::scalable_size<1U>>(0);
Example of using the second possibility:
In a C piece of code:
#define SCALABLE_SIZE(N) (N), 1
typedef float svfloat1 __attribute__((ext_vector_type(SCALABLE_SIZE(1U))));
typedef float svfloat4 __attribute__((ext_vector_type(SCALABLE_SIZE(4U))));
In a C++ piece of code:
namespace cpp {
template <typename T, size_t N>
using fixed_size_simd = T [[clang::ext_vector_type(N, false)]];
template <typename T, size_t N>
using scalable_size_simd = T [[clang::ext_vector_type(N, true)]];
template <typename T, size_t N = internal::native_vector_size<T>,
bool S = internal::native_vector_scalable<T>>
using simd = T [[clang::ext_vector_type(N, S)]];
} // namespace cpp
cpp::simd<int, 1, true>> svi = cpp::iota<int, 1, true>(0);
(Note: I have some concerns regarding how this approach could be used in the concat<>() function template, and anything alike, see [3]).
Proof of concept
The PoC code presented in [3] modifies the Clang’s SemaType.cpp routines so that the ext_vector_type attribute (extended either way) maps the demanded scalable vector types to the Clang’s built-in SVE types (when targeting CPUs with SVE). For example, __attribute((ext_vector_type(SCALABLE_SIZE(1)))) int data type is being turned into the Clang’s built-in __SVInt32_t data type. This however unearths several shortcomings in the currently existing built-in scalable vector data types (see the discussion in [3]).
Although the author is in favor of the first (using negative numbers) approach (it seems simpler in many ways) the discussion which emerged in [3] shows that the more favorable is the second (adding optional parameter) approach.
[1] Vector Extensions (Using the GNU Compiler Collection (GCC))