[flang] More intrinsics
authorpeter klausler <pklausler@nvidia.com>
Thu, 31 May 2018 23:15:18 +0000 (16:15 -0700)
committerpeter klausler <pklausler@nvidia.com>
Thu, 14 Jun 2018 20:52:28 +0000 (13:52 -0700)
Original-commit: flang-compiler/f18@55f974be59e2a691439159c99bef0f3250eb8fb3
Reviewed-on: https://github.com/flang-compiler/f18/pull/101
Tree-same-pre-rewrite: false

flang/lib/evaluate/fixed-point.h
flang/test/evaluate/fixed-point-test.cc

index 87588e0..d5e9559 100644 (file)
@@ -22,6 +22,7 @@
 // ("Signed" here means two's-complement, just to be clear.)
 
 #include "leading-zero-bit-count.h"
+#include "bit-population-count.h"
 #include <cinttypes>
 #include <climits>
 #include <cstddef>
@@ -138,6 +139,22 @@ public:
     }
   }
 
+  static constexpr FixedPoint HUGE() { return MASKR(bits-1); }
+
+  // Returns the number of full decimal digits that can be represented.
+  static constexpr int RANGE() {
+    if (bits < 4) {
+      return 0;
+    }
+    FixedPoint x{HUGE}, ten{std::uint64_t{10}};
+    int digits{0};
+    while (x.Compare(ten) != Ordering::Less) {
+      ++digits;
+      x = x.DivideUnsigned(ten).quotient;
+    }
+    return digits;
+  }
+
   constexpr FixedPoint &operator=(const FixedPoint &) = default;
 
   constexpr bool IsZero() const {
@@ -181,9 +198,35 @@ public:
     return bits;
   }
 
-  // POPCNT intrinsic
-  // TODO pmk
-  // pmk also POPPAR
+  // Count the number of bit positions that are set.
+  constexpr int POPCNT() const {
+    int count{0};
+    for (int j{0}; j < parts; ++j) {
+      count += BitPopulationCount(part_[j]);
+    }
+    return count;
+  }
+
+  // True when POPCNT is odd.
+  constexpr bool POPPAR() const { return POPCNT() & 1; }
+
+  constexpr int TRAILZ() const {
+    auto minus1{AddUnsigned(MASKR(bits))};  // { x-1, carry = x > 0 }
+    if (!minus1.carry) {
+      return bits;  // was zero
+    } else {
+      // x ^ (x-1) has all bits set at and below original least-order set bit.
+      return POPCNT(IEOR(minus1.value)) - 1;
+    }
+  }
+
+  constexpr bool BTEST(int pos) const {
+    if (pos < 0 || pos >= bits) {
+      return false;
+    } else {
+      return (LEPart(pos / partBits) >> (pos % partBits)) & 1;
+    }
+  }
 
   constexpr Ordering CompareUnsigned(const FixedPoint &y) const {
     for (int j{parts}; j-- > 0;) {
@@ -197,6 +240,15 @@ public:
     return Ordering::Equal;
   }
 
+  constexpr bool BGE(const FixedPoint &y) const {
+    return CompareUnsigned(y) != Ordering::Less;
+  }
+  constexpr bool BGT(const FixedPoint &y) const {
+    return CompareUnsigned(y) == Ordering::Greater;
+  }
+  constexpr bool BLE(const FixedPoint &y) const { return !BGT(y); }
+  constexpr bool BLT(const FixedPoint &y) const { return !BGE(y); }
+
   constexpr Ordering CompareSigned(const FixedPoint &y) const {
     bool isNegative{IsNegative()};
     if (isNegative != y.IsNegative()) {
@@ -252,6 +304,14 @@ public:
     return {result, overflow};
   }
 
+  constexpr ValueWithOverflow ABS() const {
+    if (IsNegative()) {
+      return Negate();
+    } else {
+      return {*this, false};
+    }
+  }
+
   // Shifts the operand left when the count is positive, right when negative.
   // Vacated bit positions are filled with zeroes.
   constexpr FixedPoint ISHFT(int count) const {
@@ -296,9 +356,65 @@ public:
     }
   }
 
-  // TODO pmk
-  // ISHFTC intrinsic - shift some least-significant bits circularly
-  // DSHIFTL/R
+  // Circular shift of a field of least-significant bits.  The least-order
+  // "size" bits are shifted circularly in place by "count" positions;
+  // the shift is leftward if count is nonnegative, rightward otherwise.
+  // Higher-order bits are unchanged.
+  constexpr FixedPoint ISHFTC(int count, int size) const {
+    if (count == 0 || size <= 0) {
+      return *this;
+    }
+    if (size > bits) {
+      size = bits;
+    }
+    if ((count %= size) == 0) {
+      return *this;
+    }
+    int middleBits, leastBits;
+    if (count > 0) {
+      middleBits = size - count;
+      leastBits = count;
+    } else {
+      middleBits = -count;
+      leastBits = size + count;
+    }
+    if (size == bits) {
+      return SHIFTL(leastBits).IOR(SHIFTR(middleBits));
+    }
+    FixedPoint unchanged{IAND(MASKL(bits - size))};
+    FixedPoint middle{IAND(MASKR(middleBits)).SHIFTL(leastBits)};
+    FixedPoint least{SHIFTR(middleBits).IAND(MASKR(leastBits))};
+    return unchanged.IOR(middle).IOR(least);
+  }
+
+  // Double shifts, aka shifts with specific fill
+  constexpr FixedPoint DSHIFTL(const FixedPoint &fill, int count) const {
+    if (count <= 0) {
+      return *this;
+    } else if (count >= 2 * bits) {
+      return {};
+    } else if (count > bits) {
+      return fill.SHIFTL(count - bits);
+    } else if (count == bits) {
+      return fill;
+    } else {
+      return SHIFTL(count).IOR(fill.SHIFTR(bits - count));
+    }
+  }
+
+  constexpr FixedPoint DSHIFTR(const FixedPoint &fill, int count) const {
+    if (count <= 0) {
+      return *this;
+    } else if (count >= 2 * bits) {
+      return {};
+    } else if (count > bits) {
+      return fill.SHIFTR(count - bits);
+    } else if (count == bits) {
+      return fill;
+    } else {
+      return SHIFTR(count).IOR(fill.SHIFTL(bits - count));
+    }
+  }
 
   // Vacated upper bits are filled with zeroes.
   constexpr FixedPoint SHIFTR(int count) const {
@@ -345,6 +461,33 @@ public:
     }
   }
 
+  // Clears a single bit.
+  constexpr FixedPoint IBCLR(int pos) const {
+    if (pos < 0 || pos >= bits) {
+      return *this;
+    } else {
+      FixedPoint result{*this};
+      result.LEPart(pos / partBits) &= ~(Part{1} << (pos % partBits));
+      return result;
+    }
+  }
+
+  // Sets a single bit.
+  constexpr FixedPoint IBSET(int pos) const {
+    if (pos < 0 || pos >= bits) {
+      return *this;
+    } else {
+      FixedPoint result{*this};
+      result.LEPart(pos / partBits) |= Part{1} << (pos % partBits);
+      return result;
+    }
+  }
+
+  // Extracts a field.
+  constexpr FixedPoint IBITS(int pos, int size) const {
+    return SHIFTR(pos).IAND(MASKR(size));
+  }
+
   constexpr FixedPoint IAND(const FixedPoint &y) const {
     FixedPoint result{nullptr};
     for (int j{0}; j < parts; ++j) {
@@ -369,6 +512,27 @@ public:
     return result;
   }
 
+  constexpr FixedPoint MERGE_BITS(const FixedPoint &y,
+                                  const FixedPoint &mask) const {
+    return IAND(mask).IOR(y.IAND(mask.NOT()));
+  }
+
+  constexpr FixedPoint MAX(const FixedPoint &y) const {
+    if (CompareSigned(y) == Ordering::Less) {
+      return y;
+    } else {
+      return *this;
+    }
+  }
+
+  constexpr FixedPoint MIN(const FixedPoint &y) const {
+    if (CompareSigned(y) == Ordering::Less) {
+      return *this;
+    } else {
+      return y;
+    }
+  }
+
   // Unsigned addition with carry.
   struct ValueWithCarry {
     FixedPoint value;
@@ -406,6 +570,26 @@ public:
     return {diff.value, overflow};
   }
 
+  // MAX(X-Y, 0)
+  constexpr FixedPoint DIM(const FixedPoint &y) const {
+    if (CompareSigned(y) != Ordering::Greater) {
+      return {};
+    } else {
+      return SubtractSigned(y).value;
+    }
+  }
+
+  constexpr ValueWithOverflow SIGN(const FixedPoint &sign) const {
+    bool goNegative{sign.IsNegative()};
+    if (goNegative == IsNegative()) {
+      return *this;
+    } else if (goNegative) {
+      return Negate();
+    } else {
+      return ABS();
+    }
+  }
+
   struct Product {
     FixedPoint upper, lower;
   };
index 2c4a19d..3436b19 100644 (file)
@@ -52,6 +52,12 @@ template<int BITS, typename FP = FixedPoint<BITS>> void exhaustiveTesting() {
     std::uint64_t lzcheck{std::uint64_t{1} << (BITS - lzbc)};
     COMPARE(x, <, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
     COMPARE(x + x + !x, >=, lzcheck)("%s, x=0x%llx, lzbc=%d", desc, x, lzbc);
+    int popcheck{0};
+    for (int j{0}; j < BITS; ++j) {
+      popcheck += (x >> j) & 1;
+    }
+    MATCH(popcheck, a.POPCNT())("%s, x=0x%llx", desc, x);
+    MATCH(popcheck & 1, a.POPPAR())("%s, x=0x%llx", desc, x);
     Ordering ord{Ordering::Equal};
     std::int64_t sx = x;
     if (x + x > maxUnsignedValue) {
@@ -180,7 +186,9 @@ template<int BITS, typename FP = FixedPoint<BITS>> void exhaustiveTesting() {
         MATCH(sx - sy * (sx / sy), quot.remainder.ToInt64())
           ("%s, x=0x%llx, y=0x%llx", desc, x, y);
       }
-      // TODO test MODULO
+      // TODO test ABS, B[GL][ET], BTEST, DIM, HUGE, MODULO, ISHFTC, DSHIFTL/R
+      // TODO test IBCLR, IBSET, IBITS, MAX, MIN, MERGE_BITS, RANGE, SIGN
+      // TODO test TRAILZ
     }
   }
 }