summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support/APInt.cpp
diff options
context:
space:
mode:
authorSimon Pilgrim <llvm-dev@redking.me.uk>2017-03-10 13:44:32 +0000
committerSimon Pilgrim <llvm-dev@redking.me.uk>2017-03-10 13:44:32 +0000
commitb02667c469493e8f1eee4601d175942c9e80c73d (patch)
treeca9f54e6c64afb485db66deae194e50ae5dc57bb /llvm/lib/Support/APInt.cpp
parent7090d145e8eb0164e5862321e76ecfc1736dd741 (diff)
downloadbcm5719-llvm-b02667c469493e8f1eee4601d175942c9e80c73d.tar.gz
bcm5719-llvm-b02667c469493e8f1eee4601d175942c9e80c73d.zip
[APInt] Add APInt::insertBits() method to insert an APInt into a larger APInt
We currently have to insert bits via a temporary variable of the same size as the target with various shift/mask stages, resulting in further temporary variables, all of which require the allocation of memory for large APInts (MaskSizeInBits > 64). This is another of the compile time issues identified in PR32037 (see also D30265). This patch adds the APInt::insertBits() helper method which avoids the temporary memory allocation and masks/inserts the raw bits directly into the target. Differential Revision: https://reviews.llvm.org/D30780 llvm-svn: 297458
Diffstat (limited to 'llvm/lib/Support/APInt.cpp')
-rw-r--r--llvm/lib/Support/APInt.cpp59
1 files changed, 59 insertions, 0 deletions
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 621d746e776..d65dffec8c0 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -588,6 +588,65 @@ void APInt::flipBit(unsigned bitPosition) {
else setBit(bitPosition);
}
+void APInt::insertBits(const APInt &subBits, unsigned bitPosition) {
+ unsigned subBitWidth = subBits.getBitWidth();
+ assert(0 < subBitWidth && (subBitWidth + bitPosition) <= BitWidth &&
+ "Illegal bit insertion");
+
+ // Insertion is a direct copy.
+ if (subBitWidth == BitWidth) {
+ *this = subBits;
+ return;
+ }
+
+ // Single word result can be done as a direct bitmask.
+ if (isSingleWord()) {
+ uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - subBitWidth);
+ VAL &= ~(mask << bitPosition);
+ VAL |= (subBits.VAL << bitPosition);
+ return;
+ }
+
+ unsigned loBit = whichBit(bitPosition);
+ unsigned loWord = whichWord(bitPosition);
+ unsigned hi1Word = whichWord(bitPosition + subBitWidth - 1);
+
+ // Insertion within a single word can be done as a direct bitmask.
+ if (loWord == hi1Word) {
+ uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - subBitWidth);
+ pVal[loWord] &= ~(mask << loBit);
+ pVal[loWord] |= (subBits.VAL << loBit);
+ return;
+ }
+
+ // Insert on word boundaries.
+ if (loBit == 0) {
+ // Direct copy whole words.
+ unsigned numWholeSubWords = subBitWidth / APINT_BITS_PER_WORD;
+ memcpy(pVal + loWord, subBits.getRawData(),
+ numWholeSubWords * APINT_WORD_SIZE);
+
+ // Mask+insert remaining bits.
+ unsigned remainingBits = subBitWidth % APINT_BITS_PER_WORD;
+ if (remainingBits != 0) {
+ uint64_t mask = UINT64_MAX >> (APINT_BITS_PER_WORD - remainingBits);
+ pVal[hi1Word] &= ~mask;
+ pVal[hi1Word] |= subBits.getWord(subBitWidth - 1);
+ }
+ return;
+ }
+
+ // General case - set/clear individual bits in dst based on src.
+ // TODO - there is scope for optimization here, but at the moment this code
+ // path is barely used so prefer readability over performance.
+ for (unsigned i = 0; i != subBitWidth; ++i) {
+ if (subBits[i])
+ setBit(bitPosition + i);
+ else
+ clearBit(bitPosition + i);
+ }
+}
+
APInt APInt::extractBits(unsigned numBits, unsigned bitPosition) const {
assert(numBits > 0 && "Can't extract zero bits");
assert(bitPosition < BitWidth && (numBits + bitPosition) <= BitWidth &&
OpenPOWER on IntegriCloud