[firtool] Error while preserving aggregates (op using value defined outside the region)
When compiling a Rocket-Chip-based Chisel design (Chipyard's RocketConfig) with any form of aggregate preservation turned on, I get a large number of errors like this, I believe during the LowerLayers pass:
generators/rocket-chip/src/main/scala/tilelink/Parameters.scala:1138:31: error: 'firrtl.subindex' op using value defined outside the region
generators/rocket-chip/src/main/scala/tilelink/Parameters.scala:1138:31: note: see current operation: %656 = "firrtl.subindex"(<<UNKNOWN SSA VALUE>>) <{index = 1 : i32}> : (!firrtl.vector<uint<1>, 5>) -> !firrtl.uint<1>
generators/rocket-chip/src/main/scala/tilelink/Monitor.scala:45:11: note: required by region isolation constraints
I use a private fork of Chipyard that is updated to a more recent snapshot of Chisel (upstream Chipyard only works with Chisel 6.x and firtool 1.75), so I'm uploading the .fir file that triggered these errors. This is the rocket-chip commit that I'm working with: https://github.com/chipsalliance/rocket-chip/commit/c9289f5a92f34ccbb62170bc507e7670b4989325
Chisel version: 7.0.0-M2+684-41db7047-SNAPSHOT
firtool version: 1.114.1
Platform: macOS 15.4.1
These errors are triggered when --preserve-aggregate is set to either 1d-vec, vec, or all (preserving more aggregates triggers a larger number of errors).
This command recreates the error:
firtool --preserve-aggregate=<anything> --split-verilog -o <output-dir> RocketConfig.fir
Please let me know if I can provide any more context.
Okay, I came up with a way simpler reproduction. The issue seems to originate from indexing into a FIRRTL aggregate from a layer, when aggregate preservation is enabled.
//> using scala 2.13.16
//> using repository https://s01.oss.sonatype.org/content/repositories/snapshots
//> using dep org.chipsalliance::chisel:7.0.0-RC1+8-81480282-SNAPSHOT
//> using plugin org.chipsalliance:::chisel-plugin:7.0.0-RC1+8-81480282-SNAPSHOT
//> using options -unchecked -deprecation -language:reflectiveCalls -feature -Xcheckinit -Xfatal-warnings -Ywarn-dead-code -Ywarn-unused -Ymacro-annotations
import chisel3._
import chisel3.ltl.AssertProperty
class Foo(addrBits: Int = 2) extends Module {
val in = IO(Input(Vec(1 << addrBits, UInt(4.W))))
val addr = IO(Input(UInt(addrBits.W)))
val out = IO(Output(Vec(1 << addrBits, UInt(4.W))))
out :<= in
AssertProperty(in(addr) === 0.U)
}
object Main extends App {
import _root_.circt.stage.ChiselStage
println(
ChiselStage.emitSystemVerilog(
new Foo,
firtoolOpts = Array(
"-disable-all-randomization",
"-strip-debug-info",
// Uncomment these two lines to trigger firtool error:
// "--preserve-aggregate",
// "vec"
)
)
)
}
With the --preserve-aggregate vec argument uncommented, you get this result:
$ scala-cli chisel-example.scala
Exception in thread "main" circt.stage.phases.Exceptions$FirtoolNonZeroExitCode: /path/to/org.chipsalliance.llvm-firtool/1.116.0/bin/firtool returned a non-zero exit code. Note that this version of Chisel (7.0.0-RC1+8-81480282-SNAPSHOT) was published against firtool version 1.116.0.
------------------------------------------------------------------------------
ExitCode:
1
STDOUT:
STDERR:
/path/to/chisel-example.scala:17:27: error: 'firrtl.subaccess' op using value defined outside the region
/path/to/chisel-example.scala:17:27: note: see current operation: %2 = "firrtl.subaccess"(<<UNKNOWN SSA VALUE>>, <<UNKNOWN SSA VALUE>>) : (!firrtl.vector<uint<4>, 4>, !firrtl.uint<2>) -> !firrtl.uint<4>
/path/to/chisel-example.scala:17:17: note: required by region isolation constraints
------------------------------------------------------------------------------
I guess this example performs a firrtl.subaccess op rather than the firrtl.subindex in the original example, but this is probably still useful for solving the original problem.
Summary from ODM: if you can attache the firrtl that would help.
Here's the .fir file for this example (from Chisel 7.0.0-RC3):
FIRRTL version 5.1.0
circuit Foo :
layer Verification, bind, "verification" :
layer Assert, bind, "verification/assert" :
layer Assume, bind, "verification/assume" :
layer Cover, bind, "verification/cover" :
public module Foo :
input clock : Clock
input reset : UInt<1>
input in : UInt<4>[4]
input addr : UInt<2>
output out : UInt<4>[4]
connect out[0], in[0]
connect out[1], in[1]
connect out[2], in[2]
connect out[3], in[3]
node _T = eq(in[addr], UInt<1>(0h0))
node has_been_reset = intrinsic(circt_has_been_reset : UInt<1>, clock, reset)
node disable = eq(has_been_reset, UInt<1>(0h0))
skip
layerblock Verification :
layerblock Assert :
node ltl_clock = intrinsic(circt_ltl_clock : UInt<1>, _T, clock)
node _T_1 = eq(disable, UInt<1>(0h0))
intrinsic(circt_verif_assert, ltl_clock, _T_1)
And here's what happens when you run firtool --verbose-pass-executions --preserve-aggregate=1d-vec test.fir:
...
[firtool] Running "firrtl-lower-layers"
test.fir:19:21: error: 'firrtl.subaccess' op using value defined outside the region
node _T = eq(in[addr], UInt<1>(0h0))
^
test.fir:19:21: note: see current operation: %2 = "firrtl.subaccess"(<<UNKNOWN SSA VALUE>>, <<UNKNOWN SSA VALUE>>) : (!firrtl.vector<uint<4>, 4>, !firrtl.uint<2>) -> !firrtl.uint<4>
test.fir:24:7: note: required by region isolation constraints
layerblock Assert :
^
Here's a log of that complete firtool execution firtool-aggregate.log
@seldridge @rwy7 This looks like it might be a bug in LowerLayers 🤔
(Yep, as indicated in original issue posting back in April! 😉 )
Amazing, thanks so much for resolving this! Indeed, this fixes the 1d-vec and vec settings of --preserve-aggregate for me. I'm getting a new error when using --preserve-aggregate=all, I'll file a new issue for that.
Filed follow-on issue here: #8931