From 223bad6d9ddd93e48678da7c3ab50b6656809157 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Sat, 27 Oct 2018 22:44:00 -0700 Subject: Revert "Instance Annotations (#865)" (#925) This reverts commit 7e2f787e125227dc389d5cf1d09717748ecfed2e.--- src/main/scala/firrtl/annotations/Annotation.scala | 71 +-- .../scala/firrtl/annotations/AnnotationUtils.scala | 18 +- .../scala/firrtl/annotations/JsonProtocol.scala | 30 +- src/main/scala/firrtl/annotations/Named.scala | 30 + src/main/scala/firrtl/annotations/Target.scala | 652 --------------------- .../scala/firrtl/annotations/TargetToken.scala | 46 -- .../annotations/analysis/DuplicationHelper.scala | 146 ----- .../transforms/EliminateTargetPaths.scala | 167 ------ 8 files changed, 51 insertions(+), 1109 deletions(-) create mode 100644 src/main/scala/firrtl/annotations/Named.scala delete mode 100644 src/main/scala/firrtl/annotations/Target.scala delete mode 100644 src/main/scala/firrtl/annotations/TargetToken.scala delete mode 100644 src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala delete mode 100644 src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala (limited to 'src/main/scala/firrtl/annotations') diff --git a/src/main/scala/firrtl/annotations/Annotation.scala b/src/main/scala/firrtl/annotations/Annotation.scala index 62c2b335..4b0591bf 100644 --- a/src/main/scala/firrtl/annotations/Annotation.scala +++ b/src/main/scala/firrtl/annotations/Annotation.scala @@ -5,15 +5,11 @@ package annotations import net.jcazevedo.moultingyaml._ import firrtl.annotations.AnnotationYamlProtocol._ -import firrtl.Utils.throwInternalError - -import scala.collection.mutable case class AnnotationException(message: String) extends Exception(message) /** Base type of auxiliary information */ -trait Annotation extends Product { - +trait Annotation { /** Update the target based on how signals are renamed */ def update(renames: RenameMap): Seq[Annotation] @@ -22,29 +18,13 @@ trait Annotation extends Product { * @note In [[logger.LogLevel.Debug]] this is called on every Annotation after every Transform */ def serialize: String = this.toString - - /** Recurses through ls to find all [[Target]] instances - * @param ls - * @return - */ - private def extractComponents(ls: scala.collection.Traversable[_]): Seq[Target] = { - ls.collect { - case c: Target => Seq(c) - case ls: scala.collection.Traversable[_] => extractComponents(ls) - }.foldRight(Seq.empty[Target])((seq, c) => c ++ seq) - } - - /** Returns all [[Target]] members in this annotation - * @return - */ - def getTargets: Seq[Target] = extractComponents(productIterator.toSeq) } /** If an Annotation does not target any [[Named]] thing in the circuit, then all updates just * return the Annotation itself */ trait NoTargetAnnotation extends Annotation { - def update(renames: RenameMap): Seq[NoTargetAnnotation] = Seq(this) + def update(renames: RenameMap) = Seq(this) } /** An Annotation that targets a single [[Named]] thing */ @@ -57,27 +37,18 @@ trait SingleTargetAnnotation[T <: Named] extends Annotation { // This mess of @unchecked and try-catch is working around the fact that T is unknown due to type // erasure. We cannot that newTarget is of type T, but a CastClassException will be thrown upon // invoking duplicate if newTarget cannot be cast to T (only possible in the concrete subclass) - def update(renames: RenameMap): Seq[Annotation] = { - target match { - case c: Target => - val x = renames.get(c) - x.map(newTargets => newTargets.map(t => duplicate(t.asInstanceOf[T]))).getOrElse(List(this)) - case _: Named => - val ret = renames.get(Target.convertNamed2Target(target)) - ret.map(_.map(newT => Target.convertTarget2Named(newT: @unchecked) match { - case newTarget: T @unchecked => - try { - duplicate(newTarget) - } - catch { - case _: java.lang.ClassCastException => - val msg = s"${this.getClass.getName} target ${target.getClass.getName} " + - s"cannot be renamed to ${newTarget.getClass}" - throw AnnotationException(msg) - } - })).getOrElse(List(this)) - } - } + def update(renames: RenameMap): Seq[Annotation] = + renames.get(target).map(_.map(newT => (newT: @unchecked) match { + case newTarget: T @unchecked => + try { + duplicate(newTarget) + } catch { + case _: java.lang.ClassCastException => + val msg = s"${this.getClass.getName} target ${target.getClass.getName} " + + s"cannot be renamed to ${newTarget.getClass}" + throw AnnotationException(msg) + } + })).getOrElse(List(this)) } @deprecated("Just extend NoTargetAnnotation", "1.1") @@ -87,7 +58,7 @@ trait SingleStringAnnotation extends NoTargetAnnotation { object Annotation { @deprecated("This returns a LegacyAnnotation, use an explicit Annotation type", "1.1") - def apply(target: Named, transform: Class[_ <: Transform], value: String): LegacyAnnotation = + def apply(target: Named, transform: Class[_ <: Transform], value: String) = new LegacyAnnotation(target, transform, value) @deprecated("This uses LegacyAnnotation, use an explicit Annotation type", "1.1") def unapply(a: LegacyAnnotation): Option[(Named, Class[_ <: Transform], String)] = @@ -121,13 +92,13 @@ final case class LegacyAnnotation private[firrtl] ( } def propagate(from: Named, tos: Seq[Named], dup: Named=>Annotation): Seq[Annotation] = tos.map(dup(_)) def check(from: Named, tos: Seq[Named], which: Annotation): Unit = {} - def duplicate(n: Named): LegacyAnnotation = new LegacyAnnotation(n, transform, value) + def duplicate(n: Named) = new LegacyAnnotation(n, transform, value) } // Private so that LegacyAnnotation can only be constructed via deprecated Annotation.apply private[firrtl] object LegacyAnnotation { // ***** Everything below here is to help people migrate off of old annotations ***** - def errorIllegalAnno(name: String): Annotation = + def errorIllegalAnno(name: String) = throw new Exception(s"Old-style annotations that look like $name are no longer supported") private val OldDeletedRegex = """(?s)DELETED by ([^\n]*)\n(.*)""".r @@ -140,9 +111,7 @@ private[firrtl] object LegacyAnnotation { import firrtl.passes.memlib._ import firrtl.passes.wiring._ import firrtl.passes.clocklist._ - // Attempt to convert common Annotations and error on the rest of old-style build-in annotations - // scalastyle:off def convertLegacyAnno(anno: LegacyAnnotation): Annotation = anno match { // All old-style Emitter annotations are illegal case LegacyAnnotation(_,_,"emitCircuit") => errorIllegalAnno("EmitCircuitAnnotation") @@ -175,8 +144,7 @@ private[firrtl] object LegacyAnnotation { case LegacyAnnotation(c: ComponentName, _, SourceRegex(pin)) => SourceAnnotation(c, pin) case LegacyAnnotation(n, _, SinkRegex(pin)) => SinkAnnotation(n, pin) case LegacyAnnotation(m: ModuleName, t, text) if t == classOf[BlackBoxSourceHelper] => - val nArgs = 3 - text.split("\n", nArgs).toList match { + text.split("\n", 3).toList match { case "resource" :: id :: _ => BlackBoxResourceAnno(m, id) case "inline" :: name :: text :: _ => BlackBoxInlineAnno(m, name, text) case "targetDir" :: targetDir :: _ => BlackBoxTargetDirAnno(targetDir) @@ -184,12 +152,11 @@ private[firrtl] object LegacyAnnotation { } case LegacyAnnotation(_, transform, "noDCE!") if transform == classOf[DeadCodeElimination] => NoDCEAnnotation - case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c.toTarget) + case LegacyAnnotation(c: ComponentName, _, "DONTtouch!") => DontTouchAnnotation(c) case LegacyAnnotation(c: ModuleName, _, "optimizableExtModule!") => OptimizableExtModuleAnnotation(c) case other => other } - // scalastyle:on def convertLegacyAnnos(annos: Seq[Annotation]): Seq[Annotation] = { var warned: Boolean = false annos.map { diff --git a/src/main/scala/firrtl/annotations/AnnotationUtils.scala b/src/main/scala/firrtl/annotations/AnnotationUtils.scala index ba9220f7..517cea26 100644 --- a/src/main/scala/firrtl/annotations/AnnotationUtils.scala +++ b/src/main/scala/firrtl/annotations/AnnotationUtils.scala @@ -64,29 +64,13 @@ object AnnotationUtils { case Array(c, m, x) => ComponentName(x, ModuleName(m, CircuitName(c))) } - /** Converts a serialized FIRRTL component into a sequence of target tokens - * @param s - * @return - */ - def toSubComponents(s: String): Seq[TargetToken] = { - import TargetToken._ - def exp2subcomp(e: ir.Expression): Seq[TargetToken] = e match { - case ir.Reference(name, _) => Seq(Ref(name)) - case ir.SubField(expr, name, _) => exp2subcomp(expr) :+ Field(name) - case ir.SubIndex(expr, idx, _) => exp2subcomp(expr) :+ Index(idx) - case ir.SubAccess(expr, idx, _) => Utils.throwInternalError(s"For string $s, cannot convert a subaccess $e into a Target") - } - exp2subcomp(toExp(s)) - } - - /** Given a serialized component/subcomponent reference, subindex, subaccess, * or subfield, return the corresponding IR expression. * E.g. "foo.bar" becomes SubField(Reference("foo", UnknownType), "bar", UnknownType) */ def toExp(s: String): Expression = { def parse(tokens: Seq[String]): Expression = { - val DecPattern = """(\d+)""".r + val DecPattern = """([1-9]\d*)""".r def findClose(tokens: Seq[String], index: Int, nOpen: Int): Seq[String] = { if(index >= tokens.size) { Utils.error("Cannot find closing bracket ]") diff --git a/src/main/scala/firrtl/annotations/JsonProtocol.scala b/src/main/scala/firrtl/annotations/JsonProtocol.scala index 36699151..7b2617f5 100644 --- a/src/main/scala/firrtl/annotations/JsonProtocol.scala +++ b/src/main/scala/firrtl/annotations/JsonProtocol.scala @@ -35,39 +35,11 @@ object JsonProtocol { { case named: ComponentName => JString(named.serialize) } )) - - class TargetSerializer extends CustomSerializer[Target](format => ( - { case JString(s) => Target.deserialize(s) }, - { case named: Target => JString(named.serialize) } - )) - class GenericTargetSerializer extends CustomSerializer[GenericTarget](format => ( - { case JString(s) => Target.deserialize(s).asInstanceOf[GenericTarget] }, - { case named: GenericTarget => JString(named.serialize) } - )) - class CircuitTargetSerializer extends CustomSerializer[CircuitTarget](format => ( - { case JString(s) => Target.deserialize(s).asInstanceOf[CircuitTarget] }, - { case named: CircuitTarget => JString(named.serialize) } - )) - class ModuleTargetSerializer extends CustomSerializer[ModuleTarget](format => ( - { case JString(s) => Target.deserialize(s).asInstanceOf[ModuleTarget] }, - { case named: ModuleTarget => JString(named.serialize) } - )) - class InstanceTargetSerializer extends CustomSerializer[InstanceTarget](format => ( - { case JString(s) => Target.deserialize(s).asInstanceOf[InstanceTarget] }, - { case named: InstanceTarget => JString(named.serialize) } - )) - class ReferenceTargetSerializer extends CustomSerializer[ReferenceTarget](format => ( - { case JString(s) => Target.deserialize(s).asInstanceOf[ReferenceTarget] }, - { case named: ReferenceTarget => JString(named.serialize) } - )) - /** Construct Json formatter for annotations */ def jsonFormat(tags: Seq[Class[_ <: Annotation]]) = { Serialization.formats(FullTypeHints(tags.toList)).withTypeHintFieldName("class") + new TransformClassSerializer + new NamedSerializer + new CircuitNameSerializer + - new ModuleNameSerializer + new ComponentNameSerializer + new TargetSerializer + - new GenericTargetSerializer + new CircuitTargetSerializer + new ModuleTargetSerializer + - new InstanceTargetSerializer + new ReferenceTargetSerializer + new ModuleNameSerializer + new ComponentNameSerializer } /** Serialize annotations to a String for emission */ diff --git a/src/main/scala/firrtl/annotations/Named.scala b/src/main/scala/firrtl/annotations/Named.scala new file mode 100644 index 00000000..3da75884 --- /dev/null +++ b/src/main/scala/firrtl/annotations/Named.scala @@ -0,0 +1,30 @@ +// See LICENSE for license details. + +package firrtl +package annotations + +import firrtl.ir.Expression +import AnnotationUtils.{validModuleName, validComponentName, toExp} + +/** + * Named classes associate an annotation with a component in a Firrtl circuit + */ +sealed trait Named { + def serialize: String +} + +final case class CircuitName(name: String) extends Named { + if(!validModuleName(name)) throw AnnotationException(s"Illegal circuit name: $name") + def serialize: String = name +} + +final case class ModuleName(name: String, circuit: CircuitName) extends Named { + if(!validModuleName(name)) throw AnnotationException(s"Illegal module name: $name") + def serialize: String = circuit.serialize + "." + name +} + +final case class ComponentName(name: String, module: ModuleName) extends Named { + if(!validComponentName(name)) throw AnnotationException(s"Illegal component name: $name") + def expr: Expression = toExp(name) + def serialize: String = module.serialize + "." + name +} diff --git a/src/main/scala/firrtl/annotations/Target.scala b/src/main/scala/firrtl/annotations/Target.scala deleted file mode 100644 index dcf5cb02..00000000 --- a/src/main/scala/firrtl/annotations/Target.scala +++ /dev/null @@ -1,652 +0,0 @@ -// See LICENSE for license details. - -package firrtl -package annotations - -import firrtl.ir.Expression -import AnnotationUtils.{toExp, validComponentName, validModuleName} -import TargetToken._ - -import scala.collection.mutable - -/** Refers to something in a FIRRTL [[firrtl.ir.Circuit]]. Used for Annotation targets. - * - * Can be in various states of completion/resolved: - * - Legal: [[TargetToken]]'s in tokens are in an order that makes sense - * - Complete: circuitOpt and moduleOpt are non-empty, and all Instance(_) are followed by OfModule(_) - * - Local: tokens does not refer to things through an instance hierarchy (no Instance(_) or OfModule(_) tokens) - */ -sealed trait Target extends Named { - - /** @return Circuit name, if it exists */ - def circuitOpt: Option[String] - - /** @return Module name, if it exists */ - def moduleOpt: Option[String] - - /** @return [[Target]] tokens */ - def tokens: Seq[TargetToken] - - /** @return Returns a new [[GenericTarget]] with new values */ - def modify(circuitOpt: Option[String] = circuitOpt, - moduleOpt: Option[String] = moduleOpt, - tokens: Seq[TargetToken] = tokens): GenericTarget = GenericTarget(circuitOpt, moduleOpt, tokens.toVector) - - /** @return Human-readable serialization */ - def serialize: String = { - val circuitString = "~" + circuitOpt.getOrElse("???") - val moduleString = "|" + moduleOpt.getOrElse("???") - val tokensString = tokens.map { - case Ref(r) => s">$r" - case Instance(i) => s"/$i" - case OfModule(o) => s":$o" - case Field(f) => s".$f" - case Index(v) => s"[$v]" - case Clock => s"@clock" - case Reset => s"@reset" - case Init => s"@init" - }.mkString("") - if(moduleOpt.isEmpty && tokens.isEmpty) { - circuitString - } else if(tokens.isEmpty) { - circuitString + moduleString - } else { - circuitString + moduleString + tokensString - } - } - - /** @return Converts this [[Target]] into a [[GenericTarget]] */ - def toGenericTarget: GenericTarget = GenericTarget(circuitOpt, moduleOpt, tokens.toVector) - - /** @return Converts this [[Target]] into either a [[CircuitName]], [[ModuleName]], or [[ComponentName]] */ - @deprecated("Use Target instead, will be removed in 1.3", "1.2") - def toNamed: Named = toGenericTarget.toNamed - - /** @return If legal, convert this [[Target]] into a [[CompleteTarget]] */ - def getComplete: Option[CompleteTarget] - - /** @return Converts this [[Target]] into a [[CompleteTarget]] */ - def complete: CompleteTarget = getComplete.get - - /** @return Converts this [[Target]] into a [[CompleteTarget]], or if it can't, return original [[Target]] */ - def tryToComplete: Target = getComplete.getOrElse(this) - - /** Whether the target is directly instantiated in its root module */ - def isLocal: Boolean -} - -object Target { - - def apply(circuitOpt: Option[String], moduleOpt: Option[String], reference: Seq[TargetToken]): GenericTarget = - GenericTarget(circuitOpt, moduleOpt, reference.toVector) - - def unapply(t: Target): Option[(Option[String], Option[String], Seq[TargetToken])] = - Some((t.circuitOpt, t.moduleOpt, t.tokens)) - - case class NamedException(message: String) extends Exception(message) - - implicit def convertCircuitTarget2CircuitName(c: CircuitTarget): CircuitName = c.toNamed - implicit def convertModuleTarget2ModuleName(c: ModuleTarget): ModuleName = c.toNamed - implicit def convertIsComponent2ComponentName(c: IsComponent): ComponentName = c.toNamed - implicit def convertTarget2Named(c: Target): Named = c.toNamed - implicit def convertCircuitName2CircuitTarget(c: CircuitName): CircuitTarget = c.toTarget - implicit def convertModuleName2ModuleTarget(c: ModuleName): ModuleTarget = c.toTarget - implicit def convertComponentName2ReferenceTarget(c: ComponentName): ReferenceTarget = c.toTarget - implicit def convertNamed2Target(n: Named): CompleteTarget = n.toTarget - - /** Converts [[ComponentName]]'s name into TargetTokens - * @param name - * @return - */ - def toTargetTokens(name: String): Seq[TargetToken] = { - val tokens = AnnotationUtils.tokenize(name) - val subComps = mutable.ArrayBuffer[TargetToken]() - subComps += Ref(tokens.head) - if(tokens.tail.nonEmpty) { - tokens.tail.zip(tokens.tail.tail).foreach { - case (".", value: String) => subComps += Field(value) - case ("[", value: String) => subComps += Index(value.toInt) - case other => - } - } - subComps - } - - /** Checks if seq only contains [[TargetToken]]'s with select keywords - * @param seq - * @param keywords - * @return - */ - def isOnly(seq: Seq[TargetToken], keywords:String*): Boolean = { - seq.map(_.is(keywords:_*)).foldLeft(false)(_ || _) && keywords.nonEmpty - } - - /** @return [[Target]] from human-readable serialization */ - def deserialize(s: String): Target = { - val regex = """(?=[~|>/:.\[@])""" - s.split(regex).foldLeft(GenericTarget(None, None, Vector.empty)) { (t, tokenString) => - val value = tokenString.tail - tokenString(0) match { - case '~' if t.circuitOpt.isEmpty && t.moduleOpt.isEmpty && t.tokens.isEmpty => - if(value == "???") t else t.copy(circuitOpt = Some(value)) - case '|' if t.moduleOpt.isEmpty && t.tokens.isEmpty => - if(value == "???") t else t.copy(moduleOpt = Some(value)) - case '/' => t.add(Instance(value)) - case ':' => t.add(OfModule(value)) - case '>' => t.add(Ref(value)) - case '.' => t.add(Field(value)) - case '[' if value.dropRight(1).toInt >= 0 => t.add(Index(value.dropRight(1).toInt)) - case '@' if value == "clock" => t.add(Clock) - case '@' if value == "init" => t.add(Init) - case '@' if value == "reset" => t.add(Reset) - case other => throw NamedException(s"Cannot deserialize Target: $s") - } - }.tryToComplete - } -} - -/** Represents incomplete or non-standard [[Target]]s - * @param circuitOpt Optional circuit name - * @param moduleOpt Optional module name - * @param tokens [[TargetToken]]s to represent the target in a circuit and module - */ -case class GenericTarget(circuitOpt: Option[String], - moduleOpt: Option[String], - tokens: Vector[TargetToken]) extends Target { - - override def toGenericTarget: GenericTarget = this - - override def toNamed: Named = getComplete match { - case Some(c: IsComponent) if c.isLocal => c.toNamed - case Some(c: ModuleTarget) => c.toNamed - case Some(c: CircuitTarget) => c.toNamed - case other => throw Target.NamedException(s"Cannot convert $this to [[Named]]") - } - - override def toTarget: CompleteTarget = getComplete.get - - override def getComplete: Option[CompleteTarget] = { - if(!isComplete) None else { - val target = this match { - case GenericTarget(Some(c), None, Vector()) => CircuitTarget(c) - case GenericTarget(Some(c), Some(m), Vector()) => ModuleTarget(c, m) - case GenericTarget(Some(c), Some(m), Ref(r) +: component) => ReferenceTarget(c, m, Nil, r, component) - case GenericTarget(Some(c), Some(m), Instance(i) +: OfModule(o) +: Vector()) => InstanceTarget(c, m, Nil, i, o) - case GenericTarget(Some(c), Some(m), component) => - val path = getPath.getOrElse(Nil) - (getRef, getInstanceOf) match { - case (Some((r, comps)), _) => ReferenceTarget(c, m, path, r, comps) - case (None, Some((i, o))) => InstanceTarget(c, m, path, i, o) - } - } - Some(target) - } - } - - override def isLocal: Boolean = !(getPath.nonEmpty && getPath.get.nonEmpty) - - /** If complete, return this [[GenericTarget]]'s path - * @return - */ - def getPath: Option[Seq[(Instance, OfModule)]] = if(isComplete) { - val allInstOfs = tokens.grouped(2).collect { case Seq(i: Instance, o:OfModule) => (i, o)}.toSeq - if(tokens.nonEmpty && tokens.last.isInstanceOf[OfModule]) Some(allInstOfs.dropRight(1)) else Some(allInstOfs) - } else { - None - } - - /** If complete and a reference, return the reference and subcomponents - * @return - */ - def getRef: Option[(String, Seq[TargetToken])] = if(isComplete) { - val (optRef, comps) = tokens.foldLeft((None: Option[String], Vector.empty[TargetToken])) { - case ((None, v), Ref(r)) => (Some(r), v) - case ((r: Some[String], comps), c) => (r, comps :+ c) - case ((r, v), other) => (None, v) - } - optRef.map(x => (x, comps)) - } else { - None - } - - /** If complete and an instance target, return the instance and ofmodule - * @return - */ - def getInstanceOf: Option[(String, String)] = if(isComplete) { - tokens.grouped(2).foldLeft(None: Option[(String, String)]) { - case (instOf, Seq(i: Instance, o: OfModule)) => Some((i.value, o.value)) - case (instOf, _) => None - } - } else { - None - } - - /** Requires the last [[TargetToken]] in tokens to be one of the [[TargetToken]] keywords - * @param default Return value if tokens is empty - * @param keywords - */ - private def requireLast(default: Boolean, keywords: String*): Unit = { - val isOne = if (tokens.isEmpty) default else tokens.last.is(keywords: _*) - require(isOne, s"${tokens.last} is not one of $keywords") - } - - /** Appends a target token to tokens, asserts legality - * @param token - * @return - */ - def add(token: TargetToken): GenericTarget = { - token match { - case _: Instance => requireLast(true, "inst", "of") - case _: OfModule => requireLast(false, "inst") - case _: Ref => requireLast(true, "inst", "of") - case _: Field => requireLast(true, "ref", "[]", ".", "init", "clock", "reset") - case _: Index => requireLast(true, "ref", "[]", ".", "init", "clock", "reset") - case Init => requireLast(true, "ref", "[]", ".", "init", "clock", "reset") - case Clock => requireLast(true, "ref", "[]", ".", "init", "clock", "reset") - case Reset => requireLast(true, "ref", "[]", ".", "init", "clock", "reset") - } - this.copy(tokens = tokens :+ token) - } - - /** Removes n number of target tokens from the right side of [[tokens]] */ - def remove(n: Int): GenericTarget = this.copy(tokens = tokens.dropRight(n)) - - /** Optionally tries to append token to tokens, fails return is not a legal Target */ - def optAdd(token: TargetToken): Option[Target] = { - try{ - Some(add(token)) - } catch { - case _: IllegalArgumentException => None - } - } - - /** Checks whether the component is legal (incomplete is ok) - * @return - */ - def isLegal: Boolean = { - try { - var comp: GenericTarget = this.copy(tokens = Vector.empty) - for(token <- tokens) { - comp = comp.add(token) - } - true - } catch { - case _: IllegalArgumentException => false - } - } - - /** Checks whether the component is legal and complete, meaning the circuitOpt and moduleOpt are nonEmpty and - * all Instance(_) are followed by OfModule(_) - * @return - */ - def isComplete: Boolean = { - isLegal && (isCircuitTarget || isModuleTarget || (isComponentTarget && tokens.tails.forall { - case Instance(_) +: OfModule(_) +: tail => true - case Instance(_) +: x +: tail => false - case x +: OfModule(_) +: tail => false - case _ => true - } )) - } - - - def isCircuitTarget: Boolean = circuitOpt.nonEmpty && moduleOpt.isEmpty && tokens.isEmpty - def isModuleTarget: Boolean = circuitOpt.nonEmpty && moduleOpt.nonEmpty && tokens.isEmpty - def isComponentTarget: Boolean = circuitOpt.nonEmpty && moduleOpt.nonEmpty && tokens.nonEmpty -} - -/** Concretely points to a FIRRTL target, no generic selectors - * IsLegal - */ -trait CompleteTarget extends Target { - - /** @return The circuit of this target */ - def circuit: String - - /** @return The [[CircuitTarget]] of this target's circuit */ - def circuitTarget: CircuitTarget = CircuitTarget(circuitOpt.get) - - def getComplete: Option[CompleteTarget] = Some(this) - - /** Adds another level of instance hierarchy - * Example: Given root=A and instance=b, transforms (Top, B)/c:C -> (Top, A)/b:B/c:C - * @param root - * @param instance - * @return - */ - def addHierarchy(root: String, instance: String): IsComponent - - override def toTarget: CompleteTarget = this -} - - -/** A member of a FIRRTL Circuit (e.g. cannot point to a CircuitTarget) - * Concrete Subclasses are: [[ModuleTarget]], [[InstanceTarget]], and [[ReferenceTarget]] - */ -trait IsMember extends CompleteTarget { - - /** @return Root module, e.g. top-level module of this target */ - def module: String - - /** @return Returns the instance hierarchy path, if one exists */ - def path: Seq[(Instance, OfModule)] - - /** @return Creates a path, assuming all Instance and OfModules in this [[IsMember]] is used as a path */ - def asPath: Seq[(Instance, OfModule)] - - /** @return Tokens of just this member's path */ - def justPath: Seq[TargetToken] - - /** @return Local tokens of what this member points (not a path) */ - def notPath: Seq[TargetToken] - - /** @return Same target without a path */ - def pathlessTarget: IsMember - - /** @return Member's path target */ - def pathTarget: CompleteTarget - - /** @return Member's top-level module target */ - def moduleTarget: ModuleTarget = ModuleTarget(circuitOpt.get, moduleOpt.get) - - /** @return Member's parent target */ - def targetParent: CompleteTarget - - /** @return List of local Instance Targets refering to each instance/ofModule in this member's path */ - def pathAsTargets: Seq[InstanceTarget] = { - val targets = mutable.ArrayBuffer[InstanceTarget]() - path.foldLeft((module, Vector.empty[InstanceTarget])) { - case ((m, vec), (Instance(i), OfModule(o))) => - (o, vec :+ InstanceTarget(circuit, m, Nil, i, o)) - }._2 - } - - /** Resets this target to have a new path - * @param newPath - * @return - */ - def setPathTarget(newPath: IsModule): CompleteTarget -} - -/** References a module-like target (e.g. a [[ModuleTarget]] or an [[InstanceTarget]]) - */ -trait IsModule extends IsMember { - - /** @return Creates a new Target, appending a ref */ - def ref(value: String): ReferenceTarget - - /** @return Creates a new Target, appending an instance and ofmodule */ - def instOf(instance: String, of: String): InstanceTarget -} - -/** A component of a FIRRTL Module (e.g. cannot point to a CircuitTarget or ModuleTarget) - */ -trait IsComponent extends IsMember { - - /** @return The [[ModuleTarget]] of the module that directly contains this component */ - def encapsulatingModule: String = if(path.isEmpty) module else path.last._2.value - - /** Removes n levels of instance hierarchy - * - * Example: n=1, transforms (Top, A)/b:B/c:C -> (Top, B)/c:C - * @param n - * @return - */ - def stripHierarchy(n: Int): IsMember - - override def toNamed: ComponentName = { - if(isLocal){ - val mn = ModuleName(module, CircuitName(circuit)) - Seq(tokens:_*) match { - case Seq(Ref(name)) => ComponentName(name, mn) - case Ref(_) :: tail if Target.isOnly(tail, ".", "[]") => - val name = tokens.foldLeft(""){ - case ("", Ref(name)) => name - case (string, Field(value)) => s"$string.$value" - case (string, Index(value)) => s"$string[$value]" - } - ComponentName(name, mn) - case Seq(Instance(name), OfModule(o)) => ComponentName(name, mn) - } - } else { - throw new Exception(s"Cannot convert $this to [[ComponentName]]") - } - } - - override def justPath: Seq[TargetToken] = path.foldLeft(Vector.empty[TargetToken]) { - case (vec, (i, o)) => vec ++ Seq(i, o) - } - - override def pathTarget: IsModule = { - if(path.isEmpty) moduleTarget else { - val (i, o) = path.last - InstanceTarget(circuit, module, path.dropRight(1), i.value, o.value) - } - } - - override def tokens = justPath ++ notPath - - override def isLocal = path.isEmpty -} - - -/** Target pointing to a FIRRTL [[firrtl.ir.Circuit]] - * @param circuit Name of a FIRRTL circuit - */ -case class CircuitTarget(circuit: String) extends CompleteTarget { - - /** Creates a [[ModuleTarget]] of provided name and this circuit - * @param m - * @return - */ - def module(m: String): ModuleTarget = ModuleTarget(circuit, m) - - override def circuitOpt: Option[String] = Some(circuit) - - override def moduleOpt: Option[String] = None - - override def tokens = Nil - - override def isLocal = true - - override def addHierarchy(root: String, instance: String): ReferenceTarget = - ReferenceTarget(circuit, root, Nil, instance, Nil) - - override def toNamed: CircuitName = CircuitName(circuit) -} - -/** Target pointing to a FIRRTL [[firrtl.ir.DefModule]] - * @param circuit Circuit containing the module - * @param module Name of the module - */ -case class ModuleTarget(circuit: String, module: String) extends IsModule { - - override def circuitOpt: Option[String] = Some(circuit) - - override def moduleOpt: Option[String] = Some(module) - - override def tokens: Seq[TargetToken] = Nil - - override def targetParent: CircuitTarget = CircuitTarget(circuit) - - override def addHierarchy(root: String, instance: String): InstanceTarget = InstanceTarget(circuit, root, Nil, instance, module) - - override def ref(value: String): ReferenceTarget = ReferenceTarget(circuit, module, Nil, value, Nil) - - override def instOf(instance: String, of: String): InstanceTarget = InstanceTarget(circuit, module, Nil, instance, of) - - override def asPath = Nil - - override def path: Seq[(Instance, OfModule)] = Nil - - override def justPath: Seq[TargetToken] = Nil - - override def notPath: Seq[TargetToken] = Nil - - override def pathlessTarget: ModuleTarget = this - - override def pathTarget: ModuleTarget = this - - override def isLocal = true - - override def setPathTarget(newPath: IsModule): IsModule = newPath - - override def toNamed: ModuleName = ModuleName(module, CircuitName(circuit)) -} - -/** Target pointing to a declared named component in a [[firrtl.ir.DefModule]] - * This includes: [[firrtl.ir.Port]], [[firrtl.ir.DefWire]], [[firrtl.ir.DefRegister]], [[firrtl.ir.DefInstance]], - * [[firrtl.ir.DefMemory]], [[firrtl.ir.DefNode]] - * @param circuit Name of the encapsulating circuit - * @param module Name of the root module of this reference - * @param path Path through instance/ofModules - * @param ref Name of component - * @param component Subcomponent of this reference, e.g. field or index - */ -case class ReferenceTarget(circuit: String, - module: String, - override val path: Seq[(Instance, OfModule)], - ref: String, - component: Seq[TargetToken]) extends IsComponent { - - /** @param value Index value of this target - * @return A new [[ReferenceTarget]] to the specified index of this [[ReferenceTarget]] - */ - def index(value: Int): ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Index(value)) - - /** @param value Field name of this target - * @return A new [[ReferenceTarget]] to the specified field of this [[ReferenceTarget]] - */ - def field(value: String): ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Field(value)) - - /** @return The initialization value of this reference, must be to a [[firrtl.ir.DefRegister]] */ - def init: ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Init) - - /** @return The reset signal of this reference, must be to a [[firrtl.ir.DefRegister]] */ - def reset: ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Reset) - - /** @return The clock signal of this reference, must be to a [[firrtl.ir.DefRegister]] */ - def clock: ReferenceTarget = ReferenceTarget(circuit, module, path, ref, component :+ Clock) - - override def circuitOpt: Option[String] = Some(circuit) - - override def moduleOpt: Option[String] = Some(module) - - override def targetParent: CompleteTarget = component match { - case Nil => - if(path.isEmpty) moduleTarget else { - val (i, o) = path.last - InstanceTarget(circuit, module, path.dropRight(1), i.value, o.value) - } - case other => ReferenceTarget(circuit, module, path, ref, component.dropRight(1)) - } - - override def notPath: Seq[TargetToken] = Ref(ref) +: component - - override def addHierarchy(root: String, instance: String): ReferenceTarget = - ReferenceTarget(circuit, root, (Instance(instance), OfModule(module)) +: path, ref, component) - - override def stripHierarchy(n: Int): ReferenceTarget = { - require(path.size >= n, s"Cannot strip $n levels of hierarchy from $this") - if(n == 0) this else { - val newModule = path(n - 1)._2.value - ReferenceTarget(circuit, newModule, path.drop(n), ref, component) - } - } - - override def pathlessTarget: ReferenceTarget = ReferenceTarget(circuit, encapsulatingModule, Nil, ref, component) - - override def setPathTarget(newPath: IsModule): ReferenceTarget = - ReferenceTarget(newPath.circuit, newPath.module, newPath.asPath, ref, component) - - override def asPath: Seq[(Instance, OfModule)] = path -} - -/** Points to an instance declaration of a module (termed an ofModule) - * @param circuit Encapsulating circuit - * @param module Root module (e.g. the base module of this target) - * @param path Path through instance/ofModules - * @param instance Name of the instance - * @param ofModule Name of the instance's module - */ -case class InstanceTarget(circuit: String, - module: String, - override val path: Seq[(Instance, OfModule)], - instance: String, - ofModule: String) extends IsModule with IsComponent { - - /** @return a [[ReferenceTarget]] referring to this declaration of this instance */ - def asReference: ReferenceTarget = ReferenceTarget(circuit, module, path, instance, Nil) - - /** @return a [[ReferenceTarget]] referring to declaration of this ofModule */ - def ofModuleTarget: ModuleTarget = ModuleTarget(circuit, ofModule) - - override def circuitOpt: Option[String] = Some(circuit) - - override def moduleOpt: Option[String] = Some(module) - - override def targetParent: IsModule = { - if(isLocal) ModuleTarget(circuit, module) else { - val (newInstance, newOfModule) = path.last - InstanceTarget(circuit, module, path.dropRight(1), newInstance.value, newOfModule.value) - } - } - - override def addHierarchy(root: String, inst: String): InstanceTarget = - InstanceTarget(circuit, root, (Instance(inst), OfModule(module)) +: path, instance, ofModule) - - override def ref(value: String): ReferenceTarget = ReferenceTarget(circuit, module, asPath, value, Nil) - - override def instOf(inst: String, of: String): InstanceTarget = InstanceTarget(circuit, module, asPath, inst, of) - - override def stripHierarchy(n: Int): IsModule = { - require(path.size >= n, s"Cannot strip $n levels of hierarchy from $this") - if(n == 0) this else { - val newModule = path(n - 1)._2.value - InstanceTarget(circuit, newModule, path.drop(n), instance, ofModule) - } - } - - override def asPath: Seq[(Instance, OfModule)] = path :+ (Instance(instance), OfModule(ofModule)) - - override def pathlessTarget: InstanceTarget = InstanceTarget(circuit, encapsulatingModule, Nil, instance, ofModule) - - override def notPath = Seq(Instance(instance), OfModule(ofModule)) - - override def setPathTarget(newPath: IsModule): InstanceTarget = - InstanceTarget(newPath.circuit, newPath.module, newPath.asPath, instance, ofModule) -} - - -/** Named classes associate an annotation with a component in a Firrtl circuit */ -@deprecated("Use Target instead, will be removed in 1.3", "1.2") -sealed trait Named { - def serialize: String - def toTarget: CompleteTarget -} - -@deprecated("Use Target instead, will be removed in 1.3", "1.2") -final case class CircuitName(name: String) extends Named { - if(!validModuleName(name)) throw AnnotationException(s"Illegal circuit name: $name") - def serialize: String = name - def toTarget: CircuitTarget = CircuitTarget(name) -} - -@deprecated("Use Target instead, will be removed in 1.3", "1.2") -final case class ModuleName(name: String, circuit: CircuitName) extends Named { - if(!validModuleName(name)) throw AnnotationException(s"Illegal module name: $name") - def serialize: String = circuit.serialize + "." + name - def toTarget: ModuleTarget = ModuleTarget(circuit.name, name) -} - -@deprecated("Use Target instead, will be removed in 1.3", "1.2") -final case class ComponentName(name: String, module: ModuleName) extends Named { - if(!validComponentName(name)) throw AnnotationException(s"Illegal component name: $name") - def expr: Expression = toExp(name) - def serialize: String = module.serialize + "." + name - def toTarget: ReferenceTarget = { - Target.toTargetTokens(name).toList match { - case Ref(r) :: components => ReferenceTarget(module.circuit.name, module.name, Nil, r, components) - case other => throw Target.NamedException(s"Cannot convert $this into [[ReferenceTarget]]: $other") - } - } -} diff --git a/src/main/scala/firrtl/annotations/TargetToken.scala b/src/main/scala/firrtl/annotations/TargetToken.scala deleted file mode 100644 index 587f30eb..00000000 --- a/src/main/scala/firrtl/annotations/TargetToken.scala +++ /dev/null @@ -1,46 +0,0 @@ -// See LICENSE for license details. - -package firrtl.annotations - -/** Building block to represent a [[Target]] of a FIRRTL component */ -sealed trait TargetToken { - def keyword: String - def value: Any - - /** Returns whether this token is one of the type of tokens whose keyword is passed as an argument - * @param keywords - * @return - */ - def is(keywords: String*): Boolean = { - keywords.map { kw => - require(TargetToken.keyword2targettoken.keySet.contains(kw), - s"Keyword $kw must be in set ${TargetToken.keyword2targettoken.keys}") - val lastClass = this.getClass - lastClass == TargetToken.keyword2targettoken(kw)("0").getClass - }.reduce(_ || _) - } -} - -/** Object containing all [[TargetToken]] subclasses */ -case object TargetToken { - case class Instance(value: String) extends TargetToken { override def keyword: String = "inst" } - case class OfModule(value: String) extends TargetToken { override def keyword: String = "of" } - case class Ref(value: String) extends TargetToken { override def keyword: String = "ref" } - case class Index(value: Int) extends TargetToken { override def keyword: String = "[]" } - case class Field(value: String) extends TargetToken { override def keyword: String = "." } - case object Clock extends TargetToken { override def keyword: String = "clock"; val value = "" } - case object Init extends TargetToken { override def keyword: String = "init"; val value = "" } - case object Reset extends TargetToken { override def keyword: String = "reset"; val value = "" } - - val keyword2targettoken = Map( - "inst" -> ((value: String) => Instance(value)), - "of" -> ((value: String) => OfModule(value)), - "ref" -> ((value: String) => Ref(value)), - "[]" -> ((value: String) => Index(value.toInt)), - "." -> ((value: String) => Field(value)), - "clock" -> ((value: String) => Clock), - "init" -> ((value: String) => Init), - "reset" -> ((value: String) => Reset) - ) -} - diff --git a/src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala b/src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala deleted file mode 100644 index ba3ca9a9..00000000 --- a/src/main/scala/firrtl/annotations/analysis/DuplicationHelper.scala +++ /dev/null @@ -1,146 +0,0 @@ -// See LICENSE for license details. - -package firrtl.annotations.analysis - -import firrtl.Namespace -import firrtl.annotations._ -import firrtl.annotations.TargetToken.{Instance, OfModule, Ref} -import firrtl.Utils.throwInternalError - -import scala.collection.mutable - -/** Used by [[firrtl.annotations.transforms.EliminateTargetPaths]] to eliminate target paths - * Calculates needed modifications to a circuit's module/instance hierarchy - */ -case class DuplicationHelper(existingModules: Set[String]) { - // Maps instances to the module it instantiates (an ofModule) - type InstanceOfModuleMap = mutable.HashMap[Instance, OfModule] - - // Maps a module to the instance/ofModules it instantiates - type ModuleHasInstanceOfModuleMap = mutable.HashMap[String, InstanceOfModuleMap] - - // Maps original module names to new duplicated modules and their encapsulated instance/ofModules - type DupMap = mutable.HashMap[String, ModuleHasInstanceOfModuleMap] - - // Internal state to keep track of how paths duplicate - private val dupMap = new DupMap() - - // Internal record of which paths are renamed to which new names, in the case of a collision - private val cachedNames = mutable.HashMap[(String, Seq[(Instance, OfModule)]), String]() ++ - existingModules.map(m => (m, Nil) -> m) - - // Internal record of all paths to ensure unique name generation - private val allModules = mutable.HashSet[String]() ++ existingModules - - /** Updates internal state (dupMap) to calculate instance hierarchy modifications so t's tokens in an instance can be - * expressed as a tokens in a module (e.g. uniquify/duplicate the instance path in t's tokens) - * @param t An instance-resolved component - */ - def expandHierarchy(t: IsMember): Unit = { - val path = t.asPath - path.reverse.tails.map { _.reverse }.foreach { duplicate(t.module, _) } - } - - /** Updates dupMap with how original module names map to new duplicated module names - * @param top Root module of a component - * @param path Path down instance hierarchy of a component - */ - private def duplicate(top: String, path: Seq[(Instance, OfModule)]): Unit = { - val (originalModule, instance, ofModule) = path.size match { - case 0 => return - case 1 => (top, path.head._1, path.head._2) - case _ => (path(path.length - 2)._2.value, path.last._1, path.last._2) - } - val originalModuleToDupedModule = dupMap.getOrElseUpdate(originalModule, new ModuleHasInstanceOfModuleMap()) - val dupedModule = getModuleName(top, path.dropRight(1)) - val dupedModuleToInstances = originalModuleToDupedModule.getOrElseUpdate(dupedModule, new InstanceOfModuleMap()) - val dupedInstanceModule = getModuleName(top, path) - dupedModuleToInstances += ((instance, OfModule(dupedInstanceModule))) - - val originalInstanceModuleToDupedModule = dupMap.getOrElseUpdate(ofModule.value, new ModuleHasInstanceOfModuleMap()) - originalInstanceModuleToDupedModule.getOrElseUpdate(dupedInstanceModule, new InstanceOfModuleMap()) - } - - /** Deterministic name-creation of a duplicated module - * @param top - * @param path - * @return - */ - def getModuleName(top: String, path: Seq[(Instance, OfModule)]): String = { - cachedNames.get((top, path)) match { - case None => // Need a new name - val prefix = path.last._2.value + "___" - val postfix = top + "_" + path.map { case (i, m) => i.value }.mkString("_") - val ns = mutable.HashSet(allModules.toSeq: _*) - val finalName = firrtl.passes.Uniquify.findValidPrefix(prefix, Seq(postfix), ns) + postfix - allModules += finalName - cachedNames((top, path)) = finalName - finalName - case Some(newName) => newName - } - } - - /** Return the duplicated module (formerly originalOfModule) instantiated by instance in newModule (formerly - * originalModule) - * @param originalModule original encapsulating module - * @param newModule new name of encapsulating module - * @param instance instance name being declared in encapsulating module - * @param originalOfModule original module being instantiated in originalModule - * @return - */ - def getNewOfModule(originalModule: String, - newModule: String, - instance: Instance, - originalOfModule: OfModule): OfModule = { - dupMap.get(originalModule) match { - case None => // No duplication, can return originalOfModule - originalOfModule - case Some(newDupedModules) => - newDupedModules.get(newModule) match { - case None if newModule != originalModule => throwInternalError("BAD") - case None => // No duplication, can return originalOfModule - originalOfModule - case Some(newDupedModule) => - newDupedModule.get(instance) match { - case None => // Not duped, can return originalOfModule - originalOfModule - case Some(newOfModule) => - newOfModule - } - } - } - } - - /** Returns the names of this module's duplicated (including the original name) - * @param module - * @return - */ - def getDuplicates(module: String): Set[String] = { - dupMap.get(module).map(_.keys.toSet[String]).getOrElse(Set.empty[String]) ++ Set(module) - } - - /** Rewrites t with new module/instance hierarchy calculated after repeated calls to [[expandHierarchy]] - * @param t A target - * @return t rewritten, is a seq because if the t.module has been duplicated, it must now refer to multiple modules - */ - def makePathless(t: IsMember): Seq[IsMember] = { - val top = t.module - val path = t.asPath - val newTops = getDuplicates(top) - newTops.map { newTop => - val newPath = mutable.ArrayBuffer[TargetToken]() - path.foldLeft((top, newTop)) { case ((originalModule, newModule), (instance, ofModule)) => - val newOfModule = getNewOfModule(originalModule, newModule, instance, ofModule) - newPath ++= Seq(instance, newOfModule) - (ofModule.value, newOfModule.value) - } - val module = if(newPath.nonEmpty) newPath.last.value.toString else newTop - t.notPath match { - case Seq() => ModuleTarget(t.circuit, module) - case Instance(i) +: OfModule(m) +: Seq() => ModuleTarget(t.circuit, module) - case Ref(r) +: components => ReferenceTarget(t.circuit, module, Nil, r, components) - } - }.toSeq - } -} - diff --git a/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala b/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala deleted file mode 100644 index 8f604c9f..00000000 --- a/src/main/scala/firrtl/annotations/transforms/EliminateTargetPaths.scala +++ /dev/null @@ -1,167 +0,0 @@ -// See LICENSE for license details. - -package firrtl.annotations.transforms - -import firrtl.Mappers._ -import firrtl.analyses.InstanceGraph -import firrtl.annotations.TargetToken.{Instance, OfModule} -import firrtl.annotations.analysis.DuplicationHelper -import firrtl.annotations._ -import firrtl.ir._ -import firrtl.{CircuitForm, CircuitState, FIRRTLException, HighForm, RenameMap, Transform, WDefInstance} - -import scala.collection.mutable - - -/** Group of targets that should become local targets - * @param targets - */ -case class ResolvePaths(targets: Seq[CompleteTarget]) extends Annotation { - override def update(renames: RenameMap): Seq[Annotation] = { - val newTargets = targets.flatMap(t => renames.get(t).getOrElse(Seq(t))) - Seq(ResolvePaths(newTargets)) - } -} - -case class NoSuchTargetException(message: String) extends FIRRTLException(message) - -/** For a set of non-local targets, modify the instance/module hierarchy of the circuit such that - * the paths in each non-local target can be removed - * - * In other words, if targeting a specific instance of a module, duplicate that module with a unique name - * and instantiate the new module instead. - * - * Consumes [[ResolvePaths]] - * - * E.g. for non-local target A/b:B/c:C/d, rename the following - * A/b:B/c:C/d -> C_/d - * A/b:B/c:C -> B_/c:C_ - * A/b:B -> A/b:B_ - * B/x -> (B/x, B_/x) // where x is any reference in B - * C/x -> (C/x, C_/x) // where x is any reference in C - */ -class EliminateTargetPaths extends Transform { - - def inputForm: CircuitForm = HighForm - - def outputForm: CircuitForm = HighForm - - /** Replaces old ofModules with new ofModules by calling dupMap methods - * Updates oldUsedOfModules, newUsedOfModules - * @param originalModule Original name of this module - * @param newModule New name of this module - * @param s - * @return - */ - private def onStmt(dupMap: DuplicationHelper, - oldUsedOfModules: mutable.HashSet[String], - newUsedOfModules: mutable.HashSet[String]) - (originalModule: String, newModule: String) - (s: Statement): Statement = s match { - case d@DefInstance(_, name, module) => - val ofModule = dupMap.getNewOfModule(originalModule, newModule, Instance(name), OfModule(module)).value - newUsedOfModules += ofModule - oldUsedOfModules += module - d.copy(module = ofModule) - case d@WDefInstance(_, name, module, _) => - val ofModule = dupMap.getNewOfModule(originalModule, newModule, Instance(name), OfModule(module)).value - newUsedOfModules += ofModule - oldUsedOfModules += module - d.copy(module = ofModule) - case other => other map onStmt(dupMap, oldUsedOfModules, newUsedOfModules)(originalModule, newModule) - } - - /** Returns a modified circuit and [[RenameMap]] containing the associated target remapping - * @param cir - * @param targets - * @return - */ - def run(cir: Circuit, targets: Seq[IsMember]): (Circuit, RenameMap) = { - - val dupMap = DuplicationHelper(cir.modules.map(_.name).toSet) - - // For each target, record its path and calculate the necessary modifications to circuit - targets.foreach { t => dupMap.expandHierarchy(t) } - - // Records original list of used ofModules - val oldUsedOfModules = mutable.HashSet[String]() - oldUsedOfModules += cir.main - - // Records new list of used ofModules - val newUsedOfModules = mutable.HashSet[String]() - newUsedOfModules += cir.main - - // Contains new list of module declarations - val duplicatedModuleList = mutable.ArrayBuffer[DefModule]() - - // Foreach module, calculate the unique names of its duplicates - // Then, update the ofModules of instances that it encapsulates - cir.modules.foreach { m => - dupMap.getDuplicates(m.name).foreach { newName => - val newM = m match { - case e: ExtModule => e.copy(name = newName) - case o: Module => - o.copy(name = newName, body = onStmt(dupMap, oldUsedOfModules, newUsedOfModules)(m.name, newName)(o.body)) - } - duplicatedModuleList += newM - } - } - - // Calculate the final module list - // A module is in the final list if: - // 1) it is a module that is instantiated (new or old) - // 2) it is an old module that was not instantiated and is still not instantiated - val finalModuleList = duplicatedModuleList.filter(m => - newUsedOfModules.contains(m.name) || (!newUsedOfModules.contains(m.name) && !oldUsedOfModules.contains(m.name)) - ) - - // Records how targets have been renamed - val renameMap = RenameMap() - - // Foreach target, calculate the pathless version and only rename targets that are instantiated - targets.foreach { t => - val newTsx = dupMap.makePathless(t) - val newTs = newTsx.filter(c => newUsedOfModules.contains(c.moduleOpt.get)) - if(newTs.nonEmpty) { - renameMap.record(t, newTs) - } - } - - // Return modified circuit and associated renameMap - (cir.copy(modules = finalModuleList), renameMap) - } - - override protected def execute(state: CircuitState): CircuitState = { - - val annotations = state.annotations.collect { case a: ResolvePaths => a } - - // Collect targets that are not local - val targets = annotations.flatMap(_.targets.collect { case x: IsMember => x }) - - // Check validity of paths in targets - val instanceOfModules = new InstanceGraph(state.circuit).getChildrenInstanceOfModule - val targetsWithInvalidPaths = mutable.ArrayBuffer[IsMember]() - targets.foreach { t => - val path = t match { - case m: ModuleTarget => Nil - case i: InstanceTarget => i.asPath - case r: ReferenceTarget => r.path - } - path.foldLeft(t.module) { case (module, (inst: Instance, of: OfModule)) => - val childrenOpt = instanceOfModules.get(module) - if(childrenOpt.isEmpty || !childrenOpt.get.contains((inst, of))) { - targetsWithInvalidPaths += t - } - of.value - } - } - if(targetsWithInvalidPaths.nonEmpty) { - val string = targetsWithInvalidPaths.mkString(",") - throw NoSuchTargetException(s"""Some targets have illegal paths that cannot be resolved/eliminated: $string""") - } - - val (newCircuit, renameMap) = run(state.circuit, targets) - - state.copy(circuit = newCircuit, renames = Some(renameMap)) - } -} -- cgit v1.2.3