Hi ( tl;dr: How do I handle intrinsic or builtin functions where there are restrictions on the arguments which can't be represented in a C function prototype? Do other ports have this problem, how do they solve it? Language extension for C++98 to provide static_assert?)
I'm trying to resolve some problems with error reporting for NEON (ARM SIMD/vector) intrinsics. eg https://bugs.linaro.org/show_bug.cgi?id=418 The NEON intrinsics are defined in a header file, arm_neon.h, which includes type definitions and inline functions which implement the intrinsics in terms of __builtin functions provided by gcc. A number of these intrinsics (eg shift by a constant, set/get Nth lane of vector) are defined to take a compile-time integer constant as one of their arguments. For example: The vshrn_n_s16 (narrowing vector shift right by a constant) intrinsic is defined as: __extension__ static __inline int8x8_t __attribute__ ((__always_inline__)) vshrn_n_s16 (int16x8_t __a, const int __b) { return (int8x8_t)__builtin_neon_vshrn_nv8hi (__a, __b, 1); } These examples demonstrate some valid and invalid use int8x16_t v = vshrn_n_u16(v1, 5); // valid int8x16_t v = vshrn_n_u16(v1, 20); // invalid, constant is out of range int x = 5; int8x16_t v = vshrn_n_u16(v1, x); // invalid, shift amount is not a compile-time constant Presently, the ARM/Aarch64 backends include some checks, but this doesn't work very well, as it allows invalid operations to persist too long. By the time the error is raised, the original source position is lost. Therefore, I would like to add some error checking at an earlier stage, with various options coming to mind: 1. Somehow arrange for __builtin_neon_vshrn_nv8hi to require a constant integer in the prescribed range as the 2nd argument. 2. Redefine the intrinsic function in arm_neon.h to include _Static_assert(__b >= 1 && __b <=8, "Shift amount out of range"); 3. Put a static assert into a macro #define vshrn_n_s16(a,b) \ ({ _Static_assert(__b >= 1 && __b <=8, "Shift amount out of range"); _vshrn_n_s16(a,b); }) 4. Some sort of language extension so that inline functions can require compile-time constants for suitably annotated arguments. eg static __inline int8x8_t __attribute__ ((__always_inline__)) vshrn_n_s16 (int16x8_t __a, const int __attribute((constant_range(1,8))) __b) Pros/cons of each approach: 1. somewhat complex to implement, errors are reported in arm_neon.h, rather than at the source line in the user's code. 2. Easy to implement. Can be adapted to support C++11 using static_assert, but doesn't work for C++98 (maybe a language extension is possible to provide the same functionality as __static_assert in C++98?) . Errors are reported in arm_neon.h, rather than user's code. 3. Easy to implement, the compiler will indicate the source line where the macro was used, so that the user can find the location of their error easily. Can also be adapted to support C++11 using static_assert, but doesn't work for C++98. 4. Results in high quality error messages, but is complex to implement. In my view, options 1&4 are potentially complex to implement. I favour one of 2 or 3, with an extension to C++98 to provide static_assert-like functionality. This is not unprecedented, as _Static_assert is provided in all C language dialects. I am interested in views on the relative merits of these approaches. Thanks Charles