diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -1503,9 +1503,11 @@ /// Insert the bits from a smaller APInt starting at bitPosition. void insertBits(const APInt &SubBits, unsigned bitPosition); + void insertBits(uint64_t SubBits, unsigned bitPosition, unsigned numBits); /// Return an APInt with the extracted bits [bitPosition,bitPosition+numBits). APInt extractBits(unsigned numBits, unsigned bitPosition) const; + uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const; /// @} /// \name Value Characterization Functions diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -401,6 +401,33 @@ } } +void APInt::insertBits(uint64_t subBits, unsigned bitPosition, unsigned numBits) { + uint64_t maskBits = maskTrailingOnes(numBits); + subBits &= maskBits; + if (isSingleWord()) { + U.VAL &= ~(maskBits << bitPosition); + U.VAL |= subBits << bitPosition; + return; + } + + unsigned loBit = whichBit(bitPosition); + unsigned loWord = whichWord(bitPosition); + unsigned hiWord = whichWord(bitPosition + numBits - 1); + if (loWord == hiWord) { + U.pVal[loWord] &= ~(maskBits << loBit); + U.pVal[loWord] |= subBits << loBit; + return; + } + + static_assert(8 * sizeof(WordType) <= 64, "This code assumes only two words affected"); + unsigned wordBits = 8 * sizeof(WordType); + U.pVal[loWord] &= ~(maskBits << loBit); + U.pVal[loWord] |= subBits << loBit; + + U.pVal[hiWord] &= ~(maskBits >> (wordBits - loBit)); + U.pVal[hiWord] |= subBits >> (wordBits - loBit); +} + APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const { assert(numBits > 0 && "Can't extract zero bits"); assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth && @@ -438,6 +465,31 @@ return Result.clearUnusedBits(); } +uint64_t APInt::extractBitsAsZExtValue(unsigned numBits, + unsigned bitPosition) const { + assert(numBits > 0 && "Can't extract zero bits"); + assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth && + "Illegal bit extraction"); + assert(numBits <= 64 && "Illegal bit extraction"); + + uint64_t maskBits = maskTrailingOnes(numBits); + if (isSingleWord()) + return (U.VAL >> bitPosition) & maskBits; + + unsigned loBit = whichBit(bitPosition); + unsigned loWord = whichWord(bitPosition); + unsigned hiWord = whichWord(bitPosition + numBits - 1); + if (loWord == hiWord) + return (U.pVal[loWord] >> loBit) & maskBits; + + static_assert(8 * sizeof(WordType) <= 64, "This code assumes only two words affected"); + unsigned wordBits = 8 * sizeof(WordType); + uint64_t retBits = U.pVal[loWord] >> loBit; + retBits |= U.pVal[hiWord] << (wordBits - loBit); + retBits &= maskBits; + return retBits; +} + unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { assert(!str.empty() && "Invalid string length"); assert((radix == 10 || radix == 8 || radix == 16 || radix == 2 || diff --git a/llvm/test/TableGen/BigEncoder.td b/llvm/test/TableGen/BigEncoder.td --- a/llvm/test/TableGen/BigEncoder.td +++ b/llvm/test/TableGen/BigEncoder.td @@ -46,21 +46,12 @@ } } - // CHECK-LABEL: case ::biz: { -// CHECK: const APInt [[x:M[0-9]+]] = APInt::getBitsSet(65, 3, 7); -// CHECK-NEXT: Value |= (op & [[x]]) << 9; -// CHECK-NEXT: const APInt [[y:M[0-9]+]] = APInt::getBitsSet(65, 7, 11); -// CHECK-NEXT: Value |= (op & [[y]]) << 1; +// CHECK: Value.insertBits(op.extractBitsAsZExtValue(4, 3), 12, 4); +// CHECK-NEXT: Value.insertBits(op.extractBitsAsZExtValue(4, 7), 8, 4); // CHECK-LABEL: case ::foo: { -// CHECK: const APInt [[x:M[0-9]+]] = APInt::getBitsSet(65, 0, 7); -// CHECK-NEXT: op &= [[x]]; -// CHECK-NEXT: op <<= 8; -// CHECK-NEXT: Value |= op; +// CHECK: Value.insertBits(op.extractBitsAsZExtValue(7, 0), 8, 7); // CHECK-LABEL: case ::bar: { -// CHECK: const APInt [[x:M[0-9]+]] = APInt::getBitsSet(65, 3, 11); -// CHECK-NEXT: op &= [[x]]; -// CHECK-NEXT: op <<= 5; -// CHECK-NEXT: Value |= op; +// CHECK: Value.insertBits(op.extractBitsAsZExtValue(8, 3), 8, 8); diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -1858,6 +1858,64 @@ EXPECT_EQ(i260.extractBits(4, 256).getZExtValue(), 0x000000000000000Full); } +TEST(APIntTest, insertBitsUInt64) { + // Tests cloned from insertBits but adapted to the numBits <= 64 constraint + uint64_t iSrc = 0x00123456; + + // Direct copy. + APInt i31(31, 0x76543210ull); + i31.insertBits(iSrc, 0, 31); + EXPECT_EQ(static_cast(0x00123456ull), i31.getSExtValue()); + + // Single word src/dst insertion. + APInt i63(63, 0x01234567FFFFFFFFull); + i63.insertBits(iSrc, 4, 31); + EXPECT_EQ(static_cast(0x012345600123456Full), i63.getSExtValue()); + + // Insert single word src into one word of dst. + APInt i120(120, UINT64_MAX, true); + i120.insertBits(iSrc, 8, 31); + EXPECT_EQ(static_cast(0xFFFFFF80123456FFull), i120.getSExtValue()); + + // Insert single word src into two words of dst. + APInt i127(127, UINT64_MAX, true); + i127.insertBits(iSrc, 48, 31); + EXPECT_EQ(i127.extractBits(64, 0).getZExtValue(), 0x3456FFFFFFFFFFFFull); + EXPECT_EQ(i127.extractBits(63, 64).getZExtValue(), 0x7FFFFFFFFFFF8012ull); + + // Insert on word boundaries. + APInt i128(128, 0); + i128.insertBits(UINT64_MAX, 0, 64); + i128.insertBits(UINT64_MAX, 64, 64); + EXPECT_EQ(-1, i128.getSExtValue()); + + APInt i256(256, UINT64_MAX, true); + i256.insertBits(0, 0, 64); + i256.insertBits(0, 64, 1); + i256.insertBits(0, 64, 64); + i256.insertBits(0, 128, 5); + i256.insertBits(0, 128, 64); + i256.insertBits(0, 192, 64); + EXPECT_EQ(0u, i256.getSExtValue()); + + APInt i257(257, 0); + i257.insertBits(APInt(96, UINT64_MAX, true), 64); + EXPECT_EQ(i257.extractBitsAsZExtValue(64, 0), 0x0000000000000000ull); + EXPECT_EQ(i257.extractBitsAsZExtValue(64, 64), 0xFFFFFFFFFFFFFFFFull); + EXPECT_EQ(i257.extractBitsAsZExtValue(64, 128), 0x00000000FFFFFFFFull); + EXPECT_EQ(i257.extractBitsAsZExtValue(64, 192), 0x0000000000000000ull); + EXPECT_EQ(i257.extractBitsAsZExtValue(1, 256), 0x0000000000000000ull); + + // General insertion. + APInt i260(260, UINT64_MAX, true); + i260.insertBits(APInt(129, 1ull << 48), 15); + EXPECT_EQ(i260.extractBitsAsZExtValue(64, 0), 0x8000000000007FFFull); + EXPECT_EQ(i260.extractBitsAsZExtValue(64, 64), 0x0000000000000000ull); + EXPECT_EQ(i260.extractBitsAsZExtValue(64, 128), 0xFFFFFFFFFFFF0000ull); + EXPECT_EQ(i260.extractBitsAsZExtValue(64, 192), 0xFFFFFFFFFFFFFFFFull); + EXPECT_EQ(i260.extractBitsAsZExtValue(4, 256), 0x000000000000000Full); +} + TEST(APIntTest, extractBits) { APInt i32(32, 0x1234567); EXPECT_EQ(0x3456, i32.extractBits(16, 4)); @@ -1881,6 +1939,33 @@ APInt(144, "281474976710655", 10).extractBits(48, 1)); } +TEST(APIntTest, extractBitsAsZExtValue) { + // Tests based on extractBits + APInt i32(32, 0x1234567); + EXPECT_EQ(0x3456u, i32.extractBitsAsZExtValue(16, 4)); + + APInt i257(257, 0xFFFFFFFFFF0000FFull, true); + EXPECT_EQ(0xFFu, i257.extractBitsAsZExtValue(16, 0)); + EXPECT_EQ((0xFFu >> 1), i257.extractBitsAsZExtValue(16, 1)); + EXPECT_EQ(0xFFFFFFFFull, i257.extractBitsAsZExtValue(32, 64)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFull, i257.extractBitsAsZExtValue(64, 128)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFull, i257.extractBitsAsZExtValue(64, 192)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFull, i257.extractBitsAsZExtValue(64, 191)); + EXPECT_EQ(0x3u, i257.extractBitsAsZExtValue(2, 255)); + EXPECT_EQ(0xFFFFFFFFFF80007Full, i257.extractBitsAsZExtValue(64, 1)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFull, i257.extractBitsAsZExtValue(64, 65)); + EXPECT_EQ(0xFFFFFFFFFF80007Full, i257.extractBitsAsZExtValue(64, 1)); + EXPECT_EQ(0xFFFFFFFFFFFFFFFFull, i257.extractBitsAsZExtValue(64, 65)); + EXPECT_EQ(0x1ull, i257.extractBitsAsZExtValue(1, 129)); + + EXPECT_EQ(APInt(48, 0), + APInt(144, "281474976710655", 10).extractBitsAsZExtValue(48, 48)); + EXPECT_EQ(APInt(48, 0x0000ffffffffffffull), + APInt(144, "281474976710655", 10).extractBitsAsZExtValue(48, 0)); + EXPECT_EQ(APInt(48, 0x00007fffffffffffull), + APInt(144, "281474976710655", 10).extractBitsAsZExtValue(48, 1)); +} + TEST(APIntTest, getLowBitsSet) { APInt i128lo64 = APInt::getLowBitsSet(128, 64); EXPECT_EQ(0u, i128lo64.countLeadingOnes()); diff --git a/llvm/utils/TableGen/CodeEmitterGen.cpp b/llvm/utils/TableGen/CodeEmitterGen.cpp --- a/llvm/utils/TableGen/CodeEmitterGen.cpp +++ b/llvm/utils/TableGen/CodeEmitterGen.cpp @@ -212,40 +212,47 @@ std::string maskStr; int opShift; + unsigned loBit = beginVarBit - N + 1; + unsigned hiBit = loBit + N; + unsigned loInstBit = beginInstBit - N + 1; if (UseAPInt) { - unsigned loBit = beginVarBit - N + 1; - unsigned hiBit = loBit + N; - maskStr = "M" + itostr(bit); - Case += " const APInt " + maskStr + " = APInt::getBitsSet(" + - itostr(BitWidth) + ", " + itostr(loBit) + ", " + itostr(hiBit) + - ");\n"; + std::string extractStr; + if (N >= 64) { + extractStr = "op.extractBits(" + itostr(hiBit - loBit) + ", " + + itostr(loBit) + ")"; + Case += " Value.insertBits(" + extractStr + ", " + + itostr(loInstBit) + ");\n"; + } else { + extractStr = "op.extractBitsAsZExtValue(" + itostr(hiBit - loBit) + + ", " + itostr(loBit) + ")"; + Case += " Value.insertBits(" + extractStr + ", " + + itostr(loInstBit) + ", " + itostr(hiBit - loBit) + ");\n"; + } } else { uint64_t opMask = ~(uint64_t)0 >> (64 - N); opShift = beginVarBit - N + 1; opMask <<= opShift; maskStr = "UINT64_C(" + utostr(opMask) + ")"; - } - opShift = beginInstBit - beginVarBit; - - if (numOperandLits == 1) { - // Because Op may be an APInt, ensure all arithmetic is done in-place - // where possible to elide copies. - Case += " op &= " + maskStr + ";\n"; - if (opShift > 0) { - Case += " op <<= " + itostr(opShift) + ";\n"; - } else if (opShift < 0) { - Case += " op >>= " + itostr(-opShift) + ";\n"; - } - Case += " Value |= op;\n"; - } else { - if (opShift > 0) { - Case += " Value |= (op & " + maskStr + ") << " + itostr(opShift) + - ";\n"; - } else if (opShift < 0) { - Case += " Value |= (op & " + maskStr + ") >> " + itostr(-opShift) + - ";\n"; + opShift = beginInstBit - beginVarBit; + + if (numOperandLits == 1) { + Case += " op &= " + maskStr + ";\n"; + if (opShift > 0) { + Case += " op <<= " + itostr(opShift) + ";\n"; + } else if (opShift < 0) { + Case += " op >>= " + itostr(-opShift) + ";\n"; + } + Case += " Value |= op;\n"; } else { - Case += " Value |= (op & " + maskStr + ");\n"; + if (opShift > 0) { + Case += " Value |= (op & " + maskStr + ") << " + + itostr(opShift) + ";\n"; + } else if (opShift < 0) { + Case += " Value |= (op & " + maskStr + ") >> " + + itostr(-opShift) + ";\n"; + } else { + Case += " Value |= (op & " + maskStr + ");\n"; + } } } } @@ -436,9 +443,12 @@ << " raw_string_ostream Msg(msg);\n" << " Msg << \"Not supported instr: \" << MI;\n" << " report_fatal_error(Msg.str());\n" - << " }\n" - << " return Value;\n" - << "}\n\n"; + << " }\n"; + if (UseAPInt) + o << " Inst = Value;\n"; + else + o << " return Value;\n"; + o << "}\n\n"; const auto &All = SubtargetFeatureInfo::getAll(Records); std::map SubtargetFeatures;