1

使用 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 生成的代码是正确的。

所以问题是,我的代码有什么问题吗?对我来说,它看起来完全像是优化器中的一个错误。

4

1 回答 1

2

您永远不会初始化数组ushort input[lineSize]and ushort vals[lineSize],因此优化器恰好将它们视为相同,这对于未定义的行为很好。

当您printf("%X %X\n", input, vals)在那里进行调用时,您将数组的地址传递给外部函数,因此优化器有理由相信它们指向的内存可能会被该外部函数更新。

于 2013-01-30T15:59:41.180 回答