[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.
This commit is contained in:
Will Dietz 2024-04-09 17:46:54 -05:00 committed by GitHub
parent 44b753d0fe
commit ca24267763
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 618 additions and 1157 deletions

View File

@ -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 <typename C>
ParseResult checkInputType(unsigned n, const Twine &msg, C &&call) {
if (n >= op.getNumOperands())
return emitError() << " missing input " << n;
if (!std::invoke(std::forward<C>(call), op.getOperand(n).getType()))
return emitError() << " input " << n << " " << msg;
return success();
}
ParseResult namedPort(unsigned n, StringRef portName);
template <typename C>
ParseResult checkInputType(unsigned n, C &&call) {
return checkInputType(n, "not of correct type", std::forward<C>(call));
}
ParseResult resetPort(unsigned n);
template <typename T>
ParseResult typedInput(unsigned n) {
return checkInputType(n, [](auto ty) { return isa<T>(ty); });
}
ParseResult hasResetInput(unsigned n) {
return checkInputType(n, "must be reset type", [](auto ty) {
auto baseType = dyn_cast<FIRRTLBaseType>(ty);
return baseType && baseType.isResetType();
});
}
template <typename T>
ParseResult sizedInput(unsigned n, int32_t size) {
return checkInputType(n, "not size " + Twine(size), [size](auto ty) {
auto t = dyn_cast<T>(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<ParamDeclAttr>())
if (param.getName().getValue().equals(name))
return param;
return {};
}
/// Get parameter value by name, if present, as requested type.
template <typename T>
ParseResult typedPort(unsigned n) {
auto ports = mod.getPorts();
if (n >= ports.size()) {
mod.emitError(name) << " missing port " << n;
return failure();
}
if (!isa<T>(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<T>(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 <typename T>
ParseResult sizedPort(unsigned n, int32_t size) {
auto ports = mod.getPorts();
if (failed(typedPort<T>(n)))
ParseResult typedOutput() {
if (failed(hasOutput()))
return failure();
if (cast<T>(ports[n].type).getWidth() != size) {
mod.emitError(name) << " port " << n << " not size " << size;
return failure();
}
if (!isa<T>(op.getResult().getType()))
return emitError() << " output not of correct type";
return success();
}
template <typename T>
ParseResult sizedOutput(int32_t size) {
if (failed(typedOutput<T>()))
return failure();
if (cast<T>(op.getResult().getType()).getWidth() != size)
return emitError() << " output not size " << size;
return success();
}
//===--------------------------------------------------------------------===//
// Output bundle element checking
//===--------------------------------------------------------------------===//
mlir::TypedValue<BundleType> getOutputBundle() {
return dyn_cast_or_null<mlir::TypedValue<BundleType>>(op.getResult());
}
ParseResult hasNOutputElements(unsigned n);
template <typename C>
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<C>(call), element.type))
return emitError() << " output element " << n << " " << msg;
return success();
}
template <typename C>
ParseResult checkOutputElement(unsigned n, StringRef name, C &&call) {
return checkOutputElement(n, name, "not of correct type",
std::forward<C>(call));
}
ParseResult hasOutputElement(unsigned n, StringRef name) {
return checkOutputElement(n, name, [](auto ty) { return true; });
}
template <typename T>
ParseResult typedOutputElement(unsigned n, StringRef name) {
return checkOutputElement(n, name, [](auto ty) { return isa<T>(ty); });
}
template <typename T>
ParseResult sizedOutputElement(unsigned n, StringRef name, int32_t size) {
return checkOutputElement(n, name, "not size " + Twine(size),
[size](auto ty) {
auto t = dyn_cast<T>(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 <typename OpTy>
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<OpTy>(gi.op, gi.op.getResultTypes(),
adaptor.getOperands());
}
};
/// Lowering helper which collects all intrinsic converters.
class IntrinsicLowerings {
private:
using ConverterFn = std::function<LogicalResult(FModuleLike)>;
public:
using ConversionMapTy =
llvm::DenseMap<StringAttr, std::unique_ptr<IntrinsicConverter>>;
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<StringAttr, ConverterFn> intmods;
/// Mapping from extmodule names to converters.
DenseMap<StringAttr, ConverterFn> 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 <typename T>
void add(StringRef name) {
addConverter<T>(intmods, name);
}
/// Registers a converter to an extmodule name.
template <typename T>
void addExtmod(StringRef name) {
addConverter<T>(extmods, name);
}
/// Registers a converter to multiple intrinsic names.
/// Registers a converter to one or more intrinsic names.
template <typename T, typename... Args>
void add(StringRef name, Args... args) {
add<T>(name);
add<T>(args...);
void add(Args... args) {
(addConverter<T>(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 <typename T>
void addConverter(DenseMap<StringAttr, ConverterFn> &map, StringRef name) {
typename std::enable_if_t<std::is_base_of_v<IntrinsicConverter, 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<T>());
}
LogicalResult doLowering(FModuleLike mod, IntrinsicConverter &conv);
unsigned numConverted = 0;
};
} // namespace firrtl

View File

@ -63,8 +63,7 @@ std::unique_ptr<mlir::Pass> createLowerCHIRRTLPass();
std::unique_ptr<mlir::Pass>
createLowerIntmodulesPass(bool fixupEICGWrapper = false);
std::unique_ptr<mlir::Pass>
createLowerIntrinsicsPass(bool fixupEICGWrapper = false);
std::unique_ptr<mlir::Pass> createLowerIntrinsicsPass();
std::unique_ptr<mlir::Pass> createIMConstPropPass();

View File

@ -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"> {

View File

@ -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<ResetType, AsyncResetType>(ports[n].type))
return success();
if (auto uintType = dyn_cast<UIntType>(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<ParamDeclAttr>(a);
if (param.getName().getValue().equals(paramName)) {
if (isa<StringAttr>(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<ParamDeclAttr>(a);
if (param.getName().getValue().equals(paramName)) {
if (isa<IntegerAttr>(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<InstanceOp>())))
/// Conversion pattern adaptor dispatching via generic intrinsic name.
class IntrinsicOpConversion final
: public OpConversionPattern<GenericIntrinsicOp> {
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<FModuleLike>())) {
if (auto extMod = dyn_cast<FExtModuleOp>(*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<FIntModuleOp>(*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<GenericIntrinsicOp>(
[this](GenericIntrinsicOp op) {
return !conversions.contains(op.getIntrinsicAttr());
});
else
target.addIllegalOp<GenericIntrinsicOp>();
RewritePatternSet patterns(context);
patterns.add<IntrinsicOpConversion>(context, conversions,
allowUnknownIntrinsics);
return mlir::applyPartialConversion(mod, target, std::move(patterns));
}

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,9 @@ LogicalResult firtool::populatePreprocessTransforms(mlir::PassManager &pm,
firrtl::createMaterializeDebugInfoPass());
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createLowerIntrinsicsPass(opt.shouldFixupEICGWrapper()));
firrtl::createLowerIntmodulesPass(opt.shouldFixupEICGWrapper()));
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createLowerIntrinsicsPass());
return success();
}

View File

@ -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
}
}

View File

@ -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>
}
}

View File

@ -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<FORMAT: none = "foo">(out found : !firrtl.uint<1>) attributes
{intrinsic = "circt.plusargs.test"}
// CHECK-NOT: NameDoesNotMatter8
firrtl.intmodule @NameDoesNotMatter8<FORMAT: none = "foo">(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" <FORMAT: none = "foo"> : () -> !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" <FORMAT: none = "foo"> : () -> !firrtl.bundle<found: uint<1>, result: uint<5>>
%found = firrtl.subfield %pav[found] : !firrtl.bundle<found: uint<1>, result: uint<5>>
%result = firrtl.subfield %pav[result] : !firrtl.bundle<found: uint<1>, 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<POW_2: i8 = 8>(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" <POW_2: i8 = 8> %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<delay: i64 = 42>(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) attributes {intrinsic = "circt.ltl.delay"}
firrtl.intmodule @LTLDelay2<delay: i64 = 42, length: i64 = 1337>(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" <delay: i64 = 42> %in0 : (!firrtl.uint<1>) -> !firrtl.uint<1>
firrtl.int.generic "circt_ltl_delay" <delay: i64 = 42, length: i64 = 1337> %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<label: none = "hello">(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" <label: none = "hello"> %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<format: none = "testing">(in clock: !firrtl.clock, in predicate: !firrtl.uint<1>, in enable: !firrtl.uint<1>) attributes {intrinsic = "circt.chisel_assert"}
firrtl.intmodule private @AssertFormat<format: none = "message: %d",
label: none = "label for assert with format string",
guards: none = "MACRO_GUARD;ASDF">(
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<format: none = "ief: %d",
label: none = "label for ifelsefatal assert",
guards: none = "MACRO_GUARD;ASDF">(
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<format: none = "text: %d",
label: none = "label for 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<label: none = "label for cover">(
in clock: !firrtl.clock,
in predicate: !firrtl.uint<1>,
in enable: !firrtl.uint<1>
) attributes {intrinsic = "circt.chisel_cover"}
firrtl.intmodule private @UnclockedAssume<format: none = "text: %d",
label: none = "label for unr",
guards: none = "MACRO_GUARD;ASDF">(
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" <format: none = "testing"> %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" <format: none = "message: %d", label: none = "label for assert with format string", guards: none = "MACRO_GUARD;ASDF"> %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" <format: none = "ief: %d", label: none = "label for ifelsefatal assert", guards: none = "MACRO_GUARD;ASDF"> %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" <format: none = "text: %d", label: none = "label for 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" <label: none = "label for 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" <format: none = "text: %d", label: none = "label for unr", guards: none = "MACRO_GUARD;ASDF"> %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) -> ()
}
}