summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Support
diff options
context:
space:
mode:
authorSimon Pilgrim <llvm-dev@redking.me.uk>2017-02-24 10:15:29 +0000
committerSimon Pilgrim <llvm-dev@redking.me.uk>2017-02-24 10:15:29 +0000
commitaed352273e8deddea35a6f9b8d4dbc9b98ba04c0 (patch)
tree6eddcff36bd08acdb134d0c0aed9f4274d71b5ae /llvm/lib/Support
parent4a705e7ea0cb911d9ec2933b99f5d1f7c1ba9ad3 (diff)
downloadbcm5719-llvm-aed352273e8deddea35a6f9b8d4dbc9b98ba04c0.tar.gz
bcm5719-llvm-aed352273e8deddea35a6f9b8d4dbc9b98ba04c0.zip
[APInt] Add APInt::setBits() method to set all bits in range
The current pattern for setting bits in range is typically: Mask |= APInt::getBitsSet(MaskSizeInBits, LoPos, HiPos); Which can be particularly slow for large APInts (MaskSizeInBits > 64) as they require the allocation memory for the temporary variable. This is one of the key compile time issues identified in PR32037. This patch adds the APInt::setBits() helper method which avoids the temporary memory allocation completely, this first implementation uses setBit() internally instead but already significantly reduces the regression in PR32037 (~10% drop). Additional optimization may be possible. I investigated whether there is need for APInt::clearBits() and APInt::flipBits() equivalents but haven't seen these patterns to be particularly common, but reusing the code would be trivial. Differential Revision: https://reviews.llvm.org/D30265 llvm-svn: 296102
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r--llvm/lib/Support/APInt.cpp33
1 files changed, 33 insertions, 0 deletions
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 35c15e04bf0..8ddbbe3a70d 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -565,6 +565,39 @@ void APInt::setBit(unsigned bitPosition) {
pVal[whichWord(bitPosition)] |= maskBit(bitPosition);
}
+void APInt::setBits(unsigned loBit, unsigned hiBit) {
+ assert(hiBit <= BitWidth && "hiBit out of range");
+ assert(loBit <= hiBit && loBit <= BitWidth && "loBit out of range");
+
+ if (loBit == hiBit)
+ return;
+
+ if (isSingleWord())
+ *this |= APInt::getBitsSet(BitWidth, loBit, hiBit);
+ else {
+ unsigned hiBit1 = hiBit - 1;
+ unsigned loWord = whichWord(loBit);
+ unsigned hiWord = whichWord(hiBit1);
+ if (loWord == hiWord) {
+ // Set bits are all within the same word, create a [loBit,hiBit) mask.
+ uint64_t mask = UINT64_MAX;
+ mask >>= (APINT_BITS_PER_WORD - (hiBit - loBit));
+ mask <<= whichBit(loBit);
+ pVal[loWord] |= mask;
+ } else {
+ // Set bits span multiple words, create a lo mask with set bits starting
+ // at loBit, a hi mask with set bits below hiBit and set all bits of the
+ // words in between.
+ uint64_t loMask = UINT64_MAX << whichBit(loBit);
+ uint64_t hiMask = UINT64_MAX >> (64 - whichBit(hiBit1) - 1);
+ pVal[loWord] |= loMask;
+ pVal[hiWord] |= hiMask;
+ for (unsigned word = loWord + 1; word < hiWord; ++word)
+ pVal[word] = UINT64_MAX;
+ }
+ }
+}
+
/// Set the given bit to 0 whose position is given as "bitPosition".
/// @brief Set a given bit to 0.
void APInt::clearBit(unsigned bitPosition) {
OpenPOWER on IntegriCloud