This repository has been archived by the owner on Aug 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix dynamic SubAccess of zero-length vectors (#1450)
* Fix dynamic SubAccess of zero-length vectors * Fixes #230 * Add new ZeroLengthVecs pass that occurs before RemoveAccesses * Include this in stage.Forms.MidForm * Add to High->Mid order in compiler test based on @seldridge feedback * Use validif to produce out-of-bounds value in ZeroLengthVecs * Update scaladoc * Fix test imports
- Loading branch information
1 parent
a9034ba
commit 1a03e63
Showing
5 changed files
with
146 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// See LICENSE for license details. | ||
|
||
package firrtl.passes | ||
|
||
import firrtl._ | ||
import firrtl.ir._ | ||
import firrtl.Mappers._ | ||
import firrtl.PrimOps._ | ||
import firrtl.options.{Dependency, PreservesAll} | ||
|
||
/** Handles dynamic accesses to zero-length vectors. | ||
* | ||
* @note Removes assignments that use a zero-length vector as a sink | ||
* @note Removes signals resulting from accesses to a zero-length vector from attach groups | ||
* @note Removes attaches that become degenerate after zero-length-accessor removal | ||
* @note Replaces "source" references to elements of zero-length vectors with always-invalid validif | ||
*/ | ||
object ZeroLengthVecs extends Pass with PreservesAll[Transform] { | ||
override val prerequisites = | ||
Seq( Dependency(PullMuxes), | ||
Dependency(ResolveKinds), | ||
Dependency(InferTypes), | ||
Dependency(ExpandConnects) ) | ||
|
||
// Pass in an expression, not just a type, since it's not possible to generate an expression of | ||
// interval type with the type alone unless you declare a component | ||
private def replaceWithDontCare(toReplace: Expression): Expression = { | ||
val default = toReplace.tpe match { | ||
case UIntType(w) => UIntLiteral(0, w) | ||
case SIntType(w) => SIntLiteral(0, w) | ||
case FixedType(w, p) => FixedLiteral(0, w, p) | ||
case it: IntervalType => | ||
val zeroType = IntervalType(Closed(0), Closed(0), IntWidth(0)) | ||
val zeroLit = DoPrim(AsInterval, Seq(SIntLiteral(0)), Seq(0, 0, 0), zeroType) | ||
DoPrim(Clip, Seq(zeroLit, toReplace), Nil, it) | ||
} | ||
ValidIf(UIntLiteral(0), default, toReplace.tpe) | ||
} | ||
|
||
private def zeroLenDerivedRefLike(expr: Expression): Boolean = (expr, expr.tpe) match { | ||
case (_, VectorType(_, 0)) => true | ||
case (WSubIndex(e, _, _, _), _) => zeroLenDerivedRefLike(e) | ||
case (WSubAccess(e, _, _, _), _) => zeroLenDerivedRefLike(e) | ||
case (WSubField(e, _, _, _), _) => zeroLenDerivedRefLike(e) | ||
case _ => false | ||
} | ||
|
||
// The connects have all been lowered, so all aggregate-typed expressions are "grounded" by WSubField/WSubAccess/WSubIndex | ||
// Map before matching because we want don't-cares to propagate UP expression trees | ||
private def dropZeroLenSubAccesses(expr: Expression): Expression = expr match { | ||
case _: WSubIndex | _: WSubAccess | _: WSubField => | ||
if (zeroLenDerivedRefLike(expr)) replaceWithDontCare(expr) else expr | ||
case e => e map dropZeroLenSubAccesses | ||
} | ||
|
||
// Attach semantics: drop all zero-length-derived members of attach group, drop stmt if trivial | ||
private def onStmt(stmt: Statement): Statement = stmt match { | ||
case Connect(_, sink, _) if zeroLenDerivedRefLike(sink) => EmptyStmt | ||
case IsInvalid(_, sink) if zeroLenDerivedRefLike(sink) => EmptyStmt | ||
case Attach(info, sinks) => | ||
val filtered = Attach(info, sinks.filterNot(zeroLenDerivedRefLike)) | ||
if (filtered.exprs.length < 2) EmptyStmt else filtered | ||
case s => s.map(onStmt).map(dropZeroLenSubAccesses) | ||
} | ||
|
||
override def run(c: Circuit): Circuit = { | ||
c.copy(modules = c.modules.map(m => m.map(onStmt))) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// See LICENSE for license details. | ||
|
||
package firrtlTests | ||
|
||
import firrtl._ | ||
import firrtl.passes._ | ||
import firrtl.testutils.FirrtlFlatSpec | ||
|
||
class ZeroLengthVecsSpec extends FirrtlFlatSpec { | ||
val transforms = Seq( | ||
ToWorkingIR, | ||
ResolveKinds, | ||
InferTypes, | ||
ResolveFlows, | ||
new InferWidths, | ||
ZeroLengthVecs, | ||
CheckTypes) | ||
protected def exec(input: String) = { | ||
transforms.foldLeft(CircuitState(parse(input), UnknownForm)) { | ||
(c: CircuitState, t: Transform) => t.runTransform(c) | ||
}.circuit.serialize | ||
} | ||
|
||
"ZeroLengthVecs" should "drop subaccesses to zero-length vectors" in { | ||
val input = | ||
"""circuit bar : | ||
| module bar : | ||
| input i : { a : UInt<8>, b : UInt<4> }[0] | ||
| input sel : UInt<1> | ||
| output foo : UInt<1>[0] | ||
| output o : UInt<8> | ||
| foo[UInt<1>(0)] <= UInt<1>(0) | ||
| o <= i[sel].a | ||
|""".stripMargin | ||
val check = | ||
"""circuit bar : | ||
| module bar : | ||
| input i : { a : UInt<8>, b : UInt<4> }[0] | ||
| input sel : UInt<1> | ||
| output foo : UInt<1>[0] | ||
| output o : UInt<8> | ||
| skip | ||
| o <= validif(UInt<1>(0), UInt<8>(0)) | ||
|""".stripMargin | ||
(parse(exec(input))) should be (parse(check)) | ||
} | ||
|
||
"ZeroLengthVecs" should "handle intervals correctly" in { | ||
val input = | ||
"""circuit bar : | ||
| module bar : | ||
| input i : Interval[3,4].0[0] | ||
| input sel : UInt<1> | ||
| output o : Interval[3,4].0 | ||
| o <= i[sel] | ||
|""".stripMargin | ||
val check = | ||
"""circuit bar : | ||
| module bar : | ||
| input i : Interval[3,4].0[0] | ||
| input sel : UInt<1> | ||
| output o : Interval[3,4].0 | ||
| o <= validif(UInt<1>(0), clip(asInterval(SInt<1>(0), 0, 0, 0), i[sel])) | ||
|""".stripMargin | ||
(parse(exec(input))) should be (parse(check)) | ||
} | ||
|
||
} |