As someone said, "Good Artists Copy; Great Artists Steal". So we can just check how other compiler writers solved this issue. I used a simple snippet:
volatile unsigned int x;
int main()
{
volatile double y = x;
return y;
}
(volatiles added to ensure the compiler does not optimize out the conversions)
Results (irrelevant instructions skipped):
Visual C++ 2010 cl /Ox (x86)
__real@41f0000000000000 DQ 041f0000000000000r ; 4.29497e+009
mov eax, DWORD PTR ?x@@3IC ; x
fild DWORD PTR ?x@@3IC ; x
test eax, eax
jns SHORT $LN4@main
fadd QWORD PTR __real@41f0000000000000
$LN4@main:
fstp QWORD PTR _y$[esp+8]
So basically the compiler is adding an adjustment value in case the sign bit was set.
Visual C++ 2010 cl /Ox (x64)
mov eax, DWORD PTR ?x@@3IC ; x
pxor xmm0, xmm0
cvtsi2sd xmm0, rax
movsdx QWORD PTR y$[rsp], xmm0
No need to adjust here because the compiler knows that rax
will have the sign bit cleared.
Visual C++ 2012 cl /Ox
__xmm@41f00000000000000000000000000000 DB 00H, 00H, 00H, 00H, 00H, 00H, 00H
DB 00H, 00H, 00H, 00H, 00H, 00H, 00H, 0f0H, 'A'
mov eax, DWORD PTR ?x@@3IC ; x
movd xmm0, eax
cvtdq2pd xmm0, xmm0
shr eax, 31 ; 0000001fH
addsd xmm0, QWORD PTR __xmm@41f00000000000000000000000000000[eax*8]
movsd QWORD PTR _y$[esp+8], xmm0
This uses branchless code to add 0 or the magic adjustment depending on whether the sign bit was cleared or set.