1 //===- unittests/ADT/FixedPointTest.cpp -- fixed point number tests -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/APFixedPoint.h" 10 #include "llvm/ADT/APFloat.h" 11 #include "llvm/ADT/APSInt.h" 12 #include "gtest/gtest.h" 13 14 using llvm::APFixedPoint; 15 using llvm::APFloat; 16 using llvm::APInt; 17 using llvm::APSInt; 18 using llvm::FixedPointSemantics; 19 20 namespace { 21 22 FixedPointSemantics Saturated(FixedPointSemantics Sema) { 23 Sema.setSaturated(true); 24 return Sema; 25 } 26 27 FixedPointSemantics getSAccumSema() { 28 return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/true, 29 /*isSaturated=*/false, 30 /*hasUnsignedPadding=*/false); 31 } 32 33 FixedPointSemantics getAccumSema() { 34 return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/true, 35 /*isSaturated=*/false, 36 /*hasUnsignedPadding=*/false); 37 } 38 39 FixedPointSemantics getLAccumSema() { 40 return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/true, 41 /*isSaturated=*/false, 42 /*hasUnsignedPadding=*/false); 43 } 44 45 FixedPointSemantics getSFractSema() { 46 return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/true, 47 /*isSaturated=*/false, 48 /*hasUnsignedPadding=*/false); 49 } 50 51 FixedPointSemantics getFractSema() { 52 return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/true, 53 /*isSaturated=*/false, 54 /*hasUnsignedPadding=*/false); 55 } 56 57 FixedPointSemantics getLFractSema() { 58 return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/true, 59 /*isSaturated=*/false, 60 /*hasUnsignedPadding=*/false); 61 } 62 63 FixedPointSemantics getUSAccumSema() { 64 return FixedPointSemantics(/*width=*/16, /*scale=*/8, /*isSigned=*/false, 65 /*isSaturated=*/false, 66 /*hasUnsignedPadding=*/false); 67 } 68 69 FixedPointSemantics getUAccumSema() { 70 return FixedPointSemantics(/*width=*/32, /*scale=*/16, /*isSigned=*/false, 71 /*isSaturated=*/false, 72 /*hasUnsignedPadding=*/false); 73 } 74 75 FixedPointSemantics getULAccumSema() { 76 return FixedPointSemantics(/*width=*/64, /*scale=*/32, /*isSigned=*/false, 77 /*isSaturated=*/false, 78 /*hasUnsignedPadding=*/false); 79 } 80 81 FixedPointSemantics getUSFractSema() { 82 return FixedPointSemantics(/*width=*/8, /*scale=*/8, /*isSigned=*/false, 83 /*isSaturated=*/false, 84 /*hasUnsignedPadding=*/false); 85 } 86 87 FixedPointSemantics getUFractSema() { 88 return FixedPointSemantics(/*width=*/16, /*scale=*/16, /*isSigned=*/false, 89 /*isSaturated=*/false, 90 /*hasUnsignedPadding=*/false); 91 } 92 93 FixedPointSemantics getULFractSema() { 94 return FixedPointSemantics(/*width=*/32, /*scale=*/32, /*isSigned=*/false, 95 /*isSaturated=*/false, 96 /*hasUnsignedPadding=*/false); 97 } 98 99 FixedPointSemantics getPadUSAccumSema() { 100 return FixedPointSemantics(/*width=*/16, /*scale=*/7, /*isSigned=*/false, 101 /*isSaturated=*/false, 102 /*hasUnsignedPadding=*/true); 103 } 104 105 FixedPointSemantics getPadUAccumSema() { 106 return FixedPointSemantics(/*width=*/32, /*scale=*/15, /*isSigned=*/false, 107 /*isSaturated=*/false, 108 /*hasUnsignedPadding=*/true); 109 } 110 111 FixedPointSemantics getPadULAccumSema() { 112 return FixedPointSemantics(/*width=*/64, /*scale=*/31, /*isSigned=*/false, 113 /*isSaturated=*/false, 114 /*hasUnsignedPadding=*/true); 115 } 116 117 FixedPointSemantics getPadUSFractSema() { 118 return FixedPointSemantics(/*width=*/8, /*scale=*/7, /*isSigned=*/false, 119 /*isSaturated=*/false, 120 /*hasUnsignedPadding=*/true); 121 } 122 123 FixedPointSemantics getPadUFractSema() { 124 return FixedPointSemantics(/*width=*/16, /*scale=*/15, /*isSigned=*/false, 125 /*isSaturated=*/false, 126 /*hasUnsignedPadding=*/true); 127 } 128 129 FixedPointSemantics getPadULFractSema() { 130 return FixedPointSemantics(/*width=*/32, /*scale=*/31, /*isSigned=*/false, 131 /*isSaturated=*/false, 132 /*hasUnsignedPadding=*/true); 133 } 134 135 FixedPointSemantics getU8Neg10() { 136 return FixedPointSemantics(/*width=*/8, /*lsb=*/FixedPointSemantics::Lsb{-10}, 137 /*isSigned=*/false, 138 /*isSaturated=*/false, 139 /*hasUnsignedPadding=*/false); 140 } 141 142 FixedPointSemantics getS16Neg18() { 143 return FixedPointSemantics(/*width=*/16, 144 /*lsb=*/FixedPointSemantics::Lsb{-18}, 145 /*isSigned=*/true, 146 /*isSaturated=*/false, 147 /*hasUnsignedPadding=*/false); 148 } 149 150 FixedPointSemantics getU8Pos4() { 151 return FixedPointSemantics(/*width=*/8, /*lsb=*/FixedPointSemantics::Lsb{4}, 152 /*isSigned=*/false, 153 /*isSaturated=*/false, 154 /*hasUnsignedPadding=*/false); 155 } 156 157 FixedPointSemantics getS32Pos2() { 158 return FixedPointSemantics(/*width=*/32, /*lsb=*/FixedPointSemantics::Lsb{2}, 159 /*isSigned=*/true, 160 /*isSaturated=*/false, 161 /*hasUnsignedPadding=*/false); 162 } 163 164 void CheckUnpaddedMax(const FixedPointSemantics &Sema) { 165 ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(), 166 APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned())); 167 } 168 169 void CheckPaddedMax(const FixedPointSemantics &Sema) { 170 ASSERT_EQ(APFixedPoint::getMax(Sema).getValue(), 171 APSInt::getMaxValue(Sema.getWidth(), !Sema.isSigned()) >> 1); 172 } 173 174 void CheckMin(const FixedPointSemantics &Sema) { 175 ASSERT_EQ(APFixedPoint::getMin(Sema).getValue(), 176 APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned())); 177 } 178 179 TEST(FixedPointTest, getMax) { 180 CheckUnpaddedMax(getSAccumSema()); 181 CheckUnpaddedMax(getAccumSema()); 182 CheckUnpaddedMax(getLAccumSema()); 183 CheckUnpaddedMax(getUSAccumSema()); 184 CheckUnpaddedMax(getUAccumSema()); 185 CheckUnpaddedMax(getULAccumSema()); 186 CheckUnpaddedMax(getSFractSema()); 187 CheckUnpaddedMax(getFractSema()); 188 CheckUnpaddedMax(getLFractSema()); 189 CheckUnpaddedMax(getUSFractSema()); 190 CheckUnpaddedMax(getUFractSema()); 191 CheckUnpaddedMax(getULFractSema()); 192 CheckUnpaddedMax(getU8Neg10()); 193 CheckUnpaddedMax(getS16Neg18()); 194 CheckUnpaddedMax(getU8Pos4()); 195 CheckUnpaddedMax(getS32Pos2()); 196 197 CheckPaddedMax(getPadUSAccumSema()); 198 CheckPaddedMax(getPadUAccumSema()); 199 CheckPaddedMax(getPadULAccumSema()); 200 CheckPaddedMax(getPadUSFractSema()); 201 CheckPaddedMax(getPadUFractSema()); 202 CheckPaddedMax(getPadULFractSema()); 203 } 204 205 TEST(FixedPointTest, getMin) { 206 CheckMin(getSAccumSema()); 207 CheckMin(getAccumSema()); 208 CheckMin(getLAccumSema()); 209 CheckMin(getUSAccumSema()); 210 CheckMin(getUAccumSema()); 211 CheckMin(getULAccumSema()); 212 CheckMin(getSFractSema()); 213 CheckMin(getFractSema()); 214 CheckMin(getLFractSema()); 215 CheckMin(getUSFractSema()); 216 CheckMin(getUFractSema()); 217 CheckMin(getULFractSema()); 218 CheckMin(getU8Neg10()); 219 CheckMin(getS16Neg18()); 220 CheckMin(getU8Pos4()); 221 CheckMin(getS32Pos2()); 222 223 CheckMin(getPadUSAccumSema()); 224 CheckMin(getPadUAccumSema()); 225 CheckMin(getPadULAccumSema()); 226 CheckMin(getPadUSFractSema()); 227 CheckMin(getPadUFractSema()); 228 CheckMin(getPadULFractSema()); 229 } 230 231 int64_t relativeShr(int64_t Int, int64_t Shift) { 232 return (Shift > 0) ? Int >> Shift : Int << -Shift; 233 } 234 235 void CheckIntPart(const FixedPointSemantics &Sema, int64_t IntPart) { 236 int64_t FullFactPart = 237 (Sema.getLsbWeight() > 0) ? 0 : (1ULL << (-Sema.getLsbWeight() - 1)); 238 239 // Value with a fraction 240 APFixedPoint ValWithFract( 241 APInt(Sema.getWidth(), 242 relativeShr(IntPart, Sema.getLsbWeight()) + FullFactPart, 243 Sema.isSigned(), /*implicitTrunc=*/true), 244 Sema); 245 ASSERT_EQ(ValWithFract.getIntPart(), IntPart); 246 247 // Just fraction 248 APFixedPoint JustFract(APInt(Sema.getWidth(), FullFactPart, Sema.isSigned(), 249 /*implicitTrunc=*/true), 250 Sema); 251 ASSERT_EQ(JustFract.getIntPart(), 0); 252 253 // Whole number 254 APFixedPoint WholeNum(APInt(Sema.getWidth(), 255 relativeShr(IntPart, Sema.getLsbWeight()), 256 Sema.isSigned(), /*implicitTrunc=*/true), 257 Sema); 258 ASSERT_EQ(WholeNum.getIntPart(), IntPart); 259 260 // Negative 261 if (Sema.isSigned()) { 262 APFixedPoint Negative(APInt(Sema.getWidth(), 263 relativeShr(IntPart, Sema.getLsbWeight()), 264 Sema.isSigned(), /*implicitTrunc=*/true), 265 Sema); 266 ASSERT_EQ(Negative.getIntPart(), IntPart); 267 } 268 } 269 270 void CheckIntPartMin(const FixedPointSemantics &Sema, int64_t Expected) { 271 EXPECT_TRUE(APSInt::compareValues(APFixedPoint::getMin(Sema).getIntPart(), 272 APSInt::get(Expected)) == 0); 273 } 274 275 void CheckIntPartMax(const FixedPointSemantics &Sema, uint64_t Expected) { 276 EXPECT_TRUE(APSInt::compareValues(APFixedPoint::getMax(Sema).getIntPart(), 277 APSInt::getUnsigned(Expected)) == 0); 278 } 279 280 void CheckIntPartRes(const FixedPointSemantics &Sema, int64_t Representation, 281 uint64_t Result) { 282 APFixedPoint Val(Representation, Sema); 283 ASSERT_EQ(Val.getIntPart().getZExtValue(), Result) ; 284 } 285 286 TEST(FixedPoint, getIntPart) { 287 // Normal values 288 CheckIntPart(getSAccumSema(), 2); 289 CheckIntPart(getAccumSema(), 2); 290 CheckIntPart(getLAccumSema(), 2); 291 CheckIntPart(getUSAccumSema(), 2); 292 CheckIntPart(getUAccumSema(), 2); 293 CheckIntPart(getULAccumSema(), 2); 294 CheckIntPart(getU8Pos4(), 32); 295 CheckIntPart(getS32Pos2(), 32); 296 297 // Zero 298 CheckIntPart(getSAccumSema(), 0); 299 CheckIntPart(getAccumSema(), 0); 300 CheckIntPart(getLAccumSema(), 0); 301 CheckIntPart(getUSAccumSema(), 0); 302 CheckIntPart(getUAccumSema(), 0); 303 CheckIntPart(getULAccumSema(), 0); 304 305 CheckIntPart(getSFractSema(), 0); 306 CheckIntPart(getFractSema(), 0); 307 CheckIntPart(getLFractSema(), 0); 308 CheckIntPart(getUSFractSema(), 0); 309 CheckIntPart(getUFractSema(), 0); 310 CheckIntPart(getULFractSema(), 0); 311 312 CheckIntPart(getS16Neg18(), 0); 313 CheckIntPart(getU8Neg10(), 0); 314 CheckIntPart(getU8Pos4(), 0); 315 CheckIntPart(getS32Pos2(), 0); 316 317 // Min 318 CheckIntPartMin(getSAccumSema(), -256); 319 CheckIntPartMin(getAccumSema(), -65536); 320 CheckIntPartMin(getLAccumSema(), -4294967296); 321 322 CheckIntPartMin(getSFractSema(), -1); 323 CheckIntPartMin(getFractSema(), -1); 324 CheckIntPartMin(getLFractSema(), -1); 325 326 CheckIntPartMin(getS32Pos2(), -8589934592); 327 328 // Max 329 CheckIntPartMax(getSAccumSema(), 255); 330 CheckIntPartMax(getAccumSema(), 65535); 331 CheckIntPartMax(getLAccumSema(), 4294967295); 332 CheckIntPartMax(getUSAccumSema(), 255); 333 CheckIntPartMax(getUAccumSema(), 65535); 334 CheckIntPartMax(getULAccumSema(), 4294967295); 335 336 CheckIntPartMax(getU8Pos4(), 255 << 4); 337 CheckIntPartMax(getS32Pos2(), 2147483647ull << 2); 338 339 CheckIntPartMax(getSFractSema(), 0); 340 CheckIntPartMax(getFractSema(), 0); 341 CheckIntPartMax(getLFractSema(), 0); 342 CheckIntPartMax(getUSFractSema(), 0); 343 CheckIntPartMax(getUFractSema(), 0); 344 CheckIntPartMax(getULFractSema(), 0); 345 346 // Padded 347 // Normal Values 348 CheckIntPart(getPadUSAccumSema(), 2); 349 CheckIntPart(getPadUAccumSema(), 2); 350 CheckIntPart(getPadULAccumSema(), 2); 351 352 // Zero 353 CheckIntPart(getPadUSAccumSema(), 0); 354 CheckIntPart(getPadUAccumSema(), 0); 355 CheckIntPart(getPadULAccumSema(), 0); 356 357 CheckIntPart(getPadUSFractSema(), 0); 358 CheckIntPart(getPadUFractSema(), 0); 359 CheckIntPart(getPadULFractSema(), 0); 360 361 // Max 362 CheckIntPartMax(getPadUSAccumSema(), 255); 363 CheckIntPartMax(getPadUAccumSema(), 65535); 364 CheckIntPartMax(getPadULAccumSema(), 4294967295); 365 366 CheckIntPartMax(getPadUSFractSema(), 0); 367 CheckIntPartMax(getPadUFractSema(), 0); 368 CheckIntPartMax(getPadULFractSema(), 0); 369 370 // Rounded Towards Zero 371 CheckIntPartRes(getSFractSema(), -127, 0); 372 CheckIntPartRes(getFractSema(), -32767, 0); 373 CheckIntPartRes(getLFractSema(), -2147483647, 0); 374 CheckIntPartRes(getS16Neg18(), -32768, 0); 375 } 376 377 TEST(FixedPoint, compare) { 378 // Equality 379 // With fractional part (2.5) 380 // Across sizes 381 ASSERT_EQ(APFixedPoint(320, getSAccumSema()), 382 APFixedPoint(81920, getAccumSema())); 383 ASSERT_EQ(APFixedPoint(320, getSAccumSema()), 384 APFixedPoint(5368709120, getLAccumSema())); 385 ASSERT_EQ(APFixedPoint(0, getSAccumSema()), APFixedPoint(0, getLAccumSema())); 386 387 ASSERT_EQ(APFixedPoint(0, getS16Neg18()), APFixedPoint(0, getU8Neg10())); 388 ASSERT_EQ(APFixedPoint(256, getS16Neg18()), APFixedPoint(1, getU8Neg10())); 389 ASSERT_EQ(APFixedPoint(32512, getS16Neg18()), 390 APFixedPoint(127, getU8Neg10())); 391 ASSERT_EQ(APFixedPoint(4, getS32Pos2()), APFixedPoint(1, getU8Pos4())); 392 ASSERT_EQ(APFixedPoint(1020, getS32Pos2()), APFixedPoint(255, getU8Pos4())); 393 394 // Across types (0.5) 395 ASSERT_EQ(APFixedPoint(64, getSAccumSema()), 396 APFixedPoint(64, getSFractSema())); 397 ASSERT_EQ(APFixedPoint(16384, getAccumSema()), 398 APFixedPoint(16384, getFractSema())); 399 ASSERT_EQ(APFixedPoint(1073741824, getLAccumSema()), 400 APFixedPoint(1073741824, getLFractSema())); 401 402 // Across widths and types (0.5) 403 ASSERT_EQ(APFixedPoint(64, getSAccumSema()), 404 APFixedPoint(16384, getFractSema())); 405 ASSERT_EQ(APFixedPoint(64, getSAccumSema()), 406 APFixedPoint(1073741824, getLFractSema())); 407 408 // Across saturation 409 ASSERT_EQ(APFixedPoint(320, getSAccumSema()), 410 APFixedPoint(81920, Saturated(getAccumSema()))); 411 412 // Across signs 413 ASSERT_EQ(APFixedPoint(320, getSAccumSema()), 414 APFixedPoint(640, getUSAccumSema())); 415 ASSERT_EQ(APFixedPoint(-320, getSAccumSema()), 416 APFixedPoint(-81920, getAccumSema())); 417 418 // Across padding 419 ASSERT_EQ(APFixedPoint(320, getSAccumSema()), 420 APFixedPoint(320, getPadUSAccumSema())); 421 ASSERT_EQ(APFixedPoint(640, getUSAccumSema()), 422 APFixedPoint(320, getPadUSAccumSema())); 423 424 // Less than 425 ASSERT_LT(APFixedPoint(-1, getSAccumSema()), APFixedPoint(0, getAccumSema())); 426 ASSERT_LT(APFixedPoint(-1, getSAccumSema()), 427 APFixedPoint(0, getUAccumSema())); 428 ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getAccumSema())); 429 ASSERT_LT(APFixedPoint(0, getSAccumSema()), APFixedPoint(1, getUAccumSema())); 430 ASSERT_LT(APFixedPoint(0, getUSAccumSema()), APFixedPoint(1, getAccumSema())); 431 ASSERT_LT(APFixedPoint(0, getUSAccumSema()), 432 APFixedPoint(1, getUAccumSema())); 433 ASSERT_LT(APFixedPoint(65280, getS16Neg18()), 434 APFixedPoint(255, getU8Neg10())); 435 436 // Greater than 437 ASSERT_GT(APFixedPoint(0, getAccumSema()), APFixedPoint(-1, getSAccumSema())); 438 ASSERT_GT(APFixedPoint(0, getUAccumSema()), 439 APFixedPoint(-1, getSAccumSema())); 440 ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getSAccumSema())); 441 ASSERT_GT(APFixedPoint(1, getUAccumSema()), APFixedPoint(0, getSAccumSema())); 442 ASSERT_GT(APFixedPoint(1, getAccumSema()), APFixedPoint(0, getUSAccumSema())); 443 ASSERT_GT(APFixedPoint(1, getUAccumSema()), 444 APFixedPoint(0, getUSAccumSema())); 445 } 446 447 // Check that a fixed point value in one sema is the same in another sema 448 void CheckUnsaturatedConversion(FixedPointSemantics Src, 449 FixedPointSemantics Dst, int64_t TestVal) { 450 int64_t ScaledVal = TestVal; 451 bool IsNegative = ScaledVal < 0; 452 if (IsNegative) 453 ScaledVal = -ScaledVal; 454 455 if (Dst.getLsbWeight() < Src.getLsbWeight()) { 456 ScaledVal <<= (Src.getLsbWeight() - Dst.getLsbWeight()); 457 } else { 458 ScaledVal >>= (Dst.getLsbWeight() - Src.getLsbWeight()); 459 } 460 461 if (IsNegative) 462 ScaledVal = -ScaledVal; 463 464 APFixedPoint Fixed(TestVal, Src); 465 APFixedPoint Expected(ScaledVal, Dst); 466 ASSERT_EQ(Fixed.convert(Dst), Expected); 467 } 468 469 // Check the value in a given fixed point sema overflows to the saturated min 470 // for another sema 471 void CheckSaturatedConversionMin(FixedPointSemantics Src, 472 FixedPointSemantics Dst, int64_t TestVal) { 473 APFixedPoint Fixed(TestVal, Src); 474 ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMin(Dst)); 475 } 476 477 // Check the value in a given fixed point sema overflows to the saturated max 478 // for another sema 479 void CheckSaturatedConversionMax(FixedPointSemantics Src, 480 FixedPointSemantics Dst, int64_t TestVal) { 481 APFixedPoint Fixed(TestVal, Src); 482 ASSERT_EQ(Fixed.convert(Dst), APFixedPoint::getMax(Dst)); 483 } 484 485 // Check one signed _Accum sema converted to other sema for different values. 486 void CheckSignedAccumConversionsAgainstOthers(FixedPointSemantics Src, 487 int64_t OneVal) { 488 int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5 489 int64_t HalfVal = (OneVal / 2); // 0.5 490 491 // +Accums to Accums 492 CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal); 493 CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal); 494 CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal); 495 CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal); 496 CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal); 497 CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal); 498 CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal); 499 CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal); 500 CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal); 501 502 // -Accums to Accums 503 CheckUnsaturatedConversion(Src, getSAccumSema(), -NormalVal); 504 CheckUnsaturatedConversion(Src, getAccumSema(), -NormalVal); 505 CheckUnsaturatedConversion(Src, getLAccumSema(), -NormalVal); 506 CheckSaturatedConversionMin(Src, Saturated(getUSAccumSema()), -NormalVal); 507 CheckSaturatedConversionMin(Src, Saturated(getUAccumSema()), -NormalVal); 508 CheckSaturatedConversionMin(Src, Saturated(getULAccumSema()), -NormalVal); 509 CheckSaturatedConversionMin(Src, Saturated(getPadUSAccumSema()), -NormalVal); 510 CheckSaturatedConversionMin(Src, Saturated(getPadUAccumSema()), -NormalVal); 511 CheckSaturatedConversionMin(Src, Saturated(getPadULAccumSema()), -NormalVal); 512 513 // +Accums to Fracts 514 CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal); 515 CheckUnsaturatedConversion(Src, getFractSema(), HalfVal); 516 CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal); 517 CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal); 518 CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal); 519 CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal); 520 CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal); 521 CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal); 522 CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal); 523 524 // -Accums to Fracts 525 CheckUnsaturatedConversion(Src, getSFractSema(), -HalfVal); 526 CheckUnsaturatedConversion(Src, getFractSema(), -HalfVal); 527 CheckUnsaturatedConversion(Src, getLFractSema(), -HalfVal); 528 CheckSaturatedConversionMin(Src, Saturated(getUSFractSema()), -HalfVal); 529 CheckSaturatedConversionMin(Src, Saturated(getUFractSema()), -HalfVal); 530 CheckSaturatedConversionMin(Src, Saturated(getULFractSema()), -HalfVal); 531 CheckSaturatedConversionMin(Src, Saturated(getPadUSFractSema()), -HalfVal); 532 CheckSaturatedConversionMin(Src, Saturated(getPadUFractSema()), -HalfVal); 533 CheckSaturatedConversionMin(Src, Saturated(getPadULFractSema()), -HalfVal); 534 535 // 0 to Accums 536 CheckUnsaturatedConversion(Src, getSAccumSema(), 0); 537 CheckUnsaturatedConversion(Src, getAccumSema(), 0); 538 CheckUnsaturatedConversion(Src, getLAccumSema(), 0); 539 CheckUnsaturatedConversion(Src, getUSAccumSema(), 0); 540 CheckUnsaturatedConversion(Src, getUAccumSema(), 0); 541 CheckUnsaturatedConversion(Src, getULAccumSema(), 0); 542 CheckUnsaturatedConversion(Src, getPadUSAccumSema(), 0); 543 CheckUnsaturatedConversion(Src, getPadUAccumSema(), 0); 544 CheckUnsaturatedConversion(Src, getPadULAccumSema(), 0); 545 546 // 0 to Fracts 547 CheckUnsaturatedConversion(Src, getSFractSema(), 0); 548 CheckUnsaturatedConversion(Src, getFractSema(), 0); 549 CheckUnsaturatedConversion(Src, getLFractSema(), 0); 550 CheckUnsaturatedConversion(Src, getUSFractSema(), 0); 551 CheckUnsaturatedConversion(Src, getUFractSema(), 0); 552 CheckUnsaturatedConversion(Src, getULFractSema(), 0); 553 CheckUnsaturatedConversion(Src, getPadUSFractSema(), 0); 554 CheckUnsaturatedConversion(Src, getPadUFractSema(), 0); 555 CheckUnsaturatedConversion(Src, getPadULFractSema(), 0); 556 } 557 558 // Check one unsigned _Accum sema converted to other sema for different 559 // values. 560 void CheckUnsignedAccumConversionsAgainstOthers(FixedPointSemantics Src, 561 int64_t OneVal) { 562 int64_t NormalVal = (OneVal * 2) + (OneVal / 2); // 2.5 563 int64_t HalfVal = (OneVal / 2); // 0.5 564 565 // +UAccums to Accums 566 CheckUnsaturatedConversion(Src, getSAccumSema(), NormalVal); 567 CheckUnsaturatedConversion(Src, getAccumSema(), NormalVal); 568 CheckUnsaturatedConversion(Src, getLAccumSema(), NormalVal); 569 CheckUnsaturatedConversion(Src, getUSAccumSema(), NormalVal); 570 CheckUnsaturatedConversion(Src, getUAccumSema(), NormalVal); 571 CheckUnsaturatedConversion(Src, getULAccumSema(), NormalVal); 572 CheckUnsaturatedConversion(Src, getPadUSAccumSema(), NormalVal); 573 CheckUnsaturatedConversion(Src, getPadUAccumSema(), NormalVal); 574 CheckUnsaturatedConversion(Src, getPadULAccumSema(), NormalVal); 575 576 // +UAccums to Fracts 577 CheckUnsaturatedConversion(Src, getSFractSema(), HalfVal); 578 CheckUnsaturatedConversion(Src, getFractSema(), HalfVal); 579 CheckUnsaturatedConversion(Src, getLFractSema(), HalfVal); 580 CheckUnsaturatedConversion(Src, getUSFractSema(), HalfVal); 581 CheckUnsaturatedConversion(Src, getUFractSema(), HalfVal); 582 CheckUnsaturatedConversion(Src, getULFractSema(), HalfVal); 583 CheckUnsaturatedConversion(Src, getPadUSFractSema(), HalfVal); 584 CheckUnsaturatedConversion(Src, getPadUFractSema(), HalfVal); 585 CheckUnsaturatedConversion(Src, getPadULFractSema(), HalfVal); 586 } 587 588 TEST(FixedPoint, AccumConversions) { 589 // Normal conversions 590 CheckSignedAccumConversionsAgainstOthers(getSAccumSema(), 128); 591 CheckUnsignedAccumConversionsAgainstOthers(getUSAccumSema(), 256); 592 CheckSignedAccumConversionsAgainstOthers(getAccumSema(), 32768); 593 CheckUnsignedAccumConversionsAgainstOthers(getUAccumSema(), 65536); 594 CheckSignedAccumConversionsAgainstOthers(getLAccumSema(), 2147483648); 595 CheckUnsignedAccumConversionsAgainstOthers(getULAccumSema(), 4294967296); 596 597 CheckUnsignedAccumConversionsAgainstOthers(getPadUSAccumSema(), 128); 598 CheckUnsignedAccumConversionsAgainstOthers(getPadUAccumSema(), 32768); 599 CheckUnsignedAccumConversionsAgainstOthers(getPadULAccumSema(), 2147483648); 600 } 601 602 TEST(FixedPoint, AccumConversionOverflow) { 603 // To SAccum max limit (65536) 604 CheckSaturatedConversionMax(getLAccumSema(), Saturated(getAccumSema()), 605 140737488355328); 606 CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUAccumSema()), 607 140737488355328); 608 CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUAccumSema()), 609 140737488355328); 610 CheckSaturatedConversionMax(getULAccumSema(), Saturated(getAccumSema()), 611 281474976710656); 612 CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUAccumSema()), 613 281474976710656); 614 CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUAccumSema()), 615 281474976710656); 616 617 CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getAccumSema()), 618 140737488355328); 619 CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUAccumSema()), 620 140737488355328); 621 CheckSaturatedConversionMax(getPadULAccumSema(), 622 Saturated(getPadUAccumSema()), 140737488355328); 623 624 // To SAccum min limit (-65536) 625 CheckSaturatedConversionMin(getLAccumSema(), Saturated(getAccumSema()), 626 -140737488355328); 627 CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUAccumSema()), 628 -140737488355328); 629 CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUAccumSema()), 630 -140737488355328); 631 } 632 633 TEST(FixedPoint, SAccumConversionOverflow) { 634 // To SAccum max limit (256) 635 CheckSaturatedConversionMax(getAccumSema(), Saturated(getSAccumSema()), 636 8388608); 637 CheckSaturatedConversionMax(getAccumSema(), Saturated(getUSAccumSema()), 638 8388608); 639 CheckSaturatedConversionMax(getAccumSema(), Saturated(getPadUSAccumSema()), 640 8388608); 641 CheckSaturatedConversionMax(getUAccumSema(), Saturated(getSAccumSema()), 642 16777216); 643 CheckSaturatedConversionMax(getUAccumSema(), Saturated(getUSAccumSema()), 644 16777216); 645 CheckSaturatedConversionMax(getUAccumSema(), Saturated(getPadUSAccumSema()), 646 16777216); 647 CheckSaturatedConversionMax(getLAccumSema(), Saturated(getSAccumSema()), 648 549755813888); 649 CheckSaturatedConversionMax(getLAccumSema(), Saturated(getUSAccumSema()), 650 549755813888); 651 CheckSaturatedConversionMax(getLAccumSema(), Saturated(getPadUSAccumSema()), 652 549755813888); 653 CheckSaturatedConversionMax(getULAccumSema(), Saturated(getSAccumSema()), 654 1099511627776); 655 CheckSaturatedConversionMax(getULAccumSema(), Saturated(getUSAccumSema()), 656 1099511627776); 657 CheckSaturatedConversionMax(getULAccumSema(), Saturated(getPadUSAccumSema()), 658 1099511627776); 659 660 CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getSAccumSema()), 661 8388608); 662 CheckSaturatedConversionMax(getPadUAccumSema(), Saturated(getUSAccumSema()), 663 8388608); 664 CheckSaturatedConversionMax(getPadUAccumSema(), 665 Saturated(getPadUSAccumSema()), 8388608); 666 CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getSAccumSema()), 667 549755813888); 668 CheckSaturatedConversionMax(getPadULAccumSema(), Saturated(getUSAccumSema()), 669 549755813888); 670 CheckSaturatedConversionMax(getPadULAccumSema(), 671 Saturated(getPadUSAccumSema()), 549755813888); 672 673 // To SAccum min limit (-256) 674 CheckSaturatedConversionMin(getAccumSema(), Saturated(getSAccumSema()), 675 -8388608); 676 CheckSaturatedConversionMin(getAccumSema(), Saturated(getUSAccumSema()), 677 -8388608); 678 CheckSaturatedConversionMin(getAccumSema(), Saturated(getPadUSAccumSema()), 679 -8388608); 680 CheckSaturatedConversionMin(getLAccumSema(), Saturated(getSAccumSema()), 681 -549755813888); 682 CheckSaturatedConversionMin(getLAccumSema(), Saturated(getUSAccumSema()), 683 -549755813888); 684 CheckSaturatedConversionMin(getLAccumSema(), Saturated(getPadUSAccumSema()), 685 -549755813888); 686 } 687 688 TEST(FixedPoint, GetValueSignAfterConversion) { 689 APFixedPoint Fixed(255 << 7, getSAccumSema()); 690 ASSERT_TRUE(Fixed.getValue().isSigned()); 691 APFixedPoint UFixed = Fixed.convert(getUSAccumSema()); 692 ASSERT_TRUE(UFixed.getValue().isUnsigned()); 693 ASSERT_EQ(UFixed.getValue(), APSInt::getUnsigned(255 << 8).extOrTrunc(16)); 694 } 695 696 TEST(FixedPoint, ModularWrapAround) { 697 // Positive to negative 698 APFixedPoint Val = APFixedPoint(1ULL << 7, getSAccumSema()); 699 ASSERT_EQ(Val.convert(getLFractSema()).getValue(), -(1ULL << 31)); 700 701 Val = APFixedPoint(1ULL << 23, getAccumSema()); 702 ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), -(1ULL << 15)); 703 704 Val = APFixedPoint(1ULL << 47, getLAccumSema()); 705 ASSERT_EQ(Val.convert(getAccumSema()).getValue(), -(1ULL << 31)); 706 707 // Negative to positive 708 Val = APFixedPoint(/*-1.5*/ -192, getSAccumSema()); 709 ASSERT_EQ(Val.convert(getLFractSema()).getValue(), 1ULL << 30); 710 711 Val = APFixedPoint(-(257 << 15), getAccumSema()); 712 ASSERT_EQ(Val.convert(getSAccumSema()).getValue(), 255 << 7); 713 714 Val = APFixedPoint(-(65537ULL << 31), getLAccumSema()); 715 ASSERT_EQ(Val.convert(getAccumSema()).getValue(), 65535 << 15); 716 717 // Signed to unsigned 718 Val = APFixedPoint(-(1 << 7), getSAccumSema()); 719 ASSERT_EQ(Val.convert(getUSAccumSema()).getValue(), 255 << 8); 720 721 Val = APFixedPoint(-(1 << 15), getAccumSema()); 722 ASSERT_EQ(Val.convert(getUAccumSema()).getValue(), 65535ULL << 16); 723 724 Val = APFixedPoint(-(1ULL << 31), getLAccumSema()); 725 ASSERT_EQ(Val.convert(getULAccumSema()).getValue().getZExtValue(), 726 4294967295ULL << 32); 727 } 728 729 enum OvfKind { MinSat, MaxSat }; 730 731 void CheckFloatToFixedConversion(APFloat &Val, const FixedPointSemantics &Sema, 732 int64_t ExpectedNonSat) { 733 bool Ovf; 734 ASSERT_EQ(APFixedPoint::getFromFloatValue(Val, Sema, &Ovf).getValue(), 735 ExpectedNonSat); 736 ASSERT_EQ(Ovf, false); 737 ASSERT_EQ( 738 APFixedPoint::getFromFloatValue(Val, Saturated(Sema), &Ovf).getValue(), 739 ExpectedNonSat); 740 ASSERT_EQ(Ovf, false); 741 } 742 743 void CheckFloatToFixedConversion(APFloat &Val, const FixedPointSemantics &Sema, 744 OvfKind ExpectedOvf) { 745 bool Ovf; 746 (void)APFixedPoint::getFromFloatValue(Val, Sema, &Ovf); 747 ASSERT_EQ(Ovf, true); 748 ASSERT_EQ( 749 APFixedPoint::getFromFloatValue(Val, Saturated(Sema), &Ovf).getValue(), 750 (ExpectedOvf == MinSat ? APFixedPoint::getMin(Sema) 751 : APFixedPoint::getMax(Sema)) 752 .getValue()); 753 ASSERT_EQ(Ovf, false); 754 } 755 756 TEST(FixedPoint, toString) { 757 ASSERT_EQ(APFixedPoint::getMax(getS16Neg18()).toString(), 758 "0.124996185302734375"); 759 ASSERT_EQ(APFixedPoint::getMin(getS16Neg18()) 760 .add(APFixedPoint(1, getS16Neg18())) 761 .toString(), 762 "-0.124996185302734375"); 763 ASSERT_EQ(APFixedPoint::getMin(getS16Neg18()).toString(), "-0.125"); 764 ASSERT_EQ(APFixedPoint::getMax(getU8Neg10()).toString(), "0.2490234375"); 765 ASSERT_EQ(APFixedPoint::getMin(getU8Neg10()).toString(), "0.0"); 766 ASSERT_EQ(APFixedPoint::getMax(getS32Pos2()).toString(), "8589934588.0"); 767 ASSERT_EQ(APFixedPoint::getMin(getS32Pos2()) 768 .add(APFixedPoint(1, getS32Pos2())) 769 .toString(), 770 "-8589934588.0"); 771 ASSERT_EQ(APFixedPoint::getMin(getS32Pos2()).toString(), "-8589934592.0"); 772 ASSERT_EQ(APFixedPoint::getMax(getU8Pos4()).toString(), "4080.0"); 773 ASSERT_EQ(APFixedPoint::getMin(getU8Pos4()).toString(), "0.0"); 774 } 775 776 TEST(FixedPoint, FloatToFixed) { 777 APFloat Val(0.0f); 778 779 // Simple exact fraction 780 Val = APFloat(0.75f); 781 CheckFloatToFixedConversion(Val, getSAccumSema(), 3ULL << 5); 782 CheckFloatToFixedConversion(Val, getAccumSema(), 3ULL << 13); 783 CheckFloatToFixedConversion(Val, getLAccumSema(), 3ULL << 29); 784 785 CheckFloatToFixedConversion(Val, getUSAccumSema(), 3ULL << 6); 786 CheckFloatToFixedConversion(Val, getUAccumSema(), 3ULL << 14); 787 CheckFloatToFixedConversion(Val, getULAccumSema(), 3ULL << 30); 788 789 CheckFloatToFixedConversion(Val, getSFractSema(), 3ULL << 5); 790 CheckFloatToFixedConversion(Val, getFractSema(), 3ULL << 13); 791 CheckFloatToFixedConversion(Val, getLFractSema(), 3ULL << 29); 792 793 CheckFloatToFixedConversion(Val, getUSFractSema(), 3ULL << 6); 794 CheckFloatToFixedConversion(Val, getUFractSema(), 3ULL << 14); 795 CheckFloatToFixedConversion(Val, getULFractSema(), 3ULL << 30); 796 797 CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); 798 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 799 CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); 800 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 801 802 // Simple negative exact fraction 803 Val = APFloat(-0.75f); 804 CheckFloatToFixedConversion(Val, getSAccumSema(), -3ULL << 5); 805 CheckFloatToFixedConversion(Val, getAccumSema(), -3ULL << 13); 806 CheckFloatToFixedConversion(Val, getLAccumSema(), -3ULL << 29); 807 808 CheckFloatToFixedConversion(Val, getUSAccumSema(), MinSat); 809 CheckFloatToFixedConversion(Val, getUAccumSema(), MinSat); 810 CheckFloatToFixedConversion(Val, getULAccumSema(), MinSat); 811 812 CheckFloatToFixedConversion(Val, getSFractSema(), -3ULL << 5); 813 CheckFloatToFixedConversion(Val, getFractSema(), -3ULL << 13); 814 CheckFloatToFixedConversion(Val, getLFractSema(), -3ULL << 29); 815 816 CheckFloatToFixedConversion(Val, getUSFractSema(), MinSat); 817 CheckFloatToFixedConversion(Val, getUFractSema(), MinSat); 818 CheckFloatToFixedConversion(Val, getULFractSema(), MinSat); 819 820 CheckFloatToFixedConversion(Val, getU8Neg10(), MinSat); 821 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 822 CheckFloatToFixedConversion(Val, getS16Neg18(), MinSat); 823 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 824 825 // Highly precise fraction 826 Val = APFloat(0.999999940395355224609375f); 827 CheckFloatToFixedConversion(Val, getSAccumSema(), 0x7FULL); 828 CheckFloatToFixedConversion(Val, getAccumSema(), 0x7FFFULL); 829 CheckFloatToFixedConversion(Val, getLAccumSema(), 0xFFFFFFULL << 7); 830 831 CheckFloatToFixedConversion(Val, getUSAccumSema(), 0xFFULL); 832 CheckFloatToFixedConversion(Val, getUAccumSema(), 0xFFFFULL); 833 CheckFloatToFixedConversion(Val, getULAccumSema(), 0xFFFFFFULL << 8); 834 835 CheckFloatToFixedConversion(Val, getSFractSema(), 0x7FULL); 836 CheckFloatToFixedConversion(Val, getFractSema(), 0x7FFFULL); 837 CheckFloatToFixedConversion(Val, getLFractSema(), 0xFFFFFFULL << 7); 838 839 CheckFloatToFixedConversion(Val, getUSFractSema(), 0xFFULL); 840 CheckFloatToFixedConversion(Val, getUFractSema(), 0xFFFFULL); 841 CheckFloatToFixedConversion(Val, getULFractSema(), 0xFFFFFFULL << 8); 842 843 CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); 844 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 845 CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); 846 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 847 848 // Integral and fraction 849 Val = APFloat(17.99609375f); 850 CheckFloatToFixedConversion(Val, getSAccumSema(), 0x11FFULL >> 1); 851 CheckFloatToFixedConversion(Val, getAccumSema(), 0x11FFULL << 7); 852 CheckFloatToFixedConversion(Val, getLAccumSema(), 0x11FFULL << 23); 853 854 CheckFloatToFixedConversion(Val, getUSAccumSema(), 0x11FFULL); 855 CheckFloatToFixedConversion(Val, getUAccumSema(), 0x11FFULL << 8); 856 CheckFloatToFixedConversion(Val, getULAccumSema(), 0x11FFULL << 24); 857 858 CheckFloatToFixedConversion(Val, getSFractSema(), MaxSat); 859 CheckFloatToFixedConversion(Val, getFractSema(), MaxSat); 860 CheckFloatToFixedConversion(Val, getLFractSema(), MaxSat); 861 862 CheckFloatToFixedConversion(Val, getUSFractSema(), MaxSat); 863 CheckFloatToFixedConversion(Val, getUFractSema(), MaxSat); 864 CheckFloatToFixedConversion(Val, getULFractSema(), MaxSat); 865 866 CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); 867 CheckFloatToFixedConversion(Val, getU8Pos4(), 1); 868 CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); 869 CheckFloatToFixedConversion(Val, getS32Pos2(), 1 << 2); 870 871 // Negative integral and fraction 872 Val = APFloat(-17.99609375f); 873 CheckFloatToFixedConversion(Val, getSAccumSema(), -0x11FELL >> 1); 874 CheckFloatToFixedConversion(Val, getAccumSema(), -0x11FFULL << 7); 875 CheckFloatToFixedConversion(Val, getLAccumSema(), -0x11FFULL << 23); 876 877 CheckFloatToFixedConversion(Val, getUSAccumSema(), MinSat); 878 CheckFloatToFixedConversion(Val, getUAccumSema(), MinSat); 879 CheckFloatToFixedConversion(Val, getULAccumSema(), MinSat); 880 881 CheckFloatToFixedConversion(Val, getSFractSema(), MinSat); 882 CheckFloatToFixedConversion(Val, getFractSema(), MinSat); 883 CheckFloatToFixedConversion(Val, getLFractSema(), MinSat); 884 885 CheckFloatToFixedConversion(Val, getUSFractSema(), MinSat); 886 CheckFloatToFixedConversion(Val, getUFractSema(), MinSat); 887 CheckFloatToFixedConversion(Val, getULFractSema(), MinSat); 888 889 CheckFloatToFixedConversion(Val, getU8Neg10(), MinSat); 890 CheckFloatToFixedConversion(Val, getU8Pos4(), MinSat); 891 CheckFloatToFixedConversion(Val, getS16Neg18(), MinSat); 892 CheckFloatToFixedConversion(Val, getS32Pos2(), -4); 893 894 // Very large value 895 Val = APFloat(1.0e38f); 896 CheckFloatToFixedConversion(Val, getSAccumSema(), MaxSat); 897 CheckFloatToFixedConversion(Val, getAccumSema(), MaxSat); 898 CheckFloatToFixedConversion(Val, getLAccumSema(), MaxSat); 899 900 CheckFloatToFixedConversion(Val, getUSAccumSema(), MaxSat); 901 CheckFloatToFixedConversion(Val, getUAccumSema(), MaxSat); 902 CheckFloatToFixedConversion(Val, getULAccumSema(), MaxSat); 903 904 CheckFloatToFixedConversion(Val, getSFractSema(), MaxSat); 905 CheckFloatToFixedConversion(Val, getFractSema(), MaxSat); 906 CheckFloatToFixedConversion(Val, getLFractSema(), MaxSat); 907 908 CheckFloatToFixedConversion(Val, getUSFractSema(), MaxSat); 909 CheckFloatToFixedConversion(Val, getUFractSema(), MaxSat); 910 CheckFloatToFixedConversion(Val, getULFractSema(), MaxSat); 911 912 CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); 913 CheckFloatToFixedConversion(Val, getU8Pos4(), MaxSat); 914 CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); 915 CheckFloatToFixedConversion(Val, getS32Pos2(), MaxSat); 916 917 // Very small value 918 Val = APFloat(1.0e-38f); 919 CheckFloatToFixedConversion(Val, getSAccumSema(), 0); 920 CheckFloatToFixedConversion(Val, getAccumSema(), 0); 921 CheckFloatToFixedConversion(Val, getLAccumSema(), 0); 922 923 CheckFloatToFixedConversion(Val, getUSAccumSema(), 0); 924 CheckFloatToFixedConversion(Val, getUAccumSema(), 0); 925 CheckFloatToFixedConversion(Val, getULAccumSema(), 0); 926 927 CheckFloatToFixedConversion(Val, getSFractSema(), 0); 928 CheckFloatToFixedConversion(Val, getFractSema(), 0); 929 CheckFloatToFixedConversion(Val, getLFractSema(), 0); 930 931 CheckFloatToFixedConversion(Val, getUSFractSema(), 0); 932 CheckFloatToFixedConversion(Val, getUFractSema(), 0); 933 CheckFloatToFixedConversion(Val, getULFractSema(), 0); 934 935 CheckFloatToFixedConversion(Val, getU8Neg10(), 0); 936 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 937 CheckFloatToFixedConversion(Val, getS16Neg18(), 0); 938 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 939 940 // Half conversion 941 Val = APFloat(0.99951171875f); 942 bool Ignored; 943 Val.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored); 944 945 CheckFloatToFixedConversion(Val, getSAccumSema(), 0x7FULL); 946 CheckFloatToFixedConversion(Val, getAccumSema(), 0x7FFULL << 4); 947 CheckFloatToFixedConversion(Val, getLAccumSema(), 0x7FFULL << 20); 948 949 CheckFloatToFixedConversion(Val, getUSAccumSema(), 0xFFULL); 950 CheckFloatToFixedConversion(Val, getUAccumSema(), 0xFFEULL << 4); 951 CheckFloatToFixedConversion(Val, getULAccumSema(), 0xFFEULL << 20); 952 953 CheckFloatToFixedConversion(Val, getSFractSema(), 0x7FULL); 954 CheckFloatToFixedConversion(Val, getFractSema(), 0x7FFULL << 4); 955 CheckFloatToFixedConversion(Val, getLFractSema(), 0x7FFULL << 20); 956 957 CheckFloatToFixedConversion(Val, getUSFractSema(), 0xFFULL); 958 CheckFloatToFixedConversion(Val, getUFractSema(), 0xFFEULL << 4); 959 CheckFloatToFixedConversion(Val, getULFractSema(), 0xFFEULL << 20); 960 961 CheckFloatToFixedConversion(Val, getU8Neg10(), MaxSat); 962 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 963 CheckFloatToFixedConversion(Val, getS16Neg18(), MaxSat); 964 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 965 966 Val = APFloat(0.124996185302734375); 967 CheckFloatToFixedConversion(Val, getU8Neg10(), 0x7f); 968 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 969 CheckFloatToFixedConversion(Val, getS16Neg18(), 0x7fff); 970 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 971 972 Val = APFloat(-0.124996185302734375); 973 CheckFloatToFixedConversion(Val, getU8Neg10(), MinSat); 974 CheckFloatToFixedConversion(Val, getU8Pos4(), 0); 975 CheckFloatToFixedConversion(Val, getS16Neg18(), -0x7fff); 976 CheckFloatToFixedConversion(Val, getS32Pos2(), 0); 977 } 978 979 void CheckFixedToFloatConversion(int64_t Val, const FixedPointSemantics &Sema, 980 float Result) { 981 APFixedPoint FXVal(Val, Sema); 982 APFloat APRes(Result); 983 ASSERT_EQ(FXVal.convertToFloat(APFloat::IEEEsingle()), APRes); 984 } 985 986 void CheckFixedToHalfConversion(int64_t Val, const FixedPointSemantics &Sema, 987 float Result) { 988 APFixedPoint FXVal(Val, Sema); 989 APFloat APRes(Result); 990 bool Ignored; 991 APRes.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored); 992 ASSERT_EQ(FXVal.convertToFloat(APFloat::IEEEhalf()), APRes); 993 } 994 995 TEST(FixedPoint, FixedToFloat) { 996 int64_t Val = 0x1ULL; 997 CheckFixedToFloatConversion(Val, getSAccumSema(), 0.0078125f); 998 CheckFixedToFloatConversion(Val, getFractSema(), 0.000030517578125f); 999 CheckFixedToFloatConversion(Val, getAccumSema(), 0.000030517578125f); 1000 CheckFixedToFloatConversion(Val, getLFractSema(), 1001 0.0000000004656612873077392578125f); 1002 1003 CheckFixedToFloatConversion(Val, getUSAccumSema(), 0.00390625f); 1004 CheckFixedToFloatConversion(Val, getUFractSema(), 0.0000152587890625f); 1005 CheckFixedToFloatConversion(Val, getUAccumSema(), 0.0000152587890625f); 1006 CheckFixedToFloatConversion(Val, getULFractSema(), 1007 0.00000000023283064365386962890625f); 1008 1009 CheckFixedToFloatConversion(Val, getU8Neg10(), 0.0009765625f); 1010 CheckFixedToFloatConversion(Val, getU8Pos4(), 16.0f); 1011 CheckFixedToFloatConversion(Val, getS16Neg18(), 0.000003814697265625f); 1012 CheckFixedToFloatConversion(Val, getS32Pos2(), 4.0f); 1013 1014 Val = 0x7FULL; 1015 CheckFixedToFloatConversion(Val, getSAccumSema(), 0.9921875f); 1016 CheckFixedToFloatConversion(Val, getFractSema(), 0.003875732421875f); 1017 CheckFixedToFloatConversion(Val, getAccumSema(), 0.003875732421875f); 1018 CheckFixedToFloatConversion(Val, getLFractSema(), 1019 0.0000000591389834880828857421875f); 1020 1021 CheckFixedToFloatConversion(Val, getUSAccumSema(), 0.49609375f); 1022 CheckFixedToFloatConversion(Val, getUFractSema(), 0.0019378662109375f); 1023 CheckFixedToFloatConversion(Val, getUAccumSema(), 0.0019378662109375f); 1024 CheckFixedToFloatConversion(Val, getULFractSema(), 1025 0.00000002956949174404144287109375f); 1026 1027 CheckFixedToFloatConversion(Val, getU8Neg10(), 0.1240234375f); 1028 CheckFixedToFloatConversion(Val, getU8Pos4(), 2032.0f); 1029 CheckFixedToFloatConversion(Val, getS16Neg18(), 0.000484466552734375f); 1030 CheckFixedToFloatConversion(Val, getS32Pos2(), 508.0f); 1031 1032 Val = -0x1ULL; 1033 CheckFixedToFloatConversion(Val, getSAccumSema(), -0.0078125f); 1034 CheckFixedToFloatConversion(Val, getFractSema(), -0.000030517578125f); 1035 CheckFixedToFloatConversion(Val, getAccumSema(), -0.000030517578125f); 1036 CheckFixedToFloatConversion(Val, getLFractSema(), 1037 -0.0000000004656612873077392578125f); 1038 1039 CheckFixedToFloatConversion(Val, getU8Neg10(), 0.249023437f); 1040 CheckFixedToFloatConversion(Val, getU8Pos4(), 4080.0f); 1041 CheckFixedToFloatConversion(Val, getS16Neg18(), -0.000003814697265625f); 1042 CheckFixedToFloatConversion(Val, getS32Pos2(), -4.0f); 1043 1044 CheckFixedToFloatConversion(-0x80ULL, getSAccumSema(), -1.0f); 1045 CheckFixedToFloatConversion(-0x8000ULL, getFractSema(), -1.0f); 1046 CheckFixedToFloatConversion(-0x8000ULL, getAccumSema(), -1.0f); 1047 CheckFixedToFloatConversion(-0x80000000ULL, getLFractSema(), -1.0f); 1048 1049 Val = 0xAFAULL; 1050 CheckFixedToFloatConversion(Val, getSAccumSema(), 21.953125f); 1051 CheckFixedToFloatConversion(Val, getFractSema(), 0.08575439453125f); 1052 CheckFixedToFloatConversion(Val, getAccumSema(), 0.08575439453125f); 1053 CheckFixedToFloatConversion(Val, getLFractSema(), 1054 0.000001308508217334747314453125f); 1055 1056 CheckFixedToFloatConversion(Val, getUSAccumSema(), 10.9765625f); 1057 CheckFixedToFloatConversion(Val, getUFractSema(), 0.042877197265625f); 1058 CheckFixedToFloatConversion(Val, getUAccumSema(), 0.042877197265625f); 1059 CheckFixedToFloatConversion(Val, getULFractSema(), 1060 0.0000006542541086673736572265625f); 1061 1062 CheckFixedToFloatConversion(Val, getS16Neg18(), 0.01071929931640625f); 1063 CheckFixedToFloatConversion(Val, getS32Pos2(), 11240.0f); 1064 1065 Val = -0xAFAULL; 1066 CheckFixedToFloatConversion(Val, getSAccumSema(), -21.953125f); 1067 CheckFixedToFloatConversion(Val, getFractSema(), -0.08575439453125f); 1068 CheckFixedToFloatConversion(Val, getAccumSema(), -0.08575439453125f); 1069 CheckFixedToFloatConversion(Val, getLFractSema(), 1070 -0.000001308508217334747314453125f); 1071 1072 CheckFixedToFloatConversion(Val, getS16Neg18(), -0.01071929931640625f); 1073 CheckFixedToFloatConversion(Val, getS32Pos2(), -11240.0f); 1074 1075 Val = 0x40000080ULL; 1076 CheckFixedToFloatConversion(Val, getAccumSema(), 32768.00390625f); 1077 CheckFixedToFloatConversion(Val, getLFractSema(), 1078 0.500000059604644775390625f); 1079 1080 CheckFixedToFloatConversion(Val, getUAccumSema(), 16384.001953125f); 1081 CheckFixedToFloatConversion(Val, getULFractSema(), 1082 0.2500000298023223876953125f); 1083 1084 CheckFixedToFloatConversion(Val, getS32Pos2(), 4294967808.0f); 1085 1086 Val = 0x40000040ULL; 1087 CheckFixedToFloatConversion(Val, getAccumSema(), 32768.0f); 1088 CheckFixedToFloatConversion(Val, getLFractSema(), 0.5f); 1089 1090 CheckFixedToFloatConversion(Val, getUAccumSema(), 16384.0f); 1091 CheckFixedToFloatConversion(Val, getULFractSema(), 0.25f); 1092 1093 CheckFixedToFloatConversion(Val, getS32Pos2(), 4294967552.0f); 1094 1095 Val = 0x7FF0ULL; 1096 CheckFixedToHalfConversion(Val, getAccumSema(), 0.99951171875f); 1097 CheckFixedToHalfConversion(Val, getLFractSema(), 0.000015251338481903076171875f); 1098 1099 CheckFixedToHalfConversion(Val, getUAccumSema(), 0.499755859375f); 1100 CheckFixedToHalfConversion(Val, getULFractSema(), 0.0000076256692409515380859375f); 1101 1102 CheckFixedToFloatConversion(Val, getS32Pos2(), 131008.0f); 1103 } 1104 1105 void CheckAdd(const APFixedPoint &Lhs, const APFixedPoint &Rhs, 1106 const APFixedPoint &Res) { 1107 bool Overflow = false; 1108 APFixedPoint Result = Lhs.add(Rhs, &Overflow); 1109 ASSERT_FALSE(Overflow); 1110 ASSERT_EQ(Result.getSemantics(), Res.getSemantics()); 1111 ASSERT_EQ(Result, Res); 1112 } 1113 1114 void CheckAddOverflow(const APFixedPoint &Lhs, const APFixedPoint &Rhs) { 1115 bool Overflow = false; 1116 APFixedPoint Result = Lhs.add(Rhs, &Overflow); 1117 ASSERT_TRUE(Overflow); 1118 } 1119 1120 TEST(FixedPoint, add) { 1121 CheckAdd(APFixedPoint(1, getS32Pos2()), APFixedPoint(1, getS32Pos2()), 1122 APFixedPoint(2, getS32Pos2())); 1123 CheckAdd(APFixedPoint(1, getS16Neg18()), APFixedPoint(1, getS16Neg18()), 1124 APFixedPoint(2, getS16Neg18())); 1125 CheckAdd(APFixedPoint(1, getU8Neg10()), APFixedPoint(1, getU8Neg10()), 1126 APFixedPoint(2, getU8Neg10())); 1127 CheckAdd(APFixedPoint(1, getU8Pos4()), APFixedPoint(1, getU8Pos4()), 1128 APFixedPoint(2, getU8Pos4())); 1129 1130 CheckAdd(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS32Pos2()), 1131 APFixedPoint(12, getS32Pos2())); 1132 CheckAdd(APFixedPoint(11, getS16Neg18()), APFixedPoint(1, getS16Neg18()), 1133 APFixedPoint(12, getS16Neg18())); 1134 CheckAdd(APFixedPoint(11, getU8Neg10()), APFixedPoint(1, getU8Neg10()), 1135 APFixedPoint(12, getU8Neg10())); 1136 CheckAdd(APFixedPoint(11, getU8Pos4()), APFixedPoint(1, getU8Pos4()), 1137 APFixedPoint(12, getU8Pos4())); 1138 1139 CheckAdd(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS16Neg18()), 1140 APFixedPoint(11534337, 1141 FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, 1142 true, false, false))); 1143 CheckAdd( 1144 APFixedPoint(11, getU8Neg10()), APFixedPoint(-9472, getS16Neg18()), 1145 APFixedPoint(-6656, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1146 true, false, false))); 1147 CheckAddOverflow( 1148 APFixedPoint::getMax(getU8Neg10()), APFixedPoint::getMax(getS16Neg18())); 1149 CheckAdd(APFixedPoint::getMin(getU8Neg10()), 1150 APFixedPoint::getMin(getS16Neg18()), 1151 APFixedPoint::getMin(getS16Neg18()) 1152 .convert(FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1153 true, false, false))); 1154 CheckAddOverflow(APFixedPoint::getMin(getS32Pos2()), 1155 APFixedPoint::getMin(getS16Neg18())); 1156 } 1157 1158 void CheckMul(const APFixedPoint &Lhs, const APFixedPoint &Rhs, 1159 const APFixedPoint &Res) { 1160 bool Overflow = false; 1161 APFixedPoint Result = Lhs.mul(Rhs, &Overflow); 1162 ASSERT_FALSE(Overflow); 1163 ASSERT_EQ(Result.getSemantics(), Res.getSemantics()); 1164 ASSERT_EQ(Result, Res); 1165 } 1166 1167 void CheckMulOverflow(const APFixedPoint &Lhs, const APFixedPoint &Rhs) { 1168 bool Overflow = false; 1169 APFixedPoint Result = Lhs.mul(Rhs, &Overflow); 1170 ASSERT_TRUE(Overflow); 1171 } 1172 1173 TEST(FixedPoint, mul) { 1174 CheckMul(APFixedPoint(1, getS32Pos2()), APFixedPoint(1, getS32Pos2()), 1175 APFixedPoint(4, getS32Pos2())); 1176 CheckMul(APFixedPoint(1, getS16Neg18()), APFixedPoint(1, getS16Neg18()), 1177 APFixedPoint(0, getS16Neg18())); 1178 CheckMul(APFixedPoint(1, getU8Neg10()), APFixedPoint(1, getU8Neg10()), 1179 APFixedPoint(0, getU8Neg10())); 1180 CheckMul(APFixedPoint(1, getU8Pos4()), APFixedPoint(1, getU8Pos4()), 1181 APFixedPoint(16, getU8Pos4())); 1182 1183 CheckMul(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS32Pos2()), 1184 APFixedPoint(44, getS32Pos2())); 1185 CheckMul(APFixedPoint(11, getS16Neg18()), APFixedPoint(1, getS16Neg18()), 1186 APFixedPoint(0, getS16Neg18())); 1187 CheckMul(APFixedPoint(11, getU8Neg10()), APFixedPoint(1, getU8Neg10()), 1188 APFixedPoint(0, getU8Neg10())); 1189 CheckMul(APFixedPoint(11, getU8Pos4()), APFixedPoint(1, getU8Pos4()), 1190 APFixedPoint(176, getU8Pos4())); 1191 1192 CheckMul(APFixedPoint(512, getS16Neg18()), APFixedPoint(512, getS16Neg18()), 1193 APFixedPoint(1, getS16Neg18())); 1194 CheckMul(APFixedPoint(32, getU8Neg10()), APFixedPoint(32, getU8Neg10()), 1195 APFixedPoint(1, getU8Neg10())); 1196 1197 CheckMul(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS16Neg18()), 1198 APFixedPoint(44, 1199 FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, 1200 true, false, false))); 1201 CheckMul( 1202 APFixedPoint(11, getU8Neg10()), APFixedPoint(-9472, getS16Neg18()), 1203 APFixedPoint(-102, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1204 true, false, false))); 1205 CheckMul( 1206 APFixedPoint::getMax(getU8Neg10()), APFixedPoint::getMax(getS16Neg18()), 1207 APFixedPoint(8159, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1208 true, false, false))); 1209 CheckMul( 1210 APFixedPoint::getMin(getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), 1211 APFixedPoint(0, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1212 true, false, false))); 1213 CheckMul(APFixedPoint::getMin(getS32Pos2()), 1214 APFixedPoint::getMin(getS16Neg18()), 1215 APFixedPoint(281474976710656, 1216 FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, 1217 true, false, false))); 1218 CheckMulOverflow(APFixedPoint::getMax(getS32Pos2()), APFixedPoint::getMax(getU8Pos4())); 1219 CheckMulOverflow(APFixedPoint::getMin(getS32Pos2()), APFixedPoint::getMax(getU8Pos4())); 1220 } 1221 1222 void CheckDiv(const APFixedPoint &Lhs, const APFixedPoint &Rhs, 1223 const APFixedPoint &Expected) { 1224 bool Overflow = false; 1225 APFixedPoint Result = Lhs.div(Rhs, &Overflow); 1226 ASSERT_FALSE(Overflow); 1227 ASSERT_EQ(Result.getSemantics(), Expected.getSemantics()); 1228 ASSERT_EQ(Result, Expected); 1229 } 1230 1231 void CheckDivOverflow(const APFixedPoint &Lhs, const APFixedPoint &Rhs) { 1232 bool Overflow = false; 1233 APFixedPoint Result = Lhs.div(Rhs, &Overflow); 1234 ASSERT_TRUE(Overflow); 1235 } 1236 1237 TEST(FixedPoint, div) { 1238 CheckDiv(APFixedPoint(1, getS32Pos2()), APFixedPoint(1, getS32Pos2()), 1239 APFixedPoint(0, getS32Pos2())); 1240 CheckDivOverflow(APFixedPoint(1, getS16Neg18()), APFixedPoint(1, getS16Neg18())); 1241 CheckDivOverflow(APFixedPoint(1, getU8Neg10()), APFixedPoint(1, getU8Neg10())); 1242 CheckDiv(APFixedPoint(1, getU8Pos4()), APFixedPoint(1, getU8Pos4()), 1243 APFixedPoint(0, getU8Pos4())); 1244 1245 CheckDiv(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS32Pos2()), 1246 APFixedPoint(2, getS32Pos2())); 1247 CheckDiv(APFixedPoint(11, getU8Pos4()), APFixedPoint(1, getU8Pos4()), 1248 APFixedPoint(0, getU8Pos4())); 1249 1250 CheckDiv(APFixedPoint(11, getS32Pos2()), APFixedPoint(1, getS16Neg18()), 1251 APFixedPoint(3023656976384, 1252 FixedPointSemantics(52, FixedPointSemantics::Lsb{-18}, 1253 true, false, false))); 1254 CheckDiv(APFixedPoint(11, getU8Neg10()), APFixedPoint(-11264, getS16Neg18()), 1255 APFixedPoint::getMin(FixedPointSemantics( 1256 17, FixedPointSemantics::Lsb{-18}, true, false, false))); 1257 CheckDiv(APFixedPoint(11, getU8Neg10()), APFixedPoint(11265, getS16Neg18()), 1258 APFixedPoint(0xfffa, 1259 FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1260 true, false, false))); 1261 CheckDivOverflow(APFixedPoint(11, getU8Neg10()), 1262 APFixedPoint(11264, getS16Neg18())); 1263 1264 CheckDivOverflow(APFixedPoint(11, getU8Neg10()), 1265 APFixedPoint(-9472, getS16Neg18())); 1266 CheckDivOverflow(APFixedPoint::getMax(getU8Neg10()), 1267 APFixedPoint::getMax(getS16Neg18())); 1268 CheckDiv( 1269 APFixedPoint::getMin(getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), 1270 APFixedPoint(0, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1271 true, false, false))); 1272 CheckDiv( 1273 APFixedPoint(1, getU8Neg10()), APFixedPoint::getMin(getS16Neg18()), 1274 APFixedPoint(-2048, FixedPointSemantics(17, FixedPointSemantics::Lsb{-18}, 1275 true, false, false))); 1276 } 1277 1278 TEST(FixedPoint, semanticsSerialization) { 1279 auto roundTrip = [](FixedPointSemantics FPS) -> bool { 1280 uint32_t I = FPS.toOpaqueInt(); 1281 FixedPointSemantics FPS2 = FixedPointSemantics::getFromOpaqueInt(I); 1282 return FPS == FPS2; 1283 }; 1284 1285 ASSERT_TRUE(roundTrip(getS32Pos2())); 1286 ASSERT_TRUE(roundTrip(getU8Pos4())); 1287 ASSERT_TRUE(roundTrip(getS16Neg18())); 1288 ASSERT_TRUE(roundTrip(getU8Neg10())); 1289 ASSERT_TRUE(roundTrip(getPadULFractSema())); 1290 ASSERT_TRUE(roundTrip(getPadUFractSema())); 1291 ASSERT_TRUE(roundTrip(getPadUSFractSema())); 1292 ASSERT_TRUE(roundTrip(getPadULAccumSema())); 1293 ASSERT_TRUE(roundTrip(getPadUAccumSema())); 1294 ASSERT_TRUE(roundTrip(getPadUSAccumSema())); 1295 ASSERT_TRUE(roundTrip(getULFractSema())); 1296 ASSERT_TRUE(roundTrip(getUFractSema())); 1297 ASSERT_TRUE(roundTrip(getUSFractSema())); 1298 ASSERT_TRUE(roundTrip(getULAccumSema())); 1299 ASSERT_TRUE(roundTrip(getUAccumSema())); 1300 ASSERT_TRUE(roundTrip(getUSAccumSema())); 1301 ASSERT_TRUE(roundTrip(getLFractSema())); 1302 ASSERT_TRUE(roundTrip(getFractSema())); 1303 ASSERT_TRUE(roundTrip(getSFractSema())); 1304 ASSERT_TRUE(roundTrip(getLAccumSema())); 1305 ASSERT_TRUE(roundTrip(getAccumSema())); 1306 ASSERT_TRUE(roundTrip(getSAccumSema())); 1307 } 1308 1309 } // namespace 1310