diff options
| -rw-r--r-- | src/main/scala/firrtl/options/DependencyManager.scala | 37 | ||||
| -rw-r--r-- | src/main/scala/firrtl/options/Phase.scala | 30 |
2 files changed, 44 insertions, 23 deletions
diff --git a/src/main/scala/firrtl/options/DependencyManager.scala b/src/main/scala/firrtl/options/DependencyManager.scala index 537f87bd..910d44bb 100644 --- a/src/main/scala/firrtl/options/DependencyManager.scala +++ b/src/main/scala/firrtl/options/DependencyManager.scala @@ -22,10 +22,11 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends override def prerequisites = currentState - override def dependents = Seq.empty override def optionalPrerequisites = Seq.empty + override def optionalPrerequisiteOf = Seq.empty + override def invalidates(a: B): Boolean = (_currentState &~ _targets)(oToD(a)) /** Requested [[firrtl.options.TransformLike TransformLike]]s that should be run. Internally, this will be converted to @@ -121,11 +122,11 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends } /** A directed graph consisting of prerequisites derived from only those transforms which are supposed to run. This - * pulls in dependents for transforms which are not in the target set. + * pulls in optionalPrerequisiteOf for transforms which are not in the target set. */ - private lazy val dependentsGraph: DiGraph[B] = { + private lazy val optionalPrerequisiteOfGraph: DiGraph[B] = { val v = new LinkedHashSet() ++ prerequisiteGraph.getVertices - DiGraph(new LinkedHashMap() ++ v.map(vv => vv -> (v & (vv._dependents).map(dToO)))).reverse + DiGraph(new LinkedHashMap() ++ v.map(vv => vv -> (v & (vv._optionalPrerequisiteOf.toSet).map(dToO)))).reverse } /** A directed graph of *optional* prerequisites. Each optional prerequisite is promoted to a full prerequisite if the @@ -139,11 +140,11 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends /** A directed graph consisting of prerequisites derived from ALL targets. This is necessary for defining targets for * [[DependencyManager]] sub-problems. */ - private lazy val otherDependents: DiGraph[B] = { + private lazy val otherPrerequisites: DiGraph[B] = { val edges = { val x = new LinkedHashMap ++ _targets .map(dependencyToObject) - .map{ a => a -> prerequisiteGraph.getVertices.filter(a._dependents(_)) } + .map{ a => a -> prerequisiteGraph.getVertices.filter(a._optionalPrerequisiteOf(_)) } x .values .reduce(_ ++ _) @@ -152,8 +153,10 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends DiGraph(edges).reverse } - /** A directed graph consisting of all prerequisites, including prerequisites derived from dependents */ - lazy val dependencyGraph: DiGraph[B] = prerequisiteGraph + dependentsGraph + optionalPrerequisitesGraph + /** A directed graph consisting of all prerequisites, including prerequisites derived from optionalPrerequisites and + * optionalPrerequisiteOf + */ + lazy val dependencyGraph: DiGraph[B] = prerequisiteGraph + optionalPrerequisiteOfGraph + optionalPrerequisitesGraph /** A directed graph consisting of invalidation edges */ lazy val invalidateGraph: DiGraph[B] = { @@ -178,9 +181,9 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends /** An ordering of [[firrtl.options.TransformLike TransformLike]]s that causes the requested [[DependencyManager.targets * targets]] to be executed starting from the [[DependencyManager.currentState currentState]]. This ordering respects - * prerequisites, dependents, and invalidates of all constituent [[firrtl.options.TransformLike TransformLike]]s. - * This uses an algorithm that attempts to reduce the number of re-lowerings due to invalidations. Re-lowerings are - * implemented as new [[DependencyManager]]s. + * prerequisites, optionalPrerequisites, optionalPrerequisiteOf, and invalidates of all constituent + * [[firrtl.options.TransformLike TransformLike]]s. This uses an algorithm that attempts to reduce the number of + * re-lowerings due to invalidations. Re-lowerings are implemented as new [[DependencyManager]]s. * @throws DependencyManagerException if a cycle exists in either the [[DependencyManager.dependencyGraph * dependencyGraph]] or the [[DependencyManager.invalidateGraph invalidateGraph]]. */ @@ -199,7 +202,7 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends v.map(vv => vv -> (new LinkedHashSet() ++ (dependencyGraph.getEdges(vv).toSeq.sortWith(cmp)))) } - cyclePossible("prerequisites/dependents", dependencyGraph) { + cyclePossible("prerequisites", dependencyGraph) { DiGraph(edges) .linearize .reverse @@ -209,10 +212,9 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends /* [todo] Seq is inefficient here, but Array has ClassTag problems. Use something else? */ val (s, l) = sorted.foldLeft((_currentState, Seq[B]())){ case ((state, out), in) => - /* The prerequisites are both prerequisites AND dependents. */ val prereqs = in._prerequisites ++ dependencyGraph.getEdges(in).toSeq.map(oToD) ++ - otherDependents.getEdges(in).toSeq.map(oToD) + otherPrerequisites.getEdges(in).toSeq.map(oToD) val preprocessing: Option[B] = { if ((prereqs -- state).nonEmpty) { Some(this.copy(prereqs.toSeq, state.toSeq)) } else { None } @@ -267,7 +269,8 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends /** Get a name of some [[firrtl.options.TransformLike TransformLike]] */ private def transformName(transform: B, suffix: String = ""): String = s""""${transform.name}$suffix"""" - /** Convert all prerequisites, dependents, and invalidates to a Graphviz representation. + /** Convert all prerequisites, optionalPrerequisites, optionalPrerequisiteOf, and invalidates to a Graphviz + * representation. * @param file the name of the output file */ def dependenciesToGraphviz: String = { @@ -291,14 +294,14 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends val connections = Seq( (prerequisiteGraph, "edge []"), - (dependentsGraph, """edge [style=bold color="#4292c6"]"""), + (optionalPrerequisiteOfGraph, """edge [style=bold color="#4292c6"]"""), (invalidateGraph, """edge [minlen=2 style=dashed constraint=false color="#fb6a4a"]"""), (optionalPrerequisitesGraph, """edge [style=dotted color="#a1d99b"]""") ) .flatMap{ case (a, b) => toGraphviz(a, b) } .mkString("\n") val nodes = - (prerequisiteGraph + dependentsGraph + invalidateGraph + otherDependents) + (prerequisiteGraph + optionalPrerequisiteOfGraph + invalidateGraph + otherPrerequisites) .getVertices .map(v => s"""${transformName(v)} [label="${v.name}"]""") diff --git a/src/main/scala/firrtl/options/Phase.scala b/src/main/scala/firrtl/options/Phase.scala index 847a4cf2..6dd5d969 100644 --- a/src/main/scala/firrtl/options/Phase.scala +++ b/src/main/scala/firrtl/options/Phase.scala @@ -106,11 +106,12 @@ trait IdentityLike[A] { this: TransformLike[A] => * "transforms") * * This trait forms the basis of the Dependency API of the Chisel/FIRRTL Hardware Compiler Framework. Dependencies are - * defined in terms of prerequisistes, dependents, and invalidates. A prerequisite is a transform that must run before - * this transform. A dependent is a transform that must run ''after'' this transform. (This can be viewed as a means of - * injecting a prerequisite into some other transform.) Finally, invalidates define the set of transforms whose effects - * this transform undos/invalidates. (Invalidation then implies that a transform that is invalidated by this transform - * and needed by another transform will need to be re-run.) + * defined in terms of prerequisistes, optional prerequisites, optional prerequisites of, and invalidates. A + * prerequisite is a transform that must run before this transform. An optional prerequisites is transform that should + * run before this transform if the other transform is a target (or the prerequisite of a target). An optional + * prerequisite of is an optional prerequisite injected into another transform. Finally, invalidates define the set of + * transforms whose effects this transform undos/invalidates. (Invalidation then implies that a transform that is + * invalidated by this transform and needed by another transform will need to be re-run.) * * This Dependency API only defines dependencies. A concrete [[DependencyManager]] is expected to be used to statically * resolve a linear ordering of transforms that satisfies dependency requirements. @@ -152,8 +153,25 @@ trait DependencyAPI[A <: DependencyAPI[A]] { this: TransformLike[_] => * @see [[firrtl.passes.CheckTypes]] for an example of an optional checking [[firrtl.Transform]] * $seqNote */ + @deprecated( + "Due to confusion, 'dependents' is being renamed to 'optionalPrerequisiteOf'. Override the latter instead.", + "FIRRTL 1.3" + ) def dependents: Seq[Dependency[A]] = Seq.empty - private[options] lazy val _dependents: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ dependents.toSet + + /** A sequence of transforms to add this transform as an `optionalPrerequisite`. The use of `optionalPrerequisiteOf` + * enables the transform declaring them to always run before some other transforms. However, declaring + * `optionalPrerequisiteOf` will not result in the sequence of transforms executing. + * + * This is useful for providing an ordering constraint to guarantee that other transforms (e.g., emitters) will not + * be scheduled before you. + * + * @note This method **will not** result in the listed transforms running. If you want to add multiple transforms at + * once, you should use a `DependencyManager` with multiple targets. + */ + def optionalPrerequisiteOf: Seq[Dependency[A]] = dependents + private[options] lazy val _optionalPrerequisiteOf: LinkedHashSet[Dependency[A]] = + new LinkedHashSet() ++ optionalPrerequisiteOf.toSet /** A function that, given *another* transform (parameter `a`) will return true if this transform invalidates/undos the * effects of the *other* transform (parameter `a`). |
