diff options
| author | Kevin Laeufer | 2020-08-11 11:51:05 -0700 |
|---|---|---|
| committer | GitHub | 2020-08-11 18:51:05 +0000 |
| commit | f7cffd230ede9a483f183182fa8e1bea3c4cdd67 (patch) | |
| tree | 42f5229632a944182543a4f20c6beb933f6f7e80 | |
| parent | 21ccf68fc0f0a3ff5a990ac9215a20f20807f4ed (diff) | |
stage: allow a RunFirrtlTransformAnnotation(_:Emitter) annotation to be used in place of a CompilerAnnotation (#1835)
9 files changed, 53 insertions, 32 deletions
diff --git a/src/main/scala/firrtl/stage/FirrtlAnnotations.scala b/src/main/scala/firrtl/stage/FirrtlAnnotations.scala index 1604e92e..91c5609b 100644 --- a/src/main/scala/firrtl/stage/FirrtlAnnotations.scala +++ b/src/main/scala/firrtl/stage/FirrtlAnnotations.scala @@ -6,11 +6,11 @@ import firrtl._ import firrtl.ir.Circuit import firrtl.annotations.{Annotation, NoTargetAnnotation} import firrtl.options.{HasShellOptions, OptionsException, ShellOption, Unserializable} - - import java.io.FileNotFoundException import java.nio.file.NoSuchFileException +import firrtl.stage.TransformManager.TransformDependency + /** Indicates that this is an [[firrtl.annotations.Annotation Annotation]] directly used in the construction of a * [[FirrtlOptions]] view. */ @@ -177,6 +177,9 @@ case class RunFirrtlTransformAnnotation(transform: Transform) extends NoTargetAn object RunFirrtlTransformAnnotation extends HasShellOptions { + def apply(transform: TransformDependency): RunFirrtlTransformAnnotation = + RunFirrtlTransformAnnotation(transform.getObject) + val options = Seq( new ShellOption[Seq[String]]( longOption = "custom-transforms", diff --git a/src/main/scala/firrtl/stage/FirrtlOptions.scala b/src/main/scala/firrtl/stage/FirrtlOptions.scala index 8028e6f2..61dec7c5 100644 --- a/src/main/scala/firrtl/stage/FirrtlOptions.scala +++ b/src/main/scala/firrtl/stage/FirrtlOptions.scala @@ -2,30 +2,25 @@ package firrtl.stage -import firrtl.Compiler import firrtl.ir.Circuit /** Internal options used to control the FIRRTL compiler stage. * @param outputFileName output file, default: `targetDir/topName.SUFFIX` with `SUFFIX` as determined by the compiler - * @param compiler which compiler to use (default: [[VerilogCompiler]]) * @param infoModeName the policy for generating [[firrtl.ir Info]] when processing FIRRTL (default: "append") * @param firrtlCircuit a [[firrtl.ir Circuit]] */ class FirrtlOptions private [stage] ( val outputFileName: Option[String] = None, - val compiler: Compiler = CompilerAnnotation().compiler, val infoModeName: String = InfoModeAnnotation().modeName, val firrtlCircuit: Option[Circuit] = None) { private [stage] def copy( outputFileName: Option[String] = outputFileName, - compiler: Compiler = compiler, infoModeName: String = infoModeName, firrtlCircuit: Option[Circuit] = firrtlCircuit ): FirrtlOptions = { new FirrtlOptions( outputFileName = outputFileName, - compiler = compiler, infoModeName = infoModeName, firrtlCircuit = firrtlCircuit ) } diff --git a/src/main/scala/firrtl/stage/package.scala b/src/main/scala/firrtl/stage/package.scala index d0a481fb..5bb7378d 100644 --- a/src/main/scala/firrtl/stage/package.scala +++ b/src/main/scala/firrtl/stage/package.scala @@ -3,8 +3,9 @@ package firrtl import firrtl.annotations.DeletedAnnotation -import firrtl.options.{OptionsView, Viewer} +import firrtl.options.OptionsView import firrtl.stage.phases.WriteEmitted +import logger.LazyLogging /** The [[stage]] package provides an implementation of the FIRRTL compiler using the [[firrtl.options]] package. This * primarily consists of: @@ -19,7 +20,7 @@ import firrtl.stage.phases.WriteEmitted * - [[FirrtlStageUtils]] containing miscellaneous utilities for [[stage]] */ package object stage { - implicit object FirrtlOptionsView extends OptionsView[FirrtlOptions] { + implicit object FirrtlOptionsView extends OptionsView[FirrtlOptions] with LazyLogging { /** * @todo custom transforms are appended as discovered, can this be prepended safely? @@ -30,30 +31,38 @@ package object stage { x match { case OutputFileAnnotation(f) => c.copy(outputFileName = Some(f)) case InfoModeAnnotation(i) => c.copy(infoModeName = i) - case CompilerAnnotation(cx) => c.copy(compiler = cx) case FirrtlCircuitAnnotation(cir) => c.copy(firrtlCircuit = Some(cir)) + case a : CompilerAnnotation => logger.warn(s"Use of CompilerAnnotation is deprecated. Ignoring $a") ; c } } } - private [firrtl] implicit object FirrtlExecutionResultView extends OptionsView[FirrtlExecutionResult] { + private [firrtl] implicit object FirrtlExecutionResultView extends OptionsView[FirrtlExecutionResult] with LazyLogging { private lazy val dummyWriteEmitted = new WriteEmitted def view(options: AnnotationSeq): FirrtlExecutionResult = { - val fopts = Viewer[FirrtlOptions].view(options) val emittedRes = options .collect{ case DeletedAnnotation(dummyWriteEmitted.name, a: EmittedAnnotation[_]) => a.value.value } .mkString("\n") + val emitters = options.collect{ case RunFirrtlTransformAnnotation(e: Emitter) => e } + if(emitters.length > 1) { + logger.warn("More than one emitter used which cannot be accurately represented" + + "in the deprecated FirrtlExecutionResult: " + emitters.map(_.name).mkString(", ")) + } + val compilers = options.collect{ case CompilerAnnotation(c) => c } + val emitType = emitters.headOption.orElse(compilers.headOption).map(_.name).getOrElse("N/A") + val form = emitters.headOption.orElse(compilers.headOption).map(_.outputForm).getOrElse(UnknownForm) + options.collectFirst{ case a: FirrtlCircuitAnnotation => a.circuit } match { case None => FirrtlExecutionFailure("No circuit found in AnnotationSeq!") case Some(a) => FirrtlExecutionSuccess( - emitType = fopts.compiler.getClass.getName, + emitType = emitType, emitted = emittedRes, circuitState = CircuitState( circuit = a, - form = fopts.compiler.outputForm, + form = form, annotations = options, renames = None )) diff --git a/src/main/scala/firrtl/stage/phases/AddDefaults.scala b/src/main/scala/firrtl/stage/phases/AddDefaults.scala index 1fb8913c..d4c5bab4 100644 --- a/src/main/scala/firrtl/stage/phases/AddDefaults.scala +++ b/src/main/scala/firrtl/stage/phases/AddDefaults.scala @@ -2,10 +2,11 @@ package firrtl.stage.phases -import firrtl.AnnotationSeq -import firrtl.options.{Phase, TargetDirAnnotation} +import firrtl.{AnnotationSeq, VerilogEmitter} +import firrtl.options.{Dependency, Phase, TargetDirAnnotation} +import firrtl.stage.TransformManager.TransformDependency import firrtl.transforms.BlackBoxTargetDirAnno -import firrtl.stage.{CompilerAnnotation, InfoModeAnnotation, FirrtlOptions} +import firrtl.stage.{CompilerAnnotation, FirrtlOptions, InfoModeAnnotation, RunFirrtlTransformAnnotation} /** [[firrtl.options.Phase Phase]] that adds default [[FirrtlOption]] [[firrtl.annotations.Annotation Annotation]]s. * This is a part of the preprocessing done by [[FirrtlStage]]. @@ -18,14 +19,17 @@ class AddDefaults extends Phase { override def invalidates(a: Phase) = false + val DefaultEmitterTarget: TransformDependency = Dependency[VerilogEmitter] + /** Append any missing default annotations to an annotation sequence */ def transform(annotations: AnnotationSeq): AnnotationSeq = { - var bb, c, im = true + var bb, c, em, im = true annotations.foreach { case _: BlackBoxTargetDirAnno => bb = false case _: CompilerAnnotation => c = false case _: InfoModeAnnotation => im = false - case a => + case RunFirrtlTransformAnnotation(_ : firrtl.Emitter) => em = false + case _ => } val default = new FirrtlOptions() @@ -34,7 +38,8 @@ class AddDefaults extends Phase { .getOrElse(TargetDirAnnotation()).directory (if (bb) Seq(BlackBoxTargetDirAnno(targetDir)) else Seq() ) ++ - (if (c) Seq(CompilerAnnotation(default.compiler)) else Seq() ) ++ + // if there is no compiler or emitter specified, add the default emitter + (if (c && em) Seq(RunFirrtlTransformAnnotation(DefaultEmitterTarget)) else Seq() ) ++ (if (im) Seq(InfoModeAnnotation()) else Seq() ) ++ annotations } diff --git a/src/main/scala/firrtl/stage/phases/AddImplicitEmitter.scala b/src/main/scala/firrtl/stage/phases/AddImplicitEmitter.scala index 4f658aa2..edf62c3a 100644 --- a/src/main/scala/firrtl/stage/phases/AddImplicitEmitter.scala +++ b/src/main/scala/firrtl/stage/phases/AddImplicitEmitter.scala @@ -2,7 +2,7 @@ package firrtl.stage.phases -import firrtl.{AnnotationSeq, EmitAnnotation, EmitCircuitAnnotation} +import firrtl.{AnnotationSeq, EmitAnnotation, EmitCircuitAnnotation, Emitter} import firrtl.stage.{CompilerAnnotation, RunFirrtlTransformAnnotation} import firrtl.options.{Dependency, Phase} @@ -18,14 +18,16 @@ class AddImplicitEmitter extends Phase { override def invalidates(a: Phase) = false def transform(annos: AnnotationSeq): AnnotationSeq = { - val emitter = annos.collectFirst{ case a: EmitAnnotation => a } + val emit = annos.collectFirst{ case a: EmitAnnotation => a } + val emitter = annos.collectFirst{ case RunFirrtlTransformAnnotation(e : Emitter) => e } val compiler = annos.collectFirst{ case CompilerAnnotation(a) => a } - if (emitter.isEmpty && compiler.nonEmpty) { + if (emit.isEmpty && (compiler.nonEmpty || emitter.nonEmpty)) { annos.flatMap{ case a: CompilerAnnotation => Seq(a, RunFirrtlTransformAnnotation(compiler.get.emitter), EmitCircuitAnnotation(compiler.get.emitter.getClass)) + case a @ RunFirrtlTransformAnnotation(e : Emitter) => Seq(a, EmitCircuitAnnotation(e.getClass)) case a => Some(a) } } else { diff --git a/src/main/scala/firrtl/stage/phases/Checks.scala b/src/main/scala/firrtl/stage/phases/Checks.scala index 1d16c7db..7ecdc47e 100644 --- a/src/main/scala/firrtl/stage/phases/Checks.scala +++ b/src/main/scala/firrtl/stage/phases/Checks.scala @@ -31,7 +31,7 @@ class Checks extends Phase { * @throws firrtl.options.OptionsException if any checks fail */ def transform(annos: AnnotationSeq): AnnotationSeq = { - val inF, inS, eam, ec, outF, comp, im, inC = collection.mutable.ListBuffer[Annotation]() + val inF, inS, eam, ec, outF, comp, emitter, im, inC = collection.mutable.ListBuffer[Annotation]() annos.foreach( _ match { case a: FirrtlFileAnnotation => a +=: inF @@ -42,6 +42,7 @@ class Checks extends Phase { case a: CompilerAnnotation => a +=: comp case a: InfoModeAnnotation => a +=: im case a: FirrtlCircuitAnnotation => a +=: inC + case a @ RunFirrtlTransformAnnotation(_ : firrtl.Emitter) => a +=: emitter case _ => }) /* At this point, only a FIRRTL Circuit should exist */ @@ -75,8 +76,8 @@ class Checks extends Phase { s"""|No more than one output file can be specified, but found '${x.mkString(", ")}' specified via: | - option or annotation: -o, --output-file, OutputFileAnnotation""".stripMargin) } - /* One mandatory compiler must be specified */ - if (comp.size != 1) { + /* One mandatory compiler (or emitter) must be specified */ + if (comp.size != 1 && emitter.isEmpty) { val x = comp.map{ case CompilerAnnotation(x) => x } val (msg, suggest) = if (comp.size == 0) { ("none found", "forget one of") } else { (s"""found '${x.mkString(", ")}'""", "use multiple of") } diff --git a/src/main/scala/firrtl/stage/phases/Compiler.scala b/src/main/scala/firrtl/stage/phases/Compiler.scala index e3a96b0e..b3e902c8 100644 --- a/src/main/scala/firrtl/stage/phases/Compiler.scala +++ b/src/main/scala/firrtl/stage/phases/Compiler.scala @@ -98,7 +98,14 @@ class Compiler extends Phase with Translator[AnnotationSeq, Seq[CompilerRun]] { def f(c: CompilerRun): CompilerRun = { val targets = c.compiler match { case Some(d) => c.transforms.reverse.map(Dependency.fromTransform(_)) ++ compilerToTransforms(d) - case None => throw new PhasePrerequisiteException("No compiler specified!") } + case None => + val hasEmitter = c.transforms.collectFirst { case _: firrtl.Emitter => true }.isDefined + if(!hasEmitter) { + throw new PhasePrerequisiteException("No compiler specified!") + } else { + c.transforms.reverse.map(Dependency.fromTransform) + } + } val tm = new firrtl.stage.transforms.Compiler(targets) /* Transform order is lazily evaluated. Force it here to remove its resolution time from actual compilation. */ val (timeResolveDependencies, _) = firrtl.Utils.time { tm.flattenedTransformOrder } diff --git a/src/test/scala/firrtlTests/stage/FirrtlOptionsViewSpec.scala b/src/test/scala/firrtlTests/stage/FirrtlOptionsViewSpec.scala index 95c2ee93..4161d29b 100644 --- a/src/test/scala/firrtlTests/stage/FirrtlOptionsViewSpec.scala +++ b/src/test/scala/firrtlTests/stage/FirrtlOptionsViewSpec.scala @@ -38,7 +38,6 @@ class FirrtlOptionsViewSpec extends AnyFlatSpec with Matchers { val out = view[FirrtlOptions](annotations) out.outputFileName should be (Some("bar")) - out.compiler.getClass should be (classOf[BazCompiler]) out.infoModeName should be ("use") out.firrtlCircuit should be (Some(grault)) } @@ -59,7 +58,6 @@ class FirrtlOptionsViewSpec extends AnyFlatSpec with Matchers { val out = view[FirrtlOptions](annotations ++ overwrites) out.outputFileName should be (Some("bar_")) - out.compiler.getClass should be (classOf[Baz_Compiler]) out.infoModeName should be ("gen") out.firrtlCircuit should be (Some(grault_)) } diff --git a/src/test/scala/firrtlTests/stage/phases/AddDefaultsSpec.scala b/src/test/scala/firrtlTests/stage/phases/AddDefaultsSpec.scala index 89f5193c..b600e6c5 100644 --- a/src/test/scala/firrtlTests/stage/phases/AddDefaultsSpec.scala +++ b/src/test/scala/firrtlTests/stage/phases/AddDefaultsSpec.scala @@ -7,8 +7,8 @@ import firrtl.NoneCompiler import firrtl.annotations.Annotation import firrtl.stage.phases.AddDefaults import firrtl.transforms.BlackBoxTargetDirAnno -import firrtl.stage.{CompilerAnnotation, InfoModeAnnotation} -import firrtl.options.{Phase, TargetDirAnnotation} +import firrtl.stage.{CompilerAnnotation, InfoModeAnnotation, RunFirrtlTransformAnnotation} +import firrtl.options.{Dependency, Phase, TargetDirAnnotation} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -21,7 +21,8 @@ class AddDefaultsSpec extends AnyFlatSpec with Matchers { it should "add expected default annotations and nothing else" in new Fixture { val expected = Seq( (a: Annotation) => a match { case BlackBoxTargetDirAnno(b) => b == TargetDirAnnotation().directory }, - (a: Annotation) => a match { case CompilerAnnotation(b) => b.getClass == CompilerAnnotation().compiler.getClass }, + (a: Annotation) => a match { case RunFirrtlTransformAnnotation(e: firrtl.Emitter) => + Dependency.fromTransform(e) == Dependency[firrtl.VerilogEmitter] }, (a: Annotation) => a match { case InfoModeAnnotation(b) => b == InfoModeAnnotation().modeName } ) phase.transform(Seq.empty).zip(expected).map { case (x, f) => f(x) should be (true) } |
