Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIRRTL] Strict Instance Operation #7143

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
cacdfc5
[NFC, FIRRTL] Rename StrictConnect to MatchingConnect. This is to re…
darthscsi Jun 3, 2024
9987c26
[FIRRTL] LHSType wrapper to indicate writable values. This is to ena…
darthscsi Jun 3, 2024
4bfea6c
[FIRRTL] Wires and Registers with read and write ports
darthscsi Jun 3, 2024
1939602
formatting
darthscsi Jun 3, 2024
8260fdf
Merge remote-tracking branch 'origin/main' into dev/darthscsi/matchin…
darthscsi Jun 3, 2024
90d26da
Merge branch 'dev/darthscsi/matchingconnect' into dev/darthscsi/lhs
darthscsi Jun 3, 2024
6a11810
Merge branch 'dev/darthscsi/lhs' into dev/darthscsi/lhs_decls
darthscsi Jun 3, 2024
ffff133
formatting
darthscsi Jun 3, 2024
7334cc8
[FIRRTL] Ops to operate on LHSType.
darthscsi Jun 3, 2024
e6ca87a
missing infra
darthscsi Jun 3, 2024
2f0ae77
Merge branch 'dev/darthscsi/lhs' into dev/darthscsi/lhs_decls
darthscsi Jun 3, 2024
54d27fa
extra line
darthscsi Jun 3, 2024
621db0a
add test
darthscsi Jun 3, 2024
5bba153
Merge branch 'dev/darthscsi/lhs_decls' into dev/darthscsi/lhs_ops
darthscsi Jun 3, 2024
59dec38
add tests
darthscsi Jun 3, 2024
e42156f
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs
darthscsi Jun 4, 2024
d53ff42
Merge branch 'dev/darthscsi/lhs' into dev/darthscsi/lhs_decls
darthscsi Jun 4, 2024
d485541
tidy
darthscsi Jun 4, 2024
794642f
Merge branch 'dev/darthscsi/lhs_decls' into dev/darthscsi/lhs_ops
darthscsi Jun 4, 2024
a5f31fe
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs
darthscsi Jun 6, 2024
f643e79
[FIRRTL] Strict Instance Operation
darthscsi Jun 7, 2024
9a95992
Merge branch 'dev/darthscsi/lhs_ops' into dev/darthscsi/lhs_instance
darthscsi Jun 7, 2024
75711fa
Add strict instances.
darthscsi Jun 7, 2024
20692bb
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs
darthscsi Jun 17, 2024
eebbfe0
Merge main and minor fixes.
darthscsi Jun 17, 2024
d04e445
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs
darthscsi Jun 17, 2024
82d815a
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs
darthscsi Jun 17, 2024
611c3b3
backout transient issue
darthscsi Jun 17, 2024
dd29f1f
backout transient issue
darthscsi Jun 17, 2024
c421b9b
several updates
darthscsi Jun 17, 2024
006aac7
parser error tests
darthscsi Jun 17, 2024
02865ee
use older clang-format
darthscsi Jun 17, 2024
6639124
Merge branch 'dev/darthscsi/lhs' into dev/darthscsi/lhs_decls
darthscsi Jun 18, 2024
1f12c9b
fix build
darthscsi Jun 18, 2024
cce41b9
Merge branch 'dev/darthscsi/lhs_decls' into dev/darthscsi/lhs_ops
darthscsi Jun 18, 2024
2b0dc58
Merge branch 'dev/darthscsi/lhs_ops' into dev/darthscsi/lhs_instance
darthscsi Jun 18, 2024
961a357
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs_decls
darthscsi Jun 20, 2024
da9757a
Merge remote-tracking branch 'origin/main' into dev/darthscsi/lhs_decls
darthscsi Jun 21, 2024
e03f7a9
Merge branch 'dev/darthscsi/lhs_decls' into dev/darthscsi/lhs_ops
darthscsi Jun 21, 2024
1835f5b
test for reg
darthscsi Jun 21, 2024
3f63125
Merge branch 'dev/darthscsi/lhs_decls' into dev/darthscsi/lhs_ops
darthscsi Jun 21, 2024
4d8f8d4
fix type and add tests
darthscsi Jun 21, 2024
ca829d2
Merge branch 'dev/darthscsi/lhs_ops' into dev/darthscsi/lhs_instance
darthscsi Jun 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 192 additions & 0 deletions include/circt/Dialect/FIRRTL/FIRRTLDeclarations.td
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,128 @@ def InstanceOp : HardwareDeclOp<"instance", [
let hasVerifier = true;
}

def StrictInstanceOp : HardwareDeclOp<"strictinstance", [
DeclareOpInterfaceMethods<FInstanceLike>,
DeclareOpInterfaceMethods<SymbolUserOpInterface>,
DeclareOpInterfaceMethods<InstanceGraphInstanceOpInterface, [
"getModuleName"
]>,
]> {
let summary = "Instantiate an instance of a module";
let description = [{
This represents an instance of a module. The results are the modules inputs
and outputs. The inputs have LHSType wrapped types, the outputs do not.

Examples:
```mlir
%0 = firrtl.strictinstance foo @Foo(in io: !firrtl.uint)
firrtl.strictconnect %0, %c0_ui
```
}];

let arguments = (ins FlatSymbolRefAttr:$moduleName, StrAttr:$name, NameKindAttr:$nameKind,
DenseBoolArrayAttr:$portDirections, StrArrayAttr:$portNames,
AnnotationArrayAttr:$annotations,
PortAnnotationsAttr:$portAnnotations,
LayerArrayAttr:$layers,
UnitAttr:$lowerToBind,
OptionalAttr<InnerSymAttr>:$inner_sym);

let results = (outs Variadic<AnyType>:$results);

let hasCustomAssemblyFormat = 1;

let builders = [
OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
"::mlir::StringRef":$moduleName,
"::mlir::StringRef":$name,
"::circt::firrtl::NameKindEnum":$nameKind,
"::mlir::ArrayRef<Direction>":$portDirections,
"::mlir::ArrayRef<Attribute>":$portNames,
CArg<"ArrayRef<Attribute>", "{}">:$annotations,
CArg<"ArrayRef<Attribute>", "{}">:$portAnnotations,
CArg<"::mlir::ArrayRef<Attribute>", "{}">:$layers,
CArg<"bool","false">:$lowerToBind,
CArg<"StringAttr", "StringAttr()">:$innerSym)>,
OpBuilder<(ins "::mlir::TypeRange":$resultTypes,
"::mlir::StringRef":$moduleName,
"::mlir::StringRef":$name,
"::circt::firrtl::NameKindEnum":$nameKind,
"::mlir::ArrayRef<Direction>":$portDirections,
"::mlir::ArrayRef<Attribute>":$portNames,
"ArrayRef<Attribute>":$annotations,
"ArrayRef<Attribute>":$portAnnotations,
"::mlir::ArrayRef<Attribute>":$layers,
"bool":$lowerToBind,
"hw::InnerSymAttr":$innerSym)>,

/// Constructor when you have the target module in hand.
OpBuilder<(ins "FModuleLike":$module,
"mlir::StringRef":$name,
CArg<"NameKindEnum", "NameKindEnum::DroppableName">:$nameKind,
CArg<"ArrayRef<Attribute>", "{}">:$annotations,
CArg<"ArrayRef<Attribute>", "{}">:$portAnnotations,
CArg<"bool","false">:$lowerToBind,
CArg<"hw::InnerSymAttr", "hw::InnerSymAttr()">:$innerSym)>,

/// Constructor when you have a port info list in hand.
OpBuilder<(ins "ArrayRef<PortInfo>":$ports,
"::mlir::StringRef":$moduleName,
"mlir::StringRef":$name,
CArg<"NameKindEnum", "NameKindEnum::DroppableName">:$nameKind,
CArg<"ArrayRef<Attribute>", "{}">:$annotations,
CArg<"ArrayRef<Attribute>", "{}">:$layers,
CArg<"bool","false">:$lowerToBind,
CArg<"hw::InnerSymAttr", "hw::InnerSymAttr()">:$innerSym)>
];

let extraClassDeclaration = [{
/// Return the port direction for the specified result number.
Direction getPortDirection(size_t resultNo) {
return direction::get(getPortDirections()[resultNo]);
}

/// Return the port name for the specified result number.
StringAttr getPortName(size_t resultNo) {
return cast<StringAttr>(getPortNames()[resultNo]);
}
StringRef getPortNameStr(size_t resultNo) {
return getPortName(resultNo).getValue();
}

/// Hooks for port annotations.
ArrayAttr getPortAnnotation(unsigned portIdx);
void setAllPortAnnotations(ArrayRef<Attribute> annotations);

/// Builds a new `StrictInstanceOp` with the ports listed in `portIndices` erased,
/// and updates any users of the remaining ports to point at the new
/// instance.
StrictInstanceOp erasePorts(OpBuilder &builder, const llvm::BitVector &portIndices);

/// Clone the instance op and add ports. This is usually used in
/// conjuction with adding ports to the referenced module. This will emit
/// the new StrictInstanceOp to the same location.
StrictInstanceOp cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports);

//===------------------------------------------------------------------===//
// Instance graph methods
//===------------------------------------------------------------------===//

// Quick lookup of the referenced module using the instance graph.
template <typename T = ::circt::igraph::ModuleOpInterface>
T getReferencedModule(::circt::igraph::InstanceGraph &instanceGraph) {
auto moduleNameAttr = getModuleNameAttr().getAttr();
auto *node = instanceGraph.lookup(moduleNameAttr);
if (!node)
return nullptr;
Operation *moduleOp = node->getModule();
return dyn_cast_or_null<T>(moduleOp);
}
}];

let hasVerifier = true;
}

def InstanceChoiceOp : HardwareDeclOp<"instance_choice", [
DeclareOpInterfaceMethods<SymbolUserOpInterface>
]> {
Expand Down Expand Up @@ -579,6 +701,41 @@ def RegResetOp : HardwareDeclOp<"regreset", [Forceable, CombDataflow]> {
let hasVerifier = 1;
}

def StrictRegOp : HardwareDeclOp<"strictreg", [Forceable, SameVariadicOperandSize]> {
let summary = "Define a new register with an optional reset";
let description = [{
Declare a new register:
```
%name, %name_write = firrtl.regreset %clockVal (reset %resetSignal, %resetValue)? : t1 (, rt)?
```
}];

let arguments = (
ins ClockType:$clockVal,
Optional<AnyResetType>:$resetSignal,
Optional<AnyRegisterType>:$resetValue,
StrAttr:$name, NameKindAttr:$nameKind,
AnnotationArrayAttr:$annotations,
OptionalAttr<InnerSymAttr>:$inner_sym,
UnitAttr:$forceable);
let results = (outs AnyRegisterType:$read, LHSType:$write, Optional<RefType>:$ref);

let assemblyFormat = [{
(`sym` $inner_sym^)? `` custom<NameKind>($nameKind)
$clockVal (`,` `reset` `(` $resetSignal^ `:` type($resetSignal) `,` $resetValue `:` type($resetValue) `)` )? (`,` `forceable` $forceable^)? `` custom<FIRRTLImplicitSSAName>(attr-dict)
`:` type($clockVal) `,` custom<OptionalLHSOpTypes>(type($write), type($read)) (`,` qualified(type($ref))^)?

}];

// let hasCanonicalizer = true;
// let hasVerifier = 1;

let extraClassDeclaration = [{
Value getResult();
}];
}


def WireOp : HardwareDeclOp<"wire", [
Forceable,
DeclareOpInterfaceMethods<SymbolUserOpInterface>
Expand Down Expand Up @@ -670,6 +827,41 @@ def WireOp : HardwareDeclOp<"wire", [
}];
}

def StrictWireOp : HardwareDeclOp<"strictwire", [
Forceable,
LHSTypeConstraint<"read", "write">,
OptRefTypeConstraint<"read", "ref">,
DeclareOpInterfaceMethods<SymbolUserOpInterface>
]> {
let summary = "Define a new wire";
let description = [{
Declare a new wire:
```
%name,%name.wp,%name.ref = firrtl.strictwire forceable : t1
```
}];

let arguments = (ins StrAttr:$name, NameKindAttr:$nameKind,
AnnotationArrayAttr:$annotations,
OptionalAttr<InnerSymAttr>:$inner_sym,
UnitAttr:$forceable); // ReferenceKinds
let results = (outs PassiveType:$read,
LHSType:$write,
Optional<RefType>:$ref);

// let hasCanonicalizer = true;

let assemblyFormat = [{
(`sym` $inner_sym^)? `` custom<NameKind>($nameKind)
(`forceable` $forceable^)? `` custom<FIRRTLImplicitSSAName>(attr-dict) `:`
custom<OptionalLHSOpTypes>(type($write), type($read)) (`,` qualified(type($ref))^)?
}];

let extraClassDeclaration = [{
Value getResult();
}];
}

//===----------------------------------------------------------------------===//
// Property Ops
//===----------------------------------------------------------------------===//
Expand Down
56 changes: 48 additions & 8 deletions include/circt/Dialect/FIRRTL/FIRRTLExpressions.td
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ def InvalidValueOp : FIRRTLOp<"invalidvalue",
let assemblyFormat = "attr-dict `:` qualified(type($result))";
}

class BaseSubfieldOp<string name, Type btype, Type rtype> : FIRRTLExprOp<name> {
class BaseSubfieldOp<string name, Type btype, Type itype, Type rtype> : FIRRTLExprOp<name> {
let summary = "Extract a subfield of another value";
let description = [{
The subfield expression refers to a subelement of an expression with a
Expand All @@ -281,44 +281,55 @@ class BaseSubfieldOp<string name, Type btype, Type rtype> : FIRRTLExprOp<name> {
```
}];

let arguments = (ins btype:$input, I32Attr:$fieldIndex);
let arguments = (ins itype:$input, I32Attr:$fieldIndex);
let results = (outs rtype:$result);
let hasVerifier = 1;
let hasCustomAssemblyFormat = 1;

let builders = [
OpBuilder<(ins "Value":$input, "StringRef":$fieldName), [{
auto bundleType = firrtl::type_cast<}] # btype # [{>(input.getType());
auto ttype = isa<LHSType>(input.getType()) ? cast<LHSType>(input.getType()).getType() : input.getType();
auto bundleType = firrtl::type_cast<}] # btype # [{>(ttype);
auto fieldIndex = bundleType.getElementIndex(fieldName);
assert(fieldIndex.has_value() && "subfield operation to unknown field");
return build($_builder, $_state, input, *fieldIndex);
}]>
];

let firrtlExtraClassDeclaration = [{
using InputType = }] # btype # [{;
using InputType = }] # itype # [{;
using InputBundleType = }] # btype # [{;

FIRRTLType stripLHS(FIRRTLType type) {
if (auto t = dyn_cast<LHSType>(type))
return t.getType();
return type;
}

/// Return true if the specified field is flipped.
bool isFieldFlipped();

/// Return a `FieldRef` to the accessed field.
FieldRef getAccessedField() {
return FieldRef(getInput(), firrtl::type_cast<InputType>(getInput().getType())
auto innerType = stripLHS(getInput().getType());
return FieldRef(getInput(), firrtl::type_cast<InputBundleType>(innerType)
.getFieldID(getFieldIndex()));
}

/// Return the name of the accessed field.
StringRef getFieldName() {
return firrtl::type_cast<InputType>(getInput().getType()).getElementName(getFieldIndex());
auto innerType = stripLHS(getInput().getType());
return firrtl::type_cast<InputBundleType>(innerType).getElementName(getFieldIndex());
}
}];
}

def SubfieldOp : BaseSubfieldOp<"subfield", BundleType, FIRRTLBaseType> {
def SubfieldOp : BaseSubfieldOp<"subfield", BundleType, BundleType, FIRRTLBaseType> {
let hasFolder = 1;
let hasCanonicalizer = 1;
}
def OpenSubfieldOp : BaseSubfieldOp<"opensubfield", OpenBundleType, FIRRTLType>;
def OpenSubfieldOp : BaseSubfieldOp<"opensubfield", OpenBundleType, OpenBundleType, FIRRTLType>;
def LHSSubfieldOp : BaseSubfieldOp<"lhssubfield", BundleType, LHSType, LHSType>;

def SubindexOp : FIRRTLExprOp<"subindex"> {
let summary = "Extract an element of a vector value";
Expand Down Expand Up @@ -377,6 +388,35 @@ def OpenSubindexOp : FIRRTLExprOp<"opensubindex"> {
}];
}

def LHSSubindexOp : FIRRTLExprOp<"lhssubindex"> {
let summary = "Reference an element of a vector value";
let description = [{
The subindex expression statically refers, by index, to a subelement
of an expression with a vector type. The index must be a non-negative
integer and cannot be equal to or exceed the length of the vector it
indexes.
```
%result = firrtl.lhssubindex %input[index] : lhs<t1>
```
}];

let arguments = (ins LHSType:$input, I32Attr:$index);
let results = (outs LHSType:$result);

let assemblyFormat =
"$input `[` $index `]` attr-dict `:` qualified(type($input))";

let firrtlExtraClassDeclaration = [{
/// Return a `FieldRef` to the accessed field.
FieldRef getAccessedField() {
auto btype = cast<BundleType>(getInput().getType().getType());
return FieldRef(getInput(), btype.getFieldID(getIndex()));
}

using InputType = FVectorType;
}];
}

def SubaccessOp : FIRRTLExprOp<"subaccess"> {
let summary = "Extract a dynamic element of a vector value";
let description = [{
Expand Down
21 changes: 21 additions & 0 deletions include/circt/Dialect/FIRRTL/FIRRTLStatements.td
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,27 @@ def MatchingConnectOp : FIRRTLOp<"matchingconnect", [FConnectLike,
custom<OptionalBinaryOpTypes>(type($dest), type($src))}];
}

def SameAnonLHSTypeOperands: PredOpTrait<
"operands must be structurally equivalent with LHS wrapper",
CPred<"areAnonymousLHSandTypeEquivalent(getDest().getType(), getSrc().getType())">>;
def StrictConnectOp : FIRRTLOp<"strictconnect", [FConnectLike,
SameAnonLHSTypeOperands]> {
let summary = "Connect two signals";
let description = [{
Connect two values with strict constraints:
```
firrtl.strictconnect %dest, %src : t1
firrtl.strictconnect %dest, %src : t1, !firrtl.alias<foo, t1>
```
}];

let arguments = (ins LHSType:$dest,
SizedPassiveType:$src);
let results = (outs);

let assemblyFormat = [{$dest `,` $src attr-dict `:` custom<OptionalLHSOpTypes>(type($dest), type($src))}];
}

def RefDefineOp : FIRRTLOp<"ref.define", [SameTypeOperands, FConnectLike]> {
let summary = "FIRRTL Define References";
let description = [{
Expand Down
1 change: 1 addition & 0 deletions include/circt/Dialect/FIRRTL/FIRRTLTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType);
/// comparison.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs);
bool areAnonymousTypesEquivalent(mlir::Type lhs, mlir::Type rhs);
bool areAnonymousLHSandTypeEquivalent(LHSType lhs, FIRRTLBaseType rhs);

mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType);

Expand Down
10 changes: 10 additions & 0 deletions include/circt/Dialect/FIRRTL/FIRRTLTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ def RWProbe : FIRRTLDialectType<
def LHSType : FIRRTLDialectType<CPred<"isa<LHSType>($_self)">,
"writable type", "::circt::firrtl::LHSType">;

class LHSTypeConstraint<string result, string input>
: TypesMatchWith<"Result must be lhs of input type",
input, result,
"type_cast<LHSType>($_self).getType()">;

class OptRefTypeConstraint<string result, string input>
: OptionalTypesMatchWith<"Result must be ref of input type",
input, result,
"type_cast<RefType>($_self).getType()">;

def ConnectableType : AnyTypeOf<[FIRRTLBaseType, ForeignType]>;
def MatchingConnectableType : AnyTypeOf<[SizedPassiveType, ForeignType]>;

Expand Down
Loading
Loading