From 37c8528cfed4395924820b54498ef761ded17393 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 17 Dec 2021 10:07:25 -0800 Subject: Deprecate all mutable methods on RenameMap (#2444) * Add renamemap.MutableRenameMap which includes these methods without deprecation * Deprecate Stringly typed RenameMap APIs which were accidentally undeprecated a while ago Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- src/test/scala/firrtl/passes/LowerTypesSpec.scala | 13 +- src/test/scala/firrtl/testutils/FirrtlSpec.scala | 3 +- .../scala/firrtlTests/MutableRenameMapSpec.scala | 877 +++++++++++++++++++++ src/test/scala/firrtlTests/RenameMapSpec.scala | 876 -------------------- .../transforms/ManipulateNamesSpec.scala | 5 +- 5 files changed, 889 insertions(+), 885 deletions(-) create mode 100644 src/test/scala/firrtlTests/MutableRenameMapSpec.scala delete mode 100644 src/test/scala/firrtlTests/RenameMapSpec.scala (limited to 'src/test') diff --git a/src/test/scala/firrtl/passes/LowerTypesSpec.scala b/src/test/scala/firrtl/passes/LowerTypesSpec.scala index 7ca98544..1d15bd70 100644 --- a/src/test/scala/firrtl/passes/LowerTypesSpec.scala +++ b/src/test/scala/firrtl/passes/LowerTypesSpec.scala @@ -5,6 +5,7 @@ import firrtl.annotations.{CircuitTarget, IsMember} import firrtl.annotations.TargetToken.{Instance, OfModule} import firrtl.analyses.InstanceKeyGraph import firrtl.{CircuitState, RenameMap, Utils} +import firrtl.renamemap.MutableRenameMap import firrtl.options.Dependency import firrtl.stage.TransformManager import firrtl.stage.TransformManager.TransformDependency @@ -252,7 +253,7 @@ class LowerTypesOfInstancesSpec extends AnyFlatSpec with FirrtlMatchers { tpe: String, module: String, namespace: Set[String], - otherRenames: RenameMap = RenameMap() + otherRenames: MutableRenameMap = MutableRenameMap() ): Lower = { val ref = firrtl.ir.DefInstance(firrtl.ir.NoInfo, n, module, parseType(tpe)) val mutableSet = scala.collection.mutable.HashSet[String]() ++ namespace @@ -298,8 +299,8 @@ class LowerTypesOfInstancesSpec extends AnyFlatSpec with FirrtlMatchers { // This is to accommodate the use-case where a port as well as an instance needs to be renames // thus requiring a two-stage translation process for reference to the port of the instance. // This two-stage translation is only supported through chaining rename maps. - val portRenames = RenameMap() - val otherRenames = RenameMap() + val portRenames = MutableRenameMap() + val otherRenames = MutableRenameMap() // The child module "c" which we assume has the following ports: b : { c : UInt<1>} and b_c : UInt<1> val c = CircuitTarget("m").module("c") @@ -362,7 +363,7 @@ class LowerTypesOfMemorySpec extends AnyFlatSpec { writers = w, readwriters = rw ) - val renames = RenameMap() + val renames = MutableRenameMap() val mutableSet = scala.collection.mutable.HashSet[String]() ++ namespace val (mems, refs) = DestructTypes.destructMemory(m, mem, mutableSet, renames, Set()) Lower(mems, refs, renames) @@ -655,10 +656,10 @@ private object LowerTypesSpecUtils { val c = CircuitState(firrtl.Parser.parse(src), Seq()) typedCompiler.execute(c).circuit.modules.head.ports.head.tpe } - case class DestructResult(fields: Seq[String], renameMap: RenameMap) + case class DestructResult(fields: Seq[String], renameMap: MutableRenameMap) def destruct(n: String, tpe: String, namespace: Set[String]): DestructResult = { val ref = firrtl.ir.Field(n, firrtl.ir.Default, parseType(tpe)) - val renames = RenameMap() + val renames = MutableRenameMap() val mutableSet = scala.collection.mutable.HashSet[String]() ++ namespace val res = DestructTypes.destruct(m, ref, mutableSet, renames, Set()) DestructResult(resultToFieldSeq(res), renames) diff --git a/src/test/scala/firrtl/testutils/FirrtlSpec.scala b/src/test/scala/firrtl/testutils/FirrtlSpec.scala index 53a8e1e3..f37f6860 100644 --- a/src/test/scala/firrtl/testutils/FirrtlSpec.scala +++ b/src/test/scala/firrtl/testutils/FirrtlSpec.scala @@ -19,6 +19,7 @@ import firrtl.stage.{FirrtlFileAnnotation, InfoModeAnnotation, RunFirrtlTransfor import firrtl.analyses.{GetNamespace, ModuleNamespaceAnnotation} import firrtl.annotations._ import firrtl.transforms.{DontTouchAnnotation, NoDedupAnnotation, RenameModules} +import firrtl.renamemap.MutableRenameMap import firrtl.util.BackendCompilationUtilities import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -64,7 +65,7 @@ object RenameTop extends Transform { case m => m } - val renames = RenameMap() + val renames = MutableRenameMap() renames.record(CircuitTarget(c.main), CircuitTarget(newTopName)) state.copy(circuit = c.copy(main = newTopName, modules = modulesx), renames = Some(renames)) } diff --git a/src/test/scala/firrtlTests/MutableRenameMapSpec.scala b/src/test/scala/firrtlTests/MutableRenameMapSpec.scala new file mode 100644 index 00000000..f8997b36 --- /dev/null +++ b/src/test/scala/firrtlTests/MutableRenameMapSpec.scala @@ -0,0 +1,877 @@ +// SPDX-License-Identifier: Apache-2.0 + +package firrtlTests + +import firrtl.RenameMap +import firrtl.renamemap.MutableRenameMap +import firrtl.RenameMap.IllegalRenameException +import firrtl.annotations._ +import firrtl.annotations.TargetToken.{Instance, OfModule} +import firrtl.analyses.InstanceKeyGraph +import firrtl.testutils._ + +class MutableRenameMapSpec extends FirrtlFlatSpec { + val cir = CircuitTarget("Top") + val cir2 = CircuitTarget("Pot") + val cir3 = CircuitTarget("Cir3") + val modA = cir.module("A") + val modA2 = cir2.module("A") + val modB = cir.module("B") + val foo = modA.ref("foo") + val foo2 = modA2.ref("foo") + val bar = modA.ref("bar") + val fizz = modA.ref("fizz") + val fooB = modB.ref("foo") + val barB = modB.ref("bar") + + val tmb = cir.module("Top").instOf("mid", "Middle").instOf("bot", "Bottom") + val tm2b = cir.module("Top").instOf("mid", "Middle2").instOf("bot", "Bottom") + val middle = cir.module("Middle") + val middle2 = cir.module("Middle2") + + behavior.of("RenameMap") + + it should "return None if it does not rename something" in { + val renames = MutableRenameMap() + renames.get(modA) should be(None) + renames.get(foo) should be(None) + } + + it should "return a Seq of renamed things if it does rename something" in { + val renames = MutableRenameMap() + renames.record(foo, bar) + renames.get(foo) should be(Some(Seq(bar))) + } + + it should "allow something to be renamed to multiple things" in { + val renames = MutableRenameMap() + renames.record(foo, bar) + renames.record(foo, fizz) + renames.get(foo) should be(Some(Seq(bar, fizz))) + } + + it should "allow something to be renamed to nothing (ie. deleted)" in { + val renames = MutableRenameMap() + renames.record(foo, Seq()) + renames.get(foo) should be(Some(Seq())) + } + + it should "return None if something is renamed to itself" in { + val renames = MutableRenameMap() + renames.record(foo, foo) + renames.get(foo) should be(None) + } + + it should "allow targets to change module" in { + val renames = MutableRenameMap() + renames.record(foo, fooB) + renames.get(foo) should be(Some(Seq(fooB))) + } + + it should "rename targets if their module is renamed" in { + val renames = MutableRenameMap() + renames.record(modA, modB) + renames.get(foo) should be(Some(Seq(fooB))) + renames.get(bar) should be(Some(Seq(barB))) + } + + it should "not rename already renamed targets if the module of the target is renamed" in { + val renames = MutableRenameMap() + renames.record(modA, modB) + renames.record(foo, bar) + renames.get(foo) should be(Some(Seq(bar))) + } + + it should "rename modules if their circuit is renamed" in { + val renames = MutableRenameMap() + renames.record(cir, cir2) + renames.get(modA) should be(Some(Seq(modA2))) + } + + it should "rename targets if their circuit is renamed" in { + val renames = MutableRenameMap() + renames.record(cir, cir2) + renames.get(foo) should be(Some(Seq(foo2))) + } + + val TopCircuit = cir + val Top = cir.module("Top") + val Top_m = Top.instOf("m", "Middle") + val Top_m_l = Top_m.instOf("l", "Leaf") + val Top_m_l_a = Top_m_l.ref("a") + val Top_m_la = Top_m.ref("l").field("a") + val Middle = cir.module("Middle") + val Middle2 = cir.module("Middle2") + val Middle_la = Middle.ref("l").field("a") + val Middle_l_a = Middle.instOf("l", "Leaf").ref("a") + + it should "rename targets if modules in the path are renamed" in { + val renames = MutableRenameMap() + renames.record(Middle, Middle2) + renames.get(Top_m) should be(Some(Seq(Top.instOf("m", "Middle2")))) + } + + it should "rename only the instance if instance and module in the path are renamed" in { + val renames = MutableRenameMap() + renames.record(Middle, Middle2) + renames.record(Top.instOf("m", "Middle"), Top.instOf("m2", "Middle")) + renames.get(Top_m) should be(Some(Seq(Top.instOf("m2", "Middle")))) + } + + it should "rename targets if instance in the path are renamed" in { + val renames = MutableRenameMap() + renames.record(Top.instOf("m", "Middle"), Top.instOf("m2", "Middle")) + renames.get(Top_m) should be(Some(Seq(Top.instOf("m2", "Middle")))) + } + + it should "rename targets if instance and ofmodule in the path are renamed" in { + val renames = MutableRenameMap() + val Top_m2 = Top.instOf("m2", "Middle2") + renames.record(Top_m, Top_m2) + renames.get(Top_m) should be(Some(Seq(Top_m2))) + } + + it should "properly do nothing if no remaps" in { + val renames = MutableRenameMap() + renames.get(Top_m_l_a) should be(None) + } + + it should "properly rename if leaf is inlined" in { + val renames = MutableRenameMap() + renames.record(Middle_l_a, Middle_la) + renames.get(Top_m_l_a) should be(Some(Seq(Top_m_la))) + } + + it should "properly rename if middle is inlined" in { + val renames = MutableRenameMap() + renames.record(Top_m_l, Top.instOf("m_l", "Leaf")) + renames.get(Top_m_l_a) should be(Some(Seq(Top.instOf("m_l", "Leaf").ref("a")))) + } + + it should "properly rename if leaf and middle are inlined" in { + val renames = MutableRenameMap() + val inlined = Top.ref("m_l_a") + renames.record(Top_m_l_a, inlined) + renames.record(Top_m_l, Nil) + renames.record(Top_m, Nil) + renames.get(Top_m_l_a) should be(Some(Seq(inlined))) + } + + it should "quickly rename a target with a long path" in { + (0 until 50 by 10).foreach { endIdx => + val renames = MutableRenameMap() + renames.record(TopCircuit.module("Y0"), TopCircuit.module("X0")) + val deepTarget = (0 until endIdx) + .foldLeft(Top: IsModule) { (t, idx) => + t.instOf("a", "A" + idx) + } + .ref("ref") + val (millis, rename) = firrtl.Utils.time(renames.get(deepTarget)) + //rename should be(None) + } + } + + it should "rename only once with multiple renames" in { + val renames = MutableRenameMap() + val Middle2 = cir.module("Middle2") + renames.record(Middle, Middle2) + renames.record(Middle.ref("l"), Middle.ref("lx")) + renames.get(Middle.ref("l")) should be(Some(Seq(Middle.ref("lx")))) + } + + it should "rename with fields" in { + val Middle_o = Middle.ref("o") + val Middle_i = Middle.ref("i") + val Middle_o_f = Middle.ref("o").field("f") + val Middle_i_f = Middle.ref("i").field("f") + val renames = MutableRenameMap() + renames.record(Middle_o, Middle_i) + renames.get(Middle_o_f) should be(Some(Seq(Middle_i_f))) + } + + it should "rename instances with same ofModule" in { + val Middle_o = Middle.instOf("o", "O") + val Middle_i = Middle.instOf("i", "O") + val renames = MutableRenameMap() + renames.record(Middle_o, Middle_i) + renames.get(Middle.instOf("o", "O")) should be(Some(Seq(Middle.instOf("i", "O")))) + } + + it should "not treat references as instances targets" in { + val Middle_o = Middle.ref("o") + val Middle_i = Middle.ref("i") + val renames = MutableRenameMap() + renames.record(Middle_o, Middle_i) + renames.get(Middle.instOf("o", "O")) should be(None) + } + + it should "be able to rename weird stuff" in { + // Renaming `from` to each of the `tos` at the same time should be ok + case class BadRename(from: CompleteTarget, tos: Seq[CompleteTarget]) + val badRenames = + Seq( //BadRename(foo, Seq(cir)), + //BadRename(foo, Seq(modB)), + //BadRename(modA, Seq(fooB)), + //BadRename(modA, Seq(cir)), + //BadRename(cir, Seq(foo)), + //BadRename(cir, Seq(modA)), + BadRename(cir, Seq(cir2, cir3)) + ) + // Run all BadRename tests + for (BadRename(from, tos) <- badRenames) { + val fromN = from + val tosN = tos.mkString(", ") + //it should s"error if a $fromN is renamed to $tosN" in { + val renames = MutableRenameMap() + for (to <- tos) { + (from, to) match { + case (f: CircuitTarget, t: CircuitTarget) => renames.record(f, t) + case (f: IsMember, t: IsMember) => renames.record(f, t) + case _ => sys.error("Unexpected!") + } + } + //a [FIRRTLException] shouldBe thrownBy { + renames.get(from) + //} + //} + } + } + + it should "not error if a circular rename occurs" in { + val renames = MutableRenameMap() + val top = CircuitTarget("Top") + renames.record(top.module("A"), top.module("B").instOf("c", "C")) + renames.record(top.module("B"), top.module("A").instOf("c", "C")) + renames.get(top.module("A")) should be { + Some(Seq(top.module("B").instOf("c", "C"))) + } + } + + it should "not error if a swapping rename occurs" in { + val renames = MutableRenameMap() + val top = CircuitTarget("Top") + renames.record(top.module("A"), top.module("B")) + renames.record(top.module("B"), top.module("A")) + renames.get(top.module("A")) should be(Some(Seq(top.module("B")))) + renames.get(top.module("B")) should be(Some(Seq(top.module("A")))) + } + + it should "error if a reference is renamed to a module and vice versa" in { + val renames = MutableRenameMap() + val top = CircuitTarget("Top") + renames.record(top.module("A").ref("ref"), top.module("B")) + renames.record(top.module("C"), top.module("D").ref("ref")) + a[IllegalRenameException] shouldBe thrownBy { + renames.get(top.module("C")) + } + a[IllegalRenameException] shouldBe thrownBy { + renames.get(top.module("A").ref("ref").field("field")) + } + renames.get(top.module("A").instOf("ref", "R")) should be(None) + } + + it should "error if we rename an instance's ofModule into a non-module" in { + val renames = MutableRenameMap() + val top = CircuitTarget("Top") + + renames.record(top.module("C"), top.module("D").ref("x")) + a[IllegalRenameException] shouldBe thrownBy { + renames.get(top.module("A").instOf("c", "C")) + } + } + + it should "error if path is renamed into a non-path" ignore { + val renames = MutableRenameMap() + val top = CircuitTarget("Top") + + renames.record(top.module("E").instOf("f", "F"), top.module("E").ref("g")) + + a[IllegalRenameException] shouldBe thrownBy { + renames.get(top.module("E").instOf("f", "F").ref("g")) + } + } + + it should "rename reference targets with paths if their corresponding pathless target are renamed" in { + val cir = CircuitTarget("Top") + val modTop = cir.module("Top") + val modA = cir.module("A") + + val aggregate = modA.ref("agg") + val subField1 = aggregate.field("field1") + val subField2 = aggregate.field("field2") + + val lowered1 = aggregate.copy(ref = "agg_field1") + val lowered2 = aggregate.copy(ref = "agg_field2") + + // simulating LowerTypes transform + val renames = MutableRenameMap() + renames.record(subField1, lowered1) + renames.record(subField2, lowered2) + renames.record(aggregate, Seq(lowered1, lowered2)) + + val path = modTop.instOf("b", "B").instOf("a", "A") + val testRef1 = subField1.setPathTarget(path) + + renames.get(testRef1) should be { + Some(Seq(testRef1.copy(ref = "agg_field1", component = Nil))) + } + } + + // ~Top|Module/i1:I1>foo.field, where rename map contains ~Top|Module/i1:I1>foo -> ~Top|Module/i1:I1>bar. + it should "properly rename reference targets with the same paths" in { + val cir = CircuitTarget("Top") + val modTop = cir.module("Top") + val mod = cir.module("Module") + + val path = mod.instOf("i1", "I1") + val oldAgg = mod.ref("foo").setPathTarget(path) + val newAgg = mod.ref("bar").setPathTarget(path) + + val renames = MutableRenameMap() + renames.record(oldAgg, newAgg) + + val testRef = oldAgg.field("field") + renames.get(testRef) should be { + Some(Seq(newAgg.field("field"))) + } + } + + it should "properly rename reference targets with partially matching paths" in { + val cir = CircuitTarget("Top") + val modTop = cir.module("Top") + val modA = cir.module("A") + val modB = cir.module("B") + + val path = modB.instOf("a", "A") + val oldRef = modA.ref("oldRef").setPathTarget(path) + val newRef = modA.ref("newRef").setPathTarget(path) + + val renames = MutableRenameMap() + renames.record(oldRef, newRef) + + val testRef = oldRef.addHierarchy("B", "b") + renames.get(testRef) should be { + Some(Seq(newRef.addHierarchy("B", "b"))) + } + } + + it should "properly rename reference targets with partially matching paths and partially matching target tokens" in { + val cir = CircuitTarget("Top") + val modTop = cir.module("Top") + val modA = cir.module("A") + val modB = cir.module("B") + + val path = modB.instOf("a", "A") + val oldAgg = modA.ref("oldAgg").setPathTarget(path).field("field1") + val newAgg = modA.ref("newAgg").setPathTarget(path) + + val renames = MutableRenameMap() + renames.record(oldAgg, newAgg) + + val testRef = oldAgg.addHierarchy("B", "b").field("field2") + renames.get(testRef) should be { + Some(Seq(newAgg.addHierarchy("B", "b").field("field2"))) + } + } + + it should "rename targets with multiple renames starting from most specific to least specific" in { + val cir = CircuitTarget("Top") + val modTop = cir.module("Top") + val modA = cir.module("A") + val modB = cir.module("B") + val modC = cir.module("C") + + // from: ~Top|A/b:B/c:C>ref.f1.f2.f3 + // to: ~Top|A/b:B/c:C>ref.f1.f2.f333 + // renamed first because it is an exact match + val from1 = modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f1") + .field("f2") + .field("f3") + val to1 = modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f1") + .field("f2") + .field("f33") + + // from: ~Top|A/b:B/c:C>ref.f1.f2 + // to: ~Top|A/b:B/c:C>ref.f1 + // renamed second because it is a parent target + val from2 = modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f1") + .field("f2") + val to2 = modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f1") + .field("f22") + + // from: ~Top|B/c:C>ref.f1 + // to: ~Top|B/c:C>ref.f11 + // renamed third because it has a smaller hierarchy + val from3 = modB + .instOf("c", "C") + .ref("ref") + .field("f1") + val to3 = modB + .instOf("c", "C") + .ref("ref") + .field("f11") + + // from: ~Top|C>ref + // to: ~Top|C>refref + // renamed last because it has no path + val from4 = modC.ref("ref") + val to4 = modC.ref("refref") + + val renames1 = MutableRenameMap() + renames1.record(from1, to1) + renames1.record(from2, to2) + renames1.record(from3, to3) + renames1.record(from4, to4) + + renames1.get(from1) should be { + Some( + Seq( + modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f1") + .field("f2") + .field("f33") + ) + ) + } + + val renames2 = MutableRenameMap() + renames2.record(from2, to2) + renames2.record(from3, to3) + renames2.record(from4, to4) + + renames2.get(from1) should be { + Some( + Seq( + modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f1") + .field("f22") + .field("f3") + ) + ) + } + + val renames3 = MutableRenameMap() + renames3.record(from3, to3) + renames3.record(from4, to4) + + renames3.get(from1) should be { + Some( + Seq( + modA + .instOf("b", "B") + .instOf("c", "C") + .ref("ref") + .field("f11") + .field("f2") + .field("f3") + ) + ) + } + } + + it should "correctly handle renaming of modules to instances" in { + val cir = CircuitTarget("Top") + val renames = MutableRenameMap() + val from = cir.module("C") + val to = cir.module("D").instOf("e", "E").instOf("f", "F") + renames.record(from, to) + renames.get(cir.module("C")) should be { + Some(Seq(cir.module("D").instOf("e", "E").instOf("f", "F"))) + } + renames.get(cir.module("A").instOf("b", "B").instOf("c", "C")) should be { + Some(Seq(cir.module("A").instOf("b", "B").instOf("c", "D").instOf("e", "E").instOf("f", "F"))) + } + } + + it should "correctly handle renaming of paths and components at the same time" in { + val cir = CircuitTarget("Top") + val renames = MutableRenameMap() + val from = cir.module("C").ref("foo").field("bar") + val to = cir.module("D").instOf("e", "E").instOf("f", "F").ref("foo").field("foo") + renames.record(from, to) + renames.get(cir.module("A").instOf("b", "B").instOf("c", "C").ref("foo").field("bar")) should be { + Some( + Seq( + cir + .module("A") + .instOf("b", "B") + .instOf("c", "D") + .instOf("e", "E") + .instOf("f", "F") + .ref("foo") + .field("foo") + ) + ) + } + } + + it should "error if an instance is renamed to a ReferenceTarget" in { + val top = CircuitTarget("Top").module("Top") + val renames = MutableRenameMap() + val from = top.instOf("a", "A") + val to = top.ref("b") + renames.record(from, to) + a[IllegalRenameException] shouldBe thrownBy { + renames.get(from) + } + } + + it should "not allow renaming of instances even if there is a matching reference rename" in { + val top = CircuitTarget("Top").module("Top") + val renames = MutableRenameMap() + val from = top.ref("a") + val to = top.ref("b") + renames.record(from, to) + renames.get(top.instOf("a", "Foo")) should be(None) + } + + it should "correctly chain renames together" in { + val top = CircuitTarget("Top") + + val renames1 = MutableRenameMap() + val from1 = top.module("A") + val to1 = top.module("Top").instOf("b", "B") + renames1.record(from1, to1) + + val renames2 = MutableRenameMap() + val from2 = top.module("B") + val to2 = top.module("B1") + renames2.record(from2, to2) + + val renames = renames1.andThen(renames2) + + renames.get(from1) should be { + Some(Seq(top.module("Top").instOf("b", "B1"))) + } + + renames.get(from2) should be { + Some(Seq(to2)) + } + } + + it should "correctly chain deleted targets" in { + val top = CircuitTarget("Top") + val modA = top.module("A") + val modA1 = top.module("A1") + val modB = top.module("B") + val modB1 = top.module("B1") + + val renames1 = MutableRenameMap() + renames1.delete(modA) + renames1.record(modB, modB1) + + val renames2 = MutableRenameMap() + renames2.record(modA, modA1) + renames2.delete(modB1) + + val renames = renames1.andThen(renames2) + + renames.get(modA) should be { + Some(Seq.empty) + } + renames.get(modB) should be { + Some(Seq.empty) + } + } + + it should "correctly ++ renameMaps" in { + val top = CircuitTarget("Top") + val modA = top.module("A") + val modA1 = top.module("A1") + val modA2 = top.module("A1") + val modB = top.module("B") + val modB1 = top.module("B1") + val modC = top.module("C") + val modC1 = top.module("C1") + + val renames1 = MutableRenameMap() + renames1.record(modA, modA1) + renames1.record(modC, modC1) + + val renames2 = MutableRenameMap() + renames2.record(modA, modA2) + renames2.record(modB, modB1) + + val renames = renames1 ++ renames2 + renames.get(modA) should be { + Some(Seq(modA2)) + } + renames.get(modB) should be { + Some(Seq(modB1)) + } + renames.get(modC) should be { + Some(Seq(modC1)) + } + } + + it should "be able to inline instances" in { + val top = CircuitTarget("Top") + val inlineRename1 = { + val inlineMod = top.module("A") + val inlineInst = top.module("A").instOf("b", "B") + val oldRef = inlineMod.ref("bar") + val prefixRef = inlineMod.ref("foo") + + val renames1 = MutableRenameMap() + renames1.record(inlineInst, inlineMod) + + val renames2 = MutableRenameMap() + renames2.record(oldRef, prefixRef) + + renames1.andThen(renames2) + } + + val inlineRename2 = { + val inlineMod = top.module("A1") + val inlineInst = top.module("A1").instOf("b", "B1") + val oldRef = inlineMod.ref("bar") + val prefixRef = inlineMod.ref("foo") + + val renames1 = MutableRenameMap() + renames1.record(inlineInst, inlineMod) + + val renames2 = MutableRenameMap() + renames2.record(oldRef, prefixRef) + + renames1.andThen(renames2) + } + + val renames = inlineRename1 ++ inlineRename2 + renames.get(top.module("A").instOf("b", "B").ref("bar")) should be { + Some(Seq(top.module("A").ref("foo"))) + } + + renames.get(top.module("A1").instOf("b", "B1").ref("bar")) should be { + Some(Seq(top.module("A1").ref("foo"))) + } + } + + it should "be able to dedup modules" in { + val top = CircuitTarget("Top") + val topMod = top.module("Top") + val dedupedMod = top.module("A") + val dupMod1 = top.module("A1") + val dupMod2 = top.module("A2") + + val relPath1 = dupMod1.addHierarchy("Foo", "a") //top.module("Foo").instOf("a", "A1") + val relPath2 = dupMod2.addHierarchy("Foo", "a") //top.module("Foo").instOf("a", "A2") + + val absPath1 = relPath1.addHierarchy("Top", "foo") + val absPath2 = relPath2.addHierarchy("Top", "foo") + + val renames1 = MutableRenameMap() + renames1.record(dupMod1, absPath1) + renames1.record(dupMod2, absPath2) + renames1.record(relPath1, absPath1) + renames1.record(relPath2, absPath2) + + val renames2 = MutableRenameMap() + renames2.record(dupMod1, dedupedMod) + renames2.record(dupMod2, dedupedMod) + + val renames = renames1.andThen(renames2) + + renames.get(dupMod1.instOf("foo", "Bar").ref("ref")) should be { + Some(Seq(absPath1.copy(ofModule = "A").instOf("foo", "Bar").ref("ref"))) + } + + renames.get(dupMod2.ref("ref")) should be { + Some(Seq(absPath2.copy(ofModule = "A").ref("ref"))) + } + + renames.get(absPath1.instOf("b", "B").ref("ref")) should be { + Some(Seq(absPath1.copy(ofModule = "A").instOf("b", "B").ref("ref"))) + } + } + + it should "should able to chain many rename maps" in { + val top = CircuitTarget("Top") + val inlineRename1 = { + val inlineMod = top.module("A") + val inlineInst = top.module("A").instOf("b", "B") + val oldRef = inlineMod.ref("bar") + val prefixRef = inlineMod.ref("foo") + + val renames1 = MutableRenameMap() + renames1.record(inlineInst, inlineMod) + + val renames2 = MutableRenameMap() + renames2.record(oldRef, prefixRef) + + renames1.andThen(renames2) + } + + val inlineRename2 = { + val inlineMod = top.module("A1") + val inlineInst = top.module("A1").instOf("b", "B1") + val oldRef = inlineMod.ref("bar") + val prefixRef = inlineMod.ref("foo") + + val renames1 = MutableRenameMap() + renames1.record(inlineInst, inlineMod) + + val renames2 = MutableRenameMap() + renames2.record(oldRef, prefixRef) + + inlineRename1.andThen(renames1).andThen(renames2) + } + + val renames = inlineRename2 + renames.get(top.module("A").instOf("b", "B").ref("bar")) should be { + Some(Seq(top.module("A").ref("foo"))) + } + + renames.get(top.module("A1").instOf("b", "B1").ref("bar")) should be { + Some(Seq(top.module("A1").ref("foo"))) + } + } + + it should "should able to chain chained rename maps" in { + val top = CircuitTarget("Top").module("Top") + val foo1 = top.instOf("foo1", "Mod") + val foo2 = top.instOf("foo2", "Mod") + val foo3 = top.instOf("foo3", "Mod") + + val bar1 = top.instOf("bar1", "Mod") + val bar2 = top.instOf("bar2", "Mod") + + val foo1Rename = MutableRenameMap() + val foo2Rename = MutableRenameMap() + + val bar1Rename = MutableRenameMap() + val bar2Rename = MutableRenameMap() + + foo1Rename.record(foo1, foo2) + foo2Rename.record(foo2, foo3) + + bar1Rename.record(foo3, bar1) + bar2Rename.record(bar1, bar2) + + val chained1 = foo1Rename.andThen(foo2Rename) + val chained2 = bar1Rename.andThen(bar2Rename) + + val renames = chained1.andThen(chained2) + + renames.get(foo1) should be { + Some(Seq(bar2)) + } + } + + it should "record a self-rename" in { + val top = CircuitTarget("Top").module("Top") + val foo = top.instOf("foo", "Mod") + val bar = top.instOf("bar", "Mod") + + val r = MutableRenameMap() + + r.record(foo, bar) + r.record(foo, foo) + + r.get(foo) should not be (empty) + (r.get(foo).get should contain).allOf(foo, bar) + } + + it should "not record the same rename multiple times" in { + val top = CircuitTarget("Top").module("Top") + val foo = top.instOf("foo", "Mod") + val bar = top.instOf("bar", "Mod") + + val r = MutableRenameMap() + + r.record(foo, bar) + r.record(foo, bar) + + r.get(foo) should not be (empty) + r.get(foo).get should contain theSameElementsAs Seq(bar) + } + + it should "not circularly rename" in { + val top = CircuitTarget("Top").module("Top") + val foo = top.instOf("foo", "Mod") + val Mod = CircuitTarget("Top").module("Mod") + val Mod2 = CircuitTarget("Top").module("Mod2") + + val r = MutableRenameMap() + + r.record(foo, Mod) + r.record(Mod, Mod2) + + r.get(foo) should not be (empty) + r.get(foo).get should contain theSameElementsAs Seq(Mod) + r.get(Mod).get should contain theSameElementsAs Seq(Mod2) + } + + it should "delete instances of deleted modules" in { + val top = CircuitTarget("Top").module("Top") + val foo = top.instOf("foo", "Mod") + val Mod = CircuitTarget("Top").module("Mod") + + val r = MutableRenameMap() + + r.delete(Mod) + r.get(foo) should be(Some(Nil)) + } + + it should "rename an instance if it has been renamed" in { + // this could happen if the instance name needed to be uniquified to avoid clashes in LowerTypes + val top = CircuitTarget("top").module("top") + + val r = MutableRenameMap() + val i = top.instOf("i", "child") + val i_ = top.instOf("i_", "child") + r.record(i, i_) + r.get(i) should be(Some(Seq(i_))) + r.get(i.ref("a")) should be(Some(Seq(i_.ref("a")))) + } + + it should "rename references to an instance's ports if the ports of the module have been renamed" in { + // this could happen if the port name needed to be uniquified to avoid clashes in LowerTypes + val top = CircuitTarget("top").module("top") + val child = CircuitTarget("top").module("child") + + val r = MutableRenameMap() + r.record(child.ref("a"), Seq(child.ref("a_0"), child.ref("a_1"))) + val i = top.instOf("i", "child") + r.get(i.ref("a")) should be(Some(Seq(i.ref("a_0"), i.ref("a_1")))) + } + + it should "rename references to renamed instance's ports if the ports of the module have been renamed" in { + // this could happen if the instance as well as the port name needed to be uniquified to avoid clashes in LowerTypes + val top = CircuitTarget("top").module("top") + val child = CircuitTarget("top").module("child") + + val portRenames = MutableRenameMap() + portRenames.record(child.ref("a"), Seq(child.ref("a_0"), child.ref("a_1"))) + + val instanceRenames = MutableRenameMap() + val i = top.instOf("i", "child") + val i_ = top.instOf("i_", "child") + instanceRenames.record(i, i_) + + // The port and instance renames must be *explicitly* chained! + val r = portRenames.andThen(instanceRenames) + r.get(i.ref("a")) should be(Some(Seq(i_.ref("a_0"), i_.ref("a_1")))) + } +} diff --git a/src/test/scala/firrtlTests/RenameMapSpec.scala b/src/test/scala/firrtlTests/RenameMapSpec.scala deleted file mode 100644 index bebeb0bf..00000000 --- a/src/test/scala/firrtlTests/RenameMapSpec.scala +++ /dev/null @@ -1,876 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package firrtlTests - -import firrtl.RenameMap -import firrtl.RenameMap.IllegalRenameException -import firrtl.annotations._ -import firrtl.annotations.TargetToken.{Instance, OfModule} -import firrtl.analyses.InstanceKeyGraph -import firrtl.testutils._ - -class RenameMapSpec extends FirrtlFlatSpec { - val cir = CircuitTarget("Top") - val cir2 = CircuitTarget("Pot") - val cir3 = CircuitTarget("Cir3") - val modA = cir.module("A") - val modA2 = cir2.module("A") - val modB = cir.module("B") - val foo = modA.ref("foo") - val foo2 = modA2.ref("foo") - val bar = modA.ref("bar") - val fizz = modA.ref("fizz") - val fooB = modB.ref("foo") - val barB = modB.ref("bar") - - val tmb = cir.module("Top").instOf("mid", "Middle").instOf("bot", "Bottom") - val tm2b = cir.module("Top").instOf("mid", "Middle2").instOf("bot", "Bottom") - val middle = cir.module("Middle") - val middle2 = cir.module("Middle2") - - behavior.of("RenameMap") - - it should "return None if it does not rename something" in { - val renames = RenameMap() - renames.get(modA) should be(None) - renames.get(foo) should be(None) - } - - it should "return a Seq of renamed things if it does rename something" in { - val renames = RenameMap() - renames.record(foo, bar) - renames.get(foo) should be(Some(Seq(bar))) - } - - it should "allow something to be renamed to multiple things" in { - val renames = RenameMap() - renames.record(foo, bar) - renames.record(foo, fizz) - renames.get(foo) should be(Some(Seq(bar, fizz))) - } - - it should "allow something to be renamed to nothing (ie. deleted)" in { - val renames = RenameMap() - renames.record(foo, Seq()) - renames.get(foo) should be(Some(Seq())) - } - - it should "return None if something is renamed to itself" in { - val renames = RenameMap() - renames.record(foo, foo) - renames.get(foo) should be(None) - } - - it should "allow targets to change module" in { - val renames = RenameMap() - renames.record(foo, fooB) - renames.get(foo) should be(Some(Seq(fooB))) - } - - it should "rename targets if their module is renamed" in { - val renames = RenameMap() - renames.record(modA, modB) - renames.get(foo) should be(Some(Seq(fooB))) - renames.get(bar) should be(Some(Seq(barB))) - } - - it should "not rename already renamed targets if the module of the target is renamed" in { - val renames = RenameMap() - renames.record(modA, modB) - renames.record(foo, bar) - renames.get(foo) should be(Some(Seq(bar))) - } - - it should "rename modules if their circuit is renamed" in { - val renames = RenameMap() - renames.record(cir, cir2) - renames.get(modA) should be(Some(Seq(modA2))) - } - - it should "rename targets if their circuit is renamed" in { - val renames = RenameMap() - renames.record(cir, cir2) - renames.get(foo) should be(Some(Seq(foo2))) - } - - val TopCircuit = cir - val Top = cir.module("Top") - val Top_m = Top.instOf("m", "Middle") - val Top_m_l = Top_m.instOf("l", "Leaf") - val Top_m_l_a = Top_m_l.ref("a") - val Top_m_la = Top_m.ref("l").field("a") - val Middle = cir.module("Middle") - val Middle2 = cir.module("Middle2") - val Middle_la = Middle.ref("l").field("a") - val Middle_l_a = Middle.instOf("l", "Leaf").ref("a") - - it should "rename targets if modules in the path are renamed" in { - val renames = RenameMap() - renames.record(Middle, Middle2) - renames.get(Top_m) should be(Some(Seq(Top.instOf("m", "Middle2")))) - } - - it should "rename only the instance if instance and module in the path are renamed" in { - val renames = RenameMap() - renames.record(Middle, Middle2) - renames.record(Top.instOf("m", "Middle"), Top.instOf("m2", "Middle")) - renames.get(Top_m) should be(Some(Seq(Top.instOf("m2", "Middle")))) - } - - it should "rename targets if instance in the path are renamed" in { - val renames = RenameMap() - renames.record(Top.instOf("m", "Middle"), Top.instOf("m2", "Middle")) - renames.get(Top_m) should be(Some(Seq(Top.instOf("m2", "Middle")))) - } - - it should "rename targets if instance and ofmodule in the path are renamed" in { - val renames = RenameMap() - val Top_m2 = Top.instOf("m2", "Middle2") - renames.record(Top_m, Top_m2) - renames.get(Top_m) should be(Some(Seq(Top_m2))) - } - - it should "properly do nothing if no remaps" in { - val renames = RenameMap() - renames.get(Top_m_l_a) should be(None) - } - - it should "properly rename if leaf is inlined" in { - val renames = RenameMap() - renames.record(Middle_l_a, Middle_la) - renames.get(Top_m_l_a) should be(Some(Seq(Top_m_la))) - } - - it should "properly rename if middle is inlined" in { - val renames = RenameMap() - renames.record(Top_m_l, Top.instOf("m_l", "Leaf")) - renames.get(Top_m_l_a) should be(Some(Seq(Top.instOf("m_l", "Leaf").ref("a")))) - } - - it should "properly rename if leaf and middle are inlined" in { - val renames = RenameMap() - val inlined = Top.ref("m_l_a") - renames.record(Top_m_l_a, inlined) - renames.record(Top_m_l, Nil) - renames.record(Top_m, Nil) - renames.get(Top_m_l_a) should be(Some(Seq(inlined))) - } - - it should "quickly rename a target with a long path" in { - (0 until 50 by 10).foreach { endIdx => - val renames = RenameMap() - renames.record(TopCircuit.module("Y0"), TopCircuit.module("X0")) - val deepTarget = (0 until endIdx) - .foldLeft(Top: IsModule) { (t, idx) => - t.instOf("a", "A" + idx) - } - .ref("ref") - val (millis, rename) = firrtl.Utils.time(renames.get(deepTarget)) - //rename should be(None) - } - } - - it should "rename only once with multiple renames" in { - val renames = RenameMap() - val Middle2 = cir.module("Middle2") - renames.record(Middle, Middle2) - renames.record(Middle.ref("l"), Middle.ref("lx")) - renames.get(Middle.ref("l")) should be(Some(Seq(Middle.ref("lx")))) - } - - it should "rename with fields" in { - val Middle_o = Middle.ref("o") - val Middle_i = Middle.ref("i") - val Middle_o_f = Middle.ref("o").field("f") - val Middle_i_f = Middle.ref("i").field("f") - val renames = RenameMap() - renames.record(Middle_o, Middle_i) - renames.get(Middle_o_f) should be(Some(Seq(Middle_i_f))) - } - - it should "rename instances with same ofModule" in { - val Middle_o = Middle.instOf("o", "O") - val Middle_i = Middle.instOf("i", "O") - val renames = RenameMap() - renames.record(Middle_o, Middle_i) - renames.get(Middle.instOf("o", "O")) should be(Some(Seq(Middle.instOf("i", "O")))) - } - - it should "not treat references as instances targets" in { - val Middle_o = Middle.ref("o") - val Middle_i = Middle.ref("i") - val renames = RenameMap() - renames.record(Middle_o, Middle_i) - renames.get(Middle.instOf("o", "O")) should be(None) - } - - it should "be able to rename weird stuff" in { - // Renaming `from` to each of the `tos` at the same time should be ok - case class BadRename(from: CompleteTarget, tos: Seq[CompleteTarget]) - val badRenames = - Seq( //BadRename(foo, Seq(cir)), - //BadRename(foo, Seq(modB)), - //BadRename(modA, Seq(fooB)), - //BadRename(modA, Seq(cir)), - //BadRename(cir, Seq(foo)), - //BadRename(cir, Seq(modA)), - BadRename(cir, Seq(cir2, cir3)) - ) - // Run all BadRename tests - for (BadRename(from, tos) <- badRenames) { - val fromN = from - val tosN = tos.mkString(", ") - //it should s"error if a $fromN is renamed to $tosN" in { - val renames = RenameMap() - for (to <- tos) { - (from, to) match { - case (f: CircuitTarget, t: CircuitTarget) => renames.record(f, t) - case (f: IsMember, t: IsMember) => renames.record(f, t) - case _ => sys.error("Unexpected!") - } - } - //a [FIRRTLException] shouldBe thrownBy { - renames.get(from) - //} - //} - } - } - - it should "not error if a circular rename occurs" in { - val renames = RenameMap() - val top = CircuitTarget("Top") - renames.record(top.module("A"), top.module("B").instOf("c", "C")) - renames.record(top.module("B"), top.module("A").instOf("c", "C")) - renames.get(top.module("A")) should be { - Some(Seq(top.module("B").instOf("c", "C"))) - } - } - - it should "not error if a swapping rename occurs" in { - val renames = RenameMap() - val top = CircuitTarget("Top") - renames.record(top.module("A"), top.module("B")) - renames.record(top.module("B"), top.module("A")) - renames.get(top.module("A")) should be(Some(Seq(top.module("B")))) - renames.get(top.module("B")) should be(Some(Seq(top.module("A")))) - } - - it should "error if a reference is renamed to a module and vice versa" in { - val renames = RenameMap() - val top = CircuitTarget("Top") - renames.record(top.module("A").ref("ref"), top.module("B")) - renames.record(top.module("C"), top.module("D").ref("ref")) - a[IllegalRenameException] shouldBe thrownBy { - renames.get(top.module("C")) - } - a[IllegalRenameException] shouldBe thrownBy { - renames.get(top.module("A").ref("ref").field("field")) - } - renames.get(top.module("A").instOf("ref", "R")) should be(None) - } - - it should "error if we rename an instance's ofModule into a non-module" in { - val renames = RenameMap() - val top = CircuitTarget("Top") - - renames.record(top.module("C"), top.module("D").ref("x")) - a[IllegalRenameException] shouldBe thrownBy { - renames.get(top.module("A").instOf("c", "C")) - } - } - - it should "error if path is renamed into a non-path" ignore { - val renames = RenameMap() - val top = CircuitTarget("Top") - - renames.record(top.module("E").instOf("f", "F"), top.module("E").ref("g")) - - a[IllegalRenameException] shouldBe thrownBy { - renames.get(top.module("E").instOf("f", "F").ref("g")) - } - } - - it should "rename reference targets with paths if their corresponding pathless target are renamed" in { - val cir = CircuitTarget("Top") - val modTop = cir.module("Top") - val modA = cir.module("A") - - val aggregate = modA.ref("agg") - val subField1 = aggregate.field("field1") - val subField2 = aggregate.field("field2") - - val lowered1 = aggregate.copy(ref = "agg_field1") - val lowered2 = aggregate.copy(ref = "agg_field2") - - // simulating LowerTypes transform - val renames = RenameMap() - renames.record(subField1, lowered1) - renames.record(subField2, lowered2) - renames.record(aggregate, Seq(lowered1, lowered2)) - - val path = modTop.instOf("b", "B").instOf("a", "A") - val testRef1 = subField1.setPathTarget(path) - - renames.get(testRef1) should be { - Some(Seq(testRef1.copy(ref = "agg_field1", component = Nil))) - } - } - - // ~Top|Module/i1:I1>foo.field, where rename map contains ~Top|Module/i1:I1>foo -> ~Top|Module/i1:I1>bar. - it should "properly rename reference targets with the same paths" in { - val cir = CircuitTarget("Top") - val modTop = cir.module("Top") - val mod = cir.module("Module") - - val path = mod.instOf("i1", "I1") - val oldAgg = mod.ref("foo").setPathTarget(path) - val newAgg = mod.ref("bar").setPathTarget(path) - - val renames = RenameMap() - renames.record(oldAgg, newAgg) - - val testRef = oldAgg.field("field") - renames.get(testRef) should be { - Some(Seq(newAgg.field("field"))) - } - } - - it should "properly rename reference targets with partially matching paths" in { - val cir = CircuitTarget("Top") - val modTop = cir.module("Top") - val modA = cir.module("A") - val modB = cir.module("B") - - val path = modB.instOf("a", "A") - val oldRef = modA.ref("oldRef").setPathTarget(path) - val newRef = modA.ref("newRef").setPathTarget(path) - - val renames = RenameMap() - renames.record(oldRef, newRef) - - val testRef = oldRef.addHierarchy("B", "b") - renames.get(testRef) should be { - Some(Seq(newRef.addHierarchy("B", "b"))) - } - } - - it should "properly rename reference targets with partially matching paths and partially matching target tokens" in { - val cir = CircuitTarget("Top") - val modTop = cir.module("Top") - val modA = cir.module("A") - val modB = cir.module("B") - - val path = modB.instOf("a", "A") - val oldAgg = modA.ref("oldAgg").setPathTarget(path).field("field1") - val newAgg = modA.ref("newAgg").setPathTarget(path) - - val renames = RenameMap() - renames.record(oldAgg, newAgg) - - val testRef = oldAgg.addHierarchy("B", "b").field("field2") - renames.get(testRef) should be { - Some(Seq(newAgg.addHierarchy("B", "b").field("field2"))) - } - } - - it should "rename targets with multiple renames starting from most specific to least specific" in { - val cir = CircuitTarget("Top") - val modTop = cir.module("Top") - val modA = cir.module("A") - val modB = cir.module("B") - val modC = cir.module("C") - - // from: ~Top|A/b:B/c:C>ref.f1.f2.f3 - // to: ~Top|A/b:B/c:C>ref.f1.f2.f333 - // renamed first because it is an exact match - val from1 = modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f1") - .field("f2") - .field("f3") - val to1 = modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f1") - .field("f2") - .field("f33") - - // from: ~Top|A/b:B/c:C>ref.f1.f2 - // to: ~Top|A/b:B/c:C>ref.f1 - // renamed second because it is a parent target - val from2 = modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f1") - .field("f2") - val to2 = modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f1") - .field("f22") - - // from: ~Top|B/c:C>ref.f1 - // to: ~Top|B/c:C>ref.f11 - // renamed third because it has a smaller hierarchy - val from3 = modB - .instOf("c", "C") - .ref("ref") - .field("f1") - val to3 = modB - .instOf("c", "C") - .ref("ref") - .field("f11") - - // from: ~Top|C>ref - // to: ~Top|C>refref - // renamed last because it has no path - val from4 = modC.ref("ref") - val to4 = modC.ref("refref") - - val renames1 = RenameMap() - renames1.record(from1, to1) - renames1.record(from2, to2) - renames1.record(from3, to3) - renames1.record(from4, to4) - - renames1.get(from1) should be { - Some( - Seq( - modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f1") - .field("f2") - .field("f33") - ) - ) - } - - val renames2 = RenameMap() - renames2.record(from2, to2) - renames2.record(from3, to3) - renames2.record(from4, to4) - - renames2.get(from1) should be { - Some( - Seq( - modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f1") - .field("f22") - .field("f3") - ) - ) - } - - val renames3 = RenameMap() - renames3.record(from3, to3) - renames3.record(from4, to4) - - renames3.get(from1) should be { - Some( - Seq( - modA - .instOf("b", "B") - .instOf("c", "C") - .ref("ref") - .field("f11") - .field("f2") - .field("f3") - ) - ) - } - } - - it should "correctly handle renaming of modules to instances" in { - val cir = CircuitTarget("Top") - val renames = RenameMap() - val from = cir.module("C") - val to = cir.module("D").instOf("e", "E").instOf("f", "F") - renames.record(from, to) - renames.get(cir.module("C")) should be { - Some(Seq(cir.module("D").instOf("e", "E").instOf("f", "F"))) - } - renames.get(cir.module("A").instOf("b", "B").instOf("c", "C")) should be { - Some(Seq(cir.module("A").instOf("b", "B").instOf("c", "D").instOf("e", "E").instOf("f", "F"))) - } - } - - it should "correctly handle renaming of paths and components at the same time" in { - val cir = CircuitTarget("Top") - val renames = RenameMap() - val from = cir.module("C").ref("foo").field("bar") - val to = cir.module("D").instOf("e", "E").instOf("f", "F").ref("foo").field("foo") - renames.record(from, to) - renames.get(cir.module("A").instOf("b", "B").instOf("c", "C").ref("foo").field("bar")) should be { - Some( - Seq( - cir - .module("A") - .instOf("b", "B") - .instOf("c", "D") - .instOf("e", "E") - .instOf("f", "F") - .ref("foo") - .field("foo") - ) - ) - } - } - - it should "error if an instance is renamed to a ReferenceTarget" in { - val top = CircuitTarget("Top").module("Top") - val renames = RenameMap() - val from = top.instOf("a", "A") - val to = top.ref("b") - renames.record(from, to) - a[IllegalRenameException] shouldBe thrownBy { - renames.get(from) - } - } - - it should "not allow renaming of instances even if there is a matching reference rename" in { - val top = CircuitTarget("Top").module("Top") - val renames = RenameMap() - val from = top.ref("a") - val to = top.ref("b") - renames.record(from, to) - renames.get(top.instOf("a", "Foo")) should be(None) - } - - it should "correctly chain renames together" in { - val top = CircuitTarget("Top") - - val renames1 = RenameMap() - val from1 = top.module("A") - val to1 = top.module("Top").instOf("b", "B") - renames1.record(from1, to1) - - val renames2 = RenameMap() - val from2 = top.module("B") - val to2 = top.module("B1") - renames2.record(from2, to2) - - val renames = renames1.andThen(renames2) - - renames.get(from1) should be { - Some(Seq(top.module("Top").instOf("b", "B1"))) - } - - renames.get(from2) should be { - Some(Seq(to2)) - } - } - - it should "correctly chain deleted targets" in { - val top = CircuitTarget("Top") - val modA = top.module("A") - val modA1 = top.module("A1") - val modB = top.module("B") - val modB1 = top.module("B1") - - val renames1 = RenameMap() - renames1.delete(modA) - renames1.record(modB, modB1) - - val renames2 = RenameMap() - renames2.record(modA, modA1) - renames2.delete(modB1) - - val renames = renames1.andThen(renames2) - - renames.get(modA) should be { - Some(Seq.empty) - } - renames.get(modB) should be { - Some(Seq.empty) - } - } - - it should "correctly ++ renameMaps" in { - val top = CircuitTarget("Top") - val modA = top.module("A") - val modA1 = top.module("A1") - val modA2 = top.module("A1") - val modB = top.module("B") - val modB1 = top.module("B1") - val modC = top.module("C") - val modC1 = top.module("C1") - - val renames1 = RenameMap() - renames1.record(modA, modA1) - renames1.record(modC, modC1) - - val renames2 = RenameMap() - renames2.record(modA, modA2) - renames2.record(modB, modB1) - - val renames = renames1 ++ renames2 - renames.get(modA) should be { - Some(Seq(modA2)) - } - renames.get(modB) should be { - Some(Seq(modB1)) - } - renames.get(modC) should be { - Some(Seq(modC1)) - } - } - - it should "be able to inline instances" in { - val top = CircuitTarget("Top") - val inlineRename1 = { - val inlineMod = top.module("A") - val inlineInst = top.module("A").instOf("b", "B") - val oldRef = inlineMod.ref("bar") - val prefixRef = inlineMod.ref("foo") - - val renames1 = RenameMap() - renames1.record(inlineInst, inlineMod) - - val renames2 = RenameMap() - renames2.record(oldRef, prefixRef) - - renames1.andThen(renames2) - } - - val inlineRename2 = { - val inlineMod = top.module("A1") - val inlineInst = top.module("A1").instOf("b", "B1") - val oldRef = inlineMod.ref("bar") - val prefixRef = inlineMod.ref("foo") - - val renames1 = RenameMap() - renames1.record(inlineInst, inlineMod) - - val renames2 = RenameMap() - renames2.record(oldRef, prefixRef) - - renames1.andThen(renames2) - } - - val renames = inlineRename1 ++ inlineRename2 - renames.get(top.module("A").instOf("b", "B").ref("bar")) should be { - Some(Seq(top.module("A").ref("foo"))) - } - - renames.get(top.module("A1").instOf("b", "B1").ref("bar")) should be { - Some(Seq(top.module("A1").ref("foo"))) - } - } - - it should "be able to dedup modules" in { - val top = CircuitTarget("Top") - val topMod = top.module("Top") - val dedupedMod = top.module("A") - val dupMod1 = top.module("A1") - val dupMod2 = top.module("A2") - - val relPath1 = dupMod1.addHierarchy("Foo", "a") //top.module("Foo").instOf("a", "A1") - val relPath2 = dupMod2.addHierarchy("Foo", "a") //top.module("Foo").instOf("a", "A2") - - val absPath1 = relPath1.addHierarchy("Top", "foo") - val absPath2 = relPath2.addHierarchy("Top", "foo") - - val renames1 = RenameMap() - renames1.record(dupMod1, absPath1) - renames1.record(dupMod2, absPath2) - renames1.record(relPath1, absPath1) - renames1.record(relPath2, absPath2) - - val renames2 = RenameMap() - renames2.record(dupMod1, dedupedMod) - renames2.record(dupMod2, dedupedMod) - - val renames = renames1.andThen(renames2) - - renames.get(dupMod1.instOf("foo", "Bar").ref("ref")) should be { - Some(Seq(absPath1.copy(ofModule = "A").instOf("foo", "Bar").ref("ref"))) - } - - renames.get(dupMod2.ref("ref")) should be { - Some(Seq(absPath2.copy(ofModule = "A").ref("ref"))) - } - - renames.get(absPath1.instOf("b", "B").ref("ref")) should be { - Some(Seq(absPath1.copy(ofModule = "A").instOf("b", "B").ref("ref"))) - } - } - - it should "should able to chain many rename maps" in { - val top = CircuitTarget("Top") - val inlineRename1 = { - val inlineMod = top.module("A") - val inlineInst = top.module("A").instOf("b", "B") - val oldRef = inlineMod.ref("bar") - val prefixRef = inlineMod.ref("foo") - - val renames1 = RenameMap() - renames1.record(inlineInst, inlineMod) - - val renames2 = RenameMap() - renames2.record(oldRef, prefixRef) - - renames1.andThen(renames2) - } - - val inlineRename2 = { - val inlineMod = top.module("A1") - val inlineInst = top.module("A1").instOf("b", "B1") - val oldRef = inlineMod.ref("bar") - val prefixRef = inlineMod.ref("foo") - - val renames1 = RenameMap() - renames1.record(inlineInst, inlineMod) - - val renames2 = RenameMap() - renames2.record(oldRef, prefixRef) - - inlineRename1.andThen(renames1).andThen(renames2) - } - - val renames = inlineRename2 - renames.get(top.module("A").instOf("b", "B").ref("bar")) should be { - Some(Seq(top.module("A").ref("foo"))) - } - - renames.get(top.module("A1").instOf("b", "B1").ref("bar")) should be { - Some(Seq(top.module("A1").ref("foo"))) - } - } - - it should "should able to chain chained rename maps" in { - val top = CircuitTarget("Top").module("Top") - val foo1 = top.instOf("foo1", "Mod") - val foo2 = top.instOf("foo2", "Mod") - val foo3 = top.instOf("foo3", "Mod") - - val bar1 = top.instOf("bar1", "Mod") - val bar2 = top.instOf("bar2", "Mod") - - val foo1Rename = RenameMap() - val foo2Rename = RenameMap() - - val bar1Rename = RenameMap() - val bar2Rename = RenameMap() - - foo1Rename.record(foo1, foo2) - foo2Rename.record(foo2, foo3) - - bar1Rename.record(foo3, bar1) - bar2Rename.record(bar1, bar2) - - val chained1 = foo1Rename.andThen(foo2Rename) - val chained2 = bar1Rename.andThen(bar2Rename) - - val renames = chained1.andThen(chained2) - - renames.get(foo1) should be { - Some(Seq(bar2)) - } - } - - it should "record a self-rename" in { - val top = CircuitTarget("Top").module("Top") - val foo = top.instOf("foo", "Mod") - val bar = top.instOf("bar", "Mod") - - val r = RenameMap() - - r.record(foo, bar) - r.record(foo, foo) - - r.get(foo) should not be (empty) - (r.get(foo).get should contain).allOf(foo, bar) - } - - it should "not record the same rename multiple times" in { - val top = CircuitTarget("Top").module("Top") - val foo = top.instOf("foo", "Mod") - val bar = top.instOf("bar", "Mod") - - val r = RenameMap() - - r.record(foo, bar) - r.record(foo, bar) - - r.get(foo) should not be (empty) - r.get(foo).get should contain theSameElementsAs Seq(bar) - } - - it should "not circularly rename" in { - val top = CircuitTarget("Top").module("Top") - val foo = top.instOf("foo", "Mod") - val Mod = CircuitTarget("Top").module("Mod") - val Mod2 = CircuitTarget("Top").module("Mod2") - - val r = RenameMap() - - r.record(foo, Mod) - r.record(Mod, Mod2) - - r.get(foo) should not be (empty) - r.get(foo).get should contain theSameElementsAs Seq(Mod) - r.get(Mod).get should contain theSameElementsAs Seq(Mod2) - } - - it should "delete instances of deleted modules" in { - val top = CircuitTarget("Top").module("Top") - val foo = top.instOf("foo", "Mod") - val Mod = CircuitTarget("Top").module("Mod") - - val r = RenameMap() - - r.delete(Mod) - r.get(foo) should be(Some(Nil)) - } - - it should "rename an instance if it has been renamed" in { - // this could happen if the instance name needed to be uniquified to avoid clashes in LowerTypes - val top = CircuitTarget("top").module("top") - - val r = RenameMap() - val i = top.instOf("i", "child") - val i_ = top.instOf("i_", "child") - r.record(i, i_) - r.get(i) should be(Some(Seq(i_))) - r.get(i.ref("a")) should be(Some(Seq(i_.ref("a")))) - } - - it should "rename references to an instance's ports if the ports of the module have been renamed" in { - // this could happen if the port name needed to be uniquified to avoid clashes in LowerTypes - val top = CircuitTarget("top").module("top") - val child = CircuitTarget("top").module("child") - - val r = RenameMap() - r.record(child.ref("a"), Seq(child.ref("a_0"), child.ref("a_1"))) - val i = top.instOf("i", "child") - r.get(i.ref("a")) should be(Some(Seq(i.ref("a_0"), i.ref("a_1")))) - } - - it should "rename references to renamed instance's ports if the ports of the module have been renamed" in { - // this could happen if the instance as well as the port name needed to be uniquified to avoid clashes in LowerTypes - val top = CircuitTarget("top").module("top") - val child = CircuitTarget("top").module("child") - - val portRenames = RenameMap() - portRenames.record(child.ref("a"), Seq(child.ref("a_0"), child.ref("a_1"))) - - val instanceRenames = RenameMap() - val i = top.instOf("i", "child") - val i_ = top.instOf("i_", "child") - instanceRenames.record(i, i_) - - // The port and instance renames must be *explicitly* chained! - val r = portRenames.andThen(instanceRenames) - r.get(i.ref("a")) should be(Some(Seq(i_.ref("a_0"), i_.ref("a_1")))) - } -} diff --git a/src/test/scala/firrtlTests/transforms/ManipulateNamesSpec.scala b/src/test/scala/firrtlTests/transforms/ManipulateNamesSpec.scala index fb516626..00849190 100644 --- a/src/test/scala/firrtlTests/transforms/ManipulateNamesSpec.scala +++ b/src/test/scala/firrtlTests/transforms/ManipulateNamesSpec.scala @@ -12,6 +12,7 @@ import firrtl.transforms.{ ManipulateNamesAllowlistResultAnnotation, ManipulateNamesBlocklistAnnotation } +import firrtl.renamemap.MutableRenameMap import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -210,7 +211,7 @@ class ManipulateNamesSpec extends AnyFlatSpec with Matchers { oldTargets = Seq(Seq(`~Foo|Bar`)) ) - val r = RenameMap() + val r = MutableRenameMap() r.delete(`~Foo|prefix_Bar`) a.update(r) should be(empty) @@ -228,7 +229,7 @@ class ManipulateNamesSpec extends AnyFlatSpec with Matchers { oldTargets = Seq(Seq(`~Foo|Bar`), Seq(`~Foo|Baz`)) ) - val r = RenameMap() + val r = MutableRenameMap() r.delete(`~Foo|prefix_Bar`) val ax = a.update(r).collect { -- cgit v1.2.3