3 ms·
> For an example of how that works, consider the following common fact about C which that's often overlooked. External function calls such as the following: mem
by RcouF1uZ4gsC 6y ago
> For an example of how that works, consider the following common fact about C which that's often overlooked. External function calls such as the following:
memcpy(foo, bar, n);
Are roughly equivalent to the following assembly, which leads compilers to assume that most cpu state is clobbered:
I think most modern C and C++ compilers know that memcpy is special and optimize accordingly. I believe some C++ compilers recognize when you are using memcpy just to do bit casting to different representations and avoid doing a memory copy at all.
- rurban 6y agoReplace modern with clang, and awful with gcc. I have no idea why gcc is still so fast overall, but its memcpy is horrible, as shown in the blog post. My own memcpy in my libc also beats the gcc/glibc one. The compilers are only good for short memcpy's. For the rest the asm hinders modern compiler optimizations.
- moonchild 6y agoNot sure what your point is calling gcc both ‘awful’ and ‘so fast overall’. Nor why you're conflating gcc and glibc. FWIW my experience has been has clang produces a superior development experience for c++ code, but that gcc is better for c. Llvm does have a more modular architecture than gcc, but it's not really fair to say that it's more modern overall. Gcc has gotten several features ahead of llvm, like hot/cold LTO separation and parallel compilation (the former is now in llvm and the latter apparently is impractical due to architectural problems). > The compilers are only good for short memcpy's. For the rest the asm hinders modern compiler optimizations Also not sure what you mean by that. TFA isn't performing memcpys with inline assembly. They're using inline assembly to perform a call to the exact same ‘memcpy’ function you would have called anyway, but also to inform the compiler that memcpy clobbers fewer functions. So it's true that this will mainly improve performance for copies of small memory regions; but the performance of large copies will be unaffected.
- jart 6y agoIf anyone's curious, here's the link to memcpy() as it's actually implemented in the Cosmopolitan headers: https://github.com/jart/cosmopolitan/blob/de09bec215675e9b0beb722df89c6f794da74f3f/libc/str/str.h#L252 https://github.com/jart/cosmopolitan/blob/de09bec215675e9b0b... One thing that the web page doesn't mention (for the sake of simplicity) is that the Cosmopolitan headers do call __builtin_memcpy() as well, but only for 2-power constexpr sizes. That's the only time when GCC and Clang both do the optimal thing. In all other cases it's faster to use asm("call MemCpy") which implements something faster than the builtin would otherwise generate. See https://github.com/jart/cosmopolitan/blob/de09bec215675e9b0beb722df89c6f794da74f3f/libc/nexgen32e/memcpy.S#L49 https://github.com/jart/cosmopolitan/blob/de09bec215675e9b0b...
- moonchild 6y ago> __builtin_constant_p Aww, I was hoping you would use the evil ICE_P - https://lkml.org/lkml/2018/3/20/805 https://lkml.org/lkml/2018/3/20/805
- CyberDildonics 6y agoEven if you are trying to avoid the standard library, visual studio will insert memcpy into a loop that is just copying memory, then the linker will error out when it can't find it.
- mkup 6y agoThis is true, but it's possible to prevent this behavior by turning off optimizations for just one function (by adding ``#pragma optimize("g", off)'' before the function definition and ``#pragma optimize("g", on)'' after the function definition).