This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Restricting arguments to intrinsic functions


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]