Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[firtool] Add option to treat EICG_wrapper as intrinsic #6499

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/circt/Dialect/FIRRTL/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ std::unique_ptr<mlir::Pass> createLowerBundleVectorTypesPass();

std::unique_ptr<mlir::Pass> createLowerCHIRRTLPass();

std::unique_ptr<mlir::Pass> createLowerIntrinsicsPass();
std::unique_ptr<mlir::Pass>
createLowerIntrinsicsPass(bool fixupEICGWrapper = false);

std::unique_ptr<mlir::Pass> createIMConstPropPass();

Expand Down
4 changes: 4 additions & 0 deletions include/circt/Dialect/FIRRTL/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,10 @@ def LowerIntrinsics : Pass<"firrtl-lower-intrinsics", "firrtl::CircuitOp"> {
intmodule to their implementation or op.
}];
let constructor = "circt::firrtl::createLowerIntrinsicsPass()";
let options = [
Option<"fixupEICGWrapper", "fixup-eicg-wrapper", "bool", "false",
"Lower `EICG_wrapper` modules into clock gate intrinsics">,
];
}

def LowerOpenAggs : Pass<"firrtl-lower-open-aggs", "firrtl::CircuitOp"> {
Expand Down
7 changes: 7 additions & 0 deletions include/circt/Firtool/Firtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class FirtoolOptions {
return addVivadoRAMAddressConflictSynthesisBugWorkaround;
}
bool shouldExtractTestCode() const { return extractTestCode; }
bool shouldFixupEICGWrapper() const { return fixupEICGWrapper; }

// Setters, used by the CAPI
FirtoolOptions &setOutputFilename(StringRef name) {
Expand Down Expand Up @@ -343,6 +344,11 @@ class FirtoolOptions {
return *this;
}

FirtoolOptions &setFixupEICGWrapper(bool value) {
fixupEICGWrapper = value;
return *this;
}

private:
std::string outputFilename;
bool disableAnnotationsUnknown;
Expand Down Expand Up @@ -387,6 +393,7 @@ class FirtoolOptions {
bool exportModuleHierarchy;
bool stripFirDebugInfo;
bool stripDebugInfo;
bool fixupEICGWrapper;
};

void registerFirtoolCLOptions();
Expand Down
63 changes: 52 additions & 11 deletions lib/Dialect/FIRRTL/Transforms/LowerIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ using namespace firrtl;
namespace {
struct LowerIntrinsicsPass : public LowerIntrinsicsBase<LowerIntrinsicsPass> {
void runOnOperation() override;
using LowerIntrinsicsBase::fixupEICGWrapper;
};
} // end anonymous namespace

Expand Down Expand Up @@ -267,6 +268,36 @@ static bool lowerCirctClockGate(InstanceGraph &ig, FModuleLike mod) {
return true;
}

static bool lowerEICGWrapperToClockGate(InstanceGraph &ig, FModuleLike mod) {
if (hasNPorts("EICG_wrapper", mod, 4) ||
namedPort("EICG_wrapper", mod, 0, "in") ||
namedPort("EICG_wrapper", mod, 1, "test_en") ||
namedPort("EICG_wrapper", mod, 2, "en") ||
namedPort("EICG_wrapper", mod, 3, "out") ||
typedPort<ClockType>("EICG_wrapper", mod, 0) ||
sizedPort<UIntType>("EICG_wrapper", mod, 1, 1) ||
sizedPort<UIntType>("EICG_wrapper", mod, 2, 1) ||
typedPort<ClockType>("EICG_wrapper", mod, 3) ||
hasNParam("EICG_wrapper", mod, 0))
return false;

for (auto *use : ig.lookup(mod)->uses()) {
auto inst = cast<InstanceOp>(use->getInstance().getOperation());
ImplicitLocOpBuilder builder(inst.getLoc(), inst);
auto in = builder.create<WireOp>(inst.getResult(0).getType()).getResult();
auto testEn =
builder.create<WireOp>(inst.getResult(1).getType()).getResult();
auto en = builder.create<WireOp>(inst.getResult(2).getType()).getResult();
inst.getResult(0).replaceAllUsesWith(in);
inst.getResult(1).replaceAllUsesWith(testEn);
inst.getResult(2).replaceAllUsesWith(en);
auto out = builder.create<ClockGateIntrinsicOp>(in, en, testEn);
inst.getResult(3).replaceAllUsesWith(out);
inst.erase();
}
return true;
}

template <bool isMux2>
static bool lowerCirctMuxCell(InstanceGraph &ig, FModuleLike mod) {
StringRef mnemonic = isMux2 ? "circt.mux2cell" : "circt.mux4cell";
Expand Down Expand Up @@ -632,6 +663,7 @@ std::pair<const char *, std::function<bool(InstanceGraph &, FModuleLike)>>
{"circt_plusargs_value", lowerCirctPlusArgValue},
{"circt.clock_gate", lowerCirctClockGate},
{"circt_clock_gate", lowerCirctClockGate},
{"EICG_wrapper", lowerEICGWrapperToClockGate}, // remove once EICG gone
{"circt.ltl.and", lowerCirctLTLAnd},
{"circt_ltl_and", lowerCirctLTLAnd},
{"circt.ltl.or", lowerCirctLTLOr},
Expand Down Expand Up @@ -674,15 +706,21 @@ void LowerIntrinsicsPass::runOnOperation() {
if (!isa<FExtModuleOp, FIntModuleOp>(op))
continue;
StringAttr intname;
if (isa<FExtModuleOp>(op)) {
auto anno = AnnotationSet(&op).getAnnotation("circt.Intrinsic");
if (!anno)
continue;
intname = anno.getMember<StringAttr>("intrinsic");
if (!intname) {
op.emitError("intrinsic annotation with no intrinsic name");
++numFailures;
continue;
if (auto extMod = dyn_cast<FExtModuleOp>(op)) {
if (fixupEICGWrapper && extMod.getDefname() == "EICG_wrapper") {
// Remove this once `EICG_wrapper` is no longer special-cased by
// firtool.
intname = extMod.getDefnameAttr();
} else {
auto anno = AnnotationSet(&op).getAnnotation("circt.Intrinsic");
if (!anno)
continue;
intname = anno.getMember<StringAttr>("intrinsic");
if (!intname) {
op.emitError("intrinsic annotation with no intrinsic name");
++numFailures;
continue;
}
}
} else {
intname = cast<FIntModuleOp>(op).getIntrinsicAttr();
Expand Down Expand Up @@ -718,6 +756,9 @@ void LowerIntrinsicsPass::runOnOperation() {
}

/// This is the pass constructor.
std::unique_ptr<mlir::Pass> circt::firrtl::createLowerIntrinsicsPass() {
return std::make_unique<LowerIntrinsicsPass>();
std::unique_ptr<mlir::Pass>
circt::firrtl::createLowerIntrinsicsPass(bool fixupEICGWrapper) {
auto pass = std::make_unique<LowerIntrinsicsPass>();
pass->fixupEICGWrapper = fixupEICGWrapper;
return pass;
}
11 changes: 9 additions & 2 deletions lib/Firtool/Firtool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ LogicalResult firtool::populatePreprocessTransforms(mlir::PassManager &pm,
LogicalResult firtool::populateCHIRRTLToLowFIRRTL(mlir::PassManager &pm,
const FirtoolOptions &opt,
StringRef inputFilename) {
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerIntrinsicsPass());
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createLowerIntrinsicsPass(opt.shouldFixupEICGWrapper()));

pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInjectDUTHierarchyPass());

Expand Down Expand Up @@ -647,6 +648,11 @@ struct FirtoolCmdOptions {
"strip-debug-info",
llvm::cl::desc("Disable source locator information in output Verilog"),
llvm::cl::init(false)};

llvm::cl::opt<bool> fixupEICGWrapper{
"fixup-eicg-wrapper",
llvm::cl::desc("Lower `EICG_wrapper` modules into clock gate intrinsics"),
llvm::cl::init(false)};
};
} // namespace

Expand Down Expand Up @@ -682,7 +688,7 @@ circt::firtool::FirtoolOptions::FirtoolOptions()
ckgModuleName("EICG_wrapper"), ckgInputName("in"), ckgOutputName("out"),
ckgEnableName("en"), ckgTestEnableName("test_en"), ckgInstName("ckg"),
exportModuleHierarchy(false), stripFirDebugInfo(true),
stripDebugInfo(false) {
stripDebugInfo(false), fixupEICGWrapper(false) {
if (!clOptions.isConstructed())
return;
outputFilename = clOptions->outputFilename;
Expand Down Expand Up @@ -729,4 +735,5 @@ circt::firtool::FirtoolOptions::FirtoolOptions()
exportModuleHierarchy = clOptions->exportModuleHierarchy;
stripFirDebugInfo = clOptions->stripFirDebugInfo;
stripDebugInfo = clOptions->stripDebugInfo;
fixupEICGWrapper = clOptions->fixupEICGWrapper;
}
18 changes: 17 additions & 1 deletion test/Dialect/FIRRTL/lower-intrinsics.mlir
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-intrinsics))' %s | FileCheck %s
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-intrinsics))' %s | FileCheck %s --check-prefixes=CHECK,CHECK-NOEICG
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-intrinsics{fixup-eicg-wrapper}))' %s | FileCheck %s --check-prefixes=CHECK,CHECK-EICG

// CHECK-LABEL: "Foo"
firrtl.circuit "Foo" {
Expand Down Expand Up @@ -220,4 +221,19 @@ firrtl.circuit "Foo" {
firrtl.strictconnect %in_reset2, %reset2 : !firrtl.asyncreset
firrtl.strictconnect %in_reset3, %reset3 : !firrtl.reset
}

// CHECK-NOEICG: LegacyClockGate
// CHECK-EICG-NOT: LegacyClockGate
firrtl.extmodule @LegacyClockGate(in in: !firrtl.clock, in test_en: !firrtl.uint<1>, in en: !firrtl.uint<1>, out out: !firrtl.clock) attributes {defname = "EICG_wrapper"}

// CHECK: FixupEICGWrapper
firrtl.module @FixupEICGWrapper(in %clock: !firrtl.clock, in %en: !firrtl.uint<1>) {
// CHECK-NOEICG: firrtl.instance
// CHECK-EICG-NOT: firrtl.instance
// CHECK-EICG: firrtl.int.clock_gate
%ckg_in, %ckg_test_en, %ckg_en, %ckg_out = firrtl.instance ckg @LegacyClockGate(in in: !firrtl.clock, in test_en: !firrtl.uint<1>, in en: !firrtl.uint<1>, out out: !firrtl.clock)
firrtl.strictconnect %ckg_in, %clock : !firrtl.clock
firrtl.strictconnect %ckg_test_en, %en : !firrtl.uint<1>
firrtl.strictconnect %ckg_en, %en : !firrtl.uint<1>
}
}