Thread overview
Infinite recursion with memcpy and memset/memclr lowerings
Jul 19, 2018
Mike Franklin
Jul 19, 2018
kinke
Jul 19, 2018
Mike Franklin
Jul 20, 2018
Mike Franklin
Jul 21, 2018
David Nadlinger
Jul 19, 2018
Johan Engelen
Jul 19, 2018
Mike Franklin
Dec 24, 2019
Johan Engelen
July 19, 2018
I ran into an interesting situation with my ARM Cortex-M experiment using LDC.

I have this function:

extern(C) void* __aeabi_memclr(void* dest, size_t num)
{
    byte* d = cast(byte*)dest;
    for(int i = 0; i < num; i++)
    {
        d[i] = cast(byte)0;
    }

    return dest;
}

LDC seems to recognize the body of the function and rewrites it as `__aeabi_memclr`, causing infinite recursion.  Is there some way I can instruct the compiler to stop doing that?

Mike
July 19, 2018
On Thursday, 19 July 2018 at 12:12:28 UTC, Mike Franklin wrote:
> I ran into an interesting situation with my ARM Cortex-M experiment using LDC.
>
> I have this function:
>
> extern(C) void* __aeabi_memclr(void* dest, size_t num)
> {
>     byte* d = cast(byte*)dest;
>     for(int i = 0; i < num; i++)
>     {
>         d[i] = cast(byte)0;
>     }
>
>     return dest;
> }
>
> LDC seems to recognize the body of the function and rewrites it as `__aeabi_memclr`, causing infinite recursion.  Is there some way I can instruct the compiler to stop doing that?
>
> Mike

Related: https://users.rust-lang.org/t/--aeabi-memclr-compiling-to-suicide-loop/4451

I don't know how to prevent LLVM from assuming the compiler-rt builtins are available.

If you don't insist on implementing everything yourself, you could use LLVM's implementations in compiler-rt, e.g., by a simple forward declaration or by using the LLVM memset intrinsic (see ldc.intrinsics) and obviously linking against the compiler-rt builtins lib (e.g., https://github.com/llvm-mirror/compiler-rt/blob/master/lib/builtins/arm/aeabi_memset.S).
July 19, 2018
On Thursday, 19 July 2018 at 12:12:28 UTC, Mike Franklin wrote:
>
> LDC seems to recognize the body of the function and rewrites it as `__aeabi_memclr`, causing infinite recursion.  Is there some way I can instruct the compiler to stop doing that?

You can use `-disable-simplify-libcalls`.

Looks like we need to implement something equivalent to Clang's `-fno-builtin` or `-ffreestanding` etc.  After some quick research, I don't think it is currently possible to disable these optimizations just for one function, can only disable it for one compiler invoke.

-Johan

July 19, 2018
On Thursday, 19 July 2018 at 14:51:02 UTC, kinke wrote:
> Related: https://users.rust-lang.org/t/--aeabi-memclr-compiling-to-suicide-loop/4451
>
> I don't know how to prevent LLVM from assuming the compiler-rt builtins are available.
>
> If you don't insist on implementing everything yourself, you could use LLVM's implementations in compiler-rt, e.g., by a simple forward declaration or by using the LLVM memset intrinsic (see ldc.intrinsics) and obviously linking against the compiler-rt builtins lib (e.g., https://github.com/llvm-mirror/compiler-rt/blob/master/lib/builtins/arm/aeabi_memset.S).

Correct me if I'm wrong, but it appears that forwarding to compiler-rt's implementation or using `ldc.intrinsics` will require linking in a C standard library.  I'd prefer to avoid that.

Mike
July 19, 2018
On Thursday, 19 July 2018 at 18:49:07 UTC, Johan Engelen wrote:

> You can use `-disable-simplify-libcalls`.

Thanks! That fixes things for now.

Mike
July 20, 2018
On Thursday, 19 July 2018 at 22:36:37 UTC, Mike Franklin wrote:

> Correct me if I'm wrong, but it appears that forwarding to compiler-rt's implementation or using `ldc.intrinsics` will require linking in a C standard library.  I'd prefer to avoid that.

FYI, I tried to implement my own `memcpy` and `memset` implementations and just have `__aeabi_memcpy` and `__aeabi_memclr` forward to those, but then the compiler recognized the `memcpy` and `memset` calls and replaced them with `__aeabi_memcpy` and `__aeabi_memclr`.  :-/

Mike

July 21, 2018
On 20 Jul 2018, at 2:35, Mike Franklin via digitalmars-d-ldc wrote:
> FYI, I tried to implement my own `memcpy` and `memset` implementations and just have `__aeabi_memcpy` and `__aeabi_memclr` forward to those, but then the compiler recognized the `memcpy` and `memset` calls and replaced them with `__aeabi_memcpy` and `__aeabi_memclr`.  :-/

Yep, this is expected behaviour without something like `-fno-builtin` or `-disable-simplify-libcalls`. C runtime libraries (glibc/compiler-rt…) are of course in exactly the same situation with GCC/Clang.

 — David
December 24, 2019
On Thursday, 19 July 2018 at 18:49:07 UTC, Johan Engelen wrote:
> On Thursday, 19 July 2018 at 12:12:28 UTC, Mike Franklin wrote:
>>
>> LDC seems to recognize the body of the function and rewrites it as `__aeabi_memclr`, causing infinite recursion.  Is there some way I can instruct the compiler to stop doing that?
>
> You can use `-disable-simplify-libcalls`.
>
> Looks like we need to implement something equivalent to Clang's `-fno-builtin` or `-ffreestanding` etc.  After some quick research, I don't think it is currently possible to disable these optimizations just for one function, can only disable it for one compiler invoke.

LLVM now supports disabling these optimizations per function: https://reviews.llvm.org/rG878ab6df033

https://github.com/ldc-developers/ldc/issues/3263