Menu

#488 The intrin.h header can cause a compiler error

v1.0 (example)
open
nobody
None
5
2015-07-14
2015-07-14
No

In the intrin.h header there is an include of x86intrin.h whenever GNUC is defined and we are compiling for x86 or x64. You can see this at the beginning of the header file where the code begins:

#if defined(GNUC) && (defined(i386) || defined(x86_64))

// etc.

#include <x86intrin.h>

// etc.

#endif

If you look at the x86intrin.h header file you will see it includes header files for all intrinsics regardless of whether the CPU feature exists or not. This is true for x86intrin.h for gcc-4.9 on up. Yet for gcc below 4.9 the x86intrin.h only included an intrinsic header file if that CPU feature actually existed. I realize that this change of the x86intrin.h header from gcc-4.8 to gcc-4.9 and up may have been mandated by a change in gcc itself and not something done by the mingw-64 developers.

In gcc 4.9 and up, in intrin.h, this leads to multiple typedefs using the same name for m64, m128, m128d, and m128i whenever the MMX CPU feature does not exist and MINGW_FORCE_SYS_INTRINS is not defined. Normally this is not a problem since MINGW_FORCE_SYS_INTRINS is defined whenever the gcc version is 4.9 and up, with the code in intrin.h of:

#if MINGW_GNUC_PREREQ(4, 9)
#define
MINGW_FORCE_SYS_INTRINS
#endif

and after all the header file change is precisely for gcc-4.9 and up implementations.

But what happens if the intrin.h header file for gcc-4.9 and up is being used by a compiler implementation in which the gcc version is set below 4.9. Now MINGW_FORCE_SYS_INTRINS is not defined and we do have multiple typedefs using the same m64, m128, m128d, and __m128i
names, which is of course a C++ error.

The workaround for this is obviously to define __MINGW_FORCE_SYS_INTRINS for such a compiler implementation, which now avoids the multiple same name typedef problem. I can attest that the workaround does work when using clang on Windows, which tags itself as gcc version 4.2.1.

It would be better if the workaround of defining __MINGW_FORCE_SYS_INTRINS were unnecessary.
This can be done in the intrin.h header file by merely using the check which allowed the x86intrin.h to be originally included in the first place. So instead of:

#ifndef MINGW_FORCE_SYS_INTRINS
#ifndef
MMX
typedef union
m64 { char v[7]; } m64;
#endif
#ifndef
SSE
typedef union
m128 { char v[16]; } m128;
#endif
#ifndef
SSE2
typedef union
m128d { char v[16]; } m128d;
typedef union
m128i { char v[16]; } __m128i;
#endif
#endif

as the code for the MMX substitution typedefs in intrin.h it should be:

#if !defined(MINGW_FORCE_SYS_INTRINS) && !(defined(GNUC) && (defined(i386) || defined(x86_64)))
#ifndef
MMX
typedef union
m64 { char v[7]; } m64;
#endif
#ifndef
SSE
typedef union
m128 { char v[16]; } m128;
#endif
#ifndef
SSE2
typedef union
m128d { char v[16]; } m128d;
typedef union
m128i { char v[16]; } __m128i;
#endif
#endif

I have tested this with clang, without defining __MINGW_FORCE_SYS_INTRINS, and can assert that this fixes the bug.

The corrected code, as I give it above, will work even with a compiler like clang which, as I have explained, sets itself as gcc version 4.2.1 but still works with gcc 4.9 on up on Windows.

Discussion


Log in to post a comment.