[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:
Will Dietz 2024-03-27 09:17:38 -05:00 committed by GitHub
parent 87020b2ed4
commit 0cff5d90dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 83 additions and 30 deletions

View File

@ -13,36 +13,24 @@
#ifndef CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
#define CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD
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.
}];
include "FIRRTLDialect.td"
let arguments = (ins FIRRTLBaseType:$arg);
let results = (outs NonConstUInt1Type:$result);
let hasFolder = 1;
let assemblyFormat = "$arg attr-dict `:` type($arg)";
}
//===----------------------------------------------------------------------===//
// Generic intrinsic operation for parsing into before lowering.
//===----------------------------------------------------------------------===//
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.
def GenericIntrinsicOp : FIRRTLOp<"int.generic",
[HasCustomSSAName]> {
let summary = "Generic intrinsic operation for FIRRTL intrinsics.";
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)";
let arguments = (
ins StrAttr:$intrinsic,
Variadic<PassiveType>:$operands,
DefaultValuedAttr<ParamDeclArrayAttr, "{}">:$parameters
);
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";
}
//===----------------------------------------------------------------------===//
// 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

View File

@ -53,7 +53,7 @@ public:
LTLConcatIntrinsicOp, LTLNotIntrinsicOp, LTLImplicationIntrinsicOp,
LTLEventuallyIntrinsicOp, LTLClockIntrinsicOp,
LTLDisableIntrinsicOp, Mux2CellIntrinsicOp, Mux4CellIntrinsicOp,
HasBeenResetIntrinsicOp, FPGAProbeIntrinsicOp,
HasBeenResetIntrinsicOp, FPGAProbeIntrinsicOp, GenericIntrinsicOp,
// Miscellaneous.
BitsPrimOp, HeadPrimOp, MuxPrimOp, PadPrimOp, ShlPrimOp, ShrPrimOp,
TailPrimOp, VerbatimExprOp, HWStructCastOp, BitCastOp, RefSendOp,
@ -180,6 +180,7 @@ public:
HANDLE(Mux2CellIntrinsicOp, Unhandled);
HANDLE(HasBeenResetIntrinsicOp, Unhandled);
HANDLE(FPGAProbeIntrinsicOp, Unhandled);
HANDLE(GenericIntrinsicOp, Unhandled);
// Miscellaneous.
HANDLE(BitsPrimOp, Unhandled);

View File

@ -1255,7 +1255,8 @@ parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers,
}
/// 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())
return;
@ -1283,7 +1284,7 @@ static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op) {
p.printSymbolName(op.getModuleName());
// 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
// external modules.
@ -1372,6 +1373,18 @@ parseOptionalParameters(OpAsmParser &parser,
});
}
/// Shim to use with assemblyFormat, custom<ParameterList>.
static ParseResult parseParameterList(OpAsmParser &parser,
ArrayAttr &parameters) {
SmallVector<Attribute> parseParameters;
if (failed(parseOptionalParameters(parser, parseParameters)))
return failure();
parameters = ArrayAttr::get(parser.getContext(), parseParameters);
return success();
}
static ParseResult parseFModuleLikeOp(OpAsmParser &parser,
OperationState &result,
bool hasSSAIdentifiers) {
@ -5764,6 +5777,9 @@ void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
genericAsmResultNames(*this, setNameFn);
}
void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
genericAsmResultNames(*this, setNameFn);
}
void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
genericAsmResultNames(*this, setNameFn);
}

View File

@ -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
%cg0 = firrtl.int.clock_gate %clock, %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