digitalmars.D.learn - Float values are wrong in union
- stunaep (3/8) Aug 21 2016 I made a union to convert between int bits and floats, but the
- jkpl (5/14) Aug 21 2016 Ok on linux, 0x7fb00000 is written, I tested under linux x86_64
- Cauterite (15/18) Aug 21 2016 I can already tell what this is going to be...
- jkpl (25/43) Aug 21 2016 That's a 32 bit codegen issue then because DMD64 's disasm shows
- Engine Machine (2/28) Aug 22 2016 x86 give 7FF and x64 gives 7FB in win.
- Basile B. (11/18) Aug 29 2016 You can hack the ABI this way:
I made a union to convert between int bits and floats, but the values are coming out wrong sometimes. This is working without issue in other languages so I'm really stumped. Here's an example:union test { int i; float f; } test t = { i : 0x7fb00000}; float t2 = t.f;//int bits 0x7fb00000 as float test t3 = { f : t2 }; writefln("%x", t3.i);//prints 7ff00000 NOT 0x7fb00000
Aug 21 2016
On Monday, 22 August 2016 at 04:37:50 UTC, stunaep wrote:I made a union to convert between int bits and floats, but the values are coming out wrong sometimes. This is working without issue in other languages so I'm really stumped. Here's an example:Ok on linux, 0x7fb00000 is written, I tested under linux x86_64 with latest dmd beta, ldc and also gdc. Which compiler and version do you use ? Which OS and archi ?union test { int i; float f; } test t = { i : 0x7fb00000}; float t2 = t.f;//int bits 0x7fb00000 as float test t3 = { f : t2 }; writefln("%x", t3.i);//prints 7ff00000 NOT 0x7fb00000
Aug 21 2016
On Monday, 22 August 2016 at 04:37:50 UTC, stunaep wrote:I made a union to convert between int bits and floats, but the values are coming out wrong sometimes.I can already tell what this is going to be... The problem is almost certainly nothing to do with your union, it's this line:float t2 = t.f;This will load 0x7fb00000 into ST(0), which instantly converts it to 7FF00000 because it's a signalling NaN, then store ST(0) in your float `t2`. Signalling NaNs are an ongoing problem in D's codegen. See Don's remarks at this page: https://issues.dlang.org/show_bug.cgi?id=16105#c2 The reason it works in other languages is because they don't place floats in the floating point registers for non-arithmetic operations. I've been trying to patch DMD's backend to behave this way too, but it's much harder than I expected (difficult codebase to understand/navigate).
Aug 21 2016
On Monday, 22 August 2016 at 04:52:40 UTC, Cauterite wrote:On Monday, 22 August 2016 at 04:37:50 UTC, stunaep wrote:That's a 32 bit codegen issue then because DMD64 's disasm shows that SSE regs are used: ==== void foo() { union test { int i; float f; } test t = { i : 0x7fb00000}; float t2 = t.f; test t3 = { f : t2 }; } === yields to === 00000000004586D0h push rbp 00000000004586D1h mov rbp, rsp 00000000004586D4h sub rsp, 10h 00000000004586D8h mov dword ptr [rbp-10h], 7FB00000h 00000000004586DFh movss xmm0, dword ptr [rbp-10h] 00000000004586E4h movss dword ptr [rbp-0Ch], xmm0 00000000004586E9h movss xmm1, dword ptr [rbp-0Ch] 00000000004586EEh movss dword ptr [rbp-08h], xmm1 00000000004586F3h leave 00000000004586F4h ret ===I made a union to convert between int bits and floats, but the values are coming out wrong sometimes.I can already tell what this is going to be... The problem is almost certainly nothing to do with your union, it's this line:float t2 = t.f;This will load 0x7fb00000 into ST(0), which instantly converts it to 7FF00000 because it's a signalling NaN, then store ST(0) in your float `t2`. Signalling NaNs are an ongoing problem in D's codegen. See Don's remarks at this page: https://issues.dlang.org/show_bug.cgi?id=16105#c2 The reason it works in other languages is because they don't place floats in the floating point registers for non-arithmetic operations. I've been trying to patch DMD's backend to behave this way too, but it's much harder than I expected (difficult codebase to understand/navigate).
Aug 21 2016
On Monday, 22 August 2016 at 05:02:41 UTC, jkpl wrote:On Monday, 22 August 2016 at 04:52:40 UTC, Cauterite wrote:x86 give 7FF and x64 gives 7FB in win.[...]That's a 32 bit codegen issue then because DMD64 's disasm shows that SSE regs are used: ==== void foo() { union test { int i; float f; } test t = { i : 0x7fb00000}; float t2 = t.f; test t3 = { f : t2 }; } === yields to === 00000000004586D0h push rbp 00000000004586D1h mov rbp, rsp 00000000004586D4h sub rsp, 10h 00000000004586D8h mov dword ptr [rbp-10h], 7FB00000h 00000000004586DFh movss xmm0, dword ptr [rbp-10h] 00000000004586E4h movss dword ptr [rbp-0Ch], xmm0 00000000004586E9h movss xmm1, dword ptr [rbp-0Ch] 00000000004586EEh movss dword ptr [rbp-08h], xmm1 00000000004586F3h leave 00000000004586F4h ret ===
Aug 22 2016
On Monday, 22 August 2016 at 18:19:52 UTC, Engine Machine wrote:On Monday, 22 August 2016 at 05:02:41 UTC, jkpl wrote:You can hack the ABI this way: void loadInScratchReg(float[1] f...) {} and pass a single float value. However when you'll start to use the param (f[0]), loading in ST(0) will happen so you must write in iasm. (Not to mention an aggressive optimizer that would be able, I think, to replace the param type if no iasm is present). example, usage of a tagged union to perform a safe bit cast: https://github.com/BBasile/iz/blob/master/import/iz/sugar.d#L1176 Not tested yet...On Monday, 22 August 2016 at 04:52:40 UTC, Cauterite wrote:x86 give 7FF and x64 gives 7FB in win.[...]That's a 32 bit codegen issue then because DMD64 's disasm shows that SSE regs are used:
Aug 29 2016