aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorAlbert Magyar2019-12-18 16:21:06 -0500
committerSchuyler Eldridge2020-02-19 19:47:17 -0500
commit68d9fc84ce510c4ff5eb1907419925d4ea548e04 (patch)
tree1c0703f49f09200661820d13d981b34ce548b6aa /src/main
parent235ec6cbdce6866c8fcd49c0000a7abeeaa4ef80 (diff)
Support Singleton Dependencies (#1275)
This makes a change to the Dependency API that breaks chisel3. This needs to [skip chisel tests], but is fixed with https://github.com/freechipsproject/chisel3/pull/1270. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Diffstat (limited to 'src/main')
-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
8 files changed, 175 insertions, 96 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 = {