<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/98389>98389</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
`llvm.fma.f16` intrinsic is expanded incorrectly on targets without native `half` FMA support
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
beetrees
</td>
</tr>
</table>
<pre>
Consider the following LLVM IR:
```llvm
declare half @llvm.fma.f16(half %a, half %b, half %c)
define half @do_fma(half %a, half %b, half %c) {
%res = call half @llvm.fma.f16(half %a, half %b, half %c)
ret half %res
}
```
On targets without native `half` FMA support, LLVM turns this into the equivalent of:
```llvm
declare float @llvm.fma.f32(float %a, float %b, float %c)
define half @do_fma(half %a, half %b, half %c) {
%a_f32 = fpext half %a to float
%b_f32 = fpext half %b to float
%c_f32 = fpext half %c to float
%res_f32 = call float @llvm.fma.f32(float %a_f32, float %b_f32, float %c_f32)
%res = fptrunc float %res_f32 to half
ret half %res
}
```
This is a miscompilation, however, as `float` does not have enough precision to do a fused-multiply-add for `half` without double rounding becoming an issue. For instance (raw bits of each `half` are in brackets): `do_fma(48.34375 (0x520b), 0.000013887882 (0x00e9), 0.12438965 (0x2ff6)) = 0.12512207 (0x3001)`, but LLVM's lowering to `float` FMA gives an incorrect result of `0.125 (0x3000)`.
A correct lowering would need to use `double` (or larger): a `double` FMA is not required as `double` is large enough to represent the result of `half * half` without any rounding. In summary, a correct lowering would look something like this:
```llvm
declare double @llvm.fmuladd.f64(double %a, double %b, double %c)
define half @do_fma(half %a, half %b, half %c) {
%a_f64 = fpext half %a to double
%b_f64 = fpext half %b to double
%c_f64 = fpext half %c to double
%res_f64 = call double @llvm.fmuladd.f64(double %a_f64, double %b_f64, double %c_f64)
%res = fptrunc double %res_f64 to half
ret half %res
}
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0Vttu4zYQ_Rr6ZRCDou4PevAmMLDALgoURV8DShzZbChSJSk7-fuClHzLpU3bXSBAzJnDIefM4YG4c3KnERuSfyH5w4pPfm9s0yJ6i-hWrREvzb3RTgq04PcIvVHKHKXewbdvv3-Hr7-SdEPoA6EbUtD5T6nDMIcEdopbhD1XPZAsZtb9wNd9UhBWzWGWc8Lu4bRorxcdYfVSfSnYS32pJ8xjP_BPVwJSfpnrAEAIWnRA0gfouFI_4pKhrEV_zlh0y-3Lh1ckXXf1iwbP7Q69g6P0ezN50NzLAwIpaKhFCgrb7xtw0zga68PhkX0_We3A76UDqb2JA8I_J3ngCrUH039mOL0y3N82njLCqiW-dH5etTernzwg_tinLI6oH_H5QiwHb-ZL3MDbD-Dt-_DuA3j3Gj6P8oyOcvln2h5j4Jq6N5FujtTvqrIfvZ10d0Gf7uBNvOr_0txvUTQOOAzSdWYYpeJeGh1HYo54QBt-chc0OHNRUBAGHWgTTjsgoDbTbg-jxU46aXS4mDDAoZ8cirthUl6O6uWOCwG9sddqPulcmKlVCNZMWgRTabEzQ_jBNUjnJlzD1liQ2nmuOwTCKsuP0ErvwPSAvNtflw16lhpay7sn9C4wm24C4CzErFqnWVrmoRJ9zhltA4jdA11TSmmSVlVZVWxOU4r1OZ2wLK3qYtnJ-r6IqTrOKqTzhDFazumU0iSkCxo2t5OPD5aw0oEyR7ShRW9uuA0PfCcP6GLvujPWYufBoptUeMsBHI85n0DnE9bXc93AaeP5nKOZlACNKMKRk8OZkEB8OJewylhQwYDsQhi_RYSbyXnuNtiLRbEI44KRbi5xEoU3YHG06IIRBV-66WMR6wZe64Hrl7MY1vBVg5uGgduXqMWPWlPGPIEzA_p9CCr5hNEUP-N-iwAv73hSXIh1X2SEVafk4luXZXu7_GkuONtIkX1kgQv_rzzwXXz7Bj_7z7vg7oPi0YGWHdEFP0vfY4zcUPg21M2hv3fDC_x0mf9qhyvRpKJOa77CJikZLbIioflq33Cs27ZiZVakXZ4kGa3LTHCRMFq0WZbQlWwYZRktE8qSJKf5mnGs6jLLBctpyZCRjOLApVpHVozdraKZNXWVVvVK8RaVi99cjGk8zk5HGAufYLYJe-7aaecCq9J5d6nipVfYLEI-f6SE56e9ldrJLjxEfB65FiguLqJewPzLjwxYTVY1e-_H-I7YlrDtTvr91K47MxC2jW9p_nc3WvMHdp6wbWzFEbadWz007K8AAAD__9zEFjM">