[flang] More intrinsics

Original-commit: flang-compiler/f18@55f974be59
Reviewed-on: https://github.com/flang-compiler/f18/pull/101
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-05-31 16:15:18 -07:00
parent 0dc145c255
commit 04711726c9
2 changed files with 199 additions and 7 deletions

View 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;
};

View 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
}
}
}