1. 分析
该库定义的一个规则为,当XMVECTOR类型作为参数传递给函数时,函数的形参列表的参数声明需要符合以下规则:前三个出现的XMVECTOR类型需要声明为FXMVECTOR,之后出现的XMVECTOR类型需要声明为CXMVECTOR。
xnamath.h中的原始定义为:
// Fix-up for (1st-3rd) XMVECTOR parameters that are pass-in-register for x86 and Xbox 360, but not for other targets
#if defined(_XM_VMX128_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
typedef const XMVECTOR FXMVECTOR;
#elif defined(_XM_X86_) && !defined(_XM_NO_INTRINSICS_)
typedef const XMVECTOR FXMVECTOR;
#elif defined(__cplusplus)
typedef const XMVECTOR& FXMVECTOR;
#else
typedef const XMVECTOR FXMVECTOR;
#endif
// Fix-up for (4th+) XMVECTOR parameters to pass in-register for Xbox 360 and by reference otherwise
#if defined(_XM_VMX128_INTRINSICS_) && !defined(_XM_NO_INTRINSICS_)
typedef const XMVECTOR CXMVECTOR;
#elif defined(__cplusplus)
typedef const XMVECTOR& CXMVECTOR;
#else
typedef const XMVECTOR CXMVECTOR;
#endif
可见该库针对x86平台和XBox 360平台,以及是否使用SIMD指令集的情况,给出了XMVECTOR不同的声明。
为什么这样声明?为了在不同平台和环境下保持类型名的一致,方便编程。平台的不同是指128bit寄存器的数量不同。
从原始定义中可以看出在XBox 360平台,参数的传递都是传值,x86平台只有前三个是传值,而不使用SIMD指令集的情况,则都是传递的引用。(个人观点有待验证)
2.测试
测试程序包含一个简单的函数声明:
#include <windows.h>
//#define _XM_NO_INTRINSICS_
#include <xnamath.h>
#include <iostream>
using namespace std;
void test(FXMVECTOR v1, FXMVECTOR v2, FXMVECTOR v3, CXMVECTOR v4) {
}
int main() {
XMVECTOR v[4];
test(v[1], v[2], v[3], v[4]);
return 0;
}
test函数的汇编代码:
void test(FXMVECTOR v1, FXMVECTOR v2, FXMVECTOR v3, CXMVECTOR v4) {
00EE1490 push ebx
00EE1491 mov ebx,esp
00EE1493 sub esp,8
00EE1496 and esp,0FFFFFFF0h
00EE1499 add esp,4
00EE149C push ebp
00EE149D mov ebp,dword ptr [ebx+4]
00EE14A0 mov dword ptr [esp+4],ebp
00EE14A4 mov ebp,esp
00EE14A6 sub esp,128h
00EE14AC push esi
00EE14AD push edi
00EE14AE lea edi,[ebp-128h]
00EE14B4 mov ecx,4Ah
00EE14B9 mov eax,0CCCCCCCCh
00EE14BE rep stos dword ptr es:[edi]
00EE14C0 movaps xmmword ptr [ebp-60h],xmm2
00EE14C4 movaps xmmword ptr [ebp-40h],xmm1
00EE14C8 movaps xmmword ptr [ebp-20h],xmm0
}
加上声明#define _XM_NO_INTRINSICS_ 后的test函数的汇编代码:(该声明的作用是不将参数传递给128bit寄存器)
void test(FXMVECTOR v1, FXMVECTOR v2, FXMVECTOR v3, CXMVECTOR v4) {
00B81490 push ebp
00B81491 mov ebp,esp
00B81493 sub esp,0C0h
00B81499 push ebx
00B8149A push esi
00B8149B push edi
00B8149C lea edi,[ebp-0C0h]
00B814A2 mov ecx,30h
00B814A7 mov eax,0CCCCCCCCh
00B814AC rep stos dword ptr es:[edi]
}
对比发现少了语句movaps,该语句功能是:移动对齐的压缩单精度浮点值。即将参数移动到三个xmm128bit寄存器。[参考]
如果将第四个参数声明为FXMVECTOR,将导致编译错误:具有 __declspec(align('16')) 的形参将不被对齐