On Thu, Oct 23, 2014 at 10:52 AM, Charles Baylis <charles.bay...@linaro.org> wrote: > 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?)
The attribute __artificial__ . Thanks, Andrew > > 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