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

    <tr>
        <th>Summary</th>
        <td>
            Clang vec_pack_to_short_fp32 implementation generates incorrect results
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    Here is the current Clang implementation of vec_pack_to_short_fp32:
https://github.com/llvm/llvm-project/blob/5f5cf6029852d703e850c5c16b386284d048dd91/clang/lib/Headers/altivec.h#L7518-L7527

Here is the corrected implementation of vec_pack_to_short_fp32:
```
static __inline__ vector unsigned short __ATTRS_o_ai 
vec_pack_to_short_fp32(vector float __a, vector float __b) { 
  vector unsigned int __resa = (vector unsigned int)__builtin_vsx_xvcvsphp(__a); 
 vector unsigned int __resb = (vector unsigned int)__builtin_vsx_xvcvsphp(__b); 
  return vec_pack(__resa, __resb); 
}
```

Here is a test program (which needs to be compiled with the -std=c11 -mcpu=power9 options) that can be used to check the results of the vec_pack_to_short_fp32 operation:
```
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdalign.h>

#pragma push_macro("vector")
#pragma push_macro("pixel")
#pragma push_macro("bool")

#undef vector
#undef pixel
#undef bool

#include <altivec.h>

#pragma pop_macro("vector")
#pragma pop_macro("pixel")
#pragma pop_macro("bool")

inline __attribute__((__always_inline__, __artificial__))
double Float16BitsToDouble(uint16_t f16_bits) {
  double dbl_result;
 __vector unsigned short f16_vect = vec_splats(f16_bits);
 __asm__("xscvhpdp %x0,%x1"
          : "=wa" (dbl_result)
 : "wa" (f16_vect));
  return dbl_result;
}

int main(int argc, char** argv) {
  alignas(16) float input_vals[8];
  alignas(16) uint16_t result_vals[8];
  for(int i = 1; i < argc; ) {
 input_vals[0] = strtof(argv[i++], NULL);
    input_vals[1] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    input_vals[2] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    input_vals[3] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    input_vals[4] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    input_vals[5] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    input_vals[6] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    input_vals[7] = (i < argc) ? strtof(argv[i++], NULL) : 0.0f;
    
    __vector float src_vect_a =
      *((const __vector float*)input_vals);
    __vector float src_vect_b =
      *((const __vector float*)(input_vals + 4));
 __vector unsigned short result_vect =
 vec_pack_to_short_fp32(src_vect_a, src_vect_b);
    *((__vector unsigned short*)result_vals) = result_vect;
    
    for(int j = 0; j < 8; j++)
      printf("Float32ToFloat16(%g) = %g\n",
 input_vals[j], Float16BitsToDouble(result_vals[j]));
  }
  return 0;
}
```

Here are the results of running the above test program when compiled with GCC 12:
```
$ ./vsx_vec_pack_to_short_fp32_test_021623_gcc 1.518 2.4447 3.3932 6.4842 -1.4912 -3.3938 -7.532 6.6662
Float32ToFloat16(1.518) = 1.51758
Float32ToFloat16(2.4447) = 2.44531
Float32ToFloat16(3.3932) = 3.39258
Float32ToFloat16(6.4842) = 6.48438
Float32ToFloat16(-1.4912) = -1.49121
Float32ToFloat16(-3.3938) = -3.39453
Float32ToFloat16(-7.532) = -7.53125
Float32ToFloat16(6.6662) = 6.66797
```

Here are the results of running the above test program when compiled with Clang 15 or Clang 17:
```
$ ./vsx_vec_pack_to_short_fp32_test_021623_clang 1.518 2.4447 3.3932 6.4842 -1.4912 -3.3938 -7.532 6.6662
Float32ToFloat16(1.518) = 1.51758
Float32ToFloat16(2.4447) = 0
Float32ToFloat16(3.3932) = -1.49121
Float32ToFloat16(6.4842) = 0
Float32ToFloat16(-1.4912) = 3.39258
Float32ToFloat16(-3.3938) = 0
Float32ToFloat16(-7.532) = -7.53125
Float32ToFloat16(6.6662) = 0
```

</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMWEtz6yYU_jV4w8QjQC8vvEjsuneR6aJN1xqEsEUuBg0gO_ffd0APW66Vm3vbZprxxAIO53znwXewqLXioDhfg-QJJNsFbV2tzfpV16qR1Dm7KHX1bf2FGw6Fha7mkLXGcOXgRlJ1gOLYSH7kylEntIJ6D0-cFQ1lXwunC1tr44p9QzAgjyDaguixdq6xfoR3AO8OwtVtuWT6CPBOytPw9dAY_cqZA3hXSl0CvEv2CdunEV7lCa6yiPA8iVjCUFqSPMV5XEVxXlUrBPCOeWRekfAbv3BacWMB3lHpxImzZQ0wec4SlD88ZwnOOlzd_4mj2hjOHK9-3EmQRv0nDK3fyGBRCCWF4kXh9zttYKtC-CsYdMCieHx5-f2PQhdUwG7rjCGc9xr2UlO_kQK8gTdzJcArCLKnXhX8m1WhvJjhlkJAtvCi9VoC4FVRlK2QTqjiZN-KtxM72aZuAM6D3RUgo4lZC-VPWyinFqDhrjVqzECQ8S74AHSmJhtAtr2bk2m-KXTcOtgYfTD06HGea8FqqDivLHQalr4ejo2QvIJn4epQIQ_WVYBsGULw4ciaFpBto8_crKBufKVYnwBXUwcZVV5Fa3nltbGas69BheG2lc76mvLD--mGuuEm1N5chQFMhGKyrTgEZGNdJZRb1oD8MrMsRfnestDvrVIpDupaYBBrDD0cKWxaWxdHyowGOAcYdykHGPvEfEe2EW9cfky01HoqOci3quL7vhRvJjv107mgZ6rhyt8Lacy6q5sPezsVfc_ZqeR9Xzs68affOSPK1vGiCPL-YMoz_WZHxulOBzVO7AUTVPqZ1aiu0m0pOdx54kDpk3D2RW_DHMB5K5RDaeHgHqVFKZztaWU4kP3mqpRFV82ADGtFcZ_ovCa_EkjB17z13cYCnF_ZuFZD7bF3Db9ZdqqbqoEAJ28RwBv_jXxwejzDHyCP0E-T7ZkCjP2hvsI4uD6IjTIDtj4-I4iBeO74eeGYPi0OHqlQAOf-kZoD8-FnNTUAPwL86KdON1EMh4r6EKDUL3UkLlTTuuJEpQXJUw6S7RWe2x1jnjp0M7v2vjYDLhGijzxV-sdNB9QT5wTZBEIEkm3YZp1xeg9wHlxJngTAT_6TbL2rv_35_DwNHpzqQYMej-Vi3Bsmu48pD4mLltF-3gr-FCvkU6zEn2Il-RQr6adYyf4rK5enkd-602oNCxNFuE9d81E4956YmVbW3ewLi6sr7DcnZ85K-RNWwtkfDEGAn2B8S3RzpD3QSs_blxvf_QvqJRg-oBfQt96NoGfsdrivOS3kZXuNZyY9F657DTsiz26voRTy8NjnfOwF4a8xQrl912xCRyT4RfetMcwmhwFCeE42KrTmzT3CfO0L6n5rnTJ1J3vTdcbeMjag6E7fmb3bUsNv75mmVUqoQ5impT7x6d33XHN1c9f9dbOBaPbXDcAxXAK88zf3-9VQeANFhFGKSXFgDKJlgnKIl3EcZ5AsyYpgmC7jPMbwAS3jFcLwIUzn8CFbJmE1TdO-xd9JSlA4ZMUPsiSfFe7sDtJ-lBA0K93BG6T9CL-ju_NikA4jMi_dOzuI98N5LH1QRnk_jBMyLx-CN4r7EcLJO-BDkEfwaZqtsk-psO5lAkqgNsNz9i_VG-vU_Y8qLvpgrX23HKbFNq_2psy-V8M3VfaO3n9SXtHd5C6qNalWZEUXfI3SLE2yLEdoUa9LVOVRGccZojFjqMrKJEYMI7bHrFzRaiHWOMIkJD2KCEHLPGU8RnTP4yiuEkpAHPEjFXIp5em41OawENa2fJ1GOcYLSUsubXgPhrHiZxgWPbEn24VZh5dSZXuwII6ksM5etDjhJF93VTvz-_3mBdKBK_97nlsoVP-WaTg-i9bI9Q-_IwtYLcC74MtfAQAA__9aubcQ">