Alignment issue, SSE, etc.

Started by
5 comments, last by Soth 17 years, 4 months ago
Please consider the following code:

typedef struct __declspec(intrin_type) __declspec(align(16)) {
	float       m128_f32[4];
} __myOwn128;

void Test(__m128 param) {} // Compiles just fine. WHY ?

void Test2(__myOwn128 param) {} // error C2719: 'param': formal parameter with __declspec(align('16')) won't be aligned --> I understand that

I don't understand why Test compiles and Test2 does not. (Actually, I am surprised that Test does compile) Anyone could enlight me please ? (And as a side question, what does __declspec(intrin_type) means ? I couldn't fint that documented anywhere, I just copy'n'pasted it from the original __m128 typedef in xmmintrin.h) Cheers, JA
Advertisement
I think I have been fooled by both the debugger and the file xmmintrin.h that let me believe that __m128 was just a mere struct mapped into a sse register.

After a couple more tests I found out that the following would compile:
struct __declspec(intrin_type) __declspec(align(16)) __m128 {	float       m128_f32[4];};int Test(__m128 v){	return 0;}


but that the following wouldn't (just changed 128 to 127...)

struct __declspec(intrin_type) __declspec(align(16)) __m127 {	float       m128_f32[4];};// error C2719: 'v': formal parameter with __declspec(align('16')) won't be alignedint Test(__m127 v) {	return 0;}


Looks like the token "__m128" is processed by the compiler as a built-in type that still needs to be declared (unlike int and such) and that can be redefined too...
Quote:Original post by janta
Looks like the token "__m128" is processed by the compiler as a built-in type that still needs to be declared (unlike int and such) and that can be redefined too...


I don't think that's the case. It seems that it is struct that's blocking the compiler's cleverness... for whatever reason.

typedef __m128 orig;typedef float __declspec(align(16)) arr[4];typedef __declspec(align(16)) struct str {	float x[4];};int test_orig(orig m) { return 0; }; // okint test_arr(arr m) { return 0; };   // okint test_str(str m) { return 0; };   // C2719:


Passing aligned types by value is a common problem, especially when using std::vector (resize() won't compile). Hint: don't do that.

Unfortunately, returning aligned types by value could be buggy as well (sample) - although it happens rarely so it can be avoided.
Looking at the docs for C2719 (you did do that right?) it says very explicity that your can't pass __declspec(align) variables as function parameters. That fact that you found a case where it "worked" is probably a compiler bug or some special case.

As to why it wouldn't be allowed, you'll have to ask MS, everything else is just speculation. My guess is that would be annoying to implement for little real value.
-Mike
__declspec(intrin_type) isn't documented because it's not supposed to be used except in MS headers declaring intrinsic types that have built in compiler support. There's no way to get the same behaviour out of your own arbitrary types as the built in __m128 type. The compiler understands those special intrinsic types and can pass them in registers and can maintain correct alignment. You should just use the compiler declared types rather than trying to declare them yourself. You can use them as data members and wrap them in your own class if you want a different interface, though you should be aware that doing so could lead to less optimal code and check the assembly that gets generated if performance is critical.

Game Programming Blog: www.mattnewport.com/blog

Quote:Original post by mattnewport
__declspec(intrin_type) isn't documented because it's not supposed to be used except in MS headers declaring intrinsic types that have built in compiler support. There's no way to get the same behaviour out of your own arbitrary types as the built in __m128 type. The compiler understands those special intrinsic types and can pass them in registers and can maintain correct alignment. You should just use the compiler declared types rather than trying to declare them yourself. You can use them as data members and wrap them in your own class if you want a different interface, though you should be aware that doing so could lead to less optimal code and check the assembly that gets generated if performance is critical.


Thanks for that reply, pretty much what as I expected. Btw I am not trying to redeclare my own stuff, I was just trying to find out why the compiler would not complain when a function such as _mm_add_ps received a __m128 parameter which is _declspec(align(16))'ed, while he would complain when another function receiving any aligned parameter.

Thanks a lot.
JA
Quote:Original post by janta
Please consider the following code:
typedef struct __declspec(intrin_type) __declspec(align(16)) {	float       m128_f32[4];} __myOwn128;void Test(__m128 param) {} // Compiles just fine. WHY ?void Test2(__myOwn128 param) {} // error C2719: 'param': formal parameter with __declspec(align('16')) won't be aligned --> I understand that



JA


try

void Test2(const __myOwn128& param) {};

it should compile and run

This topic is closed to new replies.

Advertisement