SIMD 컬러 lerp 함수로 작업하면서 이상한 행동을했고 최소한의 프로그램으로 정리했습니다. 이 예제의 SIMD 코드는 더 이상 lerp를 수행하지 않지만 32 비트 색상에서 XMM 레지스터로 압축을 풀고 다시 32 비트로 압축 해제합니다.MSVC++ 2015 - 내 프로그램에서 SSE 컴파일러 버그 또는 버그/정의되지 않은 동작이 발생합니까?
릴리스 x64 모드에서 MSVC++ 2015 (업데이트 3)에서 다음 코드는 올바른 결과를 산출하지는 않지만 디버그 x64 또는 릴리스/디버그 x86에서는 올바르게 작동합니다.
이#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "emmintrin.h"
struct Color4
{
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t alpha;
Color4(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255)
: red(red), green(green), blue(blue), alpha(alpha) {}
explicit Color4(uint32_t rgba)
{
red = (uint8_t)(rgba & 0xFF);
green = (uint8_t)((rgba >> 8)&0xFF);
blue = (uint8_t)((rgba >> 16) & 0xFF);
alpha = (uint8_t)((rgba >> 24) & 0xFF);
}
};
Color4 PackUnpack(Color4 col)
{
uint32_t tmp;
memcpy(&tmp, &col, sizeof(tmp));
__m128 aFloat = _mm_cvtepi32_ps(
_mm_unpacklo_epi16(
_mm_unpacklo_epi8(
_mm_set1_epi32(tmp),
_mm_setzero_si128()
),
_mm_setzero_si128()
)
);
__m128i ret = _mm_packus_epi16(
_mm_packs_epi32(
_mm_cvtps_epi32(aFloat),
_mm_setzero_si128()
),
_mm_setzero_si128()
);
return Color4((uint32_t)_mm_cvtsi128_si32(ret));
}
int main()
{
#ifdef _DEBUG
printf("DEBUG\n");
#else
printf("RELEASE\n");
#endif
Color4 c = PackUnpack(Color4(32, 64, 128, 255));
// Debug x64 or Debug/Release x86: Prints "32 64 128 255"
// Release x64: Prints "255 0 0 0"
printf("%d %d %d %d\n", c.red, c.green, c.blue, c.alpha);
return 0;
}
릴리스 x64의 출력은 다음과 같습니다 :이 유일한 그렇지 않으면 빈에서 Win32 C++ 콘솔 응용 프로그램 프로젝트의 코드
RELEASE
255 0 0 0
디버그 x64 및 모든 86의 출력 :
DEBUG
32 64 128 255
XMM 레지스터에로드 할 상수 값을 사전 계산하여 _mm_set1_epi32
(앞의 movdqa
지침 참조) 건너 뛰기가 엉망인 것 같습니다.
main:
00007FF674391070 sub rsp,38h
00007FF674391074 lea rcx,[string "RELEASE\n" (07FF674392200h)]
00007FF67439107B call printf (07FF674391010h)
00007FF674391080 movdqa xmm0,xmmword ptr [[email protected] (07FF674392220h)]
00007FF674391088 lea rcx,[string "%d %d %d %d\n" (07FF674392210h)]
00007FF67439108F xorps xmm2,xmm2
00007FF674391092 mov dword ptr [rsp+40h],0FF804020h
00007FF67439109A punpcklbw xmm0,xmm2
00007FF67439109E punpcklwd xmm0,xmm2
00007FF6743910A2 cvtdq2ps xmm0,xmm0
00007FF6743910A5 cvtps2dq xmm1,xmm0
00007FF6743910A9 packssdw xmm1,xmm2
00007FF6743910AD packuswb xmm1,xmm2
00007FF6743910B1 movd r10d,xmm1
00007FF6743910B6 mov edx,r10d
00007FF6743910B9 mov r8d,r10d
00007FF6743910BC shr edx,10h
00007FF6743910BF mov eax,r10d
00007FF6743910C2 shr r8d,8
00007FF6743910C6 movzx r9d,dl
00007FF6743910CA shr eax,18h
00007FF6743910CD movzx edx,r10b
00007FF6743910D1 movzx r8d,r8b
00007FF6743910D5 mov dword ptr [rsp+20h],eax
00007FF6743910D9 call printf (07FF674391010h)
00007FF6743910DE xor eax,eax
00007FF6743910E0 add rsp,38h
00007FF6743910E4 ret
우분투 14.04 64에 g++
4.8.4와 함께이 시도하고 그것은 또는 해제 -O3
와 함께 잘 작동합니다.
제 질문은 입니다 이것은 컴파일러 버그, 정의되지 않은/구현을 사용하여 정의 된 동작 또는 내 평범한 버그가있는 코드입니까?
은 (코드는 표준 아니기 때문에 여전히 ... 나는 방어 적이기로 대체 Color4, 밖으로 uint32_t 값을 얻기 위해 노동 조합을 통해 더 주사위 형 말장난을 사용하지하는 데 사용됩니다.)
도움이 될 수 있습니다 그 : https://support.microsoft.com/en-us/help/3207317/visual-co ptimizer-fixes-for-visual-studio-2015-update-3 –
예기치 않은 동작은 VS 2017에서 동일합니다. – Timbo
컴파일러 버그처럼 보입니다. 'memcpy' 대신'tmp = color.red + 256 * (col.blue + 256 * (col.green + 256 * col.alpha)));를 사용하면 어떻게됩니까? – 1201ProgramAlarm