mirror of https://github.com/llvm/circt.git
[FIRRTL] Add generic intrinsic op. (#6874)
Add generic intrinsic operation to FIRRTL. Not used anywhere, just adding to the IR to build on. Re-use module parameter printing/parsing for use as custom printer on the op. See PR for more context.
This commit is contained in:
parent
87020b2ed4
commit
0cff5d90dd
|
@ -13,36 +13,24 @@
|
||||||
#ifndef CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
|
#ifndef CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
|
||||||
#define CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
|
#define CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
|
||||||
|
|
||||||
def IsXIntrinsicOp : FIRRTLOp<"int.isX",
|
include "FIRRTLDialect.td"
|
||||||
[HasCustomSSAName, Pure]> {
|
|
||||||
let summary = "Test for 'x";
|
|
||||||
let description = [{
|
|
||||||
The `int.isX` expression checks that the operand is not a verilog literal
|
|
||||||
'x. FIRRTL doesn't have a notion of 'x per-se, but x can come in to the
|
|
||||||
system from external modules and from SV constructs. Verification
|
|
||||||
constructs need to explicitly test for 'x.
|
|
||||||
}];
|
|
||||||
|
|
||||||
let arguments = (ins FIRRTLBaseType:$arg);
|
//===----------------------------------------------------------------------===//
|
||||||
let results = (outs NonConstUInt1Type:$result);
|
// Generic intrinsic operation for parsing into before lowering.
|
||||||
let hasFolder = 1;
|
//===----------------------------------------------------------------------===//
|
||||||
let assemblyFormat = "$arg attr-dict `:` type($arg)";
|
|
||||||
}
|
|
||||||
|
|
||||||
def HasBeenResetIntrinsicOp : FIRRTLOp<"int.has_been_reset", [Pure]> {
|
def GenericIntrinsicOp : FIRRTLOp<"int.generic",
|
||||||
let summary = "Check that a proper reset has been seen.";
|
[HasCustomSSAName]> {
|
||||||
let description = [{
|
let summary = "Generic intrinsic operation for FIRRTL intrinsics.";
|
||||||
The result of `firrtl.int.has_been_reset` reads as 0 immediately after simulation
|
|
||||||
startup and after each power-cycle in a power-aware simulation. The result
|
|
||||||
remains 0 before and during reset and only switches to 1 after the reset is
|
|
||||||
deasserted again.
|
|
||||||
|
|
||||||
See the corresponding `verif.has_been_reset` operation.
|
let arguments = (
|
||||||
}];
|
ins StrAttr:$intrinsic,
|
||||||
let arguments = (ins NonConstClockType:$clock, AnyResetType:$reset);
|
Variadic<PassiveType>:$operands,
|
||||||
let results = (outs NonConstUInt1Type:$result);
|
DefaultValuedAttr<ParamDeclArrayAttr, "{}">:$parameters
|
||||||
let hasFolder = 1;
|
);
|
||||||
let assemblyFormat = "$clock `,` $reset attr-dict `:` type($reset)";
|
|
||||||
|
let results = (outs Optional<PassiveType>:$result);
|
||||||
|
let assemblyFormat = "$intrinsic custom<ParameterList>($parameters) ($operands^)? attr-dict-with-keyword `:` functional-type($operands, $result)";
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -135,4 +123,41 @@ def ClockInverterIntrinsicOp : FIRRTLOp<"int.clock_inv", []> {
|
||||||
let assemblyFormat = "$input attr-dict";
|
let assemblyFormat = "$input attr-dict";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Other intrinsics
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
def IsXIntrinsicOp : FIRRTLOp<"int.isX",
|
||||||
|
[HasCustomSSAName, Pure]> {
|
||||||
|
let summary = "Test for 'x";
|
||||||
|
let description = [{
|
||||||
|
The `int.isX` expression checks that the operand is not a verilog literal
|
||||||
|
'x. FIRRTL doesn't have a notion of 'x per-se, but x can come in to the
|
||||||
|
system from external modules and from SV constructs. Verification
|
||||||
|
constructs need to explicitly test for 'x.
|
||||||
|
}];
|
||||||
|
|
||||||
|
let arguments = (ins FIRRTLBaseType:$arg);
|
||||||
|
let results = (outs NonConstUInt1Type:$result);
|
||||||
|
let hasFolder = 1;
|
||||||
|
let assemblyFormat = "$arg attr-dict `:` type($arg)";
|
||||||
|
}
|
||||||
|
|
||||||
|
def HasBeenResetIntrinsicOp : FIRRTLOp<"int.has_been_reset", [Pure]> {
|
||||||
|
let summary = "Check that a proper reset has been seen.";
|
||||||
|
let description = [{
|
||||||
|
The result of `firrtl.int.has_been_reset` reads as 0 immediately after simulation
|
||||||
|
startup and after each power-cycle in a power-aware simulation. The result
|
||||||
|
remains 0 before and during reset and only switches to 1 after the reset is
|
||||||
|
deasserted again.
|
||||||
|
|
||||||
|
See the corresponding `verif.has_been_reset` operation.
|
||||||
|
}];
|
||||||
|
let arguments = (ins NonConstClockType:$clock, AnyResetType:$reset);
|
||||||
|
let results = (outs NonConstUInt1Type:$result);
|
||||||
|
let hasFolder = 1;
|
||||||
|
let assemblyFormat = "$clock `,` $reset attr-dict `:` type($reset)";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
|
#endif // CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
LTLConcatIntrinsicOp, LTLNotIntrinsicOp, LTLImplicationIntrinsicOp,
|
LTLConcatIntrinsicOp, LTLNotIntrinsicOp, LTLImplicationIntrinsicOp,
|
||||||
LTLEventuallyIntrinsicOp, LTLClockIntrinsicOp,
|
LTLEventuallyIntrinsicOp, LTLClockIntrinsicOp,
|
||||||
LTLDisableIntrinsicOp, Mux2CellIntrinsicOp, Mux4CellIntrinsicOp,
|
LTLDisableIntrinsicOp, Mux2CellIntrinsicOp, Mux4CellIntrinsicOp,
|
||||||
HasBeenResetIntrinsicOp, FPGAProbeIntrinsicOp,
|
HasBeenResetIntrinsicOp, FPGAProbeIntrinsicOp, GenericIntrinsicOp,
|
||||||
// Miscellaneous.
|
// Miscellaneous.
|
||||||
BitsPrimOp, HeadPrimOp, MuxPrimOp, PadPrimOp, ShlPrimOp, ShrPrimOp,
|
BitsPrimOp, HeadPrimOp, MuxPrimOp, PadPrimOp, ShlPrimOp, ShrPrimOp,
|
||||||
TailPrimOp, VerbatimExprOp, HWStructCastOp, BitCastOp, RefSendOp,
|
TailPrimOp, VerbatimExprOp, HWStructCastOp, BitCastOp, RefSendOp,
|
||||||
|
@ -180,6 +180,7 @@ public:
|
||||||
HANDLE(Mux2CellIntrinsicOp, Unhandled);
|
HANDLE(Mux2CellIntrinsicOp, Unhandled);
|
||||||
HANDLE(HasBeenResetIntrinsicOp, Unhandled);
|
HANDLE(HasBeenResetIntrinsicOp, Unhandled);
|
||||||
HANDLE(FPGAProbeIntrinsicOp, Unhandled);
|
HANDLE(FPGAProbeIntrinsicOp, Unhandled);
|
||||||
|
HANDLE(GenericIntrinsicOp, Unhandled);
|
||||||
|
|
||||||
// Miscellaneous.
|
// Miscellaneous.
|
||||||
HANDLE(BitsPrimOp, Unhandled);
|
HANDLE(BitsPrimOp, Unhandled);
|
||||||
|
|
|
@ -1255,7 +1255,8 @@ parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a paramter list for a module or instance.
|
/// Print a paramter list for a module or instance.
|
||||||
static void printParameterList(ArrayAttr parameters, OpAsmPrinter &p) {
|
static void printParameterList(OpAsmPrinter &p, Operation *op,
|
||||||
|
ArrayAttr parameters) {
|
||||||
if (!parameters || parameters.empty())
|
if (!parameters || parameters.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1283,7 +1284,7 @@ static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op) {
|
||||||
p.printSymbolName(op.getModuleName());
|
p.printSymbolName(op.getModuleName());
|
||||||
|
|
||||||
// Print the parameter list (if non-empty).
|
// Print the parameter list (if non-empty).
|
||||||
printParameterList(op->getAttrOfType<ArrayAttr>("parameters"), p);
|
printParameterList(p, op, op->getAttrOfType<ArrayAttr>("parameters"));
|
||||||
|
|
||||||
// Both modules and external modules have a body, but it is always empty for
|
// Both modules and external modules have a body, but it is always empty for
|
||||||
// external modules.
|
// external modules.
|
||||||
|
@ -1372,6 +1373,18 @@ parseOptionalParameters(OpAsmParser &parser,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shim to use with assemblyFormat, custom<ParameterList>.
|
||||||
|
static ParseResult parseParameterList(OpAsmParser &parser,
|
||||||
|
ArrayAttr ¶meters) {
|
||||||
|
SmallVector<Attribute> parseParameters;
|
||||||
|
if (failed(parseOptionalParameters(parser, parseParameters)))
|
||||||
|
return failure();
|
||||||
|
|
||||||
|
parameters = ArrayAttr::get(parser.getContext(), parseParameters);
|
||||||
|
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
static ParseResult parseFModuleLikeOp(OpAsmParser &parser,
|
static ParseResult parseFModuleLikeOp(OpAsmParser &parser,
|
||||||
OperationState &result,
|
OperationState &result,
|
||||||
bool hasSSAIdentifiers) {
|
bool hasSSAIdentifiers) {
|
||||||
|
@ -5764,6 +5777,9 @@ void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
|
||||||
void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
|
void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
|
||||||
genericAsmResultNames(*this, setNameFn);
|
genericAsmResultNames(*this, setNameFn);
|
||||||
}
|
}
|
||||||
|
void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
|
||||||
|
genericAsmResultNames(*this, setNameFn);
|
||||||
|
}
|
||||||
void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
|
void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
|
||||||
genericAsmResultNames(*this, setNameFn);
|
genericAsmResultNames(*this, setNameFn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,17 @@ firrtl.module @Intrinsics(in %ui : !firrtl.uint, in %clock: !firrtl.clock, in %u
|
||||||
// CHECK-NEXT: firrtl.int.clock_gate %clock, %ui1, %ui1
|
// CHECK-NEXT: firrtl.int.clock_gate %clock, %ui1, %ui1
|
||||||
%cg0 = firrtl.int.clock_gate %clock, %ui1
|
%cg0 = firrtl.int.clock_gate %clock, %ui1
|
||||||
%cg1 = firrtl.int.clock_gate %clock, %ui1, %ui1
|
%cg1 = firrtl.int.clock_gate %clock, %ui1, %ui1
|
||||||
|
|
||||||
|
// CHECK-NEXT: firrtl.int.generic "clock_gate" %clock, %ui1 : (!firrtl.clock, !firrtl.uint<1>)
|
||||||
|
// CHECK-NEXT: firrtl.int.generic "noargs" : () -> !firrtl.uint<32>
|
||||||
|
// CHECK-NEXT: firrtl.int.generic "params" <FORMAT: none = "foobar"> : () -> !firrtl.bundle<x: uint<1>>
|
||||||
|
// CHECK-NEXT: firrtl.int.generic "params_and_operand" <X: i64 = 123> %ui1 : (!firrtl.uint<1>) -> !firrtl.clock
|
||||||
|
// CHECK-NEXT: firrtl.int.generic "inputs" %clock, %ui1, %clock : (!firrtl.clock, !firrtl.uint<1>, !firrtl.clock) -> ()
|
||||||
|
%cg2 = firrtl.int.generic "clock_gate" %clock, %ui1 : (!firrtl.clock, !firrtl.uint<1>) -> !firrtl.clock
|
||||||
|
%noargs = firrtl.int.generic "noargs" : () -> !firrtl.uint<32>
|
||||||
|
%p = firrtl.int.generic "params" <FORMAT: none = "foobar"> : () -> !firrtl.bundle<x: uint<1>>
|
||||||
|
%po = firrtl.int.generic "params_and_operand" <X: i64 = 123> %ui1 : (!firrtl.uint<1>) -> !firrtl.clock
|
||||||
|
firrtl.int.generic "inputs" %clock, %ui1, %clock : (!firrtl.clock, !firrtl.uint<1>, !firrtl.clock) -> ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: firrtl.module @FPGAProbe
|
// CHECK-LABEL: firrtl.module @FPGAProbe
|
||||||
|
|
Loading…
Reference in New Issue