CIRCT  19.0.0git
FIRRTLOps.h
Go to the documentation of this file.
1 //===- FIRRTLOps.h - Declare FIRRTL dialect operations ----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file declares the operation class for the FIRRTL IR.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef CIRCT_DIALECT_FIRRTL_OPS_H
14 #define CIRCT_DIALECT_FIRRTL_OPS_H
15 
22 #include "circt/Dialect/SV/SVOps.h"
24 #include "circt/Support/FieldRef.h"
26 #include "mlir/IR/Builders.h"
27 #include "mlir/IR/OpImplementation.h"
28 #include "mlir/IR/RegionKindInterface.h"
29 #include "mlir/IR/SymbolTable.h"
30 #include "mlir/Interfaces/FunctionInterfaces.h"
31 #include "mlir/Interfaces/InferTypeOpInterface.h"
32 #include "mlir/Interfaces/SideEffectInterfaces.h"
33 
34 namespace circt {
35 namespace firrtl {
36 
37 class MatchingConnectOp;
38 
39 // works for regs, nodes, and wires
40 bool hasDroppableName(Operation *op);
41 
42 /// Return true if the specified operation is a firrtl expression.
43 bool isExpression(Operation *op);
44 
45 /// Return the number of ports in a module-like thing (modules, memories, etc)
46 size_t getNumPorts(Operation *op);
47 
48 /// Return true if the specified operation has a constant value. This trivially
49 /// checks for `firrtl.constant` and friends, but also looks through subaccesses
50 /// and correctly handles wires driven with only constant values.
51 bool isConstant(Operation *op);
52 bool isConstant(Value value);
53 
54 /// Returns true if the value results from an expression with duplex flow.
55 /// Duplex values have special treatment in bundle connect operations, and
56 /// their flip orientation is not used to determine the direction of each
57 /// pairwise connect.
58 bool isDuplexValue(Value val);
59 
60 enum class Flow : uint8_t { None, Source, Sink, Duplex };
61 
62 /// Get a flow's reverse.
63 Flow swapFlow(Flow flow);
64 
65 constexpr bool isValidSrc(Flow flow) {
66  return uint8_t(flow) & uint8_t(Flow::Source);
67 }
68 
69 constexpr bool isValidDst(Flow flow) {
70  return uint8_t(flow) & uint8_t(Flow::Sink);
71 }
72 
73 /// Compute the flow for a Value, \p val, as determined by the FIRRTL
74 /// specification. This recursively walks backwards from \p val to the
75 /// declaration. The resulting flow is a combination of the declaration flow
76 /// (output ports and instance inputs are sinks, registers and wires are
77 /// duplex, anything else is a source) and the number of intermediary flips.
78 /// An even number of flips will result in the same flow as the declaration.
79 /// An odd number of flips will result in reversed flow being returned. The
80 /// reverse of source is sink. The reverse of sink is source. The reverse of
81 /// duplex is duplex. The \p accumulatedFlow parameter sets the initial flow.
82 /// A user should normally \a not have to change this from its default of \p
83 /// Flow::Source.
84 Flow foldFlow(Value val, Flow accumulatedFlow = Flow::Source);
85 
86 enum class DeclKind { Port, Instance, Other };
87 
88 DeclKind getDeclarationKind(Value val);
89 
90 enum class ReadPortSubfield { addr, en, clk, data };
91 enum class WritePortSubfield { addr, en, clk, data, mask };
93 
94 /// Allow 'or'ing MemDirAttr. This allows combining Read and Write into
95 /// ReadWrite.
96 inline MemDirAttr operator|(MemDirAttr lhs, MemDirAttr rhs) {
97  return static_cast<MemDirAttr>(
98  static_cast<std::underlying_type<MemDirAttr>::type>(lhs) |
99  static_cast<std::underlying_type<MemDirAttr>::type>(rhs));
100 }
101 
102 inline MemDirAttr &operator|=(MemDirAttr &lhs, MemDirAttr rhs) {
103  lhs = lhs | rhs;
104  return lhs;
105 }
106 
107 /// Return the StringAttr for the inner_sym name, if it exists.
108 inline StringAttr getInnerSymName(Operation *op) {
109  auto s = op->getAttrOfType<hw::InnerSymAttr>(
111  if (s)
112  return s.getSymName();
113  return StringAttr();
114 }
115 
116 /// Check whether a block argument ("port") or the operation defining a value
117 /// has a `DontTouch` annotation, or a symbol that should prevent certain types
118 /// of canonicalizations.
119 bool hasDontTouch(Value value);
120 
121 /// Check whether an operation has a `DontTouch` annotation, or a symbol that
122 /// should prevent certain types of canonicalizations.
123 bool hasDontTouch(Operation *op);
124 
125 /// Scan all the uses of the specified value, checking to see if there is
126 /// exactly one connect that has the value as its destination. This returns the
127 /// operation if found and if all the other users are "reads" from the value.
128 /// Returns null if there are no connects, or multiple connects to the value, or
129 /// if the value is involved in an `AttachOp`.
130 ///
131 /// Note that this will simply return the connect, which is located *anywhere*
132 /// after the definition of the value. Users of this function are likely
133 /// interested in the source side of the returned connect, the definition of
134 /// which does likely not dominate the original value.
135 MatchingConnectOp getSingleConnectUserOf(Value value);
136 
137 // Out-of-line implementation of various trait verification methods and
138 // functions commonly used among operations.
139 namespace impl {
140 LogicalResult verifySameOperandsIntTypeKind(Operation *op);
141 
142 // Type inference adaptor for FIRRTL operations.
143 LogicalResult inferReturnTypes(
144  MLIRContext *context, std::optional<Location> loc, ValueRange operands,
145  DictionaryAttr attrs, mlir::OpaqueProperties properties,
146  mlir::RegionRange regions, SmallVectorImpl<Type> &results,
147  llvm::function_ref<FIRRTLType(ValueRange, ArrayRef<NamedAttribute>,
148  std::optional<Location>)>
149  callback);
150 
151 // Common type inference functions.
153  std::optional<Location> loc);
155  std::optional<Location> loc);
157  std::optional<Location> loc);
159  std::optional<Location> loc);
160 FIRRTLType inferReductionResult(FIRRTLType arg, std::optional<Location> loc);
161 
162 // Common parsed argument validation functions.
163 LogicalResult validateBinaryOpArguments(ValueRange operands,
164  ArrayRef<NamedAttribute> attrs,
165  Location loc);
166 LogicalResult validateUnaryOpArguments(ValueRange operands,
167  ArrayRef<NamedAttribute> attrs,
168  Location loc);
169 LogicalResult validateOneOperandOneConst(ValueRange operands,
170  ArrayRef<NamedAttribute> attrs,
171  Location loc);
172 } // namespace impl
173 
174 /// A binary operation where the operands have the same integer kind.
175 template <typename ConcreteOp>
177  : public OpTrait::TraitBase<ConcreteOp, SameOperandsIntTypeKind> {
178 public:
179  static LogicalResult verifyTrait(Operation *op) {
181  }
182 };
183 
184 // This is a summary of a FIRRTL::MemOp. It defines the relevant properties of
185 // the FIRRTL memory, and can be constructed by parsing its attributes.
186 struct FirMemory {
187  size_t numReadPorts;
190  size_t dataWidth;
191  size_t depth;
192  size_t readLatency;
193  size_t writeLatency;
194  size_t maskBits;
195  seq::RUW readUnderWrite;
196  seq::WUW writeUnderWrite;
197  SmallVector<int32_t> writeClockIDs;
198  StringAttr modName;
199  bool isMasked;
200  MemoryInitAttr init;
201  StringAttr prefix;
202 
203  // Location is carried along but not considered part of the identity of this.
204  Location loc;
205  // Flag to indicate if the memory was under the DUT hierarchy, only used in
206  // LowerToHW. Not part of the identity.
207  bool isInDut = false;
208  // The original MemOp, only used in LowerToHW. Also not part of the identity.
209  Operation *op = nullptr;
210 
211  auto getTuple() const {
212  return std::make_tuple(
215  writeClockIDs, init ? init.getFilename().getValue() : "",
216  init ? init.getIsBinary() : false, init ? init.getIsInline() : false,
217  prefix ? prefix.getValue() : "");
218  }
219  bool operator<(const FirMemory &rhs) const {
220  return getTuple() < rhs.getTuple();
221  }
222  bool operator==(const FirMemory &rhs) const {
223  return getTuple() == rhs.getTuple();
224  }
225  StringAttr getFirMemoryName() const;
226 
227  /**
228  * Check whether the memory is a seq mem.
229  *
230  * The following conditions must hold:
231  * 1. read latency and write latency of one.
232  * 2. undefined read-under-write behavior.
233  */
234  bool isSeqMem() const {
235  if (readLatency != 1 || writeLatency != 1)
236  return false;
237  return dataWidth > 0;
238  }
239 };
240 
241 } // namespace firrtl
242 } // namespace circt
243 
244 #define GET_OP_CLASSES
245 #include "circt/Dialect/FIRRTL/FIRRTL.h.inc"
246 
247 //===----------------------------------------------------------------------===//
248 // Traits
249 //===----------------------------------------------------------------------===//
250 
251 namespace llvm {
252 template <>
253 struct DenseMapInfo<circt::firrtl::FModuleOp> {
254  using Operation = mlir::Operation;
255  using FModuleOp = circt::firrtl::FModuleOp;
256  static inline FModuleOp getEmptyKey() {
257  return FModuleOp::getFromOpaquePointer(
258  DenseMapInfo<Operation *>::getEmptyKey());
259  }
260  static inline FModuleOp getTombstoneKey() {
261  return FModuleOp::getFromOpaquePointer(
262  DenseMapInfo<Operation *>::getTombstoneKey());
263  }
264  static unsigned getHashValue(const FModuleOp &val) {
265  return DenseMapInfo<Operation *>::getHashValue(val);
266  }
267  static bool isEqual(const FModuleOp &lhs, const FModuleOp &rhs) {
268  return lhs == rhs;
269  }
270 };
271 } // end namespace llvm
272 
273 #endif // CIRCT_DIALECT_FIRRTL_OPS_H
A binary operation where the operands have the same integer kind.
Definition: FIRRTLOps.h:177
static LogicalResult verifyTrait(Operation *op)
Definition: FIRRTLOps.h:179
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
LogicalResult validateBinaryOpArguments(ValueRange operands, ArrayRef< NamedAttribute > attrs, Location loc)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
LogicalResult inferReturnTypes(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results, llvm::function_ref< FIRRTLType(ValueRange, ArrayRef< NamedAttribute >, std::optional< Location >)> callback)
LogicalResult validateUnaryOpArguments(ValueRange operands, ArrayRef< NamedAttribute > attrs, Location loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult validateOneOperandOneConst(ValueRange operands, ArrayRef< NamedAttribute > attrs, Location loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Definition: FIRRTLOps.cpp:179
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
Definition: FIRRTLOps.cpp:4571
constexpr bool isValidDst(Flow flow)
Definition: FIRRTLOps.h:69
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
Definition: FIRRTLOps.cpp:209
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
Definition: FIRRTLOps.cpp:314
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
Definition: FIRRTLOps.cpp:298
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
Definition: FIRRTLOps.cpp:99
bool hasDroppableName(Operation *op)
Return true if the name is droppable.
constexpr bool isValidSrc(Flow flow)
Definition: FIRRTLOps.h:65
MatchingConnectOp getSingleConnectUserOf(Value value)
Scan all the uses of the specified value, checking to see if there is exactly one connect that has th...
MemDirAttr operator|(MemDirAttr lhs, MemDirAttr rhs)
Allow 'or'ing MemDirAttr.
Definition: FIRRTLOps.h:96
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
Definition: FIRRTLOps.cpp:3942
DeclKind getDeclarationKind(Value val)
Definition: FIRRTLOps.cpp:286
StringAttr getInnerSymName(Operation *op)
Return the StringAttr for the inner_sym name, if it exists.
Definition: FIRRTLOps.h:108
MemDirAttr & operator|=(MemDirAttr &lhs, MemDirAttr rhs)
Definition: FIRRTLOps.h:102
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
bool isSeqMem() const
Check whether the memory is a seq mem.
Definition: FIRRTLOps.h:234
bool operator==(const FirMemory &rhs) const
Definition: FIRRTLOps.h:222
MemoryInitAttr init
Definition: FIRRTLOps.h:200
StringAttr getFirMemoryName() const
Definition: FIRRTLOps.cpp:3282
bool operator<(const FirMemory &rhs) const
Definition: FIRRTLOps.h:219
auto getTuple() const
Definition: FIRRTLOps.h:211
SmallVector< int32_t > writeClockIDs
Definition: FIRRTLOps.h:197
static unsigned getHashValue(const FModuleOp &val)
Definition: FIRRTLOps.h:264
static bool isEqual(const FModuleOp &lhs, const FModuleOp &rhs)
Definition: FIRRTLOps.h:267