CIRCT  20.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 // Common type inference functions.
144  std::optional<Location> loc);
146  std::optional<Location> loc);
148  std::optional<Location> loc);
150  std::optional<Location> loc);
151 FIRRTLType inferReductionResult(FIRRTLType arg, std::optional<Location> loc);
152 } // namespace impl
153 
154 /// A binary operation where the operands have the same integer kind.
155 template <typename ConcreteOp>
157  : public OpTrait::TraitBase<ConcreteOp, SameOperandsIntTypeKind> {
158 public:
159  static LogicalResult verifyTrait(Operation *op) {
161  }
162 };
163 
164 // This is a summary of a FIRRTL::MemOp. It defines the relevant properties of
165 // the FIRRTL memory, and can be constructed by parsing its attributes.
166 struct FirMemory {
167  size_t numReadPorts;
170  size_t dataWidth;
171  size_t depth;
172  size_t readLatency;
173  size_t writeLatency;
174  size_t maskBits;
175  seq::RUW readUnderWrite;
176  seq::WUW writeUnderWrite;
177  SmallVector<int32_t> writeClockIDs;
178  StringAttr modName;
179  bool isMasked;
180  MemoryInitAttr init;
181  StringAttr prefix;
182 
183  // Location is carried along but not considered part of the identity of this.
184  Location loc;
185  // Flag to indicate if the memory was under the DUT hierarchy, only used in
186  // LowerToHW. Not part of the identity.
187  bool isInDut = false;
188  // The original MemOp, only used in LowerToHW. Also not part of the identity.
189  Operation *op = nullptr;
190 
191  auto getTuple() const {
192  return std::make_tuple(
195  writeClockIDs, init ? init.getFilename().getValue() : "",
196  init ? init.getIsBinary() : false, init ? init.getIsInline() : false,
197  prefix ? prefix.getValue() : "");
198  }
199  bool operator<(const FirMemory &rhs) const {
200  return getTuple() < rhs.getTuple();
201  }
202  bool operator==(const FirMemory &rhs) const {
203  return getTuple() == rhs.getTuple();
204  }
205  StringAttr getFirMemoryName() const;
206 
207  /**
208  * Check whether the memory is a seq mem.
209  *
210  * The following conditions must hold:
211  * 1. read latency and write latency of one.
212  * 2. undefined read-under-write behavior.
213  */
214  bool isSeqMem() const {
215  if (readLatency != 1 || writeLatency != 1)
216  return false;
217  return dataWidth > 0;
218  }
219 };
220 
221 } // namespace firrtl
222 } // namespace circt
223 
224 #define GET_OP_CLASSES
225 #include "circt/Dialect/FIRRTL/FIRRTL.h.inc"
226 
227 //===----------------------------------------------------------------------===//
228 // Traits
229 //===----------------------------------------------------------------------===//
230 
231 namespace llvm {
232 template <>
233 struct DenseMapInfo<circt::firrtl::FModuleOp> {
234  using Operation = mlir::Operation;
235  using FModuleOp = circt::firrtl::FModuleOp;
236  static inline FModuleOp getEmptyKey() {
237  return FModuleOp::getFromOpaquePointer(
239  }
240  static inline FModuleOp getTombstoneKey() {
241  return FModuleOp::getFromOpaquePointer(
243  }
244  static unsigned getHashValue(const FModuleOp &val) {
246  }
247  static bool isEqual(const FModuleOp &lhs, const FModuleOp &rhs) {
248  return lhs == rhs;
249  }
250 };
251 } // end namespace llvm
252 
253 #endif // CIRCT_DIALECT_FIRRTL_OPS_H
A binary operation where the operands have the same integer kind.
Definition: FIRRTLOps.h:157
static LogicalResult verifyTrait(Operation *op)
Definition: FIRRTLOps.h:159
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< 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 verifySameOperandsIntTypeKind(Operation *op)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Definition: FIRRTLOps.cpp:182
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
Definition: FIRRTLOps.cpp:4588
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:212
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
Definition: FIRRTLOps.cpp:317
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
Definition: FIRRTLOps.cpp:301
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
Definition: FIRRTLOps.cpp:102
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:3959
DeclKind getDeclarationKind(Value val)
Definition: FIRRTLOps.cpp:289
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:214
bool operator==(const FirMemory &rhs) const
Definition: FIRRTLOps.h:202
MemoryInitAttr init
Definition: FIRRTLOps.h:180
StringAttr getFirMemoryName() const
Definition: FIRRTLOps.cpp:3318
bool operator<(const FirMemory &rhs) const
Definition: FIRRTLOps.h:199
auto getTuple() const
Definition: FIRRTLOps.h:191
SmallVector< int32_t > writeClockIDs
Definition: FIRRTLOps.h:177
static unsigned getHashValue(const FModuleOp &val)
Definition: FIRRTLOps.h:244
static bool isEqual(const FModuleOp &lhs, const FModuleOp &rhs)
Definition: FIRRTLOps.h:247