<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/123387>123387</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            `fmaf` is an empty unreachable function with optimizations on cortex-m33
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            bug,
            libc
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          PiJoules
      </td>
    </tr>
</table>

<pre>
    The generic `fmaf` implementation in llvm-libc is

```
namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(float, fmaf, (float x, float y, float z)) {
  return fputil::fma<float>(x, y, z);
}

} // namespace LIBC_NAMESPACE_DECL
```

On cortex-m33, `fputil::fma<float>` is

```
template <> LIBC_INLINE float fma(float x, float y, float z) {
 return __builtin_fmaf(x, y, z);
}
```

However, clang replaces the `__builtin_fmaf` call with a call to a normal `fmaf` at `-O0`

```
; Function Attrs: mustprogress noinline nounwind optnone
define linkonce_odr hidden noundef float @_ZN22__llvm_libc_20_0_0_git6fputil3fmaIffEET_T0_S3_S3_(float noundef %x, float noundef %y, float noundef %z) #0 comdat {
entry:
  %x.addr = alloca float, align 4
  %y.addr = alloca float, align 4
  %z.addr = alloca float, align 4
  store float %x, ptr %x.addr, align 4
  store float %y, ptr %y.addr, align 4
  store float %z, ptr %z.addr, align 4
  %0 = load float, ptr %x.addr, align 4
  %1 = load float, ptr %y.addr, align 4
  %2 = load float, ptr %z.addr, align 4
  %call = call float @fmaf(float noundef %0, float noundef %1, float noundef %2) #2
  ret float %call
}
``` 

Since `fmaf` just calls `fputil::fma<float>`, we end up with a circular dependency. With `-Os` or `-O3`, clang removes the function body for `fmaf`

```
define hidden noundef float @fmaf(float %x, float %y, float %z) #0 {
entry:
  unreachable
}
```

and since the entire function is `unreachable`, this just ends up becoming an empty function

```
fmaf:
 .fnstart
@ %bb.0:                                @ %entry
.Lfunc_end0:
        .size   fmaf, .Lfunc_end0-fmaf
 .cantunwind
        .fnend
```

It seems either (1) clang is incorrectly lowering the `__builtin_fmaf` to `fmaf` or (2) llvm-libc should have tighter checks on ensuring that a builtin call won't be lowered to a libcall. I would assume this shouldn't be lowered to a libcall in the first place since `__ARM_FEATURE_FMA` is defined, but perhaps it might be permissible for any compiler to lower a builtin call to a normal function call?

This can be reproduced by building armv8m.main-unknown-none-eabi runtimes from the fuchsia cache file. Alternatively, the fma.cpp code expands to 

```
namespace [[gnu::visibility("hidden")]] __llvm_libc_20_0_0_git {

namespace fputil {
inline float fma(float x, float y, float z) {
 return __builtin_fmaf(x, y, z);
}
}  // namespace fputil

float fmaf(float x, float y, float z);

decltype(__llvm_libc_20_0_0_git::fmaf) __fmaf_impl__ __asm__("fmaf");
decltype(__llvm_libc_20_0_0_git::fmaf) fmaf [[gnu::alias("fmaf")]];
float __fmaf_impl__ (float x, float y, float z) {
  return fputil::fma(x, y, z);
}

}  // namespace __llvm_libc_20_0_0_git
```

which can be compiled with

```
clang++ --target=armv8m.main-none-eabi -mthumb -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33 -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Os -ffreestanding -nostdlibinc -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti /tmp/test.cc
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy8V0tv4zgS_jX0pSBDpvzKwQfHD2wW6XRjOrML7EWgqJLFaYoUSMqJ8-sXJOVHEieduYxjxBLJetdXVWTWip1CXJDJLZmsB6xztTaLH-LfupNoB4UuD4vHGmGHCo3gQKZp1bCKTFMQTSuxQeWYE1qBUCDlvkmkKDgIS9Kl_07T_psuFWvQtowj3N_drvKH5bfNzx_L1SZfb1b3QGa3keT-_j_f8nBi--fD6vHu-wOh80pq5ghdQRBOV3Bcg-ewGh4P58cXQm8Ivem5Ahh0nVFQtZ0TkmRLki2rhpFsFRlnG0LngVPgEaizoM9s3RsyWwOhW0K38Kkdb2wm6fK7Aq6Nw-ekybKg-jT9RA_v2CvOc9i0kjkEkq1Itomi7x7u7x42vcmez--dcvRI75A8LzohnVB5dOxnTnht1r_0E-7R-JNcMrUDg61kHC24Gr2Nb1hPU-BMSngSrgYWn50GBkqbhsnLxGLOvyXfz8Jeyc5uYdspHpJu6ZyxJFtC01nXGr0zaC0oLZQUCkHpTj0JVYJundIKSbossfI7UqhfWnHMdWmgFmWJKpwuseq9RcZp_r8HSvPcp3Xu0zqnae7_dsJNYwizqmF3VbXZPOaPaf4z899TFI78CJ1cBORi9XB1NYaJZilw3ZRekxAyVM4cfMr4fPYsh6wsDZBsDUxKzRmcQMKk2CkYH08evnzy5WsnrdMGj27qjWudOWv1G4LDBcHhKwQvFwQvVwkInaRBb6lZedb6U60InYw-prmuGKET-jHNh7qFdPdk4eGUYD3o3qVAejUxRldXaZ8u9Fjozm7zwt7jFyKmfgrF8RJ2f3XWBf3sb0uUV-QJAVUJXXuCtDC8k8xAiS2qEhU_DOG_fi-g2XoZ2sSXrGdyLB2N3veVozpC27ceqCJBr-L7YtCj-SMAv_Lvaxi-ht8r2F3BW6cMMl6zQuJHBZGpEmzwqTcDlRPmwhoRnHrJJjrA1cJGz6MqrfdmgVw3Qu2AKcCmdYcTk_fmB_uiisNKWceM8yfGqTeoKIapL42_-fSno7npcnjvxeWoyvRofPwMrXhBgFMHvjiYhDWvBGfKxZJ7SVkpDAtvPHbnwCI2FlC4Gj2A5iMfhJgUwoJQXBuD3MkDSP2Exrvlw_bi9GU268AvgOM8lthad7KEmu0RnNjVDg3wGvkvC1oBKtv1IpgDBr2Avm9pRejMQYFRFSxj-_J8mZRDuIOnwJxZ2zUYAxvlfUro56aQ98JYB6GF9mkUjFz-8S3fbpaPf_6xybfflnE8gJj2pQ9D0Tlo0dSstSAcNN4qL6tF0whrRSExoIipg-8nrZBovAJBl7dGXjbkU-qGKpJtY8wevVmcKS_CYGt02XEsoTgERmXIW9Ps582wYUIlnfql9JNKfPNNkBUCTKecaNBCZXTTI57XVviRgAc_SBzCUjo0ijmxR3mIOEGfeUPetsB1iYDPLfOI8VH_ZNQMc-3tTnWxku2FFYWQwh0InRNKY-Eg1OcJmazJZA3X-_15Pj3zjiWy3-knjn9oFput4f042pfsoOVJj-ork3LW21Yil-7QIqHz62449YPK658HTXN_EchzyHNmmzyPjo1H6In53-Tsf9_GjknB7DvuIWhRRjTotVJ_IwwfXRK-cDN4H4sPjHxXA59qwesjoHp8lqGjvs_qUBcJvSX0FpLEMbNDR7L1Jd7OOEsaV3dNAUkTLE1YIUi2trpyVQtJwwyvX9MSelu1hN6W1u_ztiPZ-nxxgaT6cbeCpFI6sdgw5QRPhHJoWm1FqBNJdUZXEuFgk74zJ98tJFVlEK1jKpSJRGnrSikKoXjkeyxF4QWfObaer43vkj0ne-ROm4RrtUdjz3ux4yTO99V-idmD4rXRSnf22r5xTviouab1_9G6IeeX_h6Ui6y8yW7YABejWTYbjdN5Oh_Ui2qcTSbTohhlN2wyntDqZlJOxzOk42JUZpPZQCxoSifpaDQb3aTT8Xw45ePxNE2rtJzdpKNRScYpNkzIoU-RoTa7gbC2w8WIZtl8NpCsQGnDjZzSotuFRF8RSn0y-ZfJemAWoakV3c6ScSqFdfbMzQkncXF5U7fnYeJiBDmX-DDB6daJRryw6HR9eW0ddEYuaudaf9eKub4Tru6KIdcNoVsvuv9JWqP_Qu4I3QarLKHb3rD9gv4_AAD__088Hgs">