Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize BitPat equals, overlap, and cover (backport #3285) #3287

Merged
merged 2 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/main/scala/chisel3/util/BitPat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int)
def =/=(that: UInt): Bool = macro SourceInfoTransform.thatArg
def ##(that: BitPat): BitPat = macro SourceInfoTransform.thatArg

override def equals(obj: Any): Boolean = {
obj match {
case that: BitPat => this.value == that.value && this.mask == that.mask && this.width == that.width
case that: BitSet => super.equals(obj)
case _ => false
}
}

override def hashCode: Int =
MurmurHash3.seqHash(Seq(this.value, this.mask, this.width))

Expand Down Expand Up @@ -362,14 +370,36 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int)
* @param that `BitPat` to be checked.
* @return true if this and that `BitPat` have overlap.
*/
def overlap(that: BitPat): Boolean = ((mask & that.mask) & (value ^ that.value)) == 0
override def overlap(that: BitSet): Boolean = that match {
case that: BitPat => ((mask & that.mask) & (value ^ that.value)) == 0
case _ => super.overlap(that)
}

/** Check whether this `BitSet` overlap with that `BitSet`, i.e. !(intersect.isEmpty)
*
* @param that `BitSet` to be checked.
* @return true if this and that `BitSet` have overlap.
* @note this version only exists to maintain binary compatibility
*/
def overlap(that: BitPat): Boolean = this.overlap(that: BitSet)

/** Check whether this `BitSet` covers that (i.e. forall b matches that, b also matches this)
*
* @param that `BitPat` to be covered
* @return true if this `BitSet` can cover that `BitSet`
*/
override def cover(that: BitSet): Boolean = that match {
case that: BitPat => (mask & (~that.mask | (value ^ that.value))) == 0
case _ => super.cover(that)
}

/** Check whether this `BitSet` covers that (i.e. forall b matches that, b also matches this)
*
* @param that `BitPat` to be covered
* @return true if this `BitSet` can cover that `BitSet`
* @note this version only exists to maintain binary compatibility
*/
def cover(that: BitPat): Boolean = (mask & (~that.mask | (value ^ that.value))) == 0
def cover(that: BitPat): Boolean = this.cover(that: BitSet)

/** Intersect `this` and `that` `BitPat`.
*
Expand Down
51 changes: 51 additions & 0 deletions src/test/scala/chiselTests/util/BitSetSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,57 @@ class BitSetSpec extends AnyFlatSpec with Matchers {
expected.equals(aBitSet.subtract(bBitSet)) should be(true)
}

it should "support checking equality" in {
val set = BitSet.fromString("""b100
|b101""".stripMargin)
val a = BitPat("b10?")
val a2 = BitPat("b10?")
val b = BitPat("b1??")

// Check both ways because BitPat overloads equals
assert(a != b)
assert(b != a)
assert(a == a2)
assert(a2 == a)
assert(set == a)
assert(a == set)
}

it should "support checking for cover" in {
val set = BitSet.fromString("""b110
|b100
|b101""".stripMargin)
val a = BitPat("b10?")
val b = BitPat("b1??")

a.cover(b) should be(false)
b.cover(a) should be(true)
set.cover(a) should be(true)
a.cover(set) should be(false)
set.cover(b) should be(false)
b.cover(set) should be(true)

}

it should "support checking for overlap" in {
val set = BitSet.fromString("""b01?0
|b0000""".stripMargin)
val a = BitPat("b00??")
val b = BitPat("b01?0")
val c = BitPat("b0000")
val d = BitPat("b1000")

a.overlap(b) should be(false)
a.overlap(c) should be(true)
b.overlap(c) should be(false)

// Check both ways because BitPat overloads overlap
set.overlap(a) should be(true)
a.overlap(set) should be(true)
set.overlap(d) should be(false)
d.overlap(set) should be(false)
}

it should "be generated from BitPat union" in {
val aBitSet = BitSet.fromString("""b001?0
|b000??""".stripMargin)
Expand Down