1 /* 2 * Copyright(c) 2020-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 /* 19 * This test checks various FP operations performed on Hexagon 20 */ 21 22 #include <stdio.h> 23 24 const int FPINVF_BIT = 1; /* Invalid */ 25 const int FPINVF = 1 << FPINVF_BIT; 26 const int FPDBZF_BIT = 2; /* Divide by zero */ 27 const int FPDBZF = 1 << FPDBZF_BIT; 28 const int FPOVFF_BIT = 3; /* Overflow */ 29 const int FPOVFF = 1 << FPOVFF_BIT; 30 const int FPUNFF_BIT = 4; /* Underflow */ 31 const int FPUNFF = 1 << FPUNFF_BIT; 32 const int FPINPF_BIT = 5; /* Inexact */ 33 const int FPINPF = 1 << FPINPF_BIT; 34 35 const int SF_ZERO = 0x00000000; 36 const int SF_NaN = 0x7fc00000; 37 const int SF_NaN_special = 0x7f800001; 38 const int SF_ANY = 0x3f800000; 39 const int SF_HEX_NAN = 0xffffffff; 40 41 const long long DF_NaN = 0x7ff8000000000000ULL; 42 const long long DF_ANY = 0x3f80000000000000ULL; 43 const long long DF_HEX_NAN = 0xffffffffffffffffULL; 44 45 int err; 46 47 #define CLEAR_FPSTATUS \ 48 "r2 = usr\n\t" \ 49 "r2 = clrbit(r2, #1)\n\t" \ 50 "r2 = clrbit(r2, #2)\n\t" \ 51 "r2 = clrbit(r2, #3)\n\t" \ 52 "r2 = clrbit(r2, #4)\n\t" \ 53 "r2 = clrbit(r2, #5)\n\t" \ 54 "usr = r2\n\t" 55 56 static void check_fpstatus_bit(int usr, int expect, int flag, const char *n) 57 { 58 int bit = 1 << flag; 59 if ((usr & bit) != (expect & bit)) { 60 printf("ERROR %s: usr = %d, expect = %d\n", n, 61 (usr >> flag) & 1, (expect >> flag) & 1); 62 err++; 63 } 64 } 65 66 static void check_fpstatus(int usr, int expect) 67 { 68 check_fpstatus_bit(usr, expect, FPINVF_BIT, "Invalid"); 69 check_fpstatus_bit(usr, expect, FPDBZF_BIT, "Div by zero"); 70 check_fpstatus_bit(usr, expect, FPOVFF_BIT, "Overflow"); 71 check_fpstatus_bit(usr, expect, FPUNFF_BIT, "Underflow"); 72 check_fpstatus_bit(usr, expect, FPINPF_BIT, "Inexact"); 73 } 74 75 static void check32(int val, int expect) 76 { 77 if (val != expect) { 78 printf("ERROR: 0x%x != 0x%x\n", val, expect); 79 err++; 80 } 81 } 82 static void check64(unsigned long long val, unsigned long long expect) 83 { 84 if (val != expect) { 85 printf("ERROR: 0x%llx != 0x%llx\n", val, expect); 86 err++; 87 } 88 } 89 90 static void check_compare_exception(void) 91 { 92 int cmp; 93 int usr; 94 95 /* Check that FP compares are quiet (don't raise any execptions) */ 96 asm (CLEAR_FPSTATUS 97 "p0 = sfcmp.eq(%2, %3)\n\t" 98 "%0 = p0\n\t" 99 "%1 = usr\n\t" 100 : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 101 : "r2", "p0", "usr"); 102 check32(cmp, 0); 103 check_fpstatus(usr, 0); 104 105 asm (CLEAR_FPSTATUS 106 "p0 = sfcmp.gt(%2, %3)\n\t" 107 "%0 = p0\n\t" 108 "%1 = usr\n\t" 109 : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 110 : "r2", "p0", "usr"); 111 check32(cmp, 0); 112 check_fpstatus(usr, 0); 113 114 asm (CLEAR_FPSTATUS 115 "p0 = sfcmp.ge(%2, %3)\n\t" 116 "%0 = p0\n\t" 117 "%1 = usr\n\t" 118 : "=r"(cmp), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 119 : "r2", "p0", "usr"); 120 check32(cmp, 0); 121 check_fpstatus(usr, 0); 122 123 asm (CLEAR_FPSTATUS 124 "p0 = dfcmp.eq(%2, %3)\n\t" 125 "%0 = p0\n\t" 126 "%1 = usr\n\t" 127 : "=r"(cmp), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 128 : "r2", "p0", "usr"); 129 check32(cmp, 0); 130 check_fpstatus(usr, 0); 131 132 asm (CLEAR_FPSTATUS 133 "p0 = dfcmp.gt(%2, %3)\n\t" 134 "%0 = p0\n\t" 135 "%1 = usr\n\t" 136 : "=r"(cmp), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 137 : "r2", "p0", "usr"); 138 check32(cmp, 0); 139 check_fpstatus(usr, 0); 140 141 asm (CLEAR_FPSTATUS 142 "p0 = dfcmp.ge(%2, %3)\n\t" 143 "%0 = p0\n\t" 144 "%1 = usr\n\t" 145 : "=r"(cmp), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 146 : "r2", "p0", "usr"); 147 check32(cmp, 0); 148 check_fpstatus(usr, 0); 149 } 150 151 static void check_sfminmax(void) 152 { 153 int minmax; 154 int usr; 155 156 /* 157 * Execute sfmin/sfmax instructions with one operand as NaN 158 * Check that 159 * Result is the other operand 160 * Invalid bit in USR is not set 161 */ 162 asm (CLEAR_FPSTATUS 163 "%0 = sfmin(%2, %3)\n\t" 164 "%1 = usr\n\t" 165 : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 166 : "r2", "usr"); 167 check64(minmax, SF_ANY); 168 check_fpstatus(usr, 0); 169 170 asm (CLEAR_FPSTATUS 171 "%0 = sfmax(%2, %3)\n\t" 172 "%1 = usr\n\t" 173 : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 174 : "r2", "usr"); 175 check64(minmax, SF_ANY); 176 check_fpstatus(usr, 0); 177 178 /* 179 * Execute sfmin/sfmax instructions with both operands NaN 180 * Check that 181 * Result is SF_HEX_NAN 182 * Invalid bit in USR is set 183 */ 184 asm (CLEAR_FPSTATUS 185 "%0 = sfmin(%2, %3)\n\t" 186 "%1 = usr\n\t" 187 : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_NaN) 188 : "r2", "usr"); 189 check64(minmax, SF_HEX_NAN); 190 check_fpstatus(usr, 0); 191 192 asm (CLEAR_FPSTATUS 193 "%0 = sfmax(%2, %3)\n\t" 194 "%1 = usr\n\t" 195 : "=r"(minmax), "=r"(usr) : "r"(SF_NaN), "r"(SF_NaN) 196 : "r2", "usr"); 197 check64(minmax, SF_HEX_NAN); 198 check_fpstatus(usr, 0); 199 } 200 201 static void check_dfminmax(void) 202 { 203 unsigned long long minmax; 204 int usr; 205 206 /* 207 * Execute dfmin/dfmax instructions with one operand as NaN 208 * Check that 209 * Result is the other operand 210 * Invalid bit in USR is set 211 */ 212 asm (CLEAR_FPSTATUS 213 "%0 = dfmin(%2, %3)\n\t" 214 "%1 = usr\n\t" 215 : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 216 : "r2", "usr"); 217 check64(minmax, DF_ANY); 218 check_fpstatus(usr, FPINVF); 219 220 asm (CLEAR_FPSTATUS 221 "%0 = dfmax(%2, %3)\n\t" 222 "%1 = usr\n\t" 223 : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 224 : "r2", "usr"); 225 check64(minmax, DF_ANY); 226 check_fpstatus(usr, FPINVF); 227 228 /* 229 * Execute dfmin/dfmax instructions with both operands NaN 230 * Check that 231 * Result is DF_HEX_NAN 232 * Invalid bit in USR is set 233 */ 234 asm (CLEAR_FPSTATUS 235 "%0 = dfmin(%2, %3)\n\t" 236 "%1 = usr\n\t" 237 : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_NaN) 238 : "r2", "usr"); 239 check64(minmax, DF_HEX_NAN); 240 check_fpstatus(usr, FPINVF); 241 242 asm (CLEAR_FPSTATUS 243 "%0 = dfmax(%2, %3)\n\t" 244 "%1 = usr\n\t" 245 : "=r"(minmax), "=r"(usr) : "r"(DF_NaN), "r"(DF_NaN) 246 : "r2", "usr"); 247 check64(minmax, DF_HEX_NAN); 248 check_fpstatus(usr, FPINVF); 249 } 250 251 static void check_canonical_NaN(void) 252 { 253 int sf_result; 254 unsigned long long df_result; 255 int usr; 256 257 /* Check that each FP instruction properly returns SF_HEX_NAN/DF_HEX_NAN */ 258 asm(CLEAR_FPSTATUS 259 "%0 = sfadd(%2, %3)\n\t" 260 "%1 = usr\n\t" 261 : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 262 : "r2", "usr"); 263 check32(sf_result, SF_HEX_NAN); 264 check_fpstatus(usr, 0); 265 266 asm(CLEAR_FPSTATUS 267 "%0 = sfsub(%2, %3)\n\t" 268 "%1 = usr\n\t" 269 : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 270 : "r2", "usr"); 271 check32(sf_result, SF_HEX_NAN); 272 check_fpstatus(usr, 0); 273 274 asm(CLEAR_FPSTATUS 275 "%0 = sfmpy(%2, %3)\n\t" 276 "%1 = usr\n\t" 277 : "=r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 278 : "r2", "usr"); 279 check32(sf_result, SF_HEX_NAN); 280 check_fpstatus(usr, 0); 281 282 sf_result = SF_ZERO; 283 asm(CLEAR_FPSTATUS 284 "%0 += sfmpy(%2, %3)\n\t" 285 "%1 = usr\n\t" 286 : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 287 : "r2", "usr"); 288 check32(sf_result, SF_HEX_NAN); 289 check_fpstatus(usr, 0); 290 291 sf_result = SF_ZERO; 292 asm(CLEAR_FPSTATUS 293 "p0 = !cmp.eq(r0, r0)\n\t" 294 "%0 += sfmpy(%2, %3, p0):scale\n\t" 295 "%1 = usr\n\t" 296 : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 297 : "r2", "usr", "p0"); 298 check32(sf_result, SF_HEX_NAN); 299 check_fpstatus(usr, 0); 300 301 sf_result = SF_ZERO; 302 asm(CLEAR_FPSTATUS 303 "%0 -= sfmpy(%2, %3)\n\t" 304 "%1 = usr\n\t" 305 : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 306 : "r2", "usr"); 307 check32(sf_result, SF_HEX_NAN); 308 check_fpstatus(usr, 0); 309 310 sf_result = SF_ZERO; 311 asm(CLEAR_FPSTATUS 312 "%0 += sfmpy(%2, %3):lib\n\t" 313 "%1 = usr\n\t" 314 : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 315 : "r2", "usr"); 316 check32(sf_result, SF_HEX_NAN); 317 check_fpstatus(usr, 0); 318 319 sf_result = SF_ZERO; 320 asm(CLEAR_FPSTATUS 321 "%0 -= sfmpy(%2, %3):lib\n\t" 322 "%1 = usr\n\t" 323 : "+r"(sf_result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) 324 : "r2", "usr"); 325 check32(sf_result, SF_HEX_NAN); 326 check_fpstatus(usr, 0); 327 328 asm(CLEAR_FPSTATUS 329 "%0 = convert_df2sf(%2)\n\t" 330 "%1 = usr\n\t" 331 : "=r"(sf_result), "=r"(usr) : "r"(DF_NaN) 332 : "r2", "usr"); 333 check32(sf_result, SF_HEX_NAN); 334 check_fpstatus(usr, 0); 335 336 asm(CLEAR_FPSTATUS 337 "%0 = dfadd(%2, %3)\n\t" 338 "%1 = usr\n\t" 339 : "=r"(df_result), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 340 : "r2", "usr"); 341 check64(df_result, DF_HEX_NAN); 342 check_fpstatus(usr, 0); 343 344 asm(CLEAR_FPSTATUS 345 "%0 = dfsub(%2, %3)\n\t" 346 "%1 = usr\n\t" 347 : "=r"(df_result), "=r"(usr) : "r"(DF_NaN), "r"(DF_ANY) 348 : "r2", "usr"); 349 check64(df_result, DF_HEX_NAN); 350 check_fpstatus(usr, 0); 351 352 asm(CLEAR_FPSTATUS 353 "%0 = convert_sf2df(%2)\n\t" 354 "%1 = usr\n\t" 355 : "=r"(df_result), "=r"(usr) : "r"(SF_NaN) 356 : "r2", "usr"); 357 check64(df_result, DF_HEX_NAN); 358 check_fpstatus(usr, 0); 359 } 360 361 int main() 362 { 363 check_compare_exception(); 364 check_sfminmax(); 365 check_dfminmax(); 366 check_canonical_NaN(); 367 368 puts(err ? "FAIL" : "PASS"); 369 return err ? 1 : 0; 370 } 371