Skip to content

Commit 3b2caf2

Browse files
committed
Add more APInt bit-twiddling operations
1 parent e54b433 commit 3b2caf2

File tree

2 files changed

+358
-3
lines changed

2 files changed

+358
-3
lines changed

Sources/LLVM/Arbitrary.swift

Lines changed: 205 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public struct APInt: IRConstant {
4141
self.value = .single(val & mask)
4242
case var .many(vals):
4343
vals[vals.endIndex - 1] &= mask
44+
self.value = .many(vals)
4445
}
4546
}
4647

@@ -537,7 +538,7 @@ extension APInt {
537538
public var signExtendedValue: Int64? {
538539
switch self.value {
539540
case let .single(val):
540-
return Int64(bitPattern: val << (64 - self.bitWidth)) >> (64 - self.bitWidth);
541+
return Int64(bitPattern: val << (64 - self.bitWidth)) >> (64 - self.bitWidth)
541542
case let .many(vals):
542543
guard (self.bitWidth - self.leadingZeroBitCount) <= 64 else {
543544
return nil
@@ -600,7 +601,6 @@ extension APInt {
600601
count += v.leadingZeroBitCount
601602
break
602603
}
603-
604604
count += bitsPerWord
605605
}
606606
// Adjust for unused bits in the most significant word (they are zero).
@@ -610,6 +610,37 @@ extension APInt {
610610
}
611611
}
612612

613+
614+
/// The number of leading ones in this value’s binary representation.
615+
public var leadingNonZeroBitCount: Int {
616+
switch self.value {
617+
case let .single(val):
618+
return (~(val << (bitsPerWord - self.bitWidth))).leadingZeroBitCount
619+
case let .many(vals):
620+
var highWordBits = self.bitWidth % bitsPerWord
621+
var shift: Int
622+
if highWordBits == 0 {
623+
highWordBits = bitsPerWord
624+
shift = 0
625+
} else {
626+
shift = bitsPerWord - highWordBits
627+
}
628+
let tail = requiredWords(for: self.bitWidth) - 1
629+
var count = (~(vals[tail] << shift)).leadingZeroBitCount
630+
if count == highWordBits {
631+
for j in (0..<tail).reversed() {
632+
if vals[j] == .max {
633+
count += bitsPerWord
634+
} else {
635+
count += (~vals[j]).leadingZeroBitCount
636+
break
637+
}
638+
}
639+
}
640+
return count
641+
}
642+
}
643+
613644
/// The number of trailing zeros in this value’s binary representation.
614645
public var trailingZeroBitCount: Int {
615646
switch self.value {
@@ -629,6 +660,25 @@ extension APInt {
629660
}
630661
}
631662

663+
/// The number of trailing ones in this value’s binary representation.
664+
public var trailingNonZeroBitCount: Int {
665+
switch self.value {
666+
case let .single(val):
667+
return (~val).trailingZeroBitCount
668+
case let .many(vals):
669+
var count = 0
670+
var i = 0
671+
while i < vals.count && vals[i] == .max {
672+
defer { i += 1 }
673+
count += bitsPerWord
674+
}
675+
if i < vals.count {
676+
count += (~vals[i]).trailingZeroBitCount
677+
}
678+
return count
679+
}
680+
}
681+
632682
/// The number of bits equal to 1 in this value’s binary representation.
633683
public var nonzeroBitCount: Int {
634684
switch self.value {
@@ -644,6 +694,159 @@ extension APInt {
644694
}
645695
}
646696

697+
// MARK: Bit Twiddling Operations
698+
699+
extension APInt {
700+
/// Sets all bits to one in this value's binary representation.
701+
public mutating func setAllBits() {
702+
switch self.value {
703+
case .single(_):
704+
self.value = .single(.max)
705+
case .many(_):
706+
self.value = .many([APInt.Word](repeating: .max, count: requiredWords(for: self.bitWidth)))
707+
}
708+
self.clearUnusedBits()
709+
}
710+
711+
/// Sets the bit at the given position to one.
712+
///
713+
/// - Parameters:
714+
/// - position: The position of the bit to set.
715+
public mutating func setBit(at position: Int) {
716+
precondition(0 <= position)
717+
precondition(position < self.bitWidth)
718+
let mask: Word = (1 as Word) << UInt64(position % bitsPerWord)
719+
switch self.value {
720+
case let .single(val):
721+
self.value = .single(val | mask)
722+
case var .many(vals):
723+
vals[position % bitsPerWord] |= mask
724+
self.value = .many(vals)
725+
}
726+
}
727+
728+
/// Sets the sign bit to one in this value's binary representation.
729+
public mutating func setSignBit() {
730+
self.setBit(at: self.bitWidth - 1)
731+
}
732+
733+
/// Sets all bits in the given range to one in this value's binary
734+
/// representation.
735+
///
736+
/// - Parameters:
737+
/// - range: The range of bits to flip.
738+
public mutating func setBits(_ range: ClosedRange<Int>) {
739+
precondition(range.upperBound <= self.bitWidth)
740+
precondition(range.lowerBound <= self.bitWidth)
741+
precondition(range.lowerBound <= range.upperBound)
742+
guard range.lowerBound != range.upperBound else {
743+
return
744+
}
745+
746+
var mask: Word = Word.max >> (bitsPerWord - (range.upperBound - range.lowerBound))
747+
mask <<= range.lowerBound
748+
switch self.value {
749+
case let .single(val):
750+
self.value = .single(val | mask)
751+
case var .many(vals) where range.lowerBound < bitsPerWord && range.upperBound <= bitsPerWord:
752+
vals[0] |= mask
753+
self.value = .many(vals)
754+
case var .many(vals):
755+
let (loWord, loShift) = range.lowerBound.quotientAndRemainder(dividingBy: bitsPerWord)
756+
let (hiWord, hiShift) = range.upperBound.quotientAndRemainder(dividingBy: bitsPerWord)
757+
758+
// If hiBit is not aligned, we need a high mask.
759+
var loMask = Word.max << loShift
760+
if hiShift != 0 {
761+
let hiMask = Word.max >> (bitsPerWord - hiShift)
762+
if hiWord == loWord {
763+
loMask &= hiMask
764+
} else {
765+
vals[hiWord] |= hiMask
766+
}
767+
}
768+
vals[loWord] |= loMask
769+
770+
// Fill any words between loWord and hiWord with all ones.
771+
if loWord < hiWord {
772+
for word in (loWord + 1)..<hiWord {
773+
vals[word] = .max
774+
}
775+
}
776+
777+
self.value = .many(vals)
778+
}
779+
}
780+
781+
/// Sets all bits in the given range to one in this value's binary
782+
/// representation.
783+
///
784+
/// - Parameters:
785+
/// - range: The range of bits to flip.
786+
public mutating func setBits(_ range: Range<Int>) {
787+
self.setBits(range.lowerBound...range.upperBound - 1)
788+
}
789+
790+
/// Sets all bits in the given range to one in this value's binary
791+
/// representation.
792+
///
793+
/// - Parameters:
794+
/// - range: The range of bits to flip.
795+
public mutating func setBits(_ range: PartialRangeUpTo<Int>) {
796+
self.setBits(0...range.upperBound - 1)
797+
}
798+
799+
/// Sets all bits in the given range to one in this value's binary
800+
/// representation.
801+
///
802+
/// - Parameters:
803+
/// - range: The range of bits to flip.
804+
public mutating func setBits(_ range: PartialRangeThrough<Int>) {
805+
self.setBits(0...range.upperBound)
806+
}
807+
808+
/// Sets all bits in the given range to one in this value's binary
809+
/// representation.
810+
///
811+
/// - Parameters:
812+
/// - range: The range of bits to flip.
813+
public mutating func setBits(_ range: PartialRangeFrom<Int>) {
814+
self.setBits(range.lowerBound...self.bitWidth)
815+
}
816+
817+
/// Clears all bits to one in this value's binary representation.
818+
public mutating func clearAllBits() {
819+
switch self.value {
820+
case .single(_):
821+
self.value = .single(0)
822+
case .many(_):
823+
self.value = .many([Word](repeating: 0, count: requiredWords(for: self.bitWidth)))
824+
}
825+
}
826+
827+
/// Sets the bit at the given position to zero.
828+
///
829+
/// - Parameters:
830+
/// - position: The position of the bit to zero.
831+
public mutating func clearBit(_ position: Int) {
832+
precondition(0 <= position)
833+
precondition(position < self.bitWidth)
834+
let mask: Word = ~((1 as Word) << UInt64(position % bitsPerWord))
835+
switch self.value {
836+
case let .single(val):
837+
self.value = .single(val | mask)
838+
case var .many(vals):
839+
vals[position % bitsPerWord] |= mask
840+
self.value = .many(vals)
841+
}
842+
}
843+
844+
/// Clears the sign bit in this value's binary representation.
845+
public mutating func clearSignBit() {
846+
self.clearBit(self.bitWidth - 1)
847+
}
848+
}
849+
647850
/// MARK: Resizing Operations
648851

649852
extension APInt {

0 commit comments

Comments
 (0)