1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
// 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)))
}
|