Winapi 为Win32编译的Win64 SSE代码产生不正确的性能计数器结果 我有一个正确运行的SSE代码,我通常为Wi64编译(我使用英特尔C++编译器14)。此代码(由SSE内部函数组成)在完成后还执行性能计数操作。当我为Win32编译相同的代码时,这个操作有一个问题

Winapi 为Win32编译的Win64 SSE代码产生不正确的性能计数器结果 我有一个正确运行的SSE代码,我通常为Wi64编译(我使用英特尔C++编译器14)。此代码(由SSE内部函数组成)在完成后还执行性能计数操作。当我为Win32编译相同的代码时,这个操作有一个问题,winapi,sse,icc,Winapi,Sse,Icc,操作简单: LARGE_INTEGER Count; QueryPerformanceCounter( &Count ); uint64_t v = Count.QuadPart; printf( "%llu\n", v ); printf( "%f\n", (double) v ); 第一个printf打印正确的64位值。第二个printf生成-1.#IND00 如果我手动分配v,错误就会消失 检查代码是否存在缓冲区不足/溢出和未初始化的访问。不知道怎么了。在Win64上没有这样的

操作简单:

LARGE_INTEGER Count;
QueryPerformanceCounter( &Count );
uint64_t v = Count.QuadPart;
printf( "%llu\n", v );
printf( "%f\n", (double) v ); 
第一个printf打印正确的64位值。第二个printf生成-1.#IND00

如果我手动分配v,错误就会消失

检查代码是否存在缓冲区不足/溢出和未初始化的访问。不知道怎么了。在Win64上没有这样的错误

编译器在该块上生成以下代码:

;;; LARGE_INTEGER Count;
;;; QueryPerformanceCounter( &Count );
    lea       eax, DWORD PTR [1408+esp]                     ;152.1
    push      eax                                           ;152.1
    call      DWORD PTR [__imp__QueryPerformanceCounter@4]  ;152.1
                            ; LOE ebx esi
.B1.94:                     ; Preds .B1.93

;;; uint64_t v = Count.QuadPart;
    mov       eax, DWORD PTR [1408+esp]                     ;153.14
    mov       edi, DWORD PTR [1412+esp]                     ;153.14
    mov       DWORD PTR [24+esp], eax                       ;153.14

;;; printf( "%llu\n", v );
    push      edi                                           ;154.1
    push      eax                                           ;154.1
    push      OFFSET FLAT: ??_C@_05A@?$CFllu?6?$AA@         ;154.1
    call      _printf                                       ;154.1
                            ; LOE ebx esi edi
.B1.344:                    ; Preds .B1.94
    add       esp, 12                                       ;154.1
                            ; LOE ebx esi edi
.B1.95:                     ; Preds .B1.344

;;; printf( "%f\n", (double) v ); 
    mov       DWORD PTR [esp], OFFSET FLAT: ??_C@_03A@?$CFf?6?$AA@ ;155.1
    mov       eax, DWORD PTR [24+esp]                       ;155.1
    mov       DWORD PTR [32+esp], eax                       ;155.1
    mov       DWORD PTR [36+esp], edi                       ;155.1
    fild      QWORD PTR [32+esp]                            ;155.1
    shr       edi, 31                                       ;155.1
    fadd      QWORD PTR [_2il0floatpacket.1575+edi*8]       ;155.1
    fstp      QWORD PTR [4+esp]                             ;155.1
    call      _printf                                       ;155.1
但是,如果我在第二次打印F后复制此部分:

QueryPerformanceCounter( &Count );
v = Count.QuadPart;
printf( "%f\n", (double) v );
printf打印正确的值。 不过,汇编程序代码有点不同:

;;; QueryPerformanceCounter( &Count );
    lea       eax, DWORD PTR [1408+esp]                     ;156.1
    push      eax                                           ;156.1
    call      DWORD PTR [__imp__QueryPerformanceCounter@4]  ;156.1
                            ; LOE ebx esi
.B1.97:                         ; Preds .B1.96

;;; v = Count.QuadPart;
;;; printf( "%f\n", (double) v );
    fild      QWORD PTR [1408+esp]                          ;158.1
    mov       eax, DWORD PTR [1412+esp]                     ;158.1
    shr       eax, 31                                       ;158.1
    mov       DWORD PTR [esp], OFFSET FLAT: ??_C@_03A@?$CFf?6?$AA@ ;158.1
    fadd      QWORD PTR [_2il0floatpacket.1575+eax*8]       ;158.1
    fstp      QWORD PTR [4+esp]                             ;158.1
    call      _printf                                       ;158.1

找到了一个解决方案:在执行SSE计算之后,应该调用_mm_empty()函数。

你能给我展示一下正确的外观吗
printf
%f
转换是双精度的,而不是浮点数(与scanf不同)。也许检查一下装配?也许您的32位代码将double放入xmm寄存器,而不是在堆栈上传递?64位ABI在xmm寄存器中传递双参数,但32位windows和linux ABI都在堆栈上传递双参数(并在x87 FP堆栈上返回它们)。也许这是一个编译器错误。大卫·赫弗南,如果我能做出这样的例子,这将很容易,而且不需要任何咨询。谢谢你的阅读。我将试着看一下集合——坦率地说,没有太多有趣的事情要做。也许是时候升级编译器了,或者忘记Win32 architecture.Odd。
static\u cast(v)
工作吗?出于某种原因,它可能会给您提供
重新解释\u cast
语义。我无法发现生成的代码有任何明显的问题。不过,在直接演员中出现的“离开”问题是一个有趣的线索。在这种情况下,您正在转换有符号的int64_t,而不是无符号的uint64_t,后者不受FPU/SSE支持,并在这里使用位hack和table伪造。能否尝试将
v
的类型切换为int64\t,并单步执行原始程序集并转储2il0floatpacket.1575表周围的16个字节?它应该在双精度浮点中包含0和2^64,但可能在这个过程中出错了。