Skip to content

Commit 5c7db4f

Browse files
authored
[FIRRTL] Add a bind op (#8384)
Currently, FIRRTL instances may be marked as "lowerToBind", which is then lowered to a HW instance marked "doNotPrint", along with a bind op in the global scope. This PR adds a bind op to FIRRTL, which in conjunction with the "doNotPrint" flag on FIRRTL instances, allows us to choose precisely where the bind operation goes, rather than having lowerToHW choose for us.
1 parent bd69493 commit 5c7db4f

File tree

6 files changed

+142
-11
lines changed

6 files changed

+142
-11
lines changed

include/circt/Dialect/FIRRTL/FIRRTLStatements.td

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ include "FIRRTLDialect.td"
1717
include "FIRRTLEnums.td"
1818
include "FIRRTLOpInterfaces.td"
1919
include "FIRRTLTypes.td"
20+
include "circt/Dialect/HW/HWAttributesNaming.td"
2021
include "circt/Dialect/HW/HWTypes.td"
2122
include "mlir/IR/SymbolInterfaces.td"
2223
include "mlir/Interfaces/SideEffectInterfaces.td"
@@ -428,4 +429,27 @@ def LayerBlockOp : FIRRTLOp<
428429
let hasCanonicalizeMethod = 1;
429430
}
430431

432+
//===----------------------------------------------------------------------===//
433+
// Bind Op
434+
//===----------------------------------------------------------------------===//
435+
436+
def BindOp
437+
: FIRRTLOp<"bind", [DeclareOpInterfaceMethods<InnerRefUserOpInterface>]> {
438+
let summary = "Indirect instantiation statement";
439+
let description = [{
440+
Indirectly instantiate a module from the context of another module. BindOp
441+
pairs with a `firrtl.instance` which tracks all information except the
442+
emission point for the bind.
443+
444+
This op exists to aid in the progressive lowering of FIRRTL surface level
445+
constructs, such as layers, to system verilog (sv dialect).
446+
}];
447+
let arguments = (ins InnerRefAttr:$instance);
448+
let assemblyFormat = "$instance attr-dict";
449+
let builders = [OpBuilder<(ins "StringAttr":$mod, "StringAttr":$name), [{
450+
auto instance = hw::InnerRefAttr::get(mod, name);
451+
build(odsBuilder, odsState, instance);
452+
}]>];
453+
}
454+
431455
#endif // CIRCT_DIALECT_FIRRTL_FIRRTLSTATEMENTS_TD

include/circt/Dialect/FIRRTL/FIRRTLVisitors.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -241,17 +241,17 @@ class StmtVisitor {
241241
ResultType dispatchStmtVisitor(Operation *op, ExtraArgs... args) {
242242
auto *thisCast = static_cast<ConcreteType *>(this);
243243
return TypeSwitch<Operation *, ResultType>(op)
244-
.template Case<
245-
AttachOp, ConnectOp, MatchingConnectOp, RefDefineOp, ForceOp,
246-
PrintFOp, FPrintFOp, SkipOp, StopOp, WhenOp, AssertOp, AssumeOp,
247-
CoverOp, PropAssignOp, RefForceOp, RefForceInitialOp, RefReleaseOp,
248-
RefReleaseInitialOp, FPGAProbeIntrinsicOp, VerifAssertIntrinsicOp,
249-
VerifAssumeIntrinsicOp, UnclockedAssumeIntrinsicOp,
250-
VerifCoverIntrinsicOp, VerifRequireIntrinsicOp,
251-
VerifEnsureIntrinsicOp, LayerBlockOp, MatchOp, ViewIntrinsicOp>(
252-
[&](auto opNode) -> ResultType {
253-
return thisCast->visitStmt(opNode, args...);
254-
})
244+
.template Case<AttachOp, ConnectOp, MatchingConnectOp, RefDefineOp,
245+
ForceOp, PrintFOp, FPrintFOp, SkipOp, StopOp, WhenOp,
246+
AssertOp, AssumeOp, CoverOp, PropAssignOp, RefForceOp,
247+
RefForceInitialOp, RefReleaseOp, RefReleaseInitialOp,
248+
FPGAProbeIntrinsicOp, VerifAssertIntrinsicOp,
249+
VerifAssumeIntrinsicOp, UnclockedAssumeIntrinsicOp,
250+
VerifCoverIntrinsicOp, VerifRequireIntrinsicOp,
251+
VerifEnsureIntrinsicOp, LayerBlockOp, MatchOp,
252+
ViewIntrinsicOp, BindOp>([&](auto opNode) -> ResultType {
253+
return thisCast->visitStmt(opNode, args...);
254+
})
255255
.Default([&](auto expr) -> ResultType {
256256
return thisCast->visitInvalidStmt(op, args...);
257257
});
@@ -302,6 +302,7 @@ class StmtVisitor {
302302
HANDLE(LayerBlockOp);
303303
HANDLE(MatchOp);
304304
HANDLE(ViewIntrinsicOp);
305+
HANDLE(BindOp);
305306

306307
#undef HANDLE
307308
};

lib/Conversion/FIRRTLToHW/LowerToHW.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ struct FIRRTLModuleLowering
577577
CircuitLoweringState &loweringState);
578578
LogicalResult lowerSimulationBody(verif::SimulationOp simulationOp,
579579
CircuitLoweringState &loweringState);
580+
LogicalResult lowerFileBody(emit::FileOp op);
580581
LogicalResult lowerBody(Operation *op, CircuitLoweringState &loweringState);
581582
};
582583

@@ -692,6 +693,11 @@ void FIRRTLModuleLowering::runOnOperation() {
692693
opsToProcess.push_back(newOp);
693694
return success();
694695
})
696+
.Case<emit::FileOp>([&](auto fileOp) {
697+
fileOp->moveBefore(topLevelModule, topLevelModule->end());
698+
opsToProcess.push_back(fileOp);
699+
return success();
700+
})
695701
.Default([&](Operation *op) {
696702
// We don't know what this op is. If it has no illegal FIRRTL
697703
// types, we can forward the operation. Otherwise, we emit an
@@ -1851,6 +1857,7 @@ struct FIRRTLLowering : public FIRRTLVisitor<FIRRTLLowering, LogicalResult> {
18511857
LogicalResult visitStmt(RefForceInitialOp op);
18521858
LogicalResult visitStmt(RefReleaseOp op);
18531859
LogicalResult visitStmt(RefReleaseInitialOp op);
1860+
LogicalResult visitStmt(BindOp op);
18541861

18551862
FailureOr<Value> lowerSubindex(SubindexOp op, Value input);
18561863
FailureOr<Value> lowerSubaccess(SubaccessOp op, Value input);
@@ -1966,6 +1973,18 @@ FIRRTLModuleLowering::lowerModuleBody(hw::HWModuleOp module,
19661973
return FIRRTLLowering(module, loweringState).run();
19671974
}
19681975

1976+
LogicalResult FIRRTLModuleLowering::lowerFileBody(emit::FileOp fileOp) {
1977+
OpBuilder b(&getContext());
1978+
fileOp->walk([&](Operation *op) {
1979+
if (auto bindOp = dyn_cast<BindOp>(op)) {
1980+
b.setInsertionPointAfter(bindOp);
1981+
b.create<sv::BindOp>(bindOp.getLoc(), bindOp.getInstanceAttr());
1982+
bindOp->erase();
1983+
}
1984+
});
1985+
return success();
1986+
}
1987+
19691988
LogicalResult
19701989
FIRRTLModuleLowering::lowerBody(Operation *op,
19711990
CircuitLoweringState &loweringState) {
@@ -1975,6 +1994,8 @@ FIRRTLModuleLowering::lowerBody(Operation *op,
19751994
return lowerFormalBody(formalOp, loweringState);
19761995
if (auto simulationOp = dyn_cast<verif::SimulationOp>(op))
19771996
return lowerSimulationBody(simulationOp, loweringState);
1997+
if (auto fileOp = dyn_cast<emit::FileOp>(op))
1998+
return lowerFileBody(fileOp);
19781999
return failure();
19792000
}
19802001

@@ -5165,6 +5186,11 @@ LogicalResult FIRRTLLowering::visitStmt(AttachOp op) {
51655186
return success();
51665187
}
51675188

5189+
LogicalResult FIRRTLLowering::visitStmt(BindOp op) {
5190+
builder.create<sv::BindOp>(op.getInstanceAttr());
5191+
return success();
5192+
}
5193+
51685194
LogicalResult FIRRTLLowering::fixupLTLOps() {
51695195
if (ltlOpFixupWorklist.empty())
51705196
return success();

lib/Dialect/FIRRTL/FIRRTLOps.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6404,6 +6404,29 @@ void HierarchicalModuleNameOp::getAsmResultNames(
64046404
setNameFn(getResult(), "hierarchicalmodulename");
64056405
}
64066406

6407+
//===----------------------------------------------------------------------===//
6408+
// BindOp
6409+
//===----------------------------------------------------------------------===//
6410+
6411+
LogicalResult BindOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
6412+
auto ref = getInstanceAttr();
6413+
auto target = ns.lookup(ref);
6414+
if (!target)
6415+
return emitError() << "target " << ref << " cannot be resolved";
6416+
6417+
if (!target.isOpOnly())
6418+
return emitError() << "target " << ref << " is not an operation";
6419+
6420+
auto instance = dyn_cast<InstanceOp>(target.getOp());
6421+
if (!instance)
6422+
return emitError() << "target " << ref << " is not an instance";
6423+
6424+
if (!instance.getDoNotPrint())
6425+
return emitError() << "target " << ref << " is not marked doNotPrint";
6426+
6427+
return success();
6428+
}
6429+
64076430
//===----------------------------------------------------------------------===//
64086431
// TblGen Generated Logic.
64096432
//===----------------------------------------------------------------------===//

test/Conversion/FIRRTLToHW/lower-to-hw.mlir

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,23 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
725725
firrtl.instance foo {doNotPrint} @foo()
726726
}
727727

728+
// Check that explicit bind ops are lowered to sv.bind, even if they are
729+
// buried in an emit block.
730+
731+
firrtl.module @BoundModule() {}
732+
733+
// CHECK-LABEL: hw.module @ExplicitBindTest()
734+
firrtl.module @ExplicitBindTest() {
735+
// CHECK: hw.instance "boundInstance" sym @boundInstance @BoundModule() -> () {doNotPrint}
736+
firrtl.instance boundInstance sym @boundInstance {doNotPrint} @BoundModule()
737+
}
738+
739+
// CHECK: emit.file "some-file.sv"
740+
emit.file "some-file.sv" {
741+
// CHECK: sv.bind <@ExplicitBindTest::@boundInstance>
742+
firrtl.bind <@ExplicitBindTest::@boundInstance>
743+
}
744+
728745
// CHECK-LABEL: hw.module private @attributes_preservation
729746
// CHECK-SAME: firrtl.foo = "bar"
730747
// CHECK-SAME: output_file = #hw.output_file<"output_fileTest.sv", excludeFromFileList>

test/Dialect/FIRRTL/errors.mlir

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,3 +2885,43 @@ firrtl.circuit "SimulationPortType3" {
28852885
out success: !firrtl.reset
28862886
)
28872887
}
2888+
2889+
// -----
2890+
2891+
firrtl.circuit "BindTargetMissingModule" {
2892+
firrtl.module @BindTargetMissing() {}
2893+
// expected-error @below {{target #hw.innerNameRef<@XXX::@YYY> cannot be resolved}}
2894+
firrtl.bind <@XXX::@YYY>
2895+
}
2896+
2897+
// -----
2898+
2899+
firrtl.circuit "BindTargetMissingInstance" {
2900+
firrtl.module @BindTargetMissingInstance() {}
2901+
// expected-error @below {{target #hw.innerNameRef<@BindTargetMissingInstance::@YYY> cannot be resolved}}
2902+
firrtl.bind <@BindTargetMissingInstance::@YYY>
2903+
}
2904+
2905+
// -----
2906+
2907+
firrtl.circuit "BindTargetNotAnInstance" {
2908+
firrtl.module @Target() {}
2909+
firrtl.module @BindTargetMissingDoNotPrintFlag() {
2910+
%wire = firrtl.wire sym @target : !firrtl.uint<8>
2911+
}
2912+
2913+
// expected-error @below {{target #hw.innerNameRef<@BindTargetMissingDoNotPrintFlag::@target> is not an instance}}
2914+
firrtl.bind <@BindTargetMissingDoNotPrintFlag::@target>
2915+
}
2916+
2917+
// -----
2918+
2919+
firrtl.circuit "BindTargetMissingDoNotPrintFlag" {
2920+
firrtl.module @Target() {}
2921+
firrtl.module @BindTargetMissingDoNotPrintFlag() {
2922+
firrtl.instance target sym @target @Target()
2923+
}
2924+
2925+
// expected-error @below {{target #hw.innerNameRef<@BindTargetMissingDoNotPrintFlag::@target> is not marked doNotPrint}}
2926+
firrtl.bind <@BindTargetMissingDoNotPrintFlag::@target>
2927+
}

0 commit comments

Comments
 (0)