aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/options/DependencyManager.scala150
-rw-r--r--src/main/scala/firrtl/options/Phase.scala66
-rw-r--r--src/main/scala/firrtl/options/phases/AddDefaults.scala8
-rw-r--r--src/main/scala/firrtl/options/phases/Checks.scala9
-rw-r--r--src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala8
-rw-r--r--src/main/scala/firrtl/options/phases/DeletedWrapper.scala9
-rw-r--r--src/main/scala/firrtl/options/phases/GetIncludes.scala8
-rw-r--r--src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala13
-rw-r--r--src/test/scala/firrtlTests/options/PhaseManagerSpec.scala179
9 files changed, 265 insertions, 185 deletions
diff --git a/src/main/scala/firrtl/options/DependencyManager.scala b/src/main/scala/firrtl/options/DependencyManager.scala
index 604a1b10..99d9c29c 100644
--- a/src/main/scala/firrtl/options/DependencyManager.scala
+++ b/src/main/scala/firrtl/options/DependencyManager.scala
@@ -18,19 +18,24 @@ case class DependencyManagerException(message: String, cause: Throwable = null)
* @tparam B the type of the [[firrtl.options.TransformLike TransformLike]]
*/
trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends TransformLike[A] with DependencyAPI[B] {
+ override lazy val prerequisites = currentState
+
+ override lazy val dependents = 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
* a set based on the ordering defined here.
*/
- def targets: Seq[Dependency]
- private lazy val _targets: LinkedHashSet[Dependency] = targets
- .foldLeft(new LinkedHashSet[Dependency]()){ case (a, b) => a += b }
+ def targets: Seq[Dependency[B]]
+ private lazy val _targets: LinkedHashSet[Dependency[B]] = targets
+ .foldLeft(new LinkedHashSet[Dependency[B]]()){ case (a, b) => a += b }
/** A sequence of [[firrtl.Transform]]s that have been run. Internally, this will be converted to an ordered set.
*/
- def currentState: Seq[Dependency]
- private lazy val _currentState: LinkedHashSet[Dependency] = currentState
- .foldLeft(new LinkedHashSet[Dependency]()){ case (a, b) => a += b }
+ def currentState: Seq[Dependency[B]]
+ private lazy val _currentState: LinkedHashSet[Dependency[B]] = currentState
+ .foldLeft(new LinkedHashSet[Dependency[B]]()){ case (a, b) => a += b }
/** Existing transform objects that have already been constructed */
def knownObjects: Set[B]
@@ -42,11 +47,11 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
/** Store of conversions between classes and objects. Objects that do not exist in the map will be lazily constructed.
*/
- protected lazy val classToObject: LinkedHashMap[Dependency, B] = {
- val init = LinkedHashMap[Dependency, B](knownObjects.map(x => x.getClass -> x).toSeq: _*)
+ protected lazy val dependencyToObject: LinkedHashMap[Dependency[B], B] = {
+ val init = LinkedHashMap[Dependency[B], B](knownObjects.map(x => oToD(x) -> x).toSeq: _*)
(_targets ++ _currentState)
.filter(!init.contains(_))
- .map(x => init(x) = safeConstruct(x))
+ .map(x => init(x) = x.getObject())
init
}
@@ -54,42 +59,42 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
* requirements. This is used to solve sub-problems arising from invalidations.
*/
protected def copy(
- targets: Seq[Dependency],
- currentState: Seq[Dependency],
- knownObjects: ISet[B] = classToObject.values.toSet): B
+ targets: Seq[Dependency[B]],
+ currentState: Seq[Dependency[B]],
+ knownObjects: ISet[B] = dependencyToObject.values.toSet): B
- /** Implicit conversion from Class[B] to B */
- private implicit def cToO(c: Dependency): B = classToObject.getOrElseUpdate(c, safeConstruct(c))
+ /** Implicit conversion from Dependency to B */
+ private implicit def dToO(d: Dependency[B]): B = dependencyToObject.getOrElseUpdate(d, d.getObject())
- /** Implicit conversion from B to Class[B] */
- private implicit def oToC(b: B): Dependency = b.getClass
+ /** Implicit conversion from B to Dependency */
+ private implicit def oToD(b: B): Dependency[B] = Dependency.fromTransform(b)
/** Modified breadth-first search that supports multiple starting nodes and a custom extractor that can be used to
* generate/filter the edges to explore. Additionally, this will include edges to previously discovered nodes.
*/
- private def bfs( start: LinkedHashSet[Dependency],
- blacklist: LinkedHashSet[Dependency],
- extractor: B => Set[Dependency] ): LinkedHashMap[B, LinkedHashSet[B]] = {
+ private def bfs( start: LinkedHashSet[Dependency[B]],
+ blacklist: LinkedHashSet[Dependency[B]],
+ extractor: B => Set[Dependency[B]] ): LinkedHashMap[B, LinkedHashSet[B]] = {
val (queue, edges) = {
- val a: Queue[Dependency] = Queue(start.toSeq:_*)
+ val a: Queue[Dependency[B]] = Queue(start.toSeq:_*)
val b: LinkedHashMap[B, LinkedHashSet[B]] = LinkedHashMap[B, LinkedHashSet[B]](
- start.map((cToO(_) -> LinkedHashSet[B]())).toSeq:_*)
+ start.map((dToO(_) -> LinkedHashSet[B]())).toSeq:_*)
(a, b)
}
while (queue.nonEmpty) {
- val u: Dependency = queue.dequeue
- for (v <- extractor(classToObject(u))) {
+ val u: Dependency[B] = queue.dequeue
+ for (v <- extractor(dependencyToObject(u))) {
if (!blacklist.contains(v) && !edges.contains(v)) {
queue.enqueue(v)
}
if (!edges.contains(v)) {
- val obj = cToO(v)
+ val obj = dToO(v)
edges(obj) = LinkedHashSet.empty
- classToObject += (v -> obj)
+ dependencyToObject += (v -> obj)
}
- edges(classToObject(u)) = edges(classToObject(u)) + classToObject(v)
+ edges(dependencyToObject(u)) = edges(dependencyToObject(u)) + dependencyToObject(v)
}
}
@@ -105,9 +110,9 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
/** A directed graph consisting of prerequisite edges */
private lazy val prerequisiteGraph: DiGraph[B] = {
val edges = bfs(
- start = _targets -- _currentState,
+ start = _targets &~ _currentState,
blacklist = _currentState,
- extractor = (p: B) => new LinkedHashSet[Dependency]() ++ p.prerequisites -- _currentState)
+ extractor = (p: B) => new LinkedHashSet[Dependency[B]]() ++ p.prerequisites &~ _currentState)
DiGraph(edges)
}
@@ -116,7 +121,7 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
*/
private lazy val dependentsGraph: DiGraph[B] = {
val v = new LinkedHashSet() ++ prerequisiteGraph.getVertices
- DiGraph(new LinkedHashMap() ++ v.map(vv => vv -> ((new LinkedHashSet() ++ vv.dependents).map(cToO) & v))).reverse
+ DiGraph(new LinkedHashMap() ++ v.map(vv => vv -> (v & (vv.dependents.toSet).map(dToO)))).reverse
}
/** A directed graph consisting of prerequisites derived from ALL targets. This is necessary for defining targets for
@@ -125,7 +130,7 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
private lazy val otherDependents: DiGraph[B] = {
val edges = {
val x = new LinkedHashMap ++ _targets
- .map(classToObject)
+ .map(dependencyToObject)
.map{ a => a -> prerequisiteGraph.getVertices.filter(a._dependents(_)) }
x
.values
@@ -140,12 +145,14 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
/** A directed graph consisting of invalidation edges */
lazy val invalidateGraph: DiGraph[B] = {
- val v = dependencyGraph.getVertices
+ val v = new LinkedHashSet() ++ dependencyGraph.getVertices
DiGraph(
bfs(
- start = _targets -- _currentState,
+ start = v.map(oToD(_)),
blacklist = _currentState,
- extractor = (p: B) => v.filter(p.invalidates).map(_.getClass).toSet))
+
+ /* Explore all invalidated transforms **EXCEPT** the current transform! */
+ extractor = (p: B) => v.filter(p.invalidates).map(oToD(_)).toSet - oToD(p)))
.reverse
}
@@ -157,14 +164,6 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
|${diGraph.findSCCs.filter(_.size > 1).mkString(" - ", "\n - ", "")}""".stripMargin, e)
}
- /** Wrap an [[IllegalAccessException]] due to attempted object construction in a [[DependencyManagerException]] */
- private def safeConstruct[A](a: Class[_ <: A]): A = try { a.newInstance } catch {
- case e: IllegalAccessException => throw new DependencyManagerException(
- s"Failed to construct '$a'! (Did you try to construct an object?)", e)
- case e: InstantiationException => throw new DependencyManagerException(
- s"Failed to construct '$a'! (Did you try to construct an inner class or a class with parameters?)", e)
- }
-
/** 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.
@@ -175,48 +174,45 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
*/
lazy val transformOrder: Seq[B] = {
- /* Topologically sort the dependency graph using the invalidate graph topological sort as a seed. This has the effect of
- * reducing (perhaps minimizing?) the number of work re-lowerings.
+ /* Topologically sort the dependency graph to determine a "good" initial ordering.
*/
val sorted = {
- val seed = cyclePossible("invalidates", invalidateGraph){ invalidateGraph.linearize }.reverse
+ val edges = {
+ val v = cyclePossible("invalidates", invalidateGraph){ invalidateGraph.linearize }.reverse
+ /* A comparison function that will sort vertices based on the topological sort of the invalidation graph */
+ val cmp =
+ (l: B, r: B) => v.foldLeft((Map.empty[B, Dependency[B] => Boolean], Set.empty[Dependency[B]])){
+ case ((m, s), r) => (m + (r -> ((a: Dependency[B]) => !s(a))), s + r) }._1(l)(r)
+ new LinkedHashMap() ++
+ v.map(vv => vv -> (new LinkedHashSet() ++ (dependencyGraph.getEdges(vv).toSeq.sortWith(cmp))))
+ }
cyclePossible("prerequisites/dependents", dependencyGraph) {
- dependencyGraph
- .seededLinearize(Some(seed))
+ DiGraph(edges)
+ .linearize
.reverse
.dropWhile(b => _currentState.contains(b))
}
}
- val (state, lowerers) = {
- /* [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 = new LinkedHashSet() ++ in.prerequisites ++
- dependencyGraph.getEdges(in).toSeq.map(oToC) ++
- otherDependents.getEdges(in).toSeq.map(oToC)
- val missing = (prereqs -- state)
- val preprocessing: Option[B] = {
- if (missing.nonEmpty) { Some(this.copy(prereqs.toSeq, state.toSeq)) }
- else { None }
- }
- ((state ++ missing + in).map(cToO).filterNot(in.invalidates).map(oToC), out ++ preprocessing :+ in)
- }
- val missing = (_targets -- s)
- val postprocessing: Option[B] = {
- if (missing.nonEmpty) { Some(this.copy(_targets.toSeq, s.toSeq)) }
- else { None }
+ /* [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 = new LinkedHashSet() ++ in.prerequisites ++
+ dependencyGraph.getEdges(in).toSeq.map(oToD) ++
+ otherDependents.getEdges(in).toSeq.map(oToD)
+ val preprocessing: Option[B] = {
+ if ((prereqs -- state).nonEmpty) { Some(this.copy(prereqs.toSeq, state.toSeq)) }
+ else { None }
}
-
- (s ++ missing, l ++ postprocessing)
+ /* "in" is added *after* invalidation because a transform my not invalidate itself! */
+ ((state ++ prereqs).map(dToO).filterNot(in.invalidates).map(oToD) + in, out ++ preprocessing :+ in)
}
-
- if (!_targets.subsetOf(state)) {
- throw new DependencyManagerException(
- s"The final state ($state) did not include the requested targets (${targets})!")
+ val postprocessing: Option[B] = {
+ if ((_targets -- s).nonEmpty) { Some(this.copy(_targets.toSeq, s.toSeq)) }
+ else { None }
}
- lowerers
+ l ++ postprocessing
}
/** A version of the [[DependencyManager.transformOrder transformOrder]] that flattens the transforms of any internal
@@ -230,7 +226,7 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
final override def transform(annotations: A): A = {
/* A local store of each wrapper to it's underlying class. */
- val wrapperToClass = new HashMap[B, Dependency]
+ val wrapperToClass = new HashMap[B, Dependency[B]]
/* The determined, flat order of transforms is wrapped with surrounding transforms while populating wrapperToClass so
* that each wrapped transform object can be dereferenced to its underlying class. Each wrapped transform is then
@@ -249,7 +245,7 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
| state: ${state.mkString("\n -", "\n -", "")}
| prerequisites: ${prerequisites.mkString("\n -", "\n -", "")}""".stripMargin)
}
- (t.transform(a), ((state + wrapperToClass(t)).map(cToO).filterNot(t.invalidates).map(oToC)))
+ (t.transform(a), ((state + wrapperToClass(t)).map(dToO).filterNot(t.invalidates).map(oToD)))
}._1
}
@@ -356,15 +352,15 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
class PhaseManager(
val targets: Seq[PhaseManager.PhaseDependency],
val currentState: Seq[PhaseManager.PhaseDependency] = Seq.empty,
- val knownObjects: Set[Phase] = Set.empty) extends Phase with DependencyManager[AnnotationSeq, Phase] {
-
- protected def copy(a: Seq[Dependency], b: Seq[Dependency], c: ISet[Phase]) = new PhaseManager(a, b, c)
+ val knownObjects: Set[Phase] = Set.empty) extends DependencyManager[AnnotationSeq, Phase] with Phase {
+ import PhaseManager.PhaseDependency
+ protected def copy(a: Seq[PhaseDependency], b: Seq[PhaseDependency], c: ISet[Phase]) = new PhaseManager(a, b, c)
}
object PhaseManager {
/** The type used to represent dependencies between [[Phase]]s */
- type PhaseDependency = Class[_ <: Phase]
+ type PhaseDependency = Dependency[Phase]
}
diff --git a/src/main/scala/firrtl/options/Phase.scala b/src/main/scala/firrtl/options/Phase.scala
index e328282f..a9656407 100644
--- a/src/main/scala/firrtl/options/Phase.scala
+++ b/src/main/scala/firrtl/options/Phase.scala
@@ -8,6 +8,61 @@ import logger.LazyLogging
import scala.collection.mutable.LinkedHashSet
+import scala.reflect
+import scala.reflect.ClassTag
+
+object Dependency {
+ def apply[A <: DependencyAPI[_] : ClassTag]: Dependency[A] = {
+ val clazz = reflect.classTag[A].runtimeClass
+ Dependency(Left(clazz.asInstanceOf[Class[A]]))
+ }
+
+ def apply[A <: DependencyAPI[_]](c: Class[_ <: A]): Dependency[A] = {
+ // It's forbidden to wrap the class of a singleton as a Dependency
+ require(c.getName.last != '$')
+ Dependency(Left(c))
+ }
+
+ def apply[A <: DependencyAPI[_]](o: A with Singleton): Dependency[A] = Dependency(Right(o))
+
+ def fromTransform[A <: DependencyAPI[_]](t: A): Dependency[A] = {
+ if (isSingleton(t)) {
+ Dependency[A](Right(t.asInstanceOf[A with Singleton]))
+ } else {
+ Dependency[A](Left(t.getClass))
+ }
+ }
+
+ private def isSingleton(obj: AnyRef): Boolean = {
+ reflect.runtime.currentMirror.reflect(obj).symbol.isModuleClass
+ }
+}
+
+case class Dependency[+A <: DependencyAPI[_]](id: Either[Class[_ <: A], A with Singleton]) {
+ def getObject(): A = id match {
+ case Left(c) => safeConstruct(c)
+ case Right(o) => o
+ }
+
+ def getSimpleName: String = id match {
+ case Left(c) => c.getSimpleName
+ case Right(o) => o.getClass.getSimpleName
+ }
+
+ def getName: String = id match {
+ case Left(c) => c.getName
+ case Right(o) => o.getClass.getName
+ }
+
+ /** Wrap an [[IllegalAccessException]] due to attempted object construction in a [[DependencyManagerException]] */
+ private def safeConstruct[A](a: Class[_ <: A]): A = try { a.newInstance } catch {
+ case e: IllegalAccessException => throw new DependencyManagerException(
+ s"Failed to construct '$a'! (Did you try to construct an object?)", e)
+ case e: InstantiationException => throw new DependencyManagerException(
+ s"Failed to construct '$a'! (Did you try to construct an inner class or a class with parameters?)", e)
+ }
+}
+
/** A polymorphic mathematical transform
* @tparam A the transformed type
*/
@@ -42,14 +97,11 @@ trait TransformLike[A] extends LazyLogging {
*/
trait DependencyAPI[A <: DependencyAPI[A]] { this: TransformLike[_] =>
- /** The type used to express dependencies: a class which itself has dependencies. */
- type Dependency = Class[_ <: A]
-
/** All transform that must run before this transform
* $seqNote
*/
- def prerequisites: Seq[Dependency] = Seq.empty
- private[options] lazy val _prerequisites: LinkedHashSet[Dependency] = new LinkedHashSet() ++ prerequisites.toSet
+ def prerequisites: Seq[Dependency[A]] = Seq.empty
+ private[options] lazy val _prerequisites: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ prerequisites.toSet
/** All transforms that must run ''after'' this transform
*
@@ -70,8 +122,8 @@ trait DependencyAPI[A <: DependencyAPI[A]] { this: TransformLike[_] =>
* @see [[firrtl.passes.CheckTypes]] for an example of an optional checking [[firrtl.Transform]]
* $seqNote
*/
- def dependents: Seq[Dependency] = Seq.empty
- private[options] lazy val _dependents: LinkedHashSet[Dependency] = new LinkedHashSet() ++ dependents.toSet
+ def dependents: Seq[Dependency[A]] = Seq.empty
+ private[options] lazy val _dependents: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ dependents.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`).
diff --git a/src/main/scala/firrtl/options/phases/AddDefaults.scala b/src/main/scala/firrtl/options/phases/AddDefaults.scala
index 8f7fe401..a327d930 100644
--- a/src/main/scala/firrtl/options/phases/AddDefaults.scala
+++ b/src/main/scala/firrtl/options/phases/AddDefaults.scala
@@ -3,14 +3,18 @@
package firrtl.options.phases
import firrtl.AnnotationSeq
-import firrtl.options.{Phase, TargetDirAnnotation}
+import firrtl.options.{Dependency, Phase, PreservesAll, TargetDirAnnotation}
/** Add default annotations for a [[Stage]]
*
* This currently only adds a [[TargetDirAnnotation]]. This isn't necessary for a [[StageOptionsView]], but downstream
* tools may expect a [[TargetDirAnnotation]] to exist.
*/
-class AddDefaults extends Phase {
+class AddDefaults extends Phase with PreservesAll[Phase] {
+
+ override val prerequisites = Seq(Dependency[GetIncludes], Dependency[ConvertLegacyAnnotations])
+
+ override val dependents = Seq.empty
def transform(annotations: AnnotationSeq): AnnotationSeq = {
val td = annotations.collectFirst{ case a: TargetDirAnnotation => a}.isEmpty
diff --git a/src/main/scala/firrtl/options/phases/Checks.scala b/src/main/scala/firrtl/options/phases/Checks.scala
index 0691e9b0..659247c9 100644
--- a/src/main/scala/firrtl/options/phases/Checks.scala
+++ b/src/main/scala/firrtl/options/phases/Checks.scala
@@ -4,12 +4,17 @@ package firrtl.options.phases
import firrtl.AnnotationSeq
import firrtl.annotations.Annotation
-import firrtl.options.{OptionsException, OutputAnnotationFileAnnotation, Phase, TargetDirAnnotation}
+import firrtl.options.{OptionsException, OutputAnnotationFileAnnotation, Phase, PreservesAll, TargetDirAnnotation}
+import firrtl.options.Dependency
/** [[firrtl.options.Phase Phase]] that validates an [[AnnotationSeq]]. If successful, views of this [[AnnotationSeq]]
* as [[StageOptions]] are guaranteed to succeed.
*/
-class Checks extends Phase {
+class Checks extends Phase with PreservesAll[Phase] {
+
+ override val prerequisites = Seq(Dependency[GetIncludes], Dependency[ConvertLegacyAnnotations], Dependency[AddDefaults])
+
+ override val dependents = Seq.empty
/** Validate an [[AnnotationSeq]] for [[StageOptions]]
* @throws OptionsException if annotations are invalid
diff --git a/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala b/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
index 39f59572..a8e86a77 100644
--- a/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
+++ b/src/main/scala/firrtl/options/phases/ConvertLegacyAnnotations.scala
@@ -4,10 +4,14 @@ package firrtl.options.phases
import firrtl.AnnotationSeq
import firrtl.annotations.LegacyAnnotation
-import firrtl.options.Phase
+import firrtl.options.{Dependency, Phase, PreservesAll}
/** Convert any [[firrtl.annotations.LegacyAnnotation LegacyAnnotation]]s to non-legacy variants */
-class ConvertLegacyAnnotations extends Phase {
+class ConvertLegacyAnnotations extends Phase with PreservesAll[Phase] {
+
+ override val prerequisites = Seq(Dependency[GetIncludes])
+
+ override val dependents = Seq.empty
def transform(annotations: AnnotationSeq): AnnotationSeq = LegacyAnnotation.convertLegacyAnnos(annotations)
diff --git a/src/main/scala/firrtl/options/phases/DeletedWrapper.scala b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
index 0a959f32..5374aa66 100644
--- a/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
+++ b/src/main/scala/firrtl/options/phases/DeletedWrapper.scala
@@ -4,7 +4,7 @@ package firrtl.options.phases
import firrtl.AnnotationSeq
import firrtl.annotations.DeletedAnnotation
-import firrtl.options.{Phase, Translator}
+import firrtl.options.{Phase, PreservesAll, Translator}
import scala.collection.mutable
@@ -12,7 +12,12 @@ import scala.collection.mutable
* wrapped [[firrtl.options.Phase Phase]] will be added as [[firrtl.annotations.DeletedAnnotation DeletedAnnotation]]s.
* @param p a [[firrtl.options.Phase Phase]] to wrap
*/
-class DeletedWrapper(p: Phase) extends Phase with Translator[AnnotationSeq, (AnnotationSeq, AnnotationSeq)] {
+class DeletedWrapper(p: Phase) extends Phase with Translator[AnnotationSeq, (AnnotationSeq, AnnotationSeq)]
+ with PreservesAll[Phase] {
+
+ override val prerequisites = Seq.empty
+
+ override val dependents = Seq.empty
override lazy val name: String = p.name
diff --git a/src/main/scala/firrtl/options/phases/GetIncludes.scala b/src/main/scala/firrtl/options/phases/GetIncludes.scala
index cb9bb840..f6c02543 100644
--- a/src/main/scala/firrtl/options/phases/GetIncludes.scala
+++ b/src/main/scala/firrtl/options/phases/GetIncludes.scala
@@ -7,7 +7,7 @@ import net.jcazevedo.moultingyaml._
import firrtl.AnnotationSeq
import firrtl.annotations.{AnnotationFileNotFoundException, JsonProtocol, LegacyAnnotation}
import firrtl.annotations.AnnotationYamlProtocol._
-import firrtl.options.{InputAnnotationFileAnnotation, Phase, StageUtils}
+import firrtl.options.{InputAnnotationFileAnnotation, Phase, PreservesAll, StageUtils}
import firrtl.FileUtils
import java.io.File
@@ -16,7 +16,11 @@ import scala.collection.mutable
import scala.util.{Try, Failure}
/** Recursively expand all [[InputAnnotationFileAnnotation]]s in an [[AnnotationSeq]] */
-class GetIncludes extends Phase {
+class GetIncludes extends Phase with PreservesAll[Phase] {
+
+ override val prerequisites = Seq.empty
+
+ override val dependents = Seq.empty
/** Read all [[annotations.Annotation]] from a file in JSON or YAML format
* @param filename a JSON or YAML file of [[annotations.Annotation]]
diff --git a/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala b/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala
index bb2a8cd6..4a638393 100644
--- a/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala
+++ b/src/main/scala/firrtl/options/phases/WriteOutputAnnotations.scala
@@ -4,14 +4,23 @@ package firrtl.options.phases
import firrtl.AnnotationSeq
import firrtl.annotations.{DeletedAnnotation, JsonProtocol}
-import firrtl.options.{Phase, StageOptions, Unserializable, Viewer}
+import firrtl.options.{Phase, PreservesAll, StageOptions, Unserializable, Viewer}
+import firrtl.options.Dependency
import java.io.PrintWriter
/** [[firrtl.options.Phase Phase]] that writes an [[AnnotationSeq]] to a file. A file is written if and only if a
* [[StageOptions]] view has a non-empty [[StageOptions.annotationFileOut annotationFileOut]].
*/
-class WriteOutputAnnotations extends Phase {
+class WriteOutputAnnotations extends Phase with PreservesAll[Phase] {
+
+ override val prerequisites =
+ Seq( Dependency[GetIncludes],
+ Dependency[ConvertLegacyAnnotations],
+ Dependency[AddDefaults],
+ Dependency[Checks] )
+
+ override val dependents = Seq.empty
/** Write the input [[AnnotationSeq]] to a fie. */
def transform(annotations: AnnotationSeq): AnnotationSeq = {
diff --git a/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala b/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala
index 518728d2..ee9d28aa 100644
--- a/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala
+++ b/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala
@@ -5,7 +5,7 @@ package firrtlTests.options
import org.scalatest.{FlatSpec, Matchers}
import firrtl.AnnotationSeq
-import firrtl.options.{DependencyManagerException, Phase, PhaseManager, PreservesAll}
+import firrtl.options.{DependencyManagerException, Phase, PhaseManager, PreservesAll, Dependency}
import java.io.{File, PrintWriter}
@@ -23,19 +23,19 @@ class A extends IdentityPhase {
/** [[Phase]] that requires [[A]] and invalidates nothing */
class B extends IdentityPhase {
- override def prerequisites: Seq[Dependency] = Seq(classOf[A])
+ override def prerequisites = Seq(Dependency[A])
override def invalidates(phase: Phase): Boolean = false
}
/** [[Phase]] that requires [[B]] and invalidates nothing */
class C extends IdentityPhase {
- override def prerequisites = Seq(classOf[A])
+ override def prerequisites = Seq(Dependency[A])
override def invalidates(phase: Phase): Boolean = false
}
/** [[Phase]] that requires [[A]] and invalidates [[A]] */
class D extends IdentityPhase {
- override def prerequisites = Seq(classOf[A])
+ override def prerequisites = Seq(Dependency[A])
override def invalidates(phase: Phase): Boolean = phase match {
case _: A => true
case _ => false
@@ -44,13 +44,13 @@ class D extends IdentityPhase {
/** [[Phase]] that requires [[B]] and invalidates nothing */
class E extends IdentityPhase {
- override def prerequisites = Seq(classOf[B])
+ override def prerequisites = Seq(Dependency[B])
override def invalidates(phase: Phase): Boolean = false
}
/** [[Phase]] that requires [[B]] and [[C]] and invalidates [[E]] */
class F extends IdentityPhase {
- override def prerequisites = Seq(classOf[B], classOf[C])
+ override def prerequisites = Seq(Dependency[B], Dependency[C])
override def invalidates(phase: Phase): Boolean = phase match {
case _: E => true
case _ => false
@@ -60,7 +60,7 @@ class F extends IdentityPhase {
/** [[Phase]] that requires [[C]] and invalidates [[F]] */
class G extends IdentityPhase {
- override def prerequisites = Seq(classOf[C])
+ override def prerequisites = Seq(Dependency[C])
override def invalidates(phase: Phase): Boolean = phase match {
case _: F => true
case _ => false
@@ -68,11 +68,11 @@ class G extends IdentityPhase {
}
class CyclicA extends IdentityPhase with PreservesAll[Phase] {
- override def prerequisites = Seq(classOf[CyclicB])
+ override def prerequisites = Seq(Dependency[CyclicB])
}
class CyclicB extends IdentityPhase with PreservesAll[Phase] {
- override def prerequisites = Seq(classOf[CyclicA])
+ override def prerequisites = Seq(Dependency[CyclicA])
}
class CyclicC extends IdentityPhase {
@@ -95,25 +95,25 @@ object ComplicatedFixture {
override def invalidates(phase: Phase): Boolean = false
}
class B extends IdentityPhase {
- override def prerequisites = Seq(classOf[A])
+ override def prerequisites = Seq(Dependency[A])
override def invalidates(phase: Phase): Boolean = false
}
class C extends IdentityPhase {
- override def prerequisites = Seq(classOf[A])
+ override def prerequisites = Seq(Dependency[A])
override def invalidates(phase: Phase): Boolean = phase match {
case _: B => true
case _ => false
}
}
class D extends IdentityPhase {
- override def prerequisites = Seq(classOf[B])
+ override def prerequisites = Seq(Dependency[B])
override def invalidates(phase: Phase): Boolean = phase match {
case _: C | _: E => true
case _ => false
}
}
class E extends IdentityPhase {
- override def prerequisites = Seq(classOf[B])
+ override def prerequisites = Seq(Dependency[B])
override def invalidates(phase: Phase): Boolean = false
}
@@ -132,13 +132,13 @@ object RepeatedAnalysisFixture {
override def invalidates(phase: Phase): Boolean = false
}
class A extends InvalidatesAnalysis {
- override def prerequisites = Seq(classOf[Analysis])
+ override def prerequisites = Seq(Dependency[Analysis])
}
class B extends InvalidatesAnalysis {
- override def prerequisites = Seq(classOf[A], classOf[Analysis])
+ override def prerequisites = Seq(Dependency[A], Dependency[Analysis])
}
class C extends InvalidatesAnalysis {
- override def prerequisites = Seq(classOf[B], classOf[Analysis])
+ override def prerequisites = Seq(Dependency[B], Dependency[Analysis])
}
}
@@ -149,21 +149,21 @@ object InvertedAnalysisFixture {
override def invalidates(phase: Phase): Boolean = false
}
class A extends IdentityPhase {
- override def prerequisites = Seq(classOf[Analysis])
+ override def prerequisites = Seq(Dependency[Analysis])
override def invalidates(phase: Phase): Boolean = phase match {
case _: Analysis => true
case _ => false
}
}
class B extends IdentityPhase {
- override def prerequisites = Seq(classOf[Analysis])
+ override def prerequisites = Seq(Dependency[Analysis])
override def invalidates(phase: Phase): Boolean = phase match {
case _: Analysis | _: A => true
case _ => false
}
}
class C extends IdentityPhase {
- override def prerequisites = Seq(classOf[Analysis])
+ override def prerequisites = Seq(Dependency[Analysis])
override def invalidates(phase: Phase): Boolean = phase match {
case _: Analysis | _: B => true
case _ => false
@@ -179,7 +179,7 @@ object DependentsFixture {
}
class Second extends IdentityPhase {
- override val prerequisites = Seq(classOf[First])
+ override val prerequisites = Seq(Dependency[First])
override def invalidates(phase: Phase): Boolean = false
}
@@ -188,8 +188,8 @@ object DependentsFixture {
* loop detection.
*/
class Custom extends IdentityPhase {
- override val prerequisites = Seq(classOf[First])
- override val dependents = Seq(classOf[Second])
+ override val prerequisites = Seq(Dependency[First])
+ override val dependents = Seq(Dependency[Second])
override def invalidates(phase: Phase): Boolean = false
}
@@ -219,7 +219,7 @@ object ChainedInvalidationFixture {
override def invalidates(phase: Phase): Boolean = false
}
class E extends IdentityPhase {
- override val prerequisites = Seq(classOf[A], classOf[B], classOf[C], classOf[D])
+ override val prerequisites = Seq(Dependency[A], Dependency[B], Dependency[C], Dependency[D])
override def invalidates(phase: Phase): Boolean = false
}
@@ -253,8 +253,8 @@ object UnrelatedFixture {
class B15 extends IdentityPhase with PreservesAll[Phase]
class B6Sub extends B6 {
- override val prerequisites = Seq(classOf[B6])
- override val dependents = Seq(classOf[B7])
+ override val prerequisites = Seq(Dependency[B6])
+ override val dependents = Seq(Dependency[B7])
}
class B6_0 extends B6Sub
@@ -275,7 +275,7 @@ object UnrelatedFixture {
class B6_15 extends B6Sub
class B8Dep extends B8 {
- override val dependents = Seq(classOf[B8])
+ override val dependents = Seq(Dependency[B8])
}
class B8_0 extends B8Dep
@@ -336,7 +336,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
behavior of this.getClass.getName
it should "do nothing if all targets are reached" in {
- val targets = Seq(classOf[A], classOf[B], classOf[C], classOf[D])
+ val targets = Seq(Dependency[A], Dependency[B], Dependency[C], Dependency[D])
val pm = new PhaseManager(targets, targets)
writeGraphviz(pm, "test_run_dir/PhaseManagerSpec/DoNothing")
@@ -345,7 +345,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
}
it should "handle a simple dependency" in {
- val targets = Seq(classOf[B])
+ val targets = Seq(Dependency[B])
val order = Seq(classOf[A], classOf[B])
val pm = new PhaseManager(targets)
@@ -355,7 +355,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
}
it should "handle a simple dependency with an invalidation" in {
- val targets = Seq(classOf[A], classOf[B], classOf[C], classOf[D])
+ val targets = Seq(Dependency[A], Dependency[B], Dependency[C], Dependency[D])
val order = Seq(classOf[A], classOf[D], classOf[A], classOf[B], classOf[C])
val pm = new PhaseManager(targets)
@@ -365,7 +365,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
}
it should "handle a dependency with two invalidates optimally" in {
- val targets = Seq(classOf[A], classOf[B], classOf[C], classOf[E], classOf[F], classOf[G])
+ val targets = Seq(Dependency[A], Dependency[B], Dependency[C], Dependency[E], Dependency[F], Dependency[G])
val pm = new PhaseManager(targets)
writeGraphviz(pm, "test_run_dir/PhaseManagerSpec/TwoInvalidates")
@@ -374,7 +374,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
}
it should "throw an exception for cyclic prerequisites" in {
- val targets = Seq(classOf[CyclicA], classOf[CyclicB])
+ val targets = Seq(Dependency[CyclicA], Dependency[CyclicB])
val pm = new PhaseManager(targets)
writeGraphviz(pm, "test_run_dir/PhaseManagerSpec/CyclicPrerequisites")
@@ -384,7 +384,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
}
it should "throw an exception for cyclic invalidates" in {
- val targets = Seq(classOf[CyclicC], classOf[CyclicD])
+ val targets = Seq(Dependency[CyclicC], Dependency[CyclicD])
val pm = new PhaseManager(targets)
writeGraphviz(pm, "test_run_dir/PhaseManagerSpec/CyclicInvalidates")
@@ -395,7 +395,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
it should "handle a complicated graph" in {
val f = ComplicatedFixture
- val targets = Seq(classOf[f.A], classOf[f.B], classOf[f.C], classOf[f.D], classOf[f.E])
+ val targets = Seq(Dependency[f.A], Dependency[f.B], Dependency[f.C], Dependency[f.D], Dependency[f.E])
val pm = new PhaseManager(targets)
writeGraphviz(pm, "test_run_dir/PhaseManagerSpec/Complicated")
@@ -406,7 +406,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
it should "handle repeated recomputed analyses" in {
val f = RepeatedAnalysisFixture
- val targets = Seq(classOf[f.A], classOf[f.B], classOf[f.C])
+ val targets = Seq(Dependency[f.A], Dependency[f.B], Dependency[f.C])
val order =
Seq( classOf[f.Analysis],
classOf[f.A],
@@ -423,7 +423,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
it should "handle inverted repeated recomputed analyses" in {
val f = InvertedAnalysisFixture
- val targets = Seq(classOf[f.A], classOf[f.B], classOf[f.C])
+ val targets = Seq(Dependency[f.A], Dependency[f.B], Dependency[f.C])
val order =
Seq( classOf[f.Analysis],
classOf[f.C],
@@ -443,12 +443,12 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
val f = DependentsFixture
info("without the custom transform it runs: First -> Second")
- val pm = new PhaseManager(Seq(classOf[f.Second]))
+ val pm = new PhaseManager(Seq(Dependency[f.Second]))
val orderNoCustom = Seq(classOf[f.First], classOf[f.Second])
pm.flattenedTransformOrder.map(_.getClass) should be (orderNoCustom)
info("with the custom transform it runs: First -> Custom -> Second")
- val pmCustom = new PhaseManager(Seq(classOf[f.Custom], classOf[f.Second]))
+ val pmCustom = new PhaseManager(Seq(Dependency[f.Custom], Dependency[f.Second]))
val orderCustom = Seq(classOf[f.First], classOf[f.Custom], classOf[f.Second])
writeGraphviz(pmCustom, "test_run_dir/PhaseManagerSpec/SingleDependent")
@@ -459,8 +459,8 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
it should "handle chained invalidation" in {
val f = ChainedInvalidationFixture
- val targets = Seq(classOf[f.A], classOf[f.E])
- val current = Seq(classOf[f.B], classOf[f.C], classOf[f.D])
+ val targets = Seq(Dependency[f.A], Dependency[f.E])
+ val current = Seq(Dependency[f.B], Dependency[f.C], Dependency[f.D])
val pm = new PhaseManager(targets, current)
val order = Seq( classOf[f.A], classOf[f.B], classOf[f.C], classOf[f.D], classOf[f.E] )
@@ -475,71 +475,72 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
/** A bunch of unrelated Phases. This ensures that these run in the order in which they are specified. */
val targets =
- Seq( classOf[f.B0],
- classOf[f.B1],
- classOf[f.B2],
- classOf[f.B3],
- classOf[f.B4],
- classOf[f.B5],
- classOf[f.B6],
- classOf[f.B7],
- classOf[f.B8],
- classOf[f.B9],
- classOf[f.B10],
- classOf[f.B11],
- classOf[f.B12],
- classOf[f.B13],
- classOf[f.B14],
- classOf[f.B15] )
+ Seq( Dependency[f.B0],
+ Dependency[f.B1],
+ Dependency[f.B2],
+ Dependency[f.B3],
+ Dependency[f.B4],
+ Dependency[f.B5],
+ Dependency[f.B6],
+ Dependency[f.B7],
+ Dependency[f.B8],
+ Dependency[f.B9],
+ Dependency[f.B10],
+ Dependency[f.B11],
+ Dependency[f.B12],
+ Dependency[f.B13],
+ Dependency[f.B14],
+ Dependency[f.B15] )
/** A sequence of custom transforms that should all run after B6 and before B7. This exercises correct ordering of the
* prerequisiteGraph and dependentsGraph.
*/
val prerequisiteTargets =
- Seq( classOf[f.B6_0],
- classOf[f.B6_1],
- classOf[f.B6_2],
- classOf[f.B6_3],
- classOf[f.B6_4],
- classOf[f.B6_5],
- classOf[f.B6_6],
- classOf[f.B6_7],
- classOf[f.B6_8],
- classOf[f.B6_9],
- classOf[f.B6_10],
- classOf[f.B6_11],
- classOf[f.B6_12],
- classOf[f.B6_13],
- classOf[f.B6_14],
- classOf[f.B6_15] )
+ Seq( Dependency[f.B6_0],
+ Dependency[f.B6_1],
+ Dependency[f.B6_2],
+ Dependency[f.B6_3],
+ Dependency[f.B6_4],
+ Dependency[f.B6_5],
+ Dependency[f.B6_6],
+ Dependency[f.B6_7],
+ Dependency[f.B6_8],
+ Dependency[f.B6_9],
+ Dependency[f.B6_10],
+ Dependency[f.B6_11],
+ Dependency[f.B6_12],
+ Dependency[f.B6_13],
+ Dependency[f.B6_14],
+ Dependency[f.B6_15] )
/** A sequence of transforms that are invalidated by B0 and only define dependents on B8. This exercises the ordering
* defined by "otherDependents".
*/
val current =
- Seq( classOf[f.B8_0],
- classOf[f.B8_1],
- classOf[f.B8_2],
- classOf[f.B8_3],
- classOf[f.B8_4],
- classOf[f.B8_5],
- classOf[f.B8_6],
- classOf[f.B8_7],
- classOf[f.B8_8],
- classOf[f.B8_9],
- classOf[f.B8_10],
- classOf[f.B8_11],
- classOf[f.B8_12],
- classOf[f.B8_13],
- classOf[f.B8_14],
- classOf[f.B8_15] )
+ Seq( Dependency[f.B8_0],
+ Dependency[f.B8_1],
+ Dependency[f.B8_2],
+ Dependency[f.B8_3],
+ Dependency[f.B8_4],
+ Dependency[f.B8_5],
+ Dependency[f.B8_6],
+ Dependency[f.B8_7],
+ Dependency[f.B8_8],
+ Dependency[f.B8_9],
+ Dependency[f.B8_10],
+ Dependency[f.B8_11],
+ Dependency[f.B8_12],
+ Dependency[f.B8_13],
+ Dependency[f.B8_14],
+ Dependency[f.B8_15] )
/** The resulting order: B0--B6, B6_0--B6_B15, B7, B8_0--B8_15, B8--B15 */
- val expected = targets.slice(0, 7) ++ prerequisiteTargets ++ Some(targets(7)) ++ current ++ targets.drop(8)
+ val expectedDeps = targets.slice(0, 7) ++ prerequisiteTargets ++ Some(targets(7)) ++ current ++ targets.drop(8)
+ val expectedClasses = expectedDeps.map { case Dependency(Left(c)) => c }
val pm = new PhaseManager(targets ++ prerequisiteTargets ++ current, current.reverse)
writeGraphviz(pm, "test_run_dir/PhaseManagerSpec/DeterministicOrder")
- pm.flattenedTransformOrder.map(_.getClass) should be (expected)
+ pm.flattenedTransformOrder.map(_.getClass) should be (expectedClasses)
}
}