Skip to content

Commit 90b2941

Browse files
committed
[FIRRTL] Support regions/blocks in LowerLayers
Fix a bug in the `LowerLayers` pass where it would not visit the blocks in operations with nested regions. This would cause the pass to produce invalid IR if the operations within a layerblock contained any operations which contained blocks which had captures outside the block. E.g., this prevented the pass from working correctly with when statements. This is part of enabling inline layers. The existing lowering of inline layers produces `sv.ifdef` operations. If an inline layer is inside a bind layer, then the inline layer (lowered to an `sv.ifdef`) needs to be walked to find any captures. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
1 parent 1edb784 commit 90b2941

File tree

2 files changed

+42
-19
lines changed

2 files changed

+42
-19
lines changed

lib/Dialect/FIRRTL/Transforms/LowerLayers.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
468468

469469
SmallVector<hw::InnerSymAttr> innerSyms;
470470
SmallVector<RWProbeOp> rwprobes;
471-
for (auto &op : llvm::make_early_inc_range(*body)) {
471+
auto layerBlockWalkResult = layerBlock.walk([&](Operation *op) {
472472
// Record any operations inside the layer block which have inner symbols.
473473
// Theses may have symbol users which need to be updated.
474474
if (auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op))
@@ -488,7 +488,7 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
488488
if (auto instOp = dyn_cast<InstanceOp>(op)) {
489489
// Ignore instances which this pass did not create.
490490
if (!createdInstances.contains(instOp))
491-
continue;
491+
return WalkResult::advance();
492492

493493
LLVM_DEBUG({
494494
llvm::dbgs()
@@ -497,7 +497,7 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
497497
<< " instance: " << instOp.getName() << "\n";
498498
});
499499
instOp->moveBefore(layerBlock);
500-
continue;
500+
return WalkResult::advance();
501501
}
502502

503503
// Handle subfields, subindexes, and subaccesses which are indexing into
@@ -510,24 +510,24 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
510510
// is exceedingly rare given that subaccesses are almost always unexepcted
511511
// when this pass runs.)
512512
if (isa<SubfieldOp, SubindexOp>(op)) {
513-
auto input = op.getOperand(0);
513+
auto input = op->getOperand(0);
514514
if (!firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive() &&
515515
!isAncestorOfValueOwner(layerBlock, input))
516-
op.moveBefore(layerBlock);
517-
continue;
516+
op->moveBefore(layerBlock);
517+
return WalkResult::advance();
518518
}
519519

520520
if (auto subOp = dyn_cast<SubaccessOp>(op)) {
521521
auto input = subOp.getInput();
522522
if (firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive())
523-
continue;
523+
return WalkResult::advance();
524524

525525
if (!isAncestorOfValueOwner(layerBlock, input) &&
526526
!isAncestorOfValueOwner(layerBlock, subOp.getIndex())) {
527527
subOp->moveBefore(layerBlock);
528-
continue;
528+
return WalkResult::advance();
529529
}
530-
auto diag = op.emitOpError()
530+
auto diag = op->emitOpError()
531531
<< "has a non-passive operand and captures a value defined "
532532
"outside its enclosing bind-convention layerblock. The "
533533
"'LowerLayers' pass cannot lower this as it would "
@@ -539,7 +539,7 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
539539

540540
if (auto rwprobe = dyn_cast<RWProbeOp>(op)) {
541541
rwprobes.push_back(rwprobe);
542-
continue;
542+
return WalkResult::advance();
543543
}
544544

545545
if (auto connect = dyn_cast<FConnectLike>(op)) {
@@ -549,22 +549,22 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
549549
auto dstInLayerBlock = isAncestorOfValueOwner(layerBlock, dst);
550550
if (!srcInLayerBlock && !dstInLayerBlock) {
551551
connect->moveBefore(layerBlock);
552-
continue;
552+
return WalkResult::advance();
553553
}
554554
// Create an input port.
555555
if (!srcInLayerBlock) {
556-
createInputPort(src, op.getLoc());
557-
continue;
556+
createInputPort(src, op->getLoc());
557+
return WalkResult::advance();
558558
}
559559
// Create an output port.
560560
if (!dstInLayerBlock) {
561561
createOutputPort(dst, src);
562562
if (!isa<RefType>(dst.getType()))
563563
connect.erase();
564-
continue;
564+
return WalkResult::advance();
565565
}
566566
// Source and destination in layer block. Nothing to do.
567-
continue;
567+
return WalkResult::advance();
568568
}
569569

570570
// Pre-emptively de-squiggle connections that we are creating. This will
@@ -587,15 +587,20 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
587587
*refResolve.getResult().getUsers().begin()))
588588
if (connect.getDest().getParentBlock() != body) {
589589
refResolve->moveBefore(layerBlock);
590-
continue;
590+
return WalkResult::advance();
591591
}
592592

593593
// For any other ops, create input ports for any captured operands.
594-
for (auto operand : op.getOperands()) {
594+
for (auto operand : op->getOperands()) {
595595
if (!isAncestorOfValueOwner(layerBlock, operand))
596-
createInputPort(operand, op.getLoc());
596+
createInputPort(operand, op->getLoc());
597597
}
598-
}
598+
599+
return WalkResult::advance();
600+
});
601+
602+
if (layerBlockWalkResult.wasInterrupted())
603+
return WalkResult::interrupt();
599604

600605
// Create the new module. This grabs a lock to modify the circuit.
601606
FModuleOp newModule = buildNewModule(builder, layerBlock, ports);

test/Dialect/FIRRTL/lower-layers.mlir

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,24 @@ firrtl.circuit "Test" {
224224
}
225225
}
226226

227+
// CHECK: firrtl.module private @CaptureInWhen_A(
228+
// CHECK-SAME: in %a: !firrtl.uint<1>
229+
// CHECK-SAME: in %cond: !firrtl.uint<1>
230+
// CHECK-SAME: )
231+
232+
// CHECK: firrtl.module @CaptureInWhen(
233+
// CHECK: %a_a, %a_cond = firrtl.instance a
234+
// CHECK-NEXT: firrtl.matchingconnect %a_cond, %cond :
235+
// CHECK-NEXT: firrtl.matchingconnect %a_a, %a :
236+
firrtl.module @CaptureInWhen(in %cond: !firrtl.uint<1>) {
237+
%a = firrtl.wire : !firrtl.uint<1>
238+
firrtl.layerblock @A {
239+
firrtl.when %cond : !firrtl.uint<1> {
240+
%b = firrtl.node %a : !firrtl.uint<1>
241+
}
242+
}
243+
}
244+
227245
//===--------------------------------------------------------------------===//
228246
// Connecting/Defining Refs
229247
//===--------------------------------------------------------------------===//

0 commit comments

Comments
 (0)