// SPDX-License-Identifier: Apache-2.0 package firrtl.options import firrtl.AnnotationSeq 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 */ trait TransformLike[A] extends LazyLogging { /** An identifier of this [[TransformLike]] that can be used for logging and informational printing */ def name: String /** A mathematical transform on some type * @param a an input object * @return an output object of the same type */ def transform(a: A): A } /** Mix-in that makes a [[firrtl.options.TransformLike TransformLike]] guaranteed to be an identity function on some * type. * @tparam A the transformed type */ trait IdentityLike[A] { this: TransformLike[A] => /** The internal operation of this transform which, in order for this to be an identity function, must return nothing. * @param a an input object * @return nothing */ protected def internalTransform(a: A): Unit = () /** This method will execute `internalTransform` and then return the original input object * @param a an input object * @return the input object */ final override def transform(a: A): A = { internalTransform(a) a } } /** Mixin that defines dependencies between [[firrtl.options.TransformLike TransformLike]]s (hereafter referred to as * "transforms") * * This trait forms the basis of the Dependency API of the Chisel/FIRRTL Hardware Compiler Framework. Dependencies are * 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. * @tparam A some transform * @define seqNote @note The use of a Seq here is to preserve input order. Internally, this will be converted to a private, * ordered Set. */ trait DependencyAPI[A <: DependencyAPI[A]] { this: TransformLike[_] => /** All transform that must run before this transform * $seqNote */ def prerequisites: Seq[Dependency[A]] = Seq.empty private[options] lazy val _prerequisites: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ prerequisites /** All transforms that, if a prerequisite of *another* transform, will run before this transform. * $seqNote */ def optionalPrerequisites: Seq[Dependency[A]] = Seq.empty private[options] lazy val _optionalPrerequisites: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ optionalPrerequisites /** All transforms that must run ''after'' this transform * * ''This is a means of prerequisite injection into some other transform.'' Normally a transform will define its own * prerequisites. Dependents exist for two main situations: * * First, they improve the composition of optional transforms. If some first transform is optional (e.g., an * expensive validation check), you would like to be able to conditionally cause it to run. If it is listed as a * prerequisite on some other, second transform then it must always run before that second transform. There's no way * to turn it off. However, by listing the second transform as a dependent of the first transform, the first * transform will only run (and be treated as a prerequisite of the second transform) if included in a list of target * transforms that should be run. * * Second, an external library would like to inject some first transform before a second transform inside FIRRTL. In * this situation, the second transform cannot have any knowledge of external libraries. The use of a dependent here * allows for prerequisite injection into FIRRTL proper. * * @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 /** 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 /** A function that, given *another* transform (parameter `a`) will return true if this transform invalidates/undos the * effects of the *other* transform (parameter `a`). * @param a transform */ def invalidates(a: A): Boolean = true } /** A trait indicating that no invalidations occur, i.e., all previous transforms are preserved * @tparam A some [[TransformLike]] */ @deprecated( "Use an explicit `override def invalidates` returning false. This will be removed in FIRRTL 1.5.", "FIRRTL 1.4" ) trait PreservesAll[A <: DependencyAPI[A]] { this: DependencyAPI[A] => override final def invalidates(a: A): Boolean = false } /** A mathematical transformation of an [[AnnotationSeq]]. * * A [[firrtl.options.Phase Phase]] forms one unit in the Chisel/FIRRTL Hardware Compiler Framework (HCF). The HCF is * built from a sequence of [[firrtl.options.Phase Phase]]s applied to an [[AnnotationSeq]]. Note that a * [[firrtl.options.Phase Phase]] may consist of multiple phases internally. */ trait Phase extends TransformLike[AnnotationSeq] with DependencyAPI[Phase] { /** The name of this [[firrtl.options.Phase Phase]]. This will be used to generate debug/error messages or when deleting * annotations. This will default to the `simpleName` of the class. * @return this phase's name * @note Override this with your own implementation for different naming behavior. */ lazy val name: String = this.getClass.getName } /** A [[firrtl.options.TransformLike TransformLike]] that internally ''translates'' the input type to some other type, * transforms the internal type, and converts back to the original type. * * This is intended to be used to insert a [[firrtl.options.TransformLike TransformLike]] parameterized by type `B` * into a sequence of [[firrtl.options.TransformLike TransformLike]]s parameterized by type `A`. * @tparam A the type of the [[firrtl.options.TransformLike TransformLike]] * @tparam B the internal type */ trait Translator[A, B] extends TransformLike[A] { /** A method converting type `A` into type `B` * @param an object of type `A` * @return an object of type `B` */ protected implicit def aToB(a: A): B /** A method converting type `B` back into type `A` * @param an object of type `B` * @return an object of type `A` */ protected implicit def bToA(b: B): A /** A transform on an internal type * @param b an object of type `B` * @return an object of type `B` */ protected def internalTransform(b: B): B /** Convert the input object to the internal type, transform the internal type, and convert back to the original type */ override final def transform(a: A): A = bToA(internalTransform(aToB(a))) }