forked from OSchip/llvm-project
[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:
parent
0dc145c255
commit
04711726c9
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue