我现在正在学习SIMD并思考如何让编译器更好地优化我的代码。现在我正在使用Visual C ++ 2013 x86。
我有一个数组,我有另一个数组,我想像这样计算:
void computeSum(float* __restrict arr, float* __restrict inp1, float* __restrict inp2, int count)
{
__declspec(align(16)) float* p1 = inp1;
__declspec(align(16)) float* p2 = inp2;
__declspec(align(16)) float* ret = arr;
while (count > 0)
{
ret[0] = p1[0] + p2[0];
ret[1] = p1[1] + p2[1];
ret[2] = p1[2] + p2[2];
ret[3] = p1[3] + p2[3];
p1 += 4;
p2 += 4;
ret += 4;
count -= 4;
}
}
我想告诉编译器数组是否与16字节边界对齐,而且任何一个都没有覆盖在另一个上,一个循环将计算4个连续浮点数的总和。
但是在生成的代码中,VC更喜欢MOVSS / ADDSS而不使用我希望的ADDPS。
如果我将项目配置为使用LLVM-vs2013工具链,则使用ADDPS来计算总和。
我知道如何使用编译器内在函数来编写SIMD代码,但这不是我想要的。
是否还有VC需要使用ADDPS指令的提示?
这是完整的代码。
#include <stdio.h>
#include <stdlib.h>
void computeSum(float* __restrict arr, float* __restrict inp1, float* __restrict inp2, int count)
{
__declspec(align(16)) float* p1 = inp1;
__declspec(align(16)) float* p2 = inp2;
__declspec(align(16)) float* ret = arr;
while (count > 0)
{
ret[0] = p1[0] + p2[0];
ret[1] = p1[1] + p2[1];
ret[2] = p1[2] + p2[2];
ret[3] = p1[3] + p2[3];
p1 += 4;
p2 += 4;
ret += 4;
count -= 4;
}
}
int main()
{
float* inp1 = (float*)_aligned_malloc(sizeof(float) * 128, 16);
float* inp2 = (float*)_aligned_malloc(sizeof(float) * 128, 16);
float* result = (float*)_aligned_malloc(sizeof(float) * 128, 16);
for (int i = 0; i < 128; ++i)
{
inp1[i] = inp2[i] = i;
}
computeSum(result, inp1, inp2, 128);
for (int i = 0; i < 128; ++i)
{
printf("%f\t", result[i]);
}
return 0;
}
答案 0 :(得分:1)
Visual C ++ 2013或更高版本将默认为x86使用/arch:SSE2
,但您仍应检查Visual Studio项目中的设置,以确保它未明确设置为其他内容。对于x64,/arch:SSE2
是隐含的。
Visual C ++唯一自动生成多通道(如ADDPS
)而不是单通道(ADDSS
)指令的时间是由自动向量化器引起的。有关详细信息,请参阅MSDN并特别注意/Qvec-report:2
开关 - 请注意,在调试配置中常见的禁用优化时不会发生这种情况。
使用显式内在函数可以更好地完成大多数SIMD(多通道)代码生成。有关这种编码风格的大量示例,请参阅DirectXMath。