mirror of https://github.com/llvm/circt.git
[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:
parent
44b753d0fe
commit
ca24267763
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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"> {
|
||||
|
|
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
|
@ -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) -> ()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue