From ca2426776387f58454417f6cd838dc5e904e139c Mon Sep 17 00:00:00 2001 From: Will Dietz Date: Tue, 9 Apr 2024 17:46:54 -0500 Subject: [PATCH] [FIRRTL] LowerIntrinsics: rewrite to lower generic ops. (#6877) Move to module pass, and use rewriting framework for safety, familiariy, and (with some help) simpler lowering code. Add LowerIntmodules to the pipeline as this is now needed for compatibility with designs not yet using the new intrinsic format. --- .../circt/Dialect/FIRRTL/FIRRTLIntrinsics.h | 270 ++++-- include/circt/Dialect/FIRRTL/Passes.h | 3 +- include/circt/Dialect/FIRRTL/Passes.td | 9 +- lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp | 177 ++-- .../FIRRTL/Transforms/LowerIntrinsics.cpp | 899 +++++------------- lib/Firtool/Firtool.cpp | 4 +- .../FIRRTL/lower-intrinsics-errors.mlir | 28 +- .../FIRRTL/lower-intrinsics-unknown.mlir | 11 - test/Dialect/FIRRTL/lower-intrinsics.mlir | 374 ++------ 9 files changed, 618 insertions(+), 1157 deletions(-) delete mode 100644 test/Dialect/FIRRTL/lower-intrinsics-unknown.mlir diff --git a/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.h b/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.h index 459a3b5b7e..f1394db2ab 100644 --- a/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.h +++ b/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.h @@ -1,4 +1,4 @@ -//===- FIRRTLDialect.h - FIRRTL dialect declaration ------------*- C++ --*-===// +//===- FIRRTLIntrinsics.h - FIRRTL intrinsics ------------------*- C++ --*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,41 +13,66 @@ #ifndef CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_H #define CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_H -#include "circt/Dialect/FIRRTL/FIRRTLOpInterfaces.h" #include "circt/Dialect/FIRRTL/FIRRTLOps.h" +#include "circt/Dialect/FIRRTL/FIRRTLTypes.h" +#include "mlir/IR/Diagnostics.h" +#include "mlir/Transforms/DialectConversion.h" namespace circt { namespace firrtl { -class InstanceGraph; -/// Base class for Intrinsic Converters. -/// -/// Intrinsic converters contain validation logic, along with a converter -/// method to transform instances to extmodules/intmodules into ops. -class IntrinsicConverter { -protected: - StringRef name; - FModuleLike mod; +/// Helper class for checking and extracting information from the generic +/// instrinsic op. +struct GenericIntrinsic { + GenericIntrinsicOp op; -public: - IntrinsicConverter(StringRef name, FModuleLike mod) : name(name), mod(mod) {} + GenericIntrinsic(GenericIntrinsicOp op) : op(op) {} - virtual ~IntrinsicConverter(); + InFlightDiagnostic emitError() { return op.emitError(op.getIntrinsic()); } - /// Checks whether the intrinsic module is well-formed. - /// - /// This or's multiple ParseResults together, returning true on failure. - virtual bool check() { return false; } + //===--------------------------------------------------------------------===// + // Input checking + //===--------------------------------------------------------------------===// - /// Transform an instance of the intrinsic. - virtual LogicalResult convert(InstanceOp op) = 0; + ParseResult hasNInputs(unsigned n); -protected: - ParseResult hasNPorts(unsigned n); + template + ParseResult checkInputType(unsigned n, const Twine &msg, C &&call) { + if (n >= op.getNumOperands()) + return emitError() << " missing input " << n; + if (!std::invoke(std::forward(call), op.getOperand(n).getType())) + return emitError() << " input " << n << " " << msg; + return success(); + } - ParseResult namedPort(unsigned n, StringRef portName); + template + ParseResult checkInputType(unsigned n, C &&call) { + return checkInputType(n, "not of correct type", std::forward(call)); + } - ParseResult resetPort(unsigned n); + template + ParseResult typedInput(unsigned n) { + return checkInputType(n, [](auto ty) { return isa(ty); }); + } + + ParseResult hasResetInput(unsigned n) { + return checkInputType(n, "must be reset type", [](auto ty) { + auto baseType = dyn_cast(ty); + return baseType && baseType.isResetType(); + }); + } + + template + ParseResult sizedInput(unsigned n, int32_t size) { + return checkInputType(n, "not size " + Twine(size), [size](auto ty) { + auto t = dyn_cast(ty); + return t && t.getWidth() == size; + }); + } + + //===--------------------------------------------------------------------===// + // Parameter checking + //===--------------------------------------------------------------------===// ParseResult hasNParam(unsigned n, unsigned c = 0); @@ -55,92 +80,173 @@ protected: ParseResult namedIntParam(StringRef paramName, bool optional = false); + ParamDeclAttr getParamByName(StringRef name) { + for (auto param : op.getParameters().getAsRange()) + if (param.getName().getValue().equals(name)) + return param; + return {}; + } + + /// Get parameter value by name, if present, as requested type. template - ParseResult typedPort(unsigned n) { - auto ports = mod.getPorts(); - if (n >= ports.size()) { - mod.emitError(name) << " missing port " << n; - return failure(); - } - if (!isa(ports[n].type)) { - mod.emitError(name) << " port " << n << " not of correct type"; - return failure(); - } + T getParamValue(StringRef name) { + auto p = getParamByName(name); + if (!p) + return {}; + return cast(p.getValue()); + } + + //===--------------------------------------------------------------------===// + // Output checking + //===--------------------------------------------------------------------===// + + ParseResult hasOutput() { + if (op.getNumResults() == 0) + return emitError() << " missing output"; + return success(); + } + ParseResult hasNoOutput() { + if (op.getNumResults() != 0) + return emitError() << " should not have outputs"; return success(); } template - ParseResult sizedPort(unsigned n, int32_t size) { - auto ports = mod.getPorts(); - if (failed(typedPort(n))) + ParseResult typedOutput() { + if (failed(hasOutput())) return failure(); - if (cast(ports[n].type).getWidth() != size) { - mod.emitError(name) << " port " << n << " not size " << size; - return failure(); - } + if (!isa(op.getResult().getType())) + return emitError() << " output not of correct type"; return success(); } + + template + ParseResult sizedOutput(int32_t size) { + if (failed(typedOutput())) + return failure(); + if (cast(op.getResult().getType()).getWidth() != size) + return emitError() << " output not size " << size; + return success(); + } + + //===--------------------------------------------------------------------===// + // Output bundle element checking + //===--------------------------------------------------------------------===// + + mlir::TypedValue getOutputBundle() { + return dyn_cast_or_null>(op.getResult()); + } + + ParseResult hasNOutputElements(unsigned n); + + template + ParseResult checkOutputElement(unsigned n, StringRef name, const Twine &msg, + C &&call) { + auto b = getOutputBundle(); + if (!b) + return emitError() << " missing output bundle"; + auto ty = b.getType(); + if (n >= ty.getNumElements()) + return emitError() << " missing output element " << n; + auto element = ty.getElement(n); + if (element.name != name) + return emitError() << " output element " << n << " is named " + << element.name << " not " << name; + if (!std::invoke(std::forward(call), element.type)) + return emitError() << " output element " << n << " " << msg; + return success(); + } + + template + ParseResult checkOutputElement(unsigned n, StringRef name, C &&call) { + return checkOutputElement(n, name, "not of correct type", + std::forward(call)); + } + + ParseResult hasOutputElement(unsigned n, StringRef name) { + return checkOutputElement(n, name, [](auto ty) { return true; }); + } + + template + ParseResult typedOutputElement(unsigned n, StringRef name) { + return checkOutputElement(n, name, [](auto ty) { return isa(ty); }); + } + + template + ParseResult sizedOutputElement(unsigned n, StringRef name, int32_t size) { + return checkOutputElement(n, name, "not size " + Twine(size), + [size](auto ty) { + auto t = dyn_cast(ty); + return t && t.getWidth() == size; + }); + } +}; + +/// Base class for Intrinsic Converters. +/// +/// Intrinsic converters contain validation logic, along with a converter +/// method to transform generic intrinsic ops to their implementation. +class IntrinsicConverter { +public: + virtual ~IntrinsicConverter() = default; + + /// Checks whether the intrinsic is well-formed. + /// + /// This or's multiple ParseResults together, returning true on failure. + virtual bool check(GenericIntrinsic gi) = 0; + + /// Transform the intrinsic to its implementation. + virtual void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) = 0; +}; + +template +class IntrinsicOpConverter : public IntrinsicConverter { +public: + /// Transform the intrinsic to its implementation. + /// Handles the simple case of just forwarding to new op kind. + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) final { + // Pass along result type and operands. No attributes. + rewriter.replaceOpWithNewOp(gi.op, gi.op.getResultTypes(), + adaptor.getOperands()); + } }; /// Lowering helper which collects all intrinsic converters. class IntrinsicLowerings { -private: - using ConverterFn = std::function; +public: + using ConversionMapTy = + llvm::DenseMap>; +private: /// Reference to the MLIR context. MLIRContext *context; - /// Reference to the instance graph to find module instances. - InstanceGraph &graph; - /// Mapping from intrinsic names to converters. - DenseMap intmods; - /// Mapping from extmodule names to converters. - DenseMap extmods; + ConversionMapTy conversions; public: - IntrinsicLowerings(MLIRContext *context, InstanceGraph &graph) - : context(context), graph(graph) {} + IntrinsicLowerings(MLIRContext *context) : context(context) {} - /// Registers a converter to an intrinsic name. - template - void add(StringRef name) { - addConverter(intmods, name); - } - - /// Registers a converter to an extmodule name. - template - void addExtmod(StringRef name) { - addConverter(extmods, name); - } - - /// Registers a converter to multiple intrinsic names. + /// Registers a converter to one or more intrinsic names. template - void add(StringRef name, Args... args) { - add(name); - add(args...); + void add(Args... args) { + (addConverter(args), ...); } - /// Lowers a module to an intrinsic, given an intrinsic name. - LogicalResult lower(CircuitOp circuit, bool allowUnknownIntrinsics = false); - - /// Return the number of intrinsics converted. - unsigned getNumConverted() const { return numConverted; } + /// Lowers all intrinsics in a module. + LogicalResult lower(FModuleOp mod, bool allowUnknownIntrinsics = false); private: template - void addConverter(DenseMap &map, StringRef name) { + typename std::enable_if_t> + addConverter(StringRef name) { auto nameAttr = StringAttr::get(context, name); - map.try_emplace(nameAttr, - [this, nameAttr](FModuleLike mod) -> LogicalResult { - T conv(nameAttr.getValue(), mod); - return doLowering(mod, conv); - }); + assert(!conversions.contains(nameAttr) && + "duplicate conversion for intrinsic"); + conversions.try_emplace(nameAttr, std::make_unique()); } - - LogicalResult doLowering(FModuleLike mod, IntrinsicConverter &conv); - - unsigned numConverted = 0; }; } // namespace firrtl diff --git a/include/circt/Dialect/FIRRTL/Passes.h b/include/circt/Dialect/FIRRTL/Passes.h index b2fe3e88be..3938445f16 100644 --- a/include/circt/Dialect/FIRRTL/Passes.h +++ b/include/circt/Dialect/FIRRTL/Passes.h @@ -63,8 +63,7 @@ std::unique_ptr createLowerCHIRRTLPass(); std::unique_ptr createLowerIntmodulesPass(bool fixupEICGWrapper = false); -std::unique_ptr -createLowerIntrinsicsPass(bool fixupEICGWrapper = false); +std::unique_ptr createLowerIntrinsicsPass(); std::unique_ptr createIMConstPropPass(); diff --git a/include/circt/Dialect/FIRRTL/Passes.td b/include/circt/Dialect/FIRRTL/Passes.td index 9aacf8d5a2..4ffac0d1a2 100644 --- a/include/circt/Dialect/FIRRTL/Passes.td +++ b/include/circt/Dialect/FIRRTL/Passes.td @@ -697,17 +697,12 @@ def LowerIntmodules : Pass<"firrtl-lower-intmodules", "firrtl::CircuitOp"> { ]; } -def LowerIntrinsics : Pass<"firrtl-lower-intrinsics", "firrtl::CircuitOp"> { +def LowerIntrinsics : Pass<"firrtl-lower-intrinsics", "firrtl::FModuleOp"> { let summary = "Lower intrinsics"; let description = [{ - This pass lowers intrinsics encoded as extmodule with annotation and - intmodule to their implementation or op. + This pass lowers generic intrinsic ops 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"> { diff --git a/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp b/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp index 061ca96756..59440bb11e 100644 --- a/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp +++ b/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp @@ -7,57 +7,34 @@ //===----------------------------------------------------------------------===// #include "circt/Dialect/FIRRTL/FIRRTLIntrinsics.h" -#include "circt/Dialect/FIRRTL/FIRRTLInstanceGraph.h" +#include "mlir/Transforms/DialectConversion.h" using namespace circt; using namespace firrtl; -IntrinsicConverter::~IntrinsicConverter() = default; - -ParseResult IntrinsicConverter::hasNPorts(unsigned n) { - if (mod.getPorts().size() != n) { - mod.emitError(name) << " has " << mod.getPorts().size() - << " ports instead of " << n; - return failure(); - } +ParseResult GenericIntrinsic::hasNInputs(unsigned n) { + if (op.getNumOperands() != n) + return emitError() << " has " << op.getNumOperands() + << " inputs instead of " << n; return success(); } -ParseResult IntrinsicConverter::namedPort(unsigned n, StringRef portName) { - auto ports = mod.getPorts(); - if (n >= ports.size()) { - mod.emitError(name) << " missing port " << n; - return failure(); - } - if (!ports[n].getName().equals(portName)) { - mod.emitError(name) << " port " << n << " named '" << ports[n].getName() - << "' instead of '" << portName << "'"; - return failure(); - } +ParseResult GenericIntrinsic::hasNOutputElements(unsigned n) { + auto b = getOutputBundle(); + if (!b) + return emitError() << " missing output bundle"; + if (b.getType().getNumElements() != n) + return emitError() << " has " << b.getType().getNumElements() + << " output elements instead of " << n; return success(); } -ParseResult IntrinsicConverter::resetPort(unsigned n) { - auto ports = mod.getPorts(); - if (n >= ports.size()) { - mod.emitError(name) << " missing port " << n; - return failure(); - } - if (isa(ports[n].type)) - return success(); - if (auto uintType = dyn_cast(ports[n].type)) - if (uintType.getWidth() == 1) - return success(); - mod.emitError(name) << " port " << n << " not of correct type"; - return failure(); -} - -ParseResult IntrinsicConverter::hasNParam(unsigned n, unsigned c) { +ParseResult GenericIntrinsic::hasNParam(unsigned n, unsigned c) { unsigned num = 0; - if (mod.getParameters()) - num = mod.getParameters().size(); + if (op.getParameters()) + num = op.getParameters().size(); if (num < n || num > n + c) { - auto d = mod.emitError(name) << " has " << num << " parameters instead of "; + auto d = emitError() << " has " << num << " parameters instead of "; if (c == 0) d << n; else @@ -67,91 +44,93 @@ ParseResult IntrinsicConverter::hasNParam(unsigned n, unsigned c) { return success(); } -ParseResult IntrinsicConverter::namedParam(StringRef paramName, bool optional) { - for (auto a : mod.getParameters()) { +ParseResult GenericIntrinsic::namedParam(StringRef paramName, bool optional) { + for (auto a : op.getParameters()) { auto param = cast(a); if (param.getName().getValue().equals(paramName)) { if (isa(param.getValue())) return success(); - mod.emitError(name) << " has parameter '" << param.getName() - << "' which should be a string but is not"; - return failure(); + return emitError() << " has parameter '" << param.getName() + << "' which should be a string but is not"; } } if (optional) return success(); - mod.emitError(name) << " is missing parameter " << paramName; - return failure(); + return emitError() << " is missing parameter " << paramName; } -ParseResult IntrinsicConverter::namedIntParam(StringRef paramName, - bool optional) { - for (auto a : mod.getParameters()) { +ParseResult GenericIntrinsic::namedIntParam(StringRef paramName, + bool optional) { + for (auto a : op.getParameters()) { auto param = cast(a); if (param.getName().getValue().equals(paramName)) { if (isa(param.getValue())) return success(); - mod.emitError(name) << " has parameter '" << param.getName() - << "' which should be an integer but is not"; - return failure(); + return emitError() << " has parameter '" << param.getName() + << "' which should be an integer but is not"; } } if (optional) return success(); - mod.emitError(name) << " is missing parameter " << paramName; - return failure(); + return emitError() << " is missing parameter " << paramName; } -LogicalResult IntrinsicLowerings::doLowering(FModuleLike mod, - IntrinsicConverter &conv) { - if (conv.check()) - return failure(); - for (auto *use : graph.lookup(mod)->uses()) - if (failed(conv.convert(use->getInstance()))) +/// Conversion pattern adaptor dispatching via generic intrinsic name. +class IntrinsicOpConversion final + : public OpConversionPattern { +public: + using OpConversionPattern::OpConversionPattern; + + using ConversionMapTy = IntrinsicLowerings::ConversionMapTy; + + IntrinsicOpConversion(MLIRContext *context, + const ConversionMapTy &conversions, + bool allowUnknownIntrinsics = false) + : OpConversionPattern(context), conversions(conversions), + allowUnknownIntrinsics(allowUnknownIntrinsics) {} + + LogicalResult + matchAndRewrite(GenericIntrinsicOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + + auto it = conversions.find(op.getIntrinsicAttr()); + if (it == conversions.end()) { + if (!allowUnknownIntrinsics) + return op.emitError("unknown intrinsic ") << op.getIntrinsicAttr(); return failure(); - return success(); -} - -LogicalResult IntrinsicLowerings::lower(CircuitOp circuit, - bool allowUnknownIntrinsics) { - unsigned numFailures = 0; - for (auto op : llvm::make_early_inc_range(circuit.getOps())) { - if (auto extMod = dyn_cast(*op)) { - // Special-case some extmodules, identifying them by name. - auto it = extmods.find(extMod.getDefnameAttr()); - if (it != extmods.end()) { - if (succeeded(it->second(op))) { - op.erase(); - ++numConverted; - } else { - ++numFailures; - } - } - continue; } - auto intMod = dyn_cast(*op); - if (!intMod) - continue; - - auto intname = intMod.getIntrinsicAttr(); - - // Find the converter and apply it. - auto it = intmods.find(intname); - if (it == intmods.end()) { - if (allowUnknownIntrinsics) - continue; - return op.emitError() << "intrinsic not recognized"; - } - if (failed(it->second(op))) { - ++numFailures; - continue; - } - ++numConverted; - op.erase(); + auto &conv = *it->second; + if (conv.check(GenericIntrinsic(op))) + return failure(); + conv.convert(GenericIntrinsic(op), adaptor, rewriter); + return success(); } - return success(numFailures == 0); +private: + const ConversionMapTy &conversions; + const bool allowUnknownIntrinsics; +}; + +LogicalResult IntrinsicLowerings::lower(FModuleOp mod, + bool allowUnknownIntrinsics) { + + ConversionTarget target(*context); + + target.markUnknownOpDynamicallyLegal([](Operation *op) { return true; }); + if (allowUnknownIntrinsics) + target.addDynamicallyLegalOp( + [this](GenericIntrinsicOp op) { + return !conversions.contains(op.getIntrinsicAttr()); + }); + else + target.addIllegalOp(); + + RewritePatternSet patterns(context); + patterns.add(context, conversions, + allowUnknownIntrinsics); + + return mlir::applyPartialConversion(mod, target, std::move(patterns)); } diff --git a/lib/Dialect/FIRRTL/Transforms/LowerIntrinsics.cpp b/lib/Dialect/FIRRTL/Transforms/LowerIntrinsics.cpp index f05df5adab..c7485521d5 100644 --- a/lib/Dialect/FIRRTL/Transforms/LowerIntrinsics.cpp +++ b/lib/Dialect/FIRRTL/Transforms/LowerIntrinsics.cpp @@ -7,78 +7,35 @@ //===----------------------------------------------------------------------===// // // This file defines the LowerIntrinsics pass. This pass processes FIRRTL -// extmodules with intrinsic annotations and rewrites the instances as -// appropriate. +// generic intrinsic operations and rewrites to their implementation. // //===----------------------------------------------------------------------===// #include "PassDetails.h" -#include "circt/Dialect/FIRRTL/FIRRTLInstanceGraph.h" #include "circt/Dialect/FIRRTL/FIRRTLIntrinsics.h" #include "circt/Dialect/FIRRTL/FIRRTLOps.h" #include "circt/Dialect/FIRRTL/FIRRTLTypes.h" -#include "circt/Dialect/FIRRTL/FIRRTLVisitors.h" -#include "circt/Dialect/FIRRTL/Namespace.h" -#include "circt/Dialect/FIRRTL/Passes.h" -#include "mlir/IR/Diagnostics.h" -#include "mlir/IR/ImplicitLocOpBuilder.h" -#include "llvm/ADT/APSInt.h" -#include "llvm/ADT/PostOrderIterator.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Debug.h" using namespace circt; using namespace firrtl; -// Get parameter by the given name. Null if not found. -static ParamDeclAttr getNamedParam(ArrayAttr params, StringRef name) { - for (auto param : params.getAsRange()) - if (param.getName().getValue().equals(name)) - return param; - return {}; -} - namespace { -class CirctSizeofConverter : public IntrinsicConverter { +class CirctSizeofConverter : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "i") || namedPort(1, "size") || - sizedPort(1, 32) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto inputTy = inst.getResult(0).getType(); - auto inputWire = builder.create(inputTy).getResult(); - inst.getResult(0).replaceAllUsesWith(inputWire); - auto size = builder.create(inputWire); - inst.getResult(1).replaceAllUsesWith(size); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.sizedOutput(32) || gi.hasNParam(0); } }; -class CirctIsXConverter : public IntrinsicConverter { +class CirctIsXConverter : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "i") || namedPort(1, "found") || - sizedPort(1, 1) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto inputTy = inst.getResult(0).getType(); - auto inputWire = builder.create(inputTy).getResult(); - inst.getResult(0).replaceAllUsesWith(inputWire); - auto size = builder.create(inputWire); - inst.getResult(1).replaceAllUsesWith(size); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.sizedOutput(1) || gi.hasNParam(0); } }; @@ -86,19 +43,15 @@ class CirctPlusArgTestConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return hasNPorts(1) || namedPort(0, "found") || sizedPort(0, 1) || - hasNParam(1) || namedParam("FORMAT"); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(0) || gi.sizedOutput(1) || gi.hasNParam(1) || + gi.namedParam("FORMAT"); } - LogicalResult convert(InstanceOp inst) override { - auto param = cast(mod.getParameters()[0]); - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto newop = builder.create( - cast(param.getValue())); - inst.getResult(0).replaceAllUsesWith(newop); - inst.erase(); - return success(); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + rewriter.replaceOpWithNewOp( + gi.op, gi.getParamValue("FORMAT")); } }; @@ -106,66 +59,53 @@ class CirctPlusArgValueConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "found") || namedPort(1, "result") || - sizedPort(0, 1) || hasNParam(1) || namedParam("FORMAT"); + bool check(GenericIntrinsic gi) override { + return gi.hasNOutputElements(2) || + gi.sizedOutputElement(0, "found", 1) || + gi.hasOutputElement(1, "result") || gi.hasNParam(1) || + gi.namedParam("FORMAT"); } - LogicalResult convert(InstanceOp inst) override { - auto param = cast(mod.getParameters()[0]); - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto newop = builder.create( - inst.getResultTypes(), cast(param.getValue())); - inst.getResult(0).replaceAllUsesWith(newop.getFound()); - inst.getResult(1).replaceAllUsesWith(newop.getResult()); - inst.erase(); - return success(); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto bty = gi.getOutputBundle().getType(); + auto newop = rewriter.create( + gi.op.getLoc(), bty.getElementType(size_t{0}), + bty.getElementType(size_t{1}), gi.getParamValue("FORMAT")); + rewriter.replaceOpWithNewOp( + gi.op, bty, ValueRange({newop.getFound(), newop.getResult()})); } }; -class CirctClockGateConverter : public IntrinsicConverter { +class CirctClockGateConverter + : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(3) || namedPort(0, "in") || namedPort(1, "en") || - namedPort(2, "out") || typedPort(0) || - sizedPort(1, 1) || typedPort(2) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto in = builder.create(inst.getResult(0).getType()).getResult(); - auto en = builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(in); - inst.getResult(1).replaceAllUsesWith(en); - auto out = builder.create(in, en, Value{}); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + if (gi.op.getNumOperands() == 3) { + return gi.typedInput(0) || gi.sizedInput(1, 1) || + gi.sizedInput(2, 1) || gi.typedOutput() || + gi.hasNParam(0); + } + if (gi.op.getNumOperands() == 2) { + return gi.typedInput(0) || gi.sizedInput(1, 1) || + gi.typedOutput() || gi.hasNParam(0); + } + gi.emitError() << " has " << gi.op.getNumOperands() + << " ports instead of 3 or 4"; + return true; } }; -class CirctClockInverterConverter : public IntrinsicConverter { +class CirctClockInverterConverter + : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "in") || namedPort(1, "out") || - typedPort(0) || typedPort(1) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto in = builder.create(inst.getResult(0).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(in); - auto out = builder.create(in); - auto name = inst.getInstanceName(); - Value outWire = builder.create(out.getType(), name).getResult(); - builder.create(outWire, out); - inst.getResult(1).replaceAllUsesWith(outWire); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.typedInput(0) || + gi.typedOutput() || gi.hasNParam(0); } }; @@ -173,367 +113,80 @@ class CirctClockDividerConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "in") || namedPort(1, "out") || - hasNParam(1) || namedIntParam("POW_2"); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.typedInput(0) || + gi.typedOutput() || gi.hasNParam(1) || + gi.namedIntParam("POW_2"); } - LogicalResult convert(InstanceOp inst) override { - auto pow2 = getNamedParam(mod.getParameters(), "POW_2") - .getValue() - .cast() - .getValue() - .getZExtValue(); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto pow2 = + gi.getParamValue("POW_2").getValue().getZExtValue(); - auto pow2Attr = - IntegerAttr::get(IntegerType::get(mod.getContext(), 64), pow2); + auto pow2Attr = rewriter.getI64IntegerAttr(pow2); - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto in = builder.create(inst.getResult(0).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(in); - auto out = builder.create(in, pow2Attr); - auto name = inst.getInstanceName(); - Value outWire = builder.create(out.getType(), name).getResult(); - builder.create(outWire, out); - inst.getResult(1).replaceAllUsesWith(outWire); - inst.erase(); - return success(); + rewriter.replaceOpWithNewOp( + gi.op, adaptor.getOperands()[0], pow2Attr); } }; -class EICGWrapperToClockGateConverter : public IntrinsicConverter { +template +class CirctLTLBinaryConverter : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - if (!AnnotationSet(mod).empty()) { - mod.emitError(name) - << " cannot have annotations since it is an intrinsic"; - return true; - } - if (mod.getPorts().size() == 4) { - return namedPort(0, "in") || namedPort(1, "test_en") || - namedPort(2, "en") || namedPort(3, "out") || - typedPort(0) || sizedPort(1, 1) || - sizedPort(2, 1) || typedPort(3) || - hasNParam(0); - } - if (mod.getPorts().size() == 3) { - return namedPort(0, "in") || namedPort(1, "en") || namedPort(2, "out") || - typedPort(0) || sizedPort(1, 1) || - typedPort(2) || hasNParam(0); - } - mod.emitError(name) << " has " << mod.getPorts().size() - << " ports instead of 3 or 4"; - return true; - } - - LogicalResult convert(InstanceOp inst) override { - if (!AnnotationSet(inst).empty()) - return inst.emitError(name) - << " instance cannot have annotations since it is an intrinsic"; - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - if (mod.getPorts().size() == 4) { - // Ports: in, test_en, en, out - auto in = builder.create(inst.getResult(0).getType()).getResult(); - auto testEn = - builder.create(inst.getResult(1).getType()).getResult(); - auto en = builder.create(inst.getResult(2).getType()).getResult(); - auto out = builder.create(in, en, testEn); - inst.getResult(0).replaceAllUsesWith(in); - inst.getResult(1).replaceAllUsesWith(testEn); - inst.getResult(2).replaceAllUsesWith(en); - inst.getResult(3).replaceAllUsesWith(out); - } else { - // Ports: in, en, out - auto in = builder.create(inst.getResult(0).getType()).getResult(); - auto en = builder.create(inst.getResult(1).getType()).getResult(); - auto out = builder.create(in, en, Value{}); - inst.getResult(0).replaceAllUsesWith(in); - inst.getResult(1).replaceAllUsesWith(en); - inst.getResult(2).replaceAllUsesWith(out); - } - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(2) || gi.sizedInput(0, 1) || + gi.sizedInput(1, 1) || gi.sizedOutput(1) || + gi.hasNParam(0); } }; -template -class CirctMuxCellConverter : public IntrinsicConverter { -private: - static constexpr unsigned portNum = isMux2 ? 4 : 6; - +template +class CirctLTLUnaryConverter : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - if (hasNPorts(portNum) || namedPort(0, "sel") || typedPort(0)) { - return true; - } - if (isMux2) { - if (namedPort(1, "high") || namedPort(2, "low") || namedPort(3, "out")) - return true; - } else { - if (namedPort(1, "v3") || namedPort(2, "v2") || namedPort(3, "v1") || - namedPort(4, "v0") || namedPort(5, "out")) - return true; - } - return false; - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - SmallVector operands; - operands.reserve(portNum - 1); - for (unsigned i = 0; i < portNum - 1; i++) { - auto v = builder.create(inst.getResult(i).getType()).getResult(); - operands.push_back(v); - inst.getResult(i).replaceAllUsesWith(v); - } - Value out; - if (isMux2) - out = builder.create(operands); - else - out = builder.create(operands); - inst.getResult(portNum - 1).replaceAllUsesWith(out); - inst.erase(); - return success(); - } -}; - -class CirctLTLAndConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(3) || namedPort(0, "lhs") || namedPort(1, "rhs") || - namedPort(2, "out") || sizedPort(0, 1) || - sizedPort(1, 1) || sizedPort(2, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto lhs = builder.create(inst.getResult(0).getType()).getResult(); - auto rhs = builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(lhs); - inst.getResult(1).replaceAllUsesWith(rhs); - auto out = builder.create(lhs.getType(), lhs, rhs); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); - } -}; - -class CirctLTLOrConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(3) || namedPort(0, "lhs") || namedPort(1, "rhs") || - namedPort(2, "out") || sizedPort(0, 1) || - sizedPort(1, 1) || sizedPort(2, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto lhs = builder.create(inst.getResult(0).getType()).getResult(); - auto rhs = builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(lhs); - inst.getResult(1).replaceAllUsesWith(rhs); - auto out = builder.create(lhs.getType(), lhs, rhs); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.sizedInput(0, 1) || + gi.sizedOutput(1) || gi.hasNParam(0); } }; class CirctLTLDelayConverter : public IntrinsicConverter { public: - CirctLTLDelayConverter(StringRef name, FModuleLike mod) - : IntrinsicConverter(name, mod) { - auto getI64Attr = [&](int64_t value) { - return IntegerAttr::get(IntegerType::get(mod.getContext(), 64), value); + using IntrinsicConverter::IntrinsicConverter; + + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.sizedInput(0, 1) || + gi.sizedOutput(1) || gi.hasNParam(1, 1) || + gi.namedIntParam("delay") || gi.namedIntParam("length", true); + } + + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto getI64Attr = [&](IntegerAttr val) { + if (!val) + return IntegerAttr(); + return rewriter.getI64IntegerAttr(val.getValue().getZExtValue()); }; - - auto params = mod.getParameters(); - delay = getI64Attr(params[0] - .cast() - .getValue() - .cast() - .getValue() - .getZExtValue()); - - if (params.size() >= 2) - if (auto lengthDecl = cast(params[1])) - length = getI64Attr( - cast(lengthDecl.getValue()).getValue().getZExtValue()); - } - - bool check() override { - return hasNPorts(2) || namedPort(0, "in") || namedPort(1, "out") || - sizedPort(0, 1) || sizedPort(1, 1) || - hasNParam(1, 2) || namedIntParam("delay") || - namedIntParam("length", true); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto in = builder.create(inst.getResult(0).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(in); - auto out = - builder.create(in.getType(), in, delay, length); - inst.getResult(1).replaceAllUsesWith(out); - inst.erase(); - return success(); - } - -private: - IntegerAttr length; - IntegerAttr delay; -}; - -class CirctLTLConcatConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(3) || namedPort(0, "lhs") || namedPort(1, "rhs") || - namedPort(2, "out") || sizedPort(0, 1) || - sizedPort(1, 1) || sizedPort(2, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto lhs = builder.create(inst.getResult(0).getType()).getResult(); - auto rhs = builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(lhs); - inst.getResult(1).replaceAllUsesWith(rhs); - auto out = builder.create(lhs.getType(), lhs, rhs); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); + auto delay = getI64Attr(gi.getParamValue("delay")); + auto length = getI64Attr(gi.getParamValue("length")); + rewriter.replaceOpWithNewOp( + gi.op, gi.op.getResultTypes(), adaptor.getOperands()[0], delay, length); } }; -class CirctLTLNotConverter : public IntrinsicConverter { +class CirctLTLClockConverter + : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "in") || namedPort(1, "out") || - sizedPort(0, 1) || sizedPort(1, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto input = - builder.create(inst.getResult(0).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(input); - auto out = builder.create(input.getType(), input); - inst.getResult(1).replaceAllUsesWith(out); - inst.erase(); - return success(); - } -}; - -class CirctLTLImplicationConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(3) || namedPort(0, "lhs") || namedPort(1, "rhs") || - namedPort(2, "out") || sizedPort(0, 1) || - sizedPort(1, 1) || sizedPort(2, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto lhs = builder.create(inst.getResult(0).getType()).getResult(); - auto rhs = builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(lhs); - inst.getResult(1).replaceAllUsesWith(rhs); - auto out = - builder.create(lhs.getType(), lhs, rhs); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); - } -}; - -class CirctLTLEventuallyConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(2) || namedPort(0, "in") || namedPort(1, "out") || - sizedPort(0, 1) || sizedPort(1, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto input = - builder.create(inst.getResult(0).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(input); - auto out = builder.create(input.getType(), input); - inst.getResult(1).replaceAllUsesWith(out); - inst.erase(); - return success(); - } -}; - -class CirctLTLClockConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(3) || namedPort(0, "in") || namedPort(1, "clock") || - namedPort(2, "out") || sizedPort(0, 1) || - typedPort(1) || sizedPort(2, 1) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto in = builder.create(inst.getResult(0).getType()).getResult(); - auto clock = - builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(in); - inst.getResult(1).replaceAllUsesWith(clock); - auto out = builder.create(in.getType(), in, clock); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); - } -}; - -class CirctLTLDisableConverter : public IntrinsicConverter { -public: - using IntrinsicConverter::IntrinsicConverter; - - bool check() override { - return hasNPorts(3) || namedPort(0, "in") || namedPort(1, "condition") || - namedPort(2, "out") || sizedPort(0, 1) || - sizedPort(1, 1) || sizedPort(2, 1) || - hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto in = builder.create(inst.getResult(0).getType()).getResult(); - auto condition = - builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(in); - inst.getResult(1).replaceAllUsesWith(condition); - auto out = - builder.create(in.getType(), in, condition); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(2) || gi.sizedInput(0, 1) || + gi.typedInput(1) || gi.sizedOutput(1) || + gi.hasNParam(0); } }; @@ -542,194 +195,144 @@ class CirctVerifConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return hasNPorts(1) || namedPort(0, "property") || - sizedPort(0, 1) || hasNParam(0, 1) || - namedParam("label", true); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(1) || gi.sizedInput(0, 1) || + gi.hasNParam(0, 1) || gi.namedParam("label", true) || + gi.hasNoOutput(); } - LogicalResult convert(InstanceOp inst) override { - auto params = mod.getParameters(); - StringAttr label; - if (!params.empty()) - if (auto labelDecl = cast(params[0])) - label = cast(labelDecl.getValue()); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto label = gi.getParamValue("label"); - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto property = - builder.create(inst.getResult(0).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(property); - builder.create(property, label); - inst.erase(); - return success(); + rewriter.replaceOpWithNewOp(gi.op, adaptor.getOperands()[0], label); } }; -class CirctHasBeenResetConverter : public IntrinsicConverter { +class CirctMux2CellConverter + : public IntrinsicOpConverter { + using IntrinsicOpConverter::IntrinsicOpConverter; + + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(3) || gi.typedInput(0) || gi.hasNParam(0) || + gi.hasOutput(); + } +}; + +class CirctMux4CellConverter + : public IntrinsicOpConverter { + using IntrinsicOpConverter::IntrinsicOpConverter; + + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(5) || gi.typedInput(0) || gi.hasNParam(0) || + gi.hasOutput(); + } +}; + +class CirctHasBeenResetConverter + : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(3) || namedPort(0, "clock") || namedPort(1, "reset") || - namedPort(2, "out") || typedPort(0) || resetPort(1) || - sizedPort(2, 1) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto clock = - builder.create(inst.getResult(0).getType()).getResult(); - auto reset = - builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(clock); - inst.getResult(1).replaceAllUsesWith(reset); - auto out = builder.create(clock, reset); - inst.getResult(2).replaceAllUsesWith(out); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(2) || gi.typedInput(0) || + gi.hasResetInput(1) || gi.sizedOutput(1) || + gi.hasNParam(0); } }; -class CirctProbeConverter : public IntrinsicConverter { +class CirctProbeConverter : public IntrinsicOpConverter { public: - using IntrinsicConverter::IntrinsicConverter; + using IntrinsicOpConverter::IntrinsicOpConverter; - bool check() override { - return hasNPorts(2) || namedPort(0, "data") || namedPort(1, "clock") || - typedPort(1) || hasNParam(0); - } - - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto clock = - builder.create(inst.getResult(0).getType()).getResult(); - auto input = - builder.create(inst.getResult(1).getType()).getResult(); - inst.getResult(0).replaceAllUsesWith(clock); - inst.getResult(1).replaceAllUsesWith(input); - builder.create(clock, input); - inst.erase(); - return success(); + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(2) || gi.typedInput(1) || gi.hasNParam(0) || + gi.hasNoOutput(); } }; -} // namespace - -// Replace range of values with new wires and return them. -template -static SmallVector replaceResults(OpBuilder &b, R &&range) { - return llvm::map_to_vector(range, [&b](auto v) { - auto w = b.create(v.getLoc(), v.getType()).getResult(); - v.replaceAllUsesWith(w); - return w; - }); -} - -// Check ports are all inputs, emit diagnostic if not. -static ParseResult allInputs(ArrayRef ports) { - for (auto &p : ports) { - if (p.direction != Direction::In) - return mlir::emitError(p.loc, "expected input port"); - } - return success(); -} - -namespace { - template class CirctAssertConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return namedPort(0, "clock") || typedPort(0) || - namedPort(1, "predicate") || sizedPort(1, 1) || - namedPort(2, "enable") || sizedPort(2, 1) || - namedParam("format", /*optional=*/true) || - namedParam("label", /*optional=*/true) || - namedParam("guards", /*optional=*/true) || allInputs(mod.getPorts()); - // TODO: Check all parameters accounted for. + bool check(GenericIntrinsic gi) override { + return gi.typedInput(0) || gi.sizedInput(1, 1) || + gi.sizedInput(2, 1) || gi.hasNParam(0, 3) || + gi.namedParam("format", /*optional=*/true) || + gi.namedParam("label", /*optional=*/true) || + gi.namedParam("guards", /*optional=*/true) || gi.hasNoOutput(); } - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto params = mod.getParameters(); - auto format = getNamedParam(params, "format"); - auto label = getNamedParam(params, "label"); - auto guards = getNamedParam(params, "guards"); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto format = gi.getParamValue("format"); + auto label = gi.getParamValue("label"); + auto guards = gi.getParamValue("guards"); - auto wires = replaceResults(builder, inst.getResults()); + auto clock = adaptor.getOperands()[0]; + auto predicate = adaptor.getOperands()[1]; + auto enable = adaptor.getOperands()[2]; - auto clock = wires[0]; - auto predicate = wires[1]; - auto enable = wires[2]; - - auto substitutions = ArrayRef(wires).drop_front(3); - auto name = label ? cast(label.getValue()).strref() : ""; + auto substitutions = adaptor.getOperands().drop_front(3); + auto name = label ? label.strref() : ""; // Message is not optional, so provide empty string if not present. - auto message = format ? cast(format.getValue()) - : builder.getStringAttr(""); - auto op = builder.template create(clock, predicate, enable, message, - substitutions, name, - /*isConcurrent=*/true); + auto message = format ? format : rewriter.getStringAttr(""); + auto op = rewriter.template replaceOpWithNewOp( + gi.op, clock, predicate, enable, message, substitutions, name, + /*isConcurrent=*/true); if (guards) { SmallVector guardStrings; - cast(guards.getValue()).strref().split(guardStrings, ';'); - // TODO: Legalize / sanity-check? - op->setAttr("guards", builder.getStrArrayAttr(guardStrings)); + guards.strref().split(guardStrings, ';', /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + rewriter.startOpModification(op); + op->setAttr("guards", rewriter.getStrArrayAttr(guardStrings)); + rewriter.finalizeOpModification(op); } - if constexpr (ifElseFatal) - op->setAttr("format", builder.getStringAttr("ifElseFatal")); - - inst.erase(); - return success(); + if constexpr (ifElseFatal) { + rewriter.startOpModification(op); + op->setAttr("format", rewriter.getStringAttr("ifElseFatal")); + rewriter.finalizeOpModification(op); + } } - -private: }; class CirctCoverConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return namedPort(0, "clock") || typedPort(0) || - namedPort(1, "predicate") || sizedPort(1, 1) || - namedPort(2, "enable") || sizedPort(2, 1) || - hasNPorts(3) || allInputs(mod.getPorts()) || - namedParam("label", /*optional=*/true) || - namedParam("guards", /*optional=*/true); - // TODO: Check all parameters accounted for. + bool check(GenericIntrinsic gi) override { + return gi.hasNInputs(3) || gi.hasNoOutput() || + gi.typedInput(0) || gi.sizedInput(1, 1) || + gi.sizedInput(2, 1) || gi.hasNParam(0, 2) || + gi.namedParam("label", /*optional=*/true) || + gi.namedParam("guards", /*optional=*/true); } - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto params = mod.getParameters(); - auto label = getNamedParam(params, "label"); - auto guards = getNamedParam(params, "guards"); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto label = gi.getParamValue("label"); + auto guards = gi.getParamValue("guards"); - auto wires = replaceResults(builder, inst.getResults()); - - auto clock = wires[0]; - auto predicate = wires[1]; - auto enable = wires[2]; - - auto name = label ? cast(label.getValue()).strref() : ""; + auto clock = adaptor.getOperands()[0]; + auto predicate = adaptor.getOperands()[1]; + auto enable = adaptor.getOperands()[2]; + auto name = label ? label.strref() : ""; // Empty message string for cover, only 'name' / label. - auto op = builder.create(clock, predicate, enable, - builder.getStringAttr(""), ValueRange{}, - name, /*isConcurrent=*/true); + auto message = rewriter.getStringAttr(""); + auto op = rewriter.replaceOpWithNewOp( + gi.op, clock, predicate, enable, message, ValueRange{}, name, + /*isConcurrent=*/true); if (guards) { SmallVector guardStrings; - cast(guards.getValue()).strref().split(guardStrings, ';'); - // TODO: Legalize / sanity-check? - op->setAttr("guards", builder.getStrArrayAttr(guardStrings)); + guards.strref().split(guardStrings, ';', /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + rewriter.startOpModification(op); + op->setAttr("guards", rewriter.getStrArrayAttr(guardStrings)); + rewriter.finalizeOpModification(op); } - - inst.erase(); - return success(); } }; @@ -737,47 +340,36 @@ class CirctUnclockedAssumeConverter : public IntrinsicConverter { public: using IntrinsicConverter::IntrinsicConverter; - bool check() override { - return namedPort(0, "predicate") || sizedPort(0, 1) || - namedPort(1, "enable") || sizedPort(1, 1) || - allInputs(mod.getPorts()) || - namedParam("format", /*optional=*/true) || - namedParam("label", /*optional=*/true) || - namedParam("guards", /*optional=*/true); - // TODO: Check all parameters accounted for. + bool check(GenericIntrinsic gi) override { + return gi.sizedInput(0, 1) || gi.sizedInput(1, 1) || + gi.hasNParam(0, 3) || gi.namedParam("format", /*optional=*/true) || + gi.namedParam("label", /*optional=*/true) || + gi.namedParam("guards", /*optional=*/true) || gi.hasNoOutput(); } - LogicalResult convert(InstanceOp inst) override { - ImplicitLocOpBuilder builder(inst.getLoc(), inst); - auto params = mod.getParameters(); - auto format = getNamedParam(params, "format"); - auto label = getNamedParam(params, "label"); - auto guards = getNamedParam(params, "guards"); + void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, + PatternRewriter &rewriter) override { + auto format = gi.getParamValue("format"); + auto label = gi.getParamValue("label"); + auto guards = gi.getParamValue("guards"); - auto wires = replaceResults(builder, inst.getResults()); - - auto predicate = wires[0]; - auto enable = wires[1]; - - auto substitutions = ArrayRef(wires).drop_front(2); - auto name = label ? cast(label.getValue()).strref() : ""; + auto predicate = adaptor.getOperands()[0]; + auto enable = adaptor.getOperands()[1]; + auto substitutions = adaptor.getOperands().drop_front(2); + auto name = label ? label.strref() : ""; // Message is not optional, so provide empty string if not present. - auto message = format ? cast(format.getValue()) - : builder.getStringAttr(""); - - auto op = builder.template create( - predicate, enable, message, substitutions, name); - + auto message = format ? format : rewriter.getStringAttr(""); + auto op = rewriter.template replaceOpWithNewOp( + gi.op, predicate, enable, message, substitutions, name); if (guards) { SmallVector guardStrings; - cast(guards.getValue()).strref().split(guardStrings, ';'); - // TODO: Legalize / sanity-check? - op->setAttr("guards", builder.getStrArrayAttr(guardStrings)); + guards.strref().split(guardStrings, ';', /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + rewriter.startOpModification(op); + op->setAttr("guards", rewriter.getStrArrayAttr(guardStrings)); + rewriter.finalizeOpModification(op); } - - inst.erase(); - return success(); } }; @@ -789,14 +381,17 @@ public: namespace { struct LowerIntrinsicsPass : public LowerIntrinsicsBase { + LogicalResult initialize(MLIRContext *context) override; void runOnOperation() override; - using LowerIntrinsicsBase::fixupEICGWrapper; + + std::shared_ptr lowering; }; } // namespace -// This is the main entrypoint for the lowering pass. -void LowerIntrinsicsPass::runOnOperation() { - IntrinsicLowerings lowering(&getContext(), getAnalysis()); +/// Initialize the conversions for use during execution. +LogicalResult LowerIntrinsicsPass::initialize(MLIRContext *context) { + IntrinsicLowerings lowering(context); + lowering.add("circt.sizeof", "circt_sizeof"); lowering.add("circt.isX", "circt_isX"); lowering.add("circt.plusargs.test", @@ -808,27 +403,32 @@ void LowerIntrinsicsPass::runOnOperation() { "circt_clock_inv"); lowering.add("circt.clock_div", "circt_clock_div"); - lowering.add("circt.ltl.and", "circt_ltl_and"); - lowering.add("circt.ltl.or", "circt_ltl_or"); + lowering.add>("circt.ltl.and", + "circt_ltl_and"); + lowering.add>("circt.ltl.or", + "circt_ltl_or"); + lowering.add>( + "circt.ltl.concat", "circt_ltl_concat"); + lowering.add>( + "circt.ltl.implication", "circt_ltl_implication"); + lowering.add>( + "circt.ltl.disable", "circt_ltl_disable"); + lowering.add>("circt.ltl.not", + "circt_ltl_not"); + lowering.add>( + "circt.ltl.eventually", "circt_ltl_eventually"); + lowering.add("circt.ltl.delay", "circt_ltl_delay"); - lowering.add("circt.ltl.concat", "circt_ltl_concat"); - lowering.add("circt.ltl.not", "circt_ltl_not"); - lowering.add("circt.ltl.implication", - "circt_ltl_implication"); - lowering.add("circt.ltl.eventually", - "circt_ltl_eventually"); lowering.add("circt.ltl.clock", "circt_ltl_clock"); - lowering.add("circt.ltl.disable", - "circt_ltl_disable"); + lowering.add>( "circt.verif.assert", "circt_verif_assert"); lowering.add>( "circt.verif.assume", "circt_verif_assume"); lowering.add>("circt.verif.cover", "circt_verif_cover"); - lowering.add>("circt.mux2cell", "circt_mux2cell"); - lowering.add>("circt.mux4cell", - "circt_mux4cell"); + lowering.add("circt.mux2cell", "circt_mux2cell"); + lowering.add("circt.mux4cell", "circt_mux4cell"); lowering.add("circt.has_been_reset", "circt_has_been_reset"); lowering.add("circt.fpga_probe", "circt_fpga_probe"); @@ -842,20 +442,17 @@ void LowerIntrinsicsPass::runOnOperation() { lowering.add("circt.unclocked_assume", "circt_unclocked_assume"); - // Remove this once `EICG_wrapper` is no longer special-cased by firtool. - if (fixupEICGWrapper) - lowering.addExtmod("EICG_wrapper"); + this->lowering = std::make_shared(std::move(lowering)); + return success(); +} - if (failed(lowering.lower(getOperation()))) +// This is the main entrypoint for the lowering pass. +void LowerIntrinsicsPass::runOnOperation() { + if (failed(lowering->lower(getOperation()))) return signalPassFailure(); - if (!lowering.getNumConverted()) - markAllAnalysesPreserved(); } /// This is the pass constructor. -std::unique_ptr -circt::firrtl::createLowerIntrinsicsPass(bool fixupEICGWrapper) { - auto pass = std::make_unique(); - pass->fixupEICGWrapper = fixupEICGWrapper; - return pass; +std::unique_ptr circt::firrtl::createLowerIntrinsicsPass() { + return std::make_unique(); } diff --git a/lib/Firtool/Firtool.cpp b/lib/Firtool/Firtool.cpp index f71ae28ce6..74816437b7 100644 --- a/lib/Firtool/Firtool.cpp +++ b/lib/Firtool/Firtool.cpp @@ -40,7 +40,9 @@ LogicalResult firtool::populatePreprocessTransforms(mlir::PassManager &pm, firrtl::createMaterializeDebugInfoPass()); pm.nest().addPass( - firrtl::createLowerIntrinsicsPass(opt.shouldFixupEICGWrapper())); + firrtl::createLowerIntmodulesPass(opt.shouldFixupEICGWrapper())); + pm.nest().nest().addPass( + firrtl::createLowerIntrinsicsPass()); return success(); } diff --git a/test/Dialect/FIRRTL/lower-intrinsics-errors.mlir b/test/Dialect/FIRRTL/lower-intrinsics-errors.mlir index b59ec30fb3..0af1adf557 100644 --- a/test/Dialect/FIRRTL/lower-intrinsics-errors.mlir +++ b/test/Dialect/FIRRTL/lower-intrinsics-errors.mlir @@ -1,20 +1,22 @@ -// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-intrinsics{fixup-eicg-wrapper}))' --split-input-file --verify-diagnostics %s +// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl.module(firrtl-lower-intrinsics)))' -verify-diagnostics --split-input-file %s -firrtl.circuit "EICGWithInstAnno" { - firrtl.extmodule @EICG_wrapper(in in: !firrtl.clock, in test_en: !firrtl.uint<1>, in en: !firrtl.uint<1>, out out: !firrtl.clock) attributes {defname = "EICG_wrapper"} - hw.hierpath private @nla [@EICGWithInstAnno::@ckg, @EICG_wrapper] - firrtl.module @EICGWithInstAnno(in %clock: !firrtl.clock, in %en: !firrtl.uint<1>) { - // expected-error @below {{EICG_wrapper instance cannot have annotations since it is an intrinsic}} - firrtl.instance ckg sym @ckg {annotations = [{circt.nonlocal = @nla, class = "DummyA"}]} @EICG_wrapper(in in: !firrtl.clock, in test_en: !firrtl.uint<1>, in en: !firrtl.uint<1>, out out: !firrtl.clock) +firrtl.circuit "UnknownIntrinsic" { + firrtl.module private @UnknownIntrinsic(in %data: !firrtl.uint<32>) { + %0 = firrtl.wire : !firrtl.uint<32> + // expected-error @below {{unknown intrinsic}} + // expected-error @below {{failed to legalize}} + firrtl.int.generic "unknown_intrinsic" %0 : (!firrtl.uint<32>) -> () + firrtl.strictconnect %0, %data : !firrtl.uint<32> } } // ----- -firrtl.circuit "EICGWithModuleAnno" { - // expected-error @below {{EICG_wrapper cannot have annotations since it is an intrinsic}} - firrtl.extmodule @EICG_wrapper(in in: !firrtl.clock, in test_en: !firrtl.uint<1>, in en: !firrtl.uint<1>, out out: !firrtl.clock) attributes {defname = "EICG_wrapper", annotations = [{class = "DummyA"}]} - firrtl.module @EICGWithModuleAnno(in %clock: !firrtl.clock, in %en: !firrtl.uint<1>) { - firrtl.instance ckg @EICG_wrapper(in in: !firrtl.clock, in test_en: !firrtl.uint<1>, in en: !firrtl.uint<1>, out out: !firrtl.clock) - } +firrtl.circuit "InvalidCGOperand" { + firrtl.module @InvalidCGOperand(in %clk: !firrtl.clock, in %en: !firrtl.uint<2>) { + // expected-error @below {{circt.clock_gate input 1 not size 1}} + // expected-error @below {{failed to legalize}} + %0 = firrtl.int.generic "circt.clock_gate" %clk, %en : (!firrtl.clock, !firrtl.uint<2>) -> !firrtl.clock + } } + diff --git a/test/Dialect/FIRRTL/lower-intrinsics-unknown.mlir b/test/Dialect/FIRRTL/lower-intrinsics-unknown.mlir deleted file mode 100644 index 4df24d793a..0000000000 --- a/test/Dialect/FIRRTL/lower-intrinsics-unknown.mlir +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-lower-intrinsics{fixup-eicg-wrapper}))' -verify-diagnostics %s - -firrtl.circuit "UnknownIntrinsic" { - // expected-error @below {{intrinsic not recognized}} - firrtl.intmodule private @UnknownIntrinsicMod(in data: !firrtl.uint<32>) attributes {intrinsic = "unknown_intrinsic"} - - firrtl.module private @UnknownIntrinsic(in %data : !firrtl.uint<32>) { - %mod_data = firrtl.instance mod @UnknownIntrinsicMod(in data: !firrtl.uint<32>) - firrtl.strictconnect %mod_data, %data : !firrtl.uint<32> - } -} diff --git a/test/Dialect/FIRRTL/lower-intrinsics.mlir b/test/Dialect/FIRRTL/lower-intrinsics.mlir index 3356990450..c1b0d2daf5 100644 --- a/test/Dialect/FIRRTL/lower-intrinsics.mlir +++ b/test/Dialect/FIRRTL/lower-intrinsics.mlir @@ -1,354 +1,146 @@ -// 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 +// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl.module(firrtl-lower-intrinsics)))' %s | FileCheck %s --check-prefixes=CHECK --implicit-check-not firrtl.int.generic // CHECK-LABEL: "Foo" firrtl.circuit "Foo" { - // CHECK-NOT: NameDoesNotMatter5 - firrtl.intmodule @NameDoesNotMatter5(in i : !firrtl.clock, out size : !firrtl.uint<32>) attributes - {intrinsic = "circt.sizeof"} - // CHECK-NOT: NameDoesNotMatter6 - firrtl.intmodule @NameDoesNotMatter6(in i : !firrtl.clock, out found : !firrtl.uint<1>) attributes - {intrinsic = "circt.isX"} - // CHECK-NOT: NameDoesNotMatter7 - firrtl.intmodule @NameDoesNotMatter7(out found : !firrtl.uint<1>) attributes - {intrinsic = "circt.plusargs.test"} - // CHECK-NOT: NameDoesNotMatter8 - firrtl.intmodule @NameDoesNotMatter8(out found : !firrtl.uint<1>, out result: !firrtl.uint<5>) attributes - {intrinsic = "circt.plusargs.value"} - - // CHECK: Foo + // CHECK-LABEL: @Foo firrtl.module @Foo(in %clk : !firrtl.clock, out %s : !firrtl.uint<32>, out %io1 : !firrtl.uint<1>, out %io2 : !firrtl.uint<1>, out %io3 : !firrtl.uint<1>, out %io4 : !firrtl.uint<5>) { - %i1, %size = firrtl.instance "" @NameDoesNotMatter5(in i : !firrtl.clock, out size : !firrtl.uint<32>) - // CHECK-NOT: NameDoesNotMatter5 - // CHECK: firrtl.int.sizeof - firrtl.strictconnect %i1, %clk : !firrtl.clock + // CHECK: firrtl.int.sizeof %clk + %size = firrtl.int.generic "circt.sizeof" %clk : (!firrtl.clock) -> !firrtl.uint<32> firrtl.strictconnect %s, %size : !firrtl.uint<32> - %i2, %found2 = firrtl.instance "" @NameDoesNotMatter6(in i : !firrtl.clock, out found : !firrtl.uint<1>) - // CHECK-NOT: NameDoesNotMatter6 // CHECK: firrtl.int.isX - firrtl.strictconnect %i2, %clk : !firrtl.clock - firrtl.strictconnect %io1, %found2 : !firrtl.uint<1> + %isX = firrtl.int.generic "circt.isX" %clk : (!firrtl.clock) -> !firrtl.uint<1> + firrtl.strictconnect %io1, %isX : !firrtl.uint<1> - %found3 = firrtl.instance "" @NameDoesNotMatter7(out found : !firrtl.uint<1>) - // CHECK-NOT: NameDoesNotMatter7 // CHECK: firrtl.int.plusargs.test "foo" - firrtl.strictconnect %io2, %found3 : !firrtl.uint<1> + %foo = firrtl.int.generic "circt.plusargs.test" : () -> !firrtl.uint<1> + firrtl.strictconnect %io2, %foo : !firrtl.uint<1> - %found4, %result1 = firrtl.instance "" @NameDoesNotMatter8(out found : !firrtl.uint<1>, out result: !firrtl.uint<5>) - // CHECK-NOT: NameDoesNotMatter8 // CHECK: firrtl.int.plusargs.value "foo" : !firrtl.uint<5> - firrtl.strictconnect %io3, %found4 : !firrtl.uint<1> - firrtl.strictconnect %io4, %result1 : !firrtl.uint<5> + %pav = firrtl.int.generic "circt.plusargs.value" : () -> !firrtl.bundle, result: uint<5>> + %found = firrtl.subfield %pav[found] : !firrtl.bundle, result: uint<5>> + %result = firrtl.subfield %pav[result] : !firrtl.bundle, result: uint<5>> + firrtl.strictconnect %io3, %found : !firrtl.uint<1> + firrtl.strictconnect %io4, %result : !firrtl.uint<5> } - - // CHECK-NOT: ClockGate1 - firrtl.intmodule @ClockGate1(in in: !firrtl.clock, in en: !firrtl.uint<1>, out out: !firrtl.clock) attributes {intrinsic = "circt.clock_gate"} - - // CHECK: ClockGate + // CHECK-LABEL: @ClockGate firrtl.module @ClockGate(in %clk: !firrtl.clock, in %en: !firrtl.uint<1>) { - // CHECK-NOT: ClockGate1 - // CHECK: firrtl.int.clock_gate - %in2, %en2, %out2 = firrtl.instance "" @ClockGate1(in in: !firrtl.clock, in en: !firrtl.uint<1>, out out: !firrtl.clock) - firrtl.strictconnect %in2, %clk : !firrtl.clock - firrtl.strictconnect %en2, %en : !firrtl.uint<1> + // CHECK-NEXT: firrtl.int.clock_gate %clk, %en + firrtl.int.generic "circt.clock_gate" %clk, %en : (!firrtl.clock, !firrtl.uint<1>) -> !firrtl.clock + // CHECK-NEXT: firrtl.int.clock_gate %clk, %en, %en + firrtl.int.generic "circt.clock_gate" %clk, %en, %en : (!firrtl.clock, !firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.clock } - // CHECK-NOT: ClockInverter1 - firrtl.intmodule @ClockInverter1(in in: !firrtl.clock, out out: !firrtl.clock) attributes {intrinsic = "circt.clock_inv"} - - // CHECK: ClockInverter + // CHECK-LABEL: @ClockInverter firrtl.module @ClockInverter(in %clk: !firrtl.clock) { - // CHECK-NOT: ClockInverter1 - // CHECK: firrtl.int.clock_inv - %in2, %out2 = firrtl.instance "" @ClockInverter1(in in: !firrtl.clock, out out: !firrtl.clock) - firrtl.strictconnect %in2, %clk : !firrtl.clock + // CHECK-NEXT: firrtl.int.clock_inv %clk + firrtl.int.generic "circt.clock_inv" %clk : (!firrtl.clock) -> !firrtl.clock } - // CHECK-NOT: ClockDivider1 - firrtl.intmodule @ClockDivider1(in in: !firrtl.clock, out out: !firrtl.clock) attributes {intrinsic = "circt.clock_div"} - - // CHECK: ClockDivider + // CHECK-LABEL: @ClockDivider firrtl.module @ClockDivider(in %clk: !firrtl.clock) { - // CHECK-NOT: ClockDivider1 - // CHECK: firrtl.int.clock_div - %in2, %out2 = firrtl.instance "" @ClockDivider1(in in: !firrtl.clock, out out: !firrtl.clock) - firrtl.strictconnect %in2, %clk : !firrtl.clock + // CHECK-NEXT: firrtl.int.clock_div %clk by 8 + firrtl.int.generic "circt.clock_div" %clk : (!firrtl.clock) -> !firrtl.clock } - // CHECK-NOT: LTLAnd - // CHECK-NOT: LTLOr - // CHECK-NOT: LTLDelay1 - // CHECK-NOT: LTLDelay2 - // CHECK-NOT: LTLConcat - // CHECK-NOT: LTLNot - // CHECK-NOT: LTLImplication - // CHECK-NOT: LTLEventually - // CHECK-NOT: LTLClock - // CHECK-NOT: LTLDisable - firrtl.intmodule @LTLAnd(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.and"} - firrtl.intmodule @LTLOr(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.or"} - firrtl.intmodule @LTLDelay1(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.delay"} - firrtl.intmodule @LTLDelay2(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.delay"} - firrtl.intmodule @LTLConcat(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.concat"} - firrtl.intmodule @LTLNot(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.not"} - firrtl.intmodule @LTLImplication(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.implication"} - firrtl.intmodule @LTLEventually(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.eventually"} - firrtl.intmodule @LTLClock(in in: !firrtl.uint<1>, in clock: !firrtl.clock, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.clock"} - firrtl.intmodule @LTLDisable(in in: !firrtl.uint<1>, in condition: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.disable"} + // CHECK-LABEL: firrtl.module @LTL( + firrtl.module @LTL(in %in0 : !firrtl.uint<1>, in %in1 : !firrtl.uint<1>, in %clk : !firrtl.clock) { + // CHECK-NEXT: firrtl.int.ltl.and %in0, %in1 : + firrtl.int.generic "circt_ltl_and" %in0, %in1: (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> + // CHECK-NEXT: firrtl.int.ltl.or %in0, %in1 : + firrtl.int.generic "circt_ltl_or" %in0, %in1 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> - // CHECK: firrtl.module @LTL() - firrtl.module @LTL() { - // CHECK-NOT: LTLAnd - // CHECK-NOT: LTLOr - // CHECK: firrtl.int.ltl.and {{%.+}}, {{%.+}} : - // CHECK: firrtl.int.ltl.or {{%.+}}, {{%.+}} : - %and.lhs, %and.rhs, %and.out = firrtl.instance "and" @LTLAnd(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) - %or.lhs, %or.rhs, %or.out = firrtl.instance "or" @LTLOr(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) + // CHECK-NEXT: firrtl.int.ltl.delay %in0, 42 : + // CHECK-NEXT: firrtl.int.ltl.delay %in0, 42, 1337 : + firrtl.int.generic "circt_ltl_delay" %in0 : (!firrtl.uint<1>) -> !firrtl.uint<1> + firrtl.int.generic "circt_ltl_delay" %in0 : (!firrtl.uint<1>) -> !firrtl.uint<1> - // CHECK-NOT: LTLDelay1 - // CHECK-NOT: LTLDelay2 - // CHECK: firrtl.int.ltl.delay {{%.+}}, 42 : - // CHECK: firrtl.int.ltl.delay {{%.+}}, 42, 1337 : - %delay1.in, %delay1.out = firrtl.instance "delay1" @LTLDelay1(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) - %delay2.in, %delay2.out = firrtl.instance "delay2" @LTLDelay2(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) + // CHECK-NEXT: firrtl.int.ltl.concat %in0, %in1 : + // CHECK-NEXT: firrtl.int.ltl.not %in0 : + // CHECK-NEXT: firrtl.int.ltl.implication %in0, %in1 : + // CHECK-NEXT: firrtl.int.ltl.eventually %in0 : + firrtl.int.generic "circt_ltl_concat" %in0, %in1: (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> + firrtl.int.generic "circt_ltl_not" %in0 : (!firrtl.uint<1>) -> !firrtl.uint<1> + firrtl.int.generic "circt_ltl_implication" %in0, %in1 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> + firrtl.int.generic "circt_ltl_eventually" %in0 : (!firrtl.uint<1>) -> !firrtl.uint<1> - // CHECK-NOT: LTLConcat - // CHECK-NOT: LTLNot - // CHECK-NOT: LTLImplication - // CHECK-NOT: LTLEventually - // CHECK: firrtl.int.ltl.concat {{%.+}}, {{%.+}} : - // CHECK: firrtl.int.ltl.not {{%.+}} : - // CHECK: firrtl.int.ltl.implication {{%.+}}, {{%.+}} : - // CHECK: firrtl.int.ltl.eventually {{%.+}} : - %concat.lhs, %concat.rhs, %concat.out = firrtl.instance "concat" @LTLConcat(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) - %not.in, %not.out = firrtl.instance "not" @LTLNot(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) - %implication.lhs, %implication.rhs, %implication.out = firrtl.instance "implication" @LTLImplication(in lhs: !firrtl.uint<1>, in rhs: !firrtl.uint<1>, out out: !firrtl.uint<1>) - %eventually.in, %eventually.out = firrtl.instance "eventually" @LTLEventually(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) - - // CHECK-NOT: LTLClock - // CHECK: firrtl.int.ltl.clock {{%.+}}, {{%.+}} : - %clock.in, %clock.clock, %clock.out = firrtl.instance "clock" @LTLClock(in in: !firrtl.uint<1>, in clock: !firrtl.clock, out out: !firrtl.uint<1>) - - // CHECK-NOT: LTLDisable - // CHECK: firrtl.int.ltl.disable {{%.+}}, {{%.+}} : - %disable.in, %disable.condition, %disable.out = firrtl.instance "disable" @LTLDisable(in in: !firrtl.uint<1>, in condition: !firrtl.uint<1>, out out: !firrtl.uint<1>) + // CHECK-NEXT: firrtl.int.ltl.clock %in0, %clk : + firrtl.int.generic "circt_ltl_clock" %in0, %clk : (!firrtl.uint<1>, !firrtl.clock) -> !firrtl.uint<1> + // CHECK-NEXT: firrtl.int.ltl.disable %in0, %in1 : + firrtl.int.generic "circt_ltl_disable" %in0, %in1: (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<1> } - // CHECK-NOT: VerifAssert1 - // CHECK-NOT: VerifAssert2 - // CHECK-NOT: VerifAssume - // CHECK-NOT: VerifCover - firrtl.intmodule @VerifAssert1(in property: !firrtl.uint<1>) attributes {intrinsic = "circt.verif.assert"} - firrtl.intmodule @VerifAssert2(in property: !firrtl.uint<1>) attributes {intrinsic = "circt.verif.assert"} - firrtl.intmodule @VerifAssume(in property: !firrtl.uint<1>) attributes {intrinsic = "circt.verif.assume"} - firrtl.intmodule @VerifCover(in property: !firrtl.uint<1>) attributes {intrinsic = "circt.verif.cover"} - - // CHECK: firrtl.module @Verif() - firrtl.module @Verif() { - // CHECK-NOT: VerifAssert1 - // CHECK-NOT: VerifAssert2 - // CHECK-NOT: VerifAssume - // CHECK-NOT: VerifCover - // CHECK: firrtl.int.verif.assert {{%.+}} : - // CHECK: firrtl.int.verif.assert {{%.+}} {label = "hello"} : - // CHECK: firrtl.int.verif.assume {{%.+}} : - // CHECK: firrtl.int.verif.cover {{%.+}} : - %assert1.property = firrtl.instance "assert1" @VerifAssert1(in property: !firrtl.uint<1>) - %assert2.property = firrtl.instance "assert2" @VerifAssert2(in property: !firrtl.uint<1>) - %assume.property = firrtl.instance "assume" @VerifAssume(in property: !firrtl.uint<1>) - %cover.property = firrtl.instance "cover" @VerifCover(in property: !firrtl.uint<1>) + // CHECK-LABEL: firrtl.module @Verif( + firrtl.module @Verif(in %in : !firrtl.uint<1>) { + // CHECK-NEXT: firrtl.int.verif.assert %in : + // CHECK-NEXT: firrtl.int.verif.assert %in {label = "hello"} : + // CHECK-NEXT: firrtl.int.verif.assume %in : + // CHECK-NEXT: firrtl.int.verif.cover %in : + firrtl.int.generic "circt_verif_assert" %in : (!firrtl.uint<1>) -> () + firrtl.int.generic "circt_verif_assert" %in : (!firrtl.uint<1>) -> () + firrtl.int.generic "circt_verif_assume" %in : (!firrtl.uint<1>) -> () + firrtl.int.generic "circt_verif_cover" %in : (!firrtl.uint<1>) -> () } - firrtl.intmodule @Mux2Cell(in sel: !firrtl.uint<1>, in high: !firrtl.uint, in low: !firrtl.uint, out out: !firrtl.uint) attributes {intrinsic = "circt.mux2cell"} - firrtl.intmodule @Mux4Cell(in sel: !firrtl.uint<2>, in v3: !firrtl.uint, in v2: !firrtl.uint, in v1: !firrtl.uint, in v0: !firrtl.uint, out out: !firrtl.uint) attributes {intrinsic = "circt.mux4cell"} - - // CHECK: firrtl.module @MuxCell() - firrtl.module @MuxCell() { - // CHECK: firrtl.int.mux2cell - // CHECK: firrtl.int.mux4cell - %sel_0, %high, %low, %out_0 = firrtl.instance "mux2" @Mux2Cell(in sel: !firrtl.uint<1>, in high: !firrtl.uint, in low: !firrtl.uint, out out: !firrtl.uint) - %sel_1, %v4, %v3, %v2, %v1, %out_1 = firrtl.instance "mux4" @Mux4Cell(in sel: !firrtl.uint<2>, in v3: !firrtl.uint, in v2: !firrtl.uint, in v1: !firrtl.uint, in v0: !firrtl.uint, out out: !firrtl.uint) + // CHECK-LABEL: firrtl.module private @MuxCell( + firrtl.module private @MuxCell(in %sel : !firrtl.uint<1>, + in %sel2 : !firrtl.uint<2>, + in %d1 : !firrtl.uint, + in %d2 : !firrtl.uint, + in %d3 : !firrtl.uint, + in %d4 : !firrtl.uint) { + // CHECK-NEXT: firrtl.int.mux2cell(%sel, %d1, %d2) + // CHECK-NEXT: firrtl.int.mux4cell(%sel2, %d1, %d2, %d3, %d4) + firrtl.int.generic "circt_mux2cell" %sel, %d1, %d2 : (!firrtl.uint<1>, !firrtl.uint, !firrtl.uint) -> !firrtl.uint + firrtl.int.generic "circt_mux4cell" %sel2, %d1, %d2, %d3, %d4 : (!firrtl.uint<2>, !firrtl.uint, !firrtl.uint, !firrtl.uint, !firrtl.uint) -> !firrtl.uint } - // CHECK-NOT: HBRInt1 - // CHECK-NOT: HBRInt2 - // CHECK-NOT: HBRInt3 - firrtl.intmodule @HBRInt1(in clock: !firrtl.clock, in reset: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.has_been_reset"} - firrtl.intmodule @HBRInt2(in clock: !firrtl.clock, in reset: !firrtl.asyncreset, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.has_been_reset"} - firrtl.intmodule @HBRInt3(in clock: !firrtl.clock, in reset: !firrtl.reset, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.has_been_reset"} - - // CHECK: HasBeenReset + // CHECK-LABEL: @HasBeenReset firrtl.module @HasBeenReset(in %clock: !firrtl.clock, in %reset1: !firrtl.uint<1>, in %reset2: !firrtl.asyncreset, in %reset3: !firrtl.reset) { - // CHECK-NOT: firrtl.instance - // CHECK: firrtl.int.has_been_reset {{%.+}}, {{%.+}} : !firrtl.uint<1> - // CHECK-NOT: firrtl.instance - // CHECK: firrtl.int.has_been_reset {{%.+}}, {{%.+}} : !firrtl.asyncreset - // CHECK-NOT: firrtl.instance - // CHECK: firrtl.int.has_been_reset {{%.+}}, {{%.+}} : !firrtl.reset - %in_clock1, %in_reset1, %hbr1 = firrtl.instance "" @HBRInt1(in clock: !firrtl.clock, in reset: !firrtl.uint<1>, out out: !firrtl.uint<1>) - %in_clock2, %in_reset2, %hbr2 = firrtl.instance "" @HBRInt2(in clock: !firrtl.clock, in reset: !firrtl.asyncreset, out out: !firrtl.uint<1>) - %in_clock3, %in_reset3, %hbr3 = firrtl.instance "" @HBRInt3(in clock: !firrtl.clock, in reset: !firrtl.reset, out out: !firrtl.uint<1>) - firrtl.strictconnect %in_clock1, %clock : !firrtl.clock - firrtl.strictconnect %in_clock2, %clock : !firrtl.clock - firrtl.strictconnect %in_clock3, %clock : !firrtl.clock - firrtl.strictconnect %in_reset1, %reset1 : !firrtl.uint<1> - firrtl.strictconnect %in_reset2, %reset2 : !firrtl.asyncreset - firrtl.strictconnect %in_reset3, %reset3 : !firrtl.reset + // CHECK-NEXT: firrtl.int.has_been_reset %clock, %reset1 : !firrtl.uint<1> + // CHECK-NEXT: firrtl.int.has_been_reset %clock, %reset2 : !firrtl.asyncreset + // CHECK-NEXT: firrtl.int.has_been_reset %clock, %reset3 : !firrtl.reset + firrtl.int.generic "circt_has_been_reset" %clock, %reset1 : (!firrtl.clock, !firrtl.uint<1>) -> !firrtl.uint<1> + firrtl.int.generic "circt_has_been_reset" %clock, %reset2 : (!firrtl.clock, !firrtl.asyncreset) -> !firrtl.uint<1> + firrtl.int.generic "circt_has_been_reset" %clock, %reset3 : (!firrtl.clock, !firrtl.reset) -> !firrtl.uint<1> } - // 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> - } - - // CHECK-NOT: CirctAssert1 - // CHECK-NOT: CirctAssert2 - // CHECK-NOT: VerifAssume - // CHECK-NOT: VerifCover -// TODO: - firrtl.intmodule private @Assert(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>) attributes {intrinsic = "circt.chisel_assert"} - firrtl.intmodule private @AssertFormat( - in clock: !firrtl.clock, - in predicate: !firrtl.uint<1>, - in enable: !firrtl.uint<1>, - in val: !firrtl.uint<1> - ) attributes {intrinsic = "circt.chisel_assert"} - firrtl.intmodule private @IfElseFatalFormat( - in clock: !firrtl.clock, - in predicate: !firrtl.uint<1>, - in enable: !firrtl.uint<1>, - in val: !firrtl.uint<1> - ) attributes {intrinsic = "circt.chisel_ifelsefatal"} - firrtl.intmodule private @Assume( - in clock: !firrtl.clock, - in predicate: !firrtl.uint<1>, - in enable: !firrtl.uint<1>, - in val: !firrtl.uint<1> - ) attributes {intrinsic = "circt.chisel_assume"} - firrtl.intmodule private @CoverLabel( - in clock: !firrtl.clock, - in predicate: !firrtl.uint<1>, - in enable: !firrtl.uint<1> - ) attributes {intrinsic = "circt.chisel_cover"} - firrtl.intmodule private @UnclockedAssume( - in predicate: !firrtl.uint<1>, - in enable: !firrtl.uint<1>, - in val: !firrtl.uint<1> - ) attributes {intrinsic = "circt.unclocked_assume"} - // CHECK-NOT: @Assert - // CHECK-NOT: @AssertFormat - // CHECK-NOT: @IfElseFatalFormat - // CHECK-NOT: @Assume - // CHECK-NOT: @CoverLabel - // CHECK-NOT: @UnclockedAssume - - // CHECK: firrtl.module @ChiselVerif( + // CHECK-LABEL: firrtl.module @ChiselVerif( firrtl.module @ChiselVerif(in %clock: !firrtl.clock, in %cond: !firrtl.uint<1>, in %enable: !firrtl.uint<1>) { - // CHECK-NOT: firrtl.instance // CHECK: firrtl.assert %{{.+}}, %{{.+}}, %{{.+}}, "testing" : // CHECK-SAME: isConcurrent = true - %assert_clock, %assert_predicate, %assert_enable = firrtl.instance assert interesting_name @Assert(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>) - firrtl.strictconnect %assert_clock, %clock : !firrtl.clock - firrtl.strictconnect %assert_predicate, %cond : !firrtl.uint<1> - firrtl.strictconnect %assert_enable, %enable : !firrtl.uint<1> - // CHECK-NOT: firrtl.instance + firrtl.int.generic "circt_chisel_assert" %clock, %cond, %enable : (!firrtl.clock, !firrtl.uint<1>, !firrtl.uint<1>) -> () // CHECK: firrtl.assert %{{.+}}, %{{.+}}, %{{.+}}, "message: %d"( // CHECK-SAME: guards = ["MACRO_GUARD", "ASDF"] // CHECK-SAME: isConcurrent = true // CHECK-SAME: name = "label for assert with format string" - %assertFormat_clock, %assertFormat_predicate, %assertFormat_enable, %assertFormat_val = firrtl.instance assertFormat interesting_name @AssertFormat(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>, in val: !firrtl.uint<1>) - firrtl.strictconnect %assertFormat_clock, %clock : !firrtl.clock - firrtl.strictconnect %assertFormat_predicate, %cond : !firrtl.uint<1> - firrtl.strictconnect %assertFormat_enable, %enable : !firrtl.uint<1> - firrtl.strictconnect %assertFormat_val, %cond : !firrtl.uint<1> - // CHECK-NOT: firrtl.instance + firrtl.int.generic "circt_chisel_assert" %clock, %cond, %enable, %cond : (!firrtl.clock, !firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1>) -> () // CHECK: firrtl.assert %{{.+}}, %{{.+}}, %{{.+}}, "ief: %d"( // CHECK-SAME: format = "ifElseFatal" // CHECK-SAME: guards = ["MACRO_GUARD", "ASDF"] // CHECK-SAME: isConcurrent = true // CHECK-SAME: name = "label for ifelsefatal assert" - %ief_clock, %ief_predicate, %ief_enable, %ief_val = firrtl.instance ief interesting_name @IfElseFatalFormat(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>, in val: !firrtl.uint<1>) - firrtl.strictconnect %ief_clock, %clock : !firrtl.clock - firrtl.strictconnect %ief_predicate, %cond : !firrtl.uint<1> - firrtl.strictconnect %ief_enable, %enable : !firrtl.uint<1> - firrtl.strictconnect %ief_val, %enable : !firrtl.uint<1> - // CHECK-NOT: firrtl.instance + firrtl.int.generic "circt_chisel_ifelsefatal" %clock, %cond, %enable, %enable : (!firrtl.clock, !firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1>) -> () // CHECK: firrtl.assume %{{.+}}, %{{.+}}, %{{.+}}, "text: %d"( // CHECK-SAME: isConcurrent = true // CHECK-SAME: name = "label for assume" - %assume_clock, %assume_predicate, %assume_enable, %assume_val = firrtl.instance assume interesting_name @Assume(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>, in val: !firrtl.uint<1>) - firrtl.strictconnect %assume_clock, %clock : !firrtl.clock - firrtl.strictconnect %assume_predicate, %cond : !firrtl.uint<1> - firrtl.strictconnect %assume_enable, %enable : !firrtl.uint<1> - firrtl.strictconnect %assume_val, %enable : !firrtl.uint<1> - // CHECK-NOT: firrtl.instance + firrtl.int.generic "circt_chisel_assume" %clock, %cond, %enable, %enable : (!firrtl.clock, !firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1>) -> () // CHECK: firrtl.cover %{{.+}}, %{{.+}}, %{{.+}}, "" : // CHECK-SAME: isConcurrent = true // CHECK-SAME: name = "label for cover" - %cover_clock, %cover_predicate, %cover_enable = firrtl.instance cover interesting_name @CoverLabel(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>) - firrtl.strictconnect %cover_clock, %clock : !firrtl.clock - firrtl.strictconnect %cover_predicate, %cond : !firrtl.uint<1> - firrtl.strictconnect %cover_enable, %enable : !firrtl.uint<1> + firrtl.int.generic "circt_chisel_cover" %clock, %cond, %enable : (!firrtl.clock, !firrtl.uint<1>, !firrtl.uint<1>) -> () - // CHECK-NOT: firrtl.instance // CHECK: firrtl.int.unclocked_assume %{{.+}}, %{{.+}}, "text: %d"( // CHECK-SAME: guards = ["MACRO_GUARD", "ASDF"] // CHECK-SAME: name = "label for unr" - %unr_predicate, %unr_enable, %unr_val = firrtl.instance unr interesting_name @UnclockedAssume(in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>, in val: !firrtl.uint<1>) - firrtl.strictconnect %unr_predicate, %cond : !firrtl.uint<1> - firrtl.strictconnect %unr_enable, %enable : !firrtl.uint<1> - firrtl.strictconnect %unr_val, %enable : !firrtl.uint<1> + firrtl.int.generic "circt.unclocked_assume" %cond, %enable, %enable : (!firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1>) -> () } - // CHECK-NOT: firrtl.intmodule private @FPGAProbeIntrinsic - firrtl.intmodule private @FPGAProbeIntrinsic(in data: !firrtl.uint, in clock: !firrtl.clock) attributes {intrinsic = "circt_fpga_probe"} - // CHECK-LABEL: firrtl.module private @ProbeIntrinsicTest firrtl.module private @ProbeIntrinsicTest(in %clock : !firrtl.clock, in %data : !firrtl.uint<32>) { - // CHECK: [[DATA:%.+]] = firrtl.wire : !firrtl.uint - // CHECK-NEXT: [[CLOCK:%.+]] = firrtl.wire : !firrtl.clock - // CHECK-NEXT: firrtl.int.fpga_probe [[CLOCK]], [[DATA]] : !firrtl.uint - // CHECK-NEXT: firrtl.strictconnect [[CLOCK]], %clock : !firrtl.clock - // CHECK-NEXT: firrtl.connect [[DATA]], %data : !firrtl.uint, !firrtl.uint<32> - %mod_data, %mod_clock = firrtl.instance mod @FPGAProbeIntrinsic(in data: !firrtl.uint, in clock: !firrtl.clock) - firrtl.strictconnect %mod_clock, %clock : !firrtl.clock - firrtl.connect %mod_data, %data : !firrtl.uint, !firrtl.uint<32> - } -} - -// CHECK-LABEL: "FixupEICGWrapper2" -firrtl.circuit "FixupEICGWrapper2" { - // CHECK-NOEICG: LegacyClockGateNoTestEn - // CHECK-EICG-NOT: LegacyClockGateNoTestEn - firrtl.extmodule @LegacyClockGateNoTestEn(in in: !firrtl.clock, in en: !firrtl.uint<1>, out out: !firrtl.clock) attributes {defname = "EICG_wrapper"} - - // CHECK: FixupEICGWrapper2 - firrtl.module @FixupEICGWrapper2(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_en, %ckg_out = firrtl.instance ckg @LegacyClockGateNoTestEn(in in: !firrtl.clock, in en: !firrtl.uint<1>, out out: !firrtl.clock) - firrtl.strictconnect %ckg_in, %clock : !firrtl.clock - firrtl.strictconnect %ckg_en, %en : !firrtl.uint<1> + // CHECK-NEXT: firrtl.int.fpga_probe %clock, %data : !firrtl.uint<32> + firrtl.int.generic "circt_fpga_probe" %data, %clock : (!firrtl.uint<32>, !firrtl.clock) -> () } }