forked from OSchip/llvm-project
[APInt] Allow extending and truncating to the same width
Allow zext, sext, trunc, truncUSat and truncSSat to extend or truncate to the same bit width, which is a no-op. Disallowing this forced clients to use workarounds like using zextOrTrunc (even though they never wanted truncation) or zextOrSelf (even though they did not want its strange behaviour of allowing a *smaller* bit width, which is also treated as a no-op). Differential Revision: https://reviews.llvm.org/D125556
This commit is contained in:
parent
1ecc3d86ae
commit
169ae6db69
|
@ -1218,7 +1218,7 @@ public:
|
||||||
/// Truncate to new width.
|
/// Truncate to new width.
|
||||||
///
|
///
|
||||||
/// Truncate the APInt to a specified width. It is an error to specify a width
|
/// Truncate the APInt to a specified width. It is an error to specify a width
|
||||||
/// that is greater than or equal to the current width.
|
/// that is greater than the current width.
|
||||||
APInt trunc(unsigned width) const;
|
APInt trunc(unsigned width) const;
|
||||||
|
|
||||||
/// Truncate to new width with unsigned saturation.
|
/// Truncate to new width with unsigned saturation.
|
||||||
|
@ -1238,7 +1238,7 @@ public:
|
||||||
///
|
///
|
||||||
/// This operation sign extends the APInt to a new width. If the high order
|
/// This operation sign extends the APInt to a new width. If the high order
|
||||||
/// bit is set, the fill on the left will be done with 1 bits, otherwise zero.
|
/// bit is set, the fill on the left will be done with 1 bits, otherwise zero.
|
||||||
/// It is an error to specify a width that is less than or equal to the
|
/// It is an error to specify a width that is less than the
|
||||||
/// current width.
|
/// current width.
|
||||||
APInt sext(unsigned width) const;
|
APInt sext(unsigned width) const;
|
||||||
|
|
||||||
|
@ -1246,7 +1246,7 @@ public:
|
||||||
///
|
///
|
||||||
/// This operation zero extends the APInt to a new width. The high order bits
|
/// This operation zero extends the APInt to a new width. The high order bits
|
||||||
/// are filled with 0 bits. It is an error to specify a width that is less
|
/// are filled with 0 bits. It is an error to specify a width that is less
|
||||||
/// than or equal to the current width.
|
/// than the current width.
|
||||||
APInt zext(unsigned width) const;
|
APInt zext(unsigned width) const;
|
||||||
|
|
||||||
/// Sign extend or truncate to width
|
/// Sign extend or truncate to width
|
||||||
|
|
|
@ -896,11 +896,14 @@ double APInt::roundToDouble(bool isSigned) const {
|
||||||
|
|
||||||
// Truncate to new width.
|
// Truncate to new width.
|
||||||
APInt APInt::trunc(unsigned width) const {
|
APInt APInt::trunc(unsigned width) const {
|
||||||
assert(width < BitWidth && "Invalid APInt Truncate request");
|
assert(width <= BitWidth && "Invalid APInt Truncate request");
|
||||||
|
|
||||||
if (width <= APINT_BITS_PER_WORD)
|
if (width <= APINT_BITS_PER_WORD)
|
||||||
return APInt(width, getRawData()[0]);
|
return APInt(width, getRawData()[0]);
|
||||||
|
|
||||||
|
if (width == BitWidth)
|
||||||
|
return *this;
|
||||||
|
|
||||||
APInt Result(getMemory(getNumWords(width)), width);
|
APInt Result(getMemory(getNumWords(width)), width);
|
||||||
|
|
||||||
// Copy full words.
|
// Copy full words.
|
||||||
|
@ -918,7 +921,7 @@ APInt APInt::trunc(unsigned width) const {
|
||||||
|
|
||||||
// Truncate to new width with unsigned saturation.
|
// Truncate to new width with unsigned saturation.
|
||||||
APInt APInt::truncUSat(unsigned width) const {
|
APInt APInt::truncUSat(unsigned width) const {
|
||||||
assert(width < BitWidth && "Invalid APInt Truncate request");
|
assert(width <= BitWidth && "Invalid APInt Truncate request");
|
||||||
|
|
||||||
// Can we just losslessly truncate it?
|
// Can we just losslessly truncate it?
|
||||||
if (isIntN(width))
|
if (isIntN(width))
|
||||||
|
@ -929,7 +932,7 @@ APInt APInt::truncUSat(unsigned width) const {
|
||||||
|
|
||||||
// Truncate to new width with signed saturation.
|
// Truncate to new width with signed saturation.
|
||||||
APInt APInt::truncSSat(unsigned width) const {
|
APInt APInt::truncSSat(unsigned width) const {
|
||||||
assert(width < BitWidth && "Invalid APInt Truncate request");
|
assert(width <= BitWidth && "Invalid APInt Truncate request");
|
||||||
|
|
||||||
// Can we just losslessly truncate it?
|
// Can we just losslessly truncate it?
|
||||||
if (isSignedIntN(width))
|
if (isSignedIntN(width))
|
||||||
|
@ -941,11 +944,14 @@ APInt APInt::truncSSat(unsigned width) const {
|
||||||
|
|
||||||
// Sign extend to a new width.
|
// Sign extend to a new width.
|
||||||
APInt APInt::sext(unsigned Width) const {
|
APInt APInt::sext(unsigned Width) const {
|
||||||
assert(Width > BitWidth && "Invalid APInt SignExtend request");
|
assert(Width >= BitWidth && "Invalid APInt SignExtend request");
|
||||||
|
|
||||||
if (Width <= APINT_BITS_PER_WORD)
|
if (Width <= APINT_BITS_PER_WORD)
|
||||||
return APInt(Width, SignExtend64(U.VAL, BitWidth));
|
return APInt(Width, SignExtend64(U.VAL, BitWidth));
|
||||||
|
|
||||||
|
if (Width == BitWidth)
|
||||||
|
return *this;
|
||||||
|
|
||||||
APInt Result(getMemory(getNumWords(Width)), Width);
|
APInt Result(getMemory(getNumWords(Width)), Width);
|
||||||
|
|
||||||
// Copy words.
|
// Copy words.
|
||||||
|
@ -965,11 +971,14 @@ APInt APInt::sext(unsigned Width) const {
|
||||||
|
|
||||||
// Zero extend to a new width.
|
// Zero extend to a new width.
|
||||||
APInt APInt::zext(unsigned width) const {
|
APInt APInt::zext(unsigned width) const {
|
||||||
assert(width > BitWidth && "Invalid APInt ZeroExtend request");
|
assert(width >= BitWidth && "Invalid APInt ZeroExtend request");
|
||||||
|
|
||||||
if (width <= APINT_BITS_PER_WORD)
|
if (width <= APINT_BITS_PER_WORD)
|
||||||
return APInt(width, U.VAL);
|
return APInt(width, U.VAL);
|
||||||
|
|
||||||
|
if (width == BitWidth)
|
||||||
|
return *this;
|
||||||
|
|
||||||
APInt Result(getMemory(getNumWords(width)), width);
|
APInt Result(getMemory(getNumWords(width)), width);
|
||||||
|
|
||||||
// Copy words.
|
// Copy words.
|
||||||
|
|
|
@ -1181,18 +1181,22 @@ TEST(APIntTest, SaturatingMath) {
|
||||||
APInt AP_100 = APInt(8, 100);
|
APInt AP_100 = APInt(8, 100);
|
||||||
APInt AP_200 = APInt(8, 200);
|
APInt AP_200 = APInt(8, 200);
|
||||||
|
|
||||||
|
EXPECT_EQ(APInt(8, 100), AP_100.truncUSat(8));
|
||||||
EXPECT_EQ(APInt(7, 100), AP_100.truncUSat(7));
|
EXPECT_EQ(APInt(7, 100), AP_100.truncUSat(7));
|
||||||
EXPECT_EQ(APInt(6, 63), AP_100.truncUSat(6));
|
EXPECT_EQ(APInt(6, 63), AP_100.truncUSat(6));
|
||||||
EXPECT_EQ(APInt(5, 31), AP_100.truncUSat(5));
|
EXPECT_EQ(APInt(5, 31), AP_100.truncUSat(5));
|
||||||
|
|
||||||
|
EXPECT_EQ(APInt(8, 200), AP_200.truncUSat(8));
|
||||||
EXPECT_EQ(APInt(7, 127), AP_200.truncUSat(7));
|
EXPECT_EQ(APInt(7, 127), AP_200.truncUSat(7));
|
||||||
EXPECT_EQ(APInt(6, 63), AP_200.truncUSat(6));
|
EXPECT_EQ(APInt(6, 63), AP_200.truncUSat(6));
|
||||||
EXPECT_EQ(APInt(5, 31), AP_200.truncUSat(5));
|
EXPECT_EQ(APInt(5, 31), AP_200.truncUSat(5));
|
||||||
|
|
||||||
|
EXPECT_EQ(APInt(8, 42), AP_42.truncSSat(8));
|
||||||
EXPECT_EQ(APInt(7, 42), AP_42.truncSSat(7));
|
EXPECT_EQ(APInt(7, 42), AP_42.truncSSat(7));
|
||||||
EXPECT_EQ(APInt(6, 31), AP_42.truncSSat(6));
|
EXPECT_EQ(APInt(6, 31), AP_42.truncSSat(6));
|
||||||
EXPECT_EQ(APInt(5, 15), AP_42.truncSSat(5));
|
EXPECT_EQ(APInt(5, 15), AP_42.truncSSat(5));
|
||||||
|
|
||||||
|
EXPECT_EQ(APInt(8, -56), AP_200.truncSSat(8));
|
||||||
EXPECT_EQ(APInt(7, -56), AP_200.truncSSat(7));
|
EXPECT_EQ(APInt(7, -56), AP_200.truncSSat(7));
|
||||||
EXPECT_EQ(APInt(6, -32), AP_200.truncSSat(6));
|
EXPECT_EQ(APInt(6, -32), AP_200.truncSSat(6));
|
||||||
EXPECT_EQ(APInt(5, -16), AP_200.truncSSat(5));
|
EXPECT_EQ(APInt(5, -16), AP_200.truncSSat(5));
|
||||||
|
@ -2637,23 +2641,28 @@ TEST(APIntTest, sext) {
|
||||||
EXPECT_EQ(~uint64_t(0), APInt(1, 1).sext(64));
|
EXPECT_EQ(~uint64_t(0), APInt(1, 1).sext(64));
|
||||||
|
|
||||||
APInt i32_max(APInt::getSignedMaxValue(32).sext(63));
|
APInt i32_max(APInt::getSignedMaxValue(32).sext(63));
|
||||||
|
EXPECT_EQ(i32_max, i32_max.sext(63));
|
||||||
EXPECT_EQ(32U, i32_max.countLeadingZeros());
|
EXPECT_EQ(32U, i32_max.countLeadingZeros());
|
||||||
EXPECT_EQ(0U, i32_max.countTrailingZeros());
|
EXPECT_EQ(0U, i32_max.countTrailingZeros());
|
||||||
EXPECT_EQ(31U, i32_max.countPopulation());
|
EXPECT_EQ(31U, i32_max.countPopulation());
|
||||||
|
|
||||||
APInt i32_min(APInt::getSignedMinValue(32).sext(63));
|
APInt i32_min(APInt::getSignedMinValue(32).sext(63));
|
||||||
|
EXPECT_EQ(i32_min, i32_min.sext(63));
|
||||||
EXPECT_EQ(32U, i32_min.countLeadingOnes());
|
EXPECT_EQ(32U, i32_min.countLeadingOnes());
|
||||||
EXPECT_EQ(31U, i32_min.countTrailingZeros());
|
EXPECT_EQ(31U, i32_min.countTrailingZeros());
|
||||||
EXPECT_EQ(32U, i32_min.countPopulation());
|
EXPECT_EQ(32U, i32_min.countPopulation());
|
||||||
|
|
||||||
APInt i32_neg1(APInt(32, ~uint64_t(0)).sext(63));
|
APInt i32_neg1(APInt(32, ~uint64_t(0)).sext(63));
|
||||||
|
EXPECT_EQ(i32_neg1, i32_neg1.sext(63));
|
||||||
EXPECT_EQ(63U, i32_neg1.countLeadingOnes());
|
EXPECT_EQ(63U, i32_neg1.countLeadingOnes());
|
||||||
EXPECT_EQ(0U, i32_neg1.countTrailingZeros());
|
EXPECT_EQ(0U, i32_neg1.countTrailingZeros());
|
||||||
EXPECT_EQ(63U, i32_neg1.countPopulation());
|
EXPECT_EQ(63U, i32_neg1.countPopulation());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(APIntTest, truncOrSelf) {
|
TEST(APIntTest, trunc) {
|
||||||
APInt val(32, 0xFFFFFFFF);
|
APInt val(32, 0xFFFFFFFF);
|
||||||
|
EXPECT_EQ(0xFFFF, val.trunc(16));
|
||||||
|
EXPECT_EQ(0xFFFFFFFF, val.trunc(32));
|
||||||
EXPECT_EQ(0xFFFF, val.truncOrSelf(16));
|
EXPECT_EQ(0xFFFF, val.truncOrSelf(16));
|
||||||
EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(32));
|
EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(32));
|
||||||
EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(64));
|
EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(64));
|
||||||
|
|
Loading…
Reference in New Issue