warning #167 that should really be an error

warning #167 that should really be an error

Hi,

I have a question about warning 167, which ICC prints for the following testcase:

 #include <xmmintrin.h>
void foo(__m128i) {}
int main() {
  foo(_mm_setzero_ps());
  return 0;
}
Why is this not an error? I mean how can a C++ compiler do an automatic cast from four floats to 2/4/8/16 signed/unsigned integers? And no, of course it doesn't do a conversion it just does a reinterpret_cast. Good that there's a warning, but I don't understand the rationale for not making this an error.

Vc: SIMD Vector Classes for C++
http://code.compeng.uni-frankfurt.de/projects/vc
8 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

I have submiited  a report, # DPD200240331,  on this to Intel compiler dvelopment team. I will update when I have more information on this.

>>...Why is this not an error? I mean how can a C++ compiler do an automatic cast from four floats to 2/4/8/16 signed/unsigned
>>integers?

Please take a look at all declarations of used SSE data types and the intrinsic function. They are as follows:
...
__m128 _mm_setzero_ps( void );
...
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128
{
float m128_f32[4];
unsigned __int64 m128_u64[2];
__int8 m128_i8[16];
__int16 m128_i16[8];
__int32 m128_i32[4];
__int64 m128_i64[2];
unsigned __int8 m128_u8[16];
unsigned __int16 m128_u16[8];
unsigned __int32 m128_u32[4];
} __m128;
...
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128i
{
__int8 m128i_i8[16];
__int16 m128i_i16[8];
__int32 m128i_i32[4];
__int64 m128i_i64[2];
unsigned __int8 m128i_u8[16];
unsigned __int16 m128i_u16[8];
unsigned __int32 m128i_u32[4];
unsigned __int64 m128i_u64[2];
} __m128i;
...

Now, do a very simple verification / test:
...
printf( "sizeof( __m128 )=%d\nsizeof( __m128i )=%d\n", sizeof( __m128 ), sizeof( __m128i ) );
...

Output should look like:
...
sizeof( __m128 )=16
sizeof( __m128i )=16
...
So, sizes are identical.

Then, Intel C++ compiler could pick unsigned __int64 m128_u64[2] from __m128 and unsigned __int64 m128i_u64[2] from __m128i to complete a cast with the warning message.

>>...I have submiited a report, # DPD200240331, on this to Intel compiler dvelopment team. I will update when I have more
>>information on this.

Thank you. Even if an internal verification won't harm I don't consider it as an error in Intel C++ compiler.

Quote:

Sergey Kostrov wrote:

So, sizes are identical.

Then, Intel C++ compiler could pick unsigned __int64 m128_u64[2] from __m128 and unsigned __int64 m128i_u64[2] from __m128i to complete a cast with the warning message.

printf("%lld - %lldn", sizeof(float), sizeof(char[4]));

I don't think equal sizes is a good argument for or against whether a cast is/should be possible. Automatic casts between differently sized integers are perfectly fine. Obviously, one can't really argue with the C++ spec here, because the SSE intrinsics are a compiler extensions developed by Intel. But it certainly makes sense to have this extension follow the spirit of the C++ spec wherever possible. If you avoid surprises in the language you can avoid serious bugs... In C++ automatic conversions between floating point and integer types exists. But nothing like this here, where float values are reinterpreted as some integers of unknown size. For builtin types this would always result in a compile error and the requirement to have the developer actually write down what he wants.

Vc: SIMD Vector Classes for C++
http://code.compeng.uni-frankfurt.de/projects/vc

Maybe, it's interesting for you to know the background: I actually did not create such broken code myself (I develop my code mostly with GCC, which does not compile this example). But while trying to reduce a miscompilation of ICC, a delta run reduced the code to a rather broken state - because ICC did not error out...

Vc: SIMD Vector Classes for C++
http://code.compeng.uni-frankfurt.de/projects/vc

I'll do a verification with Microsoft C++ compiler in VS 2005.

>>...In C++ automatic conversions between floating point and integer types exists. But nothing like this here, where float values are
>>reinterpreted as some integers of unknown size. For builtin types this would always result in a compile error...

Take into account that you're dealing with unions ( it is a different world! ):

typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 {
...
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128i {
...

not a more common typedef struct declarations.

Here are results of my verification on a Windows platform:

[ Microsoft C++ compiler ]
...
..\common\prttests.cpp(8543) : error C2664: 'foo' : cannot convert parameter 1 from '__m128' to '__m128i'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
...

[ Intel C++ compiler ]
...
.\../../Common/PrtTests.cpp(8543): error: argument of type "__m128" is incompatible with parameter of type "__m128i"
foo( _mm_setzero_ps() );
...

So, it is clear that there is a problem on a Linux platform with Intel C++ compiler. Thanks for the information!

Leave a Comment

Please sign in to add a comment. Not a member? Join today