Jump to page: 1 2
Thread overview
MinGW-w64 runtime library inclusion (Clang-compiled) for proper Win64 support?
Jun 03, 2013
kink
Jun 03, 2013
kink
Jun 03, 2013
kink
Jun 06, 2013
kink
Jun 12, 2013
David Nadlinger
Jun 14, 2013
kink
Jun 14, 2013
kink
Jun 15, 2013
kink
Jun 15, 2013
kink
Jun 15, 2013
bearophile
Jun 15, 2013
David Nadlinger
Jun 15, 2013
bearophile
Jun 15, 2013
David Nadlinger
Jun 16, 2013
kink
Jun 16, 2013
kink
Jun 22, 2013
kink
Jun 29, 2013
kink
June 03, 2013
Hi guys,

first of all, a big fat thank-you to David & Kai for your dedication, it's looking good and getting better!

I recently synced the LDC sources, compiled it on my Win8 x64 system using MSVC 2012 and latest LLVM 3.4 sources and ran a few tests (the whole procedure has gotten even less painful, thank you very much Kai!). I soon figured out that printing reals still results in garbage, e.g.:

<code>
import std.stdio: writefln;
import std.conv:  to;

int main()
{
    real r = 2;
    writefln("%%g (double): %g", cast(double) r);
    writefln("%%g:          %g", r);
    string s = to!string(r);
    writefln("to!string:   %s", s);

    s = "2.0";
    r = to!real(s);
    writefln("%s parsed as %g", s, cast(double) r);

    return 0;
}
</code>

outputs something like:

%g (double): 2
%g:          3.95253e-323
to!string:   4.94066e-324
2.0 parsed as 2

The problem is that the underlying calls to MSVCRT's snprintf() pass reals as unsupported 80-bit 'long doubles' (MSVCRT doesn't support this type at all), and yes, I know the Wiki page mentions broken reals support. ;)

So I was wondering about how to tackle this task, considering Phobos' std.math strongly encourages using the real type. It's nice that we exploit LLVM intrinsics, LLVM assembly, D assembly and D workarounds in LDC, DRuntime and Phobos to circumvent some issues caused by Microsoft's shameful missing C99 support in their runtime (in general, math.h just being an example). But as you know, there are still missing functions (=> linking issues), broken implementations and bugs.

My idea was to include the MinGW(-w64) runtime library, since afaik MinGW mainly addresses exactly Microsoft's lacking compatibility. I really like LDC's ability to output MSVC-compatible objects and the usage of the MS linker, i.e. the pretty smooth integration into the Visual-Studio-ecosystem, and don't want to use LDC based on MinGW(-w64) and its object-file format.

I first tried to compile a few modules of the MinGW-w64-CRT source using VC 2012. Obviously loads of issues with incompatible keywords, assembly syntax etc. arised and the 'long double' type simply maps to 'double' (you may very well call that cheating), so there's no way to get that to work unless coding everything in naked assembly.

Then I tried to compile a few modules with Clang (latest source & latest LLVM, compiled painlessly with MSVC 2012 as well). It seems to swallow MinGW's code quite well - nice. I succeeded in linking a dummy DLL (compiled with Clang and linked with MSVCRT; Clang is supposed to have troubles with Microsoft's C++ headers, but the C headers should work) to a D executable (compiled with LDC, of course). So imho with MinGW's runtime (or a trimmed-down version thereof) as additional (default?) static/dynamic library we'd have a nice fallback for missing functions.

Unfortunately, there are ABI issues, even a minimalistic

__declspec(dllexport) int foo(int a) { return a + 3; }

in the dummy library returns garbage in x64 mode, in both LDC and MSVC executables - but works in x86 mode, at least when called from a dummy MSVC executable (my LDC is on a strict diet and is allowed to spit out x64 code only). So Clang apparently doesn't support the Win64 ABI yet, *sigh*.

Anyway, I'd like to know what you think about including a (most likely tailored) MinGW runtime library, compiled with Clang, with LDC for Windows to obtain max compatibility.
June 03, 2013
> %g (double): 2
> %g:          3.95253e-323
> to!string:   4.94066e-324
> 2.0 parsed as 2

Btw, DMD v2.063 prints similar garbage in x64 mode, just in case you were wondering. The huge amount of work required to circumvent all MSVCRT shortcomings in DRuntime and Phobos is probably why we won't see official Win64 support in DMD anytime soon, if ever.
June 03, 2013
PS: For those who don't know: the MinGW C runtime is just an additional layer on top of Microsoft's Visual C Runtime, adding missing functionality. What we need would ideally be a clean D port of missing and relevant MinGW-runtime parts into DRuntime/Phobos, for both DMD and LDC on Win64. Since that's quite a task and especially because it is only needed for a single, yet the most popular OS, my proposal is to include relevant parts of the MinGW runtime layer directly with the Win64 D compiler, so that we have a solid fallback for the time being.
June 06, 2013
> Unfortunately, there are ABI issues, even a minimalistic
>
> __declspec(dllexport) int foo(int a) { return a + 3; }
>
> in the dummy library returns garbage in x64 mode.

Discard that, I was erroneously using a Clang 3.3 build. It works using a very recent 3.4 build. A similar dummy function using "long double" doesn't work though, but that's not really surprising.

Once these ABI issues are fixed, I think the main task would consist in emulating all included MinGW C system headers (not present or incomplete in MSVC) by custom ones and getting rid of superfluous modules - I guess that'd be a manageable effort.
June 12, 2013
Hi,

Sorry for my late response, but I haven't really looked at Win64 support in LDC at all, apart from some playing around with SEH quite some while back. Thus, I was hoping that Kai would answer first – maybe he has already something up the sleeves in this area?

Anyway, I'd strongly argue that any such code should be shared between any D compilers targeting Win64/MSCRT, as you mentioned as well. And the current stance of pretty much everybody on the druntime/Phobos core team is that all code has to be Boost-licensed (or similar) to be considered for inclusion in the current

I haven't checked what the exact licensing situation of the MinGW runtime is (apart from some parts which I know are public domain) but I imagine there might be potential problems in this area. Thus, I'd encourage you to primarily discuss this on the upstream (druntime/Phobos) development lists.

David
June 14, 2013
> I haven't checked what the exact licensing situation of the MinGW runtime is (apart from some parts which I know are public domain) but I imagine there might be potential problems in this area.

Hi David, from what I've seen, the MinGW-w64 CRT seems to be entirely public domain.

I got the whole thing (latest v2.0.8) to compile; a few linking issues remain, working these out wouldn't be a problem. I chose to use the MinGW-w64 headers exclusively (no MS headers) to keep things simple and basically only had to adapt a few headers in a few places after I let Clang 3.4 run in a GCC-compatible way (cmdline options: -c -nostdinc -target x86_64-pc-win32 -Xclang -cxx-abi -Xclang microsoft -fno-ms-compatibility -fmsc-version=0).

The thing is that Clang maps C "long double" to double as well, just like MSVC. I'm not sure if that's generally the case when targeting Windows or only if Clang itself has been compiled with MSVC and not with MinGW. GCC's __float80 does not seem to be supported either. So I think there's probably a good reason for the dropped x87 support; I don't know about how well it is still supported in x86 hardware nowadays and how slow it is compared to scalar SSE code.

So maybe the best course of action would be to map D's real type to double as well, either as default setting in LDC for Windows or at least as option. I wouldn't miss the x87 type; I just want working reals support as it's used in Phobos' std.math all over the place.
June 14, 2013
> Hi David, from what I've seen, the MinGW-w64 CRT seems to be entirely public domain.

Damn, I should have checked first before making such a statement; e.g., there are modules under the Zope Public License, copyrights by Sun, Lucent etc.
June 15, 2013
> The thing is that Clang maps C "long double" to double as well, just like MSVC. I'm not sure if that's generally the case when targeting Windows or only if Clang itself has been compiled with MSVC and not with MinGW.

I've just looked into the Clang sources; the "long double" mapping depends on the target triple, in this case specifically the OS component. "win32" specifies a Visual Studio target, for which "long double" is remapped to double (doesn't happen for the corresponding MinGW target). I commented out the remapping in the constructor of the VisualStudioWindowsX86_64TargetInfo class; the "long double" x87 type is now supported. A dummy function

__declspec(dllexport) long double foo(long double x) { return x + 2.5; }

is now compiled to (dumpbin /disasm)

push        rbp
mov         rbp,rsp
sub         rsp,10h
fld         tbyte ptr [rbp+30h]
fld         st(0)
fstp        tbyte ptr [rbp-10h]
fld         dword ptr [180005698h]
faddp       st(1),st
add         rsp,10h
pop         rbp
ret

which looks quite okay. Calling it from an LDC-compiled exe still doesn't work though (returns NaN, probably an ABI issue). Still, it's an improvement. ;)
June 15, 2013
Of course it is an ABI issue. Since MS doesn't support the x87 type, it obviously isn't mentioned in the Win64 ABI docs. Clang's ABI assumes it is passed by-val on the stack whereas in LDC we treat it as a struct > 64 bits and hence pass it by-ref (a pointer to a private copy for the callee, allocated by the caller; the Win64 way of passing larger structs by-val). Clang returns an x87 in the ST(0) x87 register and LDC expects the result there - perfect. I guess I'll have to modify Clang/LLVM further to pass x87s by-ref, that seems more appropriate to me.
This shouldn't be a problem for Win32 though as x87s should be passed ordinarily by-val.
June 15, 2013
kink:

> This shouldn't be a problem for Win32 though as x87s should be passed ordinarily by-val.

See the D ABI:
http://dlang.org/abi.html

Bye,
bearophile
« First   ‹ Prev
1 2