[GSoC] 'Independency of D from the C Standard Library' progress and update thread

Stefanos Baziotis sdi1600105 at di.uoa.gr
Thu Sep 5 21:50:04 UTC 2019


On Thursday, 5 September 2019 at 21:17:07 UTC, H. S. Teoh wrote:

Thanks for the descriptive comment! Some comments from me:

>
> Read the discussion that Stefanos referred to. Here are some of 
> the key blocking issues:
>
> - C library APIs like memcpy, memset, etc., are not only in the 
> C
>   library, but are often implemented as *intrinsics* in 
> compilers. One
>   of the most important effects of this is that optimizers 
> recognize
>   them and understand their semantics, and can sometimes 
> produce better
>   code because of that. For example:
>
> 	int x, y=5;
> 	memcpy(&x, &y, int.sizeof); // C version
> 	... // optimizer knows that now x==5.
>
>   Using a D version of memcpy in the above code can mean that 
> the
>   optimizer does *not* recognize that x==5, which can lead to 
> poorer
>   performance.
>
> - Even if the previous point isn't an issue, there's still the 
> problem
>   of maintenance: the D version of mem* needs to be 
> continuously updated
>   because hardware is constantly evolving, and it takes 
> significant
>   manpower to (1) port the implementation to every supported
>   architecture, (2) make sure they take maximum advantage of 
> the quirks
>   of the targeted platform, and (3) checking that they are 
> actually
>   faster than the C implementations (which is available on 
> basically any
>   new platform anyway).
>

- For the first 2, let me thank again Manu and Johan helped who 
me realize them! Note also that we don't currently know of a way 
of informing LLVM or GCC
about the semantics and thus get this optimization. The closest 
thing
we have is LLVM  recognizing that a function does what e.g. 
memcpy() does
by name. Which is a bad assumption to build upon.

> - D already has syntax for abstractly representing a memcpy 
> operation:
>   a[] = b[]. This syntax is type-safe, memory-safe, and the 
> compiler can
>   lower it to whatever it likes, including memcpy, or a custom
>   implementation specialized for the target platform. That's 
> where such
>   primitives really belong, actually. (Historically they went 
> into the C
>   library, but these days compilers are more and more building 
> them into
>   intrinsics that can drive various codegen strategies 
> (inlining,
>   arch-specific optimizations, etc). They're gradually becoming 
> more
>   like low-level compiler primitives than your average C library
>   functions.)
>

AFAIK, this is implemented in the druntime. And the druntime
calls memcpy(). Essentially the goal of this project was to create
versions that would be used from the druntime, not the user. 
Other than that,
I agree!

> The current work Stefanos has produced has a big performance 
> impact mainly only in DMD, which is known to have a weak 
> optimizer,

Actually, when I was optimizing for DMD, I used assembly mainly 
because
I had to reach libc in performance. And using DMD, the only way 
to do
that is using assembly. A more useful goal would be to not try to 
reach
libc (certainly not in x86_64). Rather, create optimized versions
but using generic D. Meaning, to optimize purely based on 
algorithms,
with very few assumptions about the hardware. Much like MUSL.

> and anyone who cares about runtime performance ought to be 
> using GDC or LDC anyway. In GDC/LDC using these custom D 
> implementations wind up being worse because they defeat the 
> respective optimizers (they no longer recognize memcpy/etc. 
> semantics from these functions, so can't optimize based on 
> that).

Actually, this project reached libc in LDC, GDC in 1-1 benchmarks 
using D
and SIMD functions (but not ASM). The problem is when used in 
context exactly
for the reasons you described.


> So lot of the effort ended up being directed towards working 
> around flaws in DMD's optimizer rather than producing *actual* 
> improvement over C's mem* primitives.

Yes essentially that was one of my first objections. To 
counter-act
the DMD flaws, you have to write ASM (if you want parity) which 
in turn
brings the question: Then why do it ? This is what libc already 
does.

> This is really the wrong way to go about things IMO; we should 
> rather be fixing DMD's optimizer instead. But once that's done 
> there's even less reason to implement mem* ourselves.

IMHO, I don't think that fixing the DMD optimizer is a good way 
to go.
Rather, as I said above, aim for generic D implementation, 
_without_ SIMD,
based purely on algorithms. This can be useful for systems that 
don't
have libc and since the DMD optimizer does not use intrinsics as 
LLVM / GCC,
the aforementioned problems, are not problems. Essentially, it's 
a win-win
situation.

- Stefanos




More information about the Digitalmars-d mailing list