Skip to content

Commit e46a4a3

Browse files
mergify[bot]jackkoenigseldridge
authored
Fix ChiselStage and Builder handling of logging (backport #3895) (#3898)
* Fix ChiselStage and Builder handling of logging (#3895) Previously, object circt.stage.ChiselStage was ignoring the Logger. Also, Chisel was not creating its own logger scope which could lead to clobbering of the Console when running invoking Chisel in the same process multiple times. Fix various places we had to workaround this behavior and fix tests checking --log-level debug. (cherry picked from commit 88d147d) # Conflicts: # src/main/scala/circt/stage/ChiselStage.scala * Resolve backport conflicts * Make logger annotations unserializable Change logger annotations to mix-in the Unserializable trait so that they will not emitted by a stage. These annotations are not intended to be seen by CIRCT and these should be stripped from the output FIRRTL text. Signed-off-by: Schuyler Eldridge <[email protected]> --------- Signed-off-by: Schuyler Eldridge <[email protected]> Co-authored-by: Jack Koenig <[email protected]> Co-authored-by: Schuyler Eldridge <[email protected]>
1 parent 31c1034 commit e46a4a3

File tree

11 files changed

+196
-80
lines changed

11 files changed

+196
-80
lines changed

core/src/main/scala/chisel3/experimental/hierarchy/core/Definition.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ object Definition extends SourceInfoDoc {
107107
context.warningFilters,
108108
context.sourceRoots,
109109
Some(context.globalNamespace),
110-
Builder.allDefinitions
110+
Builder.allDefinitions,
111+
context.loggerOptions
111112
)
112113
}
113114
dynamicContext.inDefinition = true

core/src/main/scala/chisel3/internal/Builder.scala

+16-3
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,22 @@ import chisel3.properties.Class
1111
import chisel3.internal.firrtl.ir._
1212
import chisel3.internal.firrtl.Converter
1313
import chisel3.internal.naming._
14-
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
14+
import _root_.firrtl.annotations.{Annotation, CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
1515
import _root_.firrtl.annotations.AnnotationUtils.validComponentName
1616
import _root_.firrtl.AnnotationSeq
1717
import _root_.firrtl.renamemap.MutableRenameMap
1818
import _root_.firrtl.util.BackendCompilationUtilities._
1919
import _root_.firrtl.{ir => fir}
2020
import chisel3.experimental.dataview.{reify, reifySingleData}
2121
import chisel3.internal.Builder.Prefix
22-
import logger.LazyLogging
22+
import logger.{LazyLogging, LoggerOption}
2323

2424
import scala.collection.mutable
2525
import scala.annotation.tailrec
2626
import java.io.File
2727
import scala.util.control.NonFatal
2828
import chisel3.ChiselException
29+
import logger.LoggerOptions
2930

3031
private[chisel3] class Namespace(keywords: Set[String], separator: Char = '_') {
3132
// This HashMap is compressed, not every name in the namespace is present here.
@@ -452,7 +453,8 @@ private[chisel3] class DynamicContext(
452453
val sourceRoots: Seq[File],
453454
val defaultNamespace: Option[Namespace],
454455
// Definitions from other scopes in the same elaboration, use allDefinitions below
455-
val outerScopeDefinitions: List[Iterable[Definition[_]]]) {
456+
val outerScopeDefinitions: List[Iterable[Definition[_]]],
457+
val loggerOptions: LoggerOptions) {
456458
val importedDefinitionAnnos = annotationSeq.collect { case a: ImportDefinitionAnnotation[_] => a }
457459

458460
// Map from proto module name to ext-module name
@@ -1000,6 +1002,17 @@ private[chisel3] object Builder extends LazyLogging {
10001002
f: => T,
10011003
dynamicContext: DynamicContext,
10021004
forceModName: Boolean = true
1005+
): (Circuit, T) = {
1006+
// Logger has its own context separate from Chisel's dynamic context
1007+
_root_.logger.Logger.makeScope(dynamicContext.loggerOptions) {
1008+
buildImpl(f, dynamicContext, forceModName)
1009+
}
1010+
}
1011+
1012+
private def buildImpl[T <: BaseModule](
1013+
f: => T,
1014+
dynamicContext: DynamicContext,
1015+
forceModName: Boolean
10031016
): (Circuit, T) = {
10041017
dynamicContextVar.withValue(Some(dynamicContext)) {
10051018
ViewParent: Unit // Must initialize the singleton in a Builder context or weird things can happen

docs/src/cookbooks/cookbook.md

-3
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,6 @@ If the indexee is a non-power-of-2 size, use the ceiling of the log2 result.
832832

833833
```scala mdoc:invisible:reset
834834
import chisel3._
835-
// Some other test is clobbering the global Logger which breaks the warnings below
836-
// Setting the output stream to the Console fixes the issue
837-
logger.Logger.setConsole()
838835
// Helper to throw away return value so it doesn't show up in mdoc
839836
def compile(gen: => chisel3.RawModule): Unit = {
840837
circt.stage.ChiselStage.emitCHIRRTL(gen)

docs/src/explanations/warnings.md

-3
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,6 @@ The supported actions are:
6161
The following example issues a warning when elaborated normally
6262

6363
```scala mdoc:invisible:reset
64-
// Some other test is clobbering the global Logger which breaks the warnings below
65-
// Setting the output stream to the Console fixes the issue
66-
logger.Logger.setConsole()
6764
// Helper to throw away return value so it doesn't show up in mdoc
6865
def compile(gen: => chisel3.RawModule, args: Array[String] = Array()): Unit = {
6966
circt.stage.ChiselStage.emitCHIRRTL(gen, args = args)

firrtl/src/main/scala/logger/Logger.scala

+25-8
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,18 @@ object Logger {
121121
* @tparam A return type of the code block
122122
* @return the original return of the code block
123123
*/
124-
def makeScope[A](options: AnnotationSeq = Seq.empty)(codeBlock: => A): A = {
124+
def makeScope[A](options: AnnotationSeq = Seq.empty)(codeBlock: => A): A =
125+
makeScope(() => setOptions(options))(codeBlock)
126+
127+
/** Set a scope for this logger based on available annotations
128+
* @param options LoggerOptions to use
129+
* @param codeBlock some Scala code over which to define this scope
130+
* @tparam A return type of the code block
131+
* @return the original return of the code block
132+
*/
133+
def makeScope[A](options: LoggerOptions)(codeBlock: => A): A = makeScope(() => setOptions(options))(codeBlock)
134+
135+
private def makeScope[A](doSetOptions: () => Unit)(codeBlock: => A): A = {
125136
val runState: LoggerState = {
126137
val newRunState = updatableLoggerState.value.getOrElse(new LoggerState)
127138
if (newRunState.fromInvoke) {
@@ -133,7 +144,7 @@ object Logger {
133144
}
134145
}
135146
updatableLoggerState.withValue(Some(runState)) {
136-
setOptions(options)
147+
doSetOptions()
137148
codeBlock
138149
}
139150
}
@@ -326,20 +337,26 @@ object Logger {
326337
Seq(new AddDefaults, Checks)
327338
.foldLeft(inputAnnotations)((a, p) => p.transform(a))
328339

329-
val lopts = view[LoggerOptions](annotations)
330-
state.globalLevel = (state.globalLevel, lopts.globalLogLevel) match {
340+
setOptions(view[LoggerOptions](annotations))
341+
}
342+
343+
/** Set logger options
344+
* @param options options to set
345+
*/
346+
def setOptions(options: LoggerOptions): Unit = {
347+
state.globalLevel = (state.globalLevel, options.globalLogLevel) match {
331348
case (LogLevel.None, LogLevel.None) => LogLevel.None
332349
case (x, LogLevel.None) => x
333350
case (LogLevel.None, x) => x
334351
case (_, x) => x
335352
}
336-
setClassLogLevels(lopts.classLogLevels)
353+
setClassLogLevels(options.classLogLevels)
337354

338-
if (lopts.logFileName.nonEmpty) {
339-
setOutput(lopts.logFileName.get)
355+
if (options.logFileName.nonEmpty) {
356+
setOutput(options.logFileName.get)
340357
}
341358

342-
state.logClassNames = lopts.logClassNames
359+
state.logClassNames = options.logClassNames
343360
}
344361
}
345362

firrtl/src/main/scala/logger/LoggerAnnotations.scala

+9-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
package logger
44

55
import firrtl.annotations.{Annotation, NoTargetAnnotation}
6-
import firrtl.options.{HasShellOptions, ShellOption}
6+
import firrtl.options.{HasShellOptions, ShellOption, Unserializable}
77

88
/** An annotation associated with a Logger command line option */
99
sealed trait LoggerOption { this: Annotation => }
@@ -16,6 +16,7 @@ sealed trait LoggerOption { this: Annotation => }
1616
case class LogLevelAnnotation(globalLogLevel: LogLevel.Value = LogLevel.None)
1717
extends NoTargetAnnotation
1818
with LoggerOption
19+
with Unserializable
1920

2021
object LogLevelAnnotation extends HasShellOptions {
2122

@@ -39,6 +40,7 @@ object LogLevelAnnotation extends HasShellOptions {
3940
case class ClassLogLevelAnnotation(className: String, level: LogLevel.Value)
4041
extends NoTargetAnnotation
4142
with LoggerOption
43+
with Unserializable
4244

4345
object ClassLogLevelAnnotation extends HasShellOptions {
4446

@@ -63,7 +65,7 @@ object ClassLogLevelAnnotation extends HasShellOptions {
6365
* - maps to [[LoggerOptions.logFileName]]
6466
* - enabled with `--log-file`
6567
*/
66-
case class LogFileAnnotation(file: Option[String]) extends NoTargetAnnotation with LoggerOption
68+
case class LogFileAnnotation(file: Option[String]) extends NoTargetAnnotation with LoggerOption with Unserializable
6769

6870
object LogFileAnnotation extends HasShellOptions {
6971

@@ -81,7 +83,11 @@ object LogFileAnnotation extends HasShellOptions {
8183
/** Enables class names in log output
8284
* - enabled with `-lcn/--log-class-names`
8385
*/
84-
case object LogClassNamesAnnotation extends NoTargetAnnotation with LoggerOption with HasShellOptions {
86+
case object LogClassNamesAnnotation
87+
extends NoTargetAnnotation
88+
with LoggerOption
89+
with HasShellOptions
90+
with Unserializable {
8591

8692
val options = Seq(
8793
new ShellOption[Unit](

src/main/scala/chisel3/aop/injecting/InjectingAspect.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import firrtl.options.Viewer.view
1212
import firrtl.{ir, _}
1313

1414
import scala.collection.mutable
15+
import logger.LoggerOptions
1516

1617
/** Aspect to inject Chisel code into a module of type M
1718
*
@@ -57,14 +58,16 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule](
5758
final def toAnnotation(modules: Iterable[M], circuit: String, moduleNames: Seq[String]): AnnotationSeq = {
5859
modules.map { module =>
5960
val chiselOptions = view[ChiselOptions](annotationsInAspect)
61+
val loggerOptions = view[LoggerOptions](annotationsInAspect)
6062
val dynamicContext =
6163
new DynamicContext(
6264
annotationsInAspect,
6365
chiselOptions.throwOnFirstError,
6466
chiselOptions.warningFilters,
6567
chiselOptions.sourceRoots,
6668
None,
67-
Nil // FIXME this maybe should somehow grab definitions from earlier elaboration
69+
Nil, // FIXME this maybe should somehow grab definitions from earlier elaboration
70+
loggerOptions
6871
)
6972
// Add existing module names into the namespace. If injection logic instantiates new modules
7073
// which would share the same name, they will get uniquified accordingly

src/main/scala/chisel3/stage/phases/Elaborate.scala

+9-3
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,26 @@ import chisel3.stage.{
1313
ThrowOnFirstErrorAnnotation
1414
}
1515
import firrtl.AnnotationSeq
16-
import firrtl.options.Phase
16+
import firrtl.options.{Dependency, Phase}
1717
import firrtl.options.Viewer.view
18+
import logger.LoggerOptions
1819

1920
/** Elaborate all [[chisel3.stage.ChiselGeneratorAnnotation]]s into [[chisel3.stage.ChiselCircuitAnnotation]]s.
2021
*/
2122
class Elaborate extends Phase {
2223

23-
override def prerequisites = Seq.empty
24+
override def prerequisites: Seq[Dependency[Phase]] = Seq(
25+
Dependency[chisel3.stage.phases.Checks],
26+
Dependency(_root_.logger.phases.Checks)
27+
)
2428
override def optionalPrerequisites = Seq.empty
2529
override def optionalPrerequisiteOf = Seq.empty
2630
override def invalidates(a: Phase) = false
2731

2832
def transform(annotations: AnnotationSeq): AnnotationSeq = annotations.flatMap {
2933
case ChiselGeneratorAnnotation(gen) =>
3034
val chiselOptions = view[ChiselOptions](annotations)
35+
val loggerOptions = view[LoggerOptions](annotations)
3136
try {
3237
val context =
3338
new DynamicContext(
@@ -36,7 +41,8 @@ class Elaborate extends Phase {
3641
chiselOptions.warningFilters,
3742
chiselOptions.sourceRoots,
3843
None,
39-
Nil
44+
Nil,
45+
loggerOptions
4046
)
4147
val (circuit, dut) =
4248
Builder.build(Module(gen()), context)

src/main/scala/circt/stage/ChiselStage.scala

+12-48
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,13 @@
33
package circt.stage
44

55
import chisel3.RawModule
6-
import chisel3.stage.{
7-
ChiselCircuitAnnotation,
8-
ChiselGeneratorAnnotation,
9-
CircuitSerializationAnnotation,
10-
PrintFullStackTraceAnnotation,
11-
SourceRootAnnotation,
12-
ThrowOnFirstErrorAnnotation,
13-
WarningConfigurationAnnotation,
14-
WarningConfigurationFileAnnotation,
15-
WarningsAsErrorsAnnotation
16-
}
6+
import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, CircuitSerializationAnnotation}
177
import chisel3.stage.CircuitSerializationAnnotation.FirrtlFileFormat
188
import firrtl.{AnnotationSeq, EmittedVerilogCircuitAnnotation}
19-
import firrtl.options.{
20-
BareShell,
21-
CustomFileEmission,
22-
Dependency,
23-
Phase,
24-
PhaseManager,
25-
Shell,
26-
Stage,
27-
StageMain,
28-
Unserializable
29-
}
9+
import firrtl.options.{CustomFileEmission, Dependency, Phase, PhaseManager, Stage, StageMain, Unserializable}
3010
import firrtl.stage.FirrtlCircuitAnnotation
3111

32-
trait CLI { this: BareShell =>
33-
parser.note("CIRCT (MLIR FIRRTL Compiler) options")
34-
Seq(
35-
CIRCTTargetAnnotation,
36-
PreserveAggregate,
37-
ChiselGeneratorAnnotation,
38-
PrintFullStackTraceAnnotation,
39-
ThrowOnFirstErrorAnnotation,
40-
WarningsAsErrorsAnnotation,
41-
WarningConfigurationAnnotation,
42-
WarningConfigurationFileAnnotation,
43-
SourceRootAnnotation,
44-
SplitVerilog,
45-
FirtoolBinaryPath,
46-
DumpFir
47-
).foreach(_.addOptions(parser))
48-
}
12+
import logger.LogLevelAnnotation
4913

5014
/** Entry point for running Chisel with the CIRCT compiler.
5115
*
@@ -58,13 +22,15 @@ class ChiselStage extends Stage {
5822
override def optionalPrerequisiteOf = Seq.empty
5923
override def invalidates(a: Phase) = false
6024

61-
override val shell = new Shell("circt") with CLI
25+
override val shell = new firrtl.options.Shell("circt") with CLI {
26+
// These are added by firrtl.options.Shell (which we must extend because we are a Stage)
27+
override protected def includeLoggerOptions = false
28+
}
6229

6330
override def run(annotations: AnnotationSeq): AnnotationSeq = {
6431

6532
val pm = new PhaseManager(
6633
targets = Seq(
67-
Dependency[chisel3.stage.phases.Checks],
6834
Dependency[chisel3.stage.phases.AddImplicitOutputFile],
6935
Dependency[chisel3.stage.phases.AddImplicitOutputAnnotationFile],
7036
Dependency[chisel3.stage.phases.MaybeAspectPhase],
@@ -73,7 +39,6 @@ class ChiselStage extends Stage {
7339
Dependency[chisel3.stage.phases.AddDedupGroupAnnotations],
7440
Dependency[chisel3.stage.phases.MaybeInjectingPhase],
7541
Dependency[circt.stage.phases.AddImplicitOutputFile],
76-
Dependency[circt.stage.phases.Checks],
7742
Dependency[circt.stage.phases.CIRCT]
7843
),
7944
currentState = Seq(
@@ -92,7 +57,6 @@ object ChiselStage {
9257
/** A phase shared by all the CIRCT backends */
9358
private def phase = new PhaseManager(
9459
Seq(
95-
Dependency[chisel3.stage.phases.Checks],
9660
Dependency[chisel3.aop.injecting.InjectingPhase],
9761
Dependency[chisel3.stage.phases.Elaborate],
9862
Dependency[chisel3.stage.phases.Convert],
@@ -111,7 +75,7 @@ object ChiselStage {
11175
val annos = Seq(
11276
ChiselGeneratorAnnotation(() => gen),
11377
CIRCTTargetAnnotation(CIRCTTarget.CHIRRTL)
114-
) ++ (new BareShell("circt") with CLI).parse(args)
78+
) ++ (new Shell("circt")).parse(args)
11579

11680
val resultAnnos = phase.transform(annos)
11781

@@ -138,7 +102,7 @@ object ChiselStage {
138102
val annos = Seq(
139103
ChiselGeneratorAnnotation(() => gen),
140104
CIRCTTargetAnnotation(CIRCTTarget.CHIRRTL)
141-
) ++ (new BareShell("circt") with CLI).parse(args)
105+
) ++ (new Shell("circt")).parse(args)
142106

143107
phase
144108
.transform(annos)
@@ -157,7 +121,7 @@ object ChiselStage {
157121
val annos = Seq(
158122
ChiselGeneratorAnnotation(() => gen),
159123
CIRCTTargetAnnotation(CIRCTTarget.FIRRTL)
160-
) ++ (new BareShell("circt") with CLI).parse(args) ++ firtoolOpts.map(FirtoolOption(_))
124+
) ++ (new Shell("circt")).parse(args) ++ firtoolOpts.map(FirtoolOption(_))
161125

162126
phase
163127
.transform(annos)
@@ -176,7 +140,7 @@ object ChiselStage {
176140
val annos = Seq(
177141
ChiselGeneratorAnnotation(() => gen),
178142
CIRCTTargetAnnotation(CIRCTTarget.HW)
179-
) ++ (new BareShell("circt") with CLI).parse(args) ++ firtoolOpts.map(FirtoolOption(_))
143+
) ++ (new Shell("circt")).parse(args) ++ firtoolOpts.map(FirtoolOption(_))
180144

181145
phase
182146
.transform(annos)
@@ -201,7 +165,7 @@ object ChiselStage {
201165
val annos = Seq(
202166
ChiselGeneratorAnnotation(() => gen),
203167
CIRCTTargetAnnotation(CIRCTTarget.SystemVerilog)
204-
) ++ (new BareShell("circt") with CLI).parse(args) ++ firtoolOpts.map(FirtoolOption(_))
168+
) ++ (new Shell("circt")).parse(args) ++ firtoolOpts.map(FirtoolOption(_))
205169
phase
206170
.transform(annos)
207171
.collectFirst {

0 commit comments

Comments
 (0)