使用VS2012 Update 1生成的控制台项目尝试以下向量减法代码。 除了禁用全局优化和启用汇编程序列表之外,我没有真正触及默认选项。
在Windows 7 x64 SP1上使用x64版本配置进行编译。
#include <stdio.h>
#include <tchar.h>
#include <emmintrin.h>
typedef unsigned short ushort;
typedef unsigned int uint;
void print(__m128i i)
{
auto& arr = i.m128i_u16;
printf("[%d %d %d %d %d %d %d %d]\n", arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]);
}
int _tmain(int argc, _TCHAR* argv[])
{
const int lineSize = 912;
ushort input[lineSize];
ushort vals[lineSize];
// printf("%X %X\n", input, vals); // note this one
for (uint i=0; i<lineSize; i+=8)
{
__m128i vecinput = _mm_loadu_si128((__m128i*) &input[i]);
__m128i vecvals = _mm_loadu_si128((__m128i*) &vals[i]);
__m128i output = _mm_subs_epu16(vecinput, vecvals);
print(output);
printf("===\n");
}
return 0;
}
在发布模式下生成的程序集:
; 20 : const int lineSize = 912;
; 21 : ushort input[lineSize];
; 22 : ushort vals[lineSize];
; without printf
; 23 : // printf("%X %X\n", input, vals);
; with printf
; 23 : printf("%X %X\n", input, vals);
lea r8, QWORD PTR vals$[rsp]
lea rdx, QWORD PTR input$[rsp]
lea rcx, OFFSET FLAT:??_C@_06NBKGFLKK@?$CFX?5?$CFX?6?$AA@
call QWORD PTR __imp_printf
; 24 :
; 25 : for (uint i=0; i<lineSize; i+=8)
xor esi, esi
lea ebp, QWORD PTR [rsi+114]
npad 2
$LL3@wmain:
; 26 : {
; 27 : __m128i vecinput = _mm_loadu_si128((__m128i*) &input[i]);
movdqu xmm1, XMMWORD PTR input$[rsp+rsi]
; 28 : __m128i vecvals = _mm_loadu_si128((__m128i*) &vals[i]);
; without printf
movdqu xmm0, xmm1
; with printf
movdqu xmm0, XMMWORD PTR vals$[rsp+rsi]
; 29 :
; 30 : __m128i output = _mm_subs_epu16(vecinput, vecvals);
; without printf
psubusw xmm1, xmm1
; with printf
psubusw xmm1, xmm0
; 15 : printf("[%d %d %d %d %d %d %d %d]\n", arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]);
pextrw ax, xmm1, 7
movzx edi, ax
pextrw ax, xmm1, 6
movzx ebx, ax
pextrw ax, xmm1, 5
mov DWORD PTR [rsp+64], edi
movzx r11d, ax
pextrw ax, xmm1, 4
mov DWORD PTR [rsp+56], ebx
movzx r10d, ax
pextrw ax, xmm1, 3
mov DWORD PTR [rsp+48], r11d
movzx ecx, ax
pextrw ax, xmm1, 2
mov DWORD PTR [rsp+40], r10d
movzx r9d, ax
pextrw ax, xmm1, 1
mov DWORD PTR [rsp+32], ecx
movzx r8d, ax
lea rcx, OFFSET FLAT:??_C@_0BL@ONEMJFJK@?$FL?$CFd?7?$CFd?7?$CFd?7?$CFd?7?$CFd?7?$CFd?7?$CFd?7?$CFd?$FN?6?$AA@
movd eax, xmm1
movzx edx, ax
call QWORD PTR __imp_printf
; 31 : print(output);
; 32 : printf("===\n");
lea rcx, OFFSET FLAT:??_C@_04LEHBMKOA@?$DN?$DN?$DN?6?$AA@
call QWORD PTR __imp_printf
lea rsi, QWORD PTR [rsi+16]
dec rbp
jne $LL3@wmain
; 33 : }
; 34 :
; 35 : return 0;
xor eax, eax
; 95 : }
mov rcx, QWORD PTR __$ArrayPad$[rsp]
xor rcx, rsp
call __security_check_cookie
lea r11, QWORD PTR [rsp+1920]
mov rbx, QWORD PTR [r11+16]
mov rbp, QWORD PTR [r11+24]
mov rsi, QWORD PTR [r11+32]
mov rsp, r11
pop rdi
ret 0
wmain ENDP
因此,vals被错误地视为与输入相同,结果将始终为0。 同样有趣的是xmm0从未被使用过,因为这种错误的优化,但仍未被抛弃。 如果取消注释该printf,则生成的代码是正确的。
所以问题是,我的代码有什么问题吗? 对我来说,它看起来像是优化器中的一个错误。
答案 0 :(得分:2)
您永远不会初始化数组ushort input[lineSize]
和ushort vals[lineSize]
,因此优化器恰好将它们视为相同,这对于未定义的行为很好。
当你在那里进行printf("%X %X\n", input, vals)
调用时,你将数组的地址传递给外部函数,因此优化器有理由相信它们指向的内存可能会被外部函数更新