CIRCT  20.0.0git
FirRegLowering.h
Go to the documentation of this file.
1 //===- FirRegLowering.h - FirReg lowering utilities ===========--*- 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 // NOLINTNEXTLINE(llvm-header-guard)
10 #ifndef CONVERSION_SEQTOSV_FIRREGLOWERING_H
11 #define CONVERSION_SEQTOSV_FIRREGLOWERING_H
12 
14 #include "circt/Dialect/HW/HWOps.h"
15 #include "circt/Dialect/SV/SVOps.h"
17 #include "circt/Support/LLVM.h"
19 #include "circt/Support/SymCache.h"
20 #include "llvm/ADT/SmallPtrSet.h"
21 
22 namespace circt {
23 
24 using namespace hw;
25 // This class computes the set of muxes that are reachable from an op.
26 // The heuristic propagates the reachability only through the 3 ops, mux,
27 // array_create and array_get. All other ops block the reachability.
28 // This analysis is built lazily on every query.
29 // The query: is a mux is reachable from a reg, results in a DFS traversal
30 // of the IR rooted at the register. This traversal is completed and the
31 // result is cached in a Map, for faster retrieval on any future query of any
32 // op in this subgraph.
34 public:
35  ReachableMuxes(HWModuleOp m) : module(m) {}
36 
37  bool isMuxReachableFrom(seq::FirRegOp regOp, comb::MuxOp muxOp);
38 
39 private:
40  void buildReachabilityFrom(Operation *startNode);
42  llvm::DenseMap<Operation *, llvm::SmallDenseSet<Operation *>> reachableMuxes;
43  llvm::SmallPtrSet<Operation *, 16> visited;
44 };
45 
46 // The op and its users information that needs to be tracked on the stack
47 // for an iterative DFS traversal.
48 struct OpUserInfo {
49  Operation *op;
51  llvm::filter_iterator<Operation::user_iterator,
52  std::function<bool(const Operation *)>>;
53 
55  static std::function<bool(const Operation *op)> opAllowsReachability;
56 
57  OpUserInfo(Operation *op)
58  : op(op), userIter(op->getUsers().begin(), op->getUsers().end(),
59  opAllowsReachability),
60  userEnd(op->getUsers().end(), op->getUsers().end(),
61  opAllowsReachability) {}
62 
64  if (unvisited) {
65  unvisited = false;
66  return true;
67  }
68  return false;
69  }
70 
71 private:
72  bool unvisited = true;
73 };
74 
75 /// Lower FirRegOp to `sv.reg` and `sv.always`.
77 public:
78  FirRegLowering(TypeConverter &typeConverter, hw::HWModuleOp module,
79  bool disableRegRandomization = false,
80  bool emitSeparateAlwaysBlocks = false);
81 
82  void lower();
83  bool needsRegRandomization() const { return needsRandom; }
84 
85  unsigned numSubaccessRestored = 0;
86 
87 private:
88  struct RegLowerInfo {
90  IntegerAttr preset;
93  int64_t randStart;
94  size_t width;
95  };
96 
97  RegLowerInfo lower(seq::FirRegOp reg);
98 
99  void initialize(OpBuilder &builder, RegLowerInfo reg, ArrayRef<Value> rands);
100  void initializeRegisterElements(Location loc, OpBuilder &builder, Value reg,
101  Value rand, unsigned &pos);
102 
103  void createTree(OpBuilder &builder, Value reg, Value term, Value next);
104  std::optional<std::tuple<Value, Value, Value>>
105  tryRestoringSubaccess(OpBuilder &builder, Value reg, Value term,
106  hw::ArrayCreateOp nextRegValue);
107 
108  void addToAlwaysBlock(Block *block, sv::EventControl clockEdge, Value clock,
109  const std::function<void(OpBuilder &)> &body,
110  sv::ResetType resetStyle = {},
111  sv::EventControl resetEdge = {}, Value reset = {},
112  const std::function<void(OpBuilder &)> &resetBody = {});
113 
114  void addToIfBlock(OpBuilder &builder, Value cond,
115  const std::function<void()> &trueSide,
116  const std::function<void()> &falseSide);
117 
118  hw::ConstantOp getOrCreateConstant(Location loc, const APInt &value) {
119  OpBuilder builder(module.getBody());
120  auto &constant = constantCache[value];
121  if (constant) {
122  constant->setLoc(builder.getFusedLoc({constant->getLoc(), loc}));
123  return constant;
124  }
125 
126  constant = builder.create<hw::ConstantOp>(loc, value);
127  return constant;
128  }
129 
130  using AlwaysKeyType = std::tuple<Block *, sv::EventControl, Value,
131  sv::ResetType, sv::EventControl, Value>;
134 
135  using IfKeyType = std::pair<Block *, Value>;
137 
140  std::unique_ptr<ReachableMuxes> reachableMuxes;
141 
142  TypeConverter &typeConverter;
144 
147 
148  bool needsRandom = false;
149 };
150 } // namespace circt
151 
152 #endif // CONVERSION_SEQTOSV_FIRREGLOWERING_H
Lower FirRegOp to sv.reg and sv.always.
std::unique_ptr< ReachableMuxes > reachableMuxes
bool needsRegRandomization() const
llvm::SmallDenseMap< std::pair< Value, unsigned >, Value > arrayIndexCache
llvm::SmallDenseMap< IfKeyType, sv::IfOp > ifCache
hw::HWModuleOp module
RegLowerInfo lower(seq::FirRegOp reg)
llvm::SmallDenseMap< APInt, hw::ConstantOp > constantCache
std::pair< Block *, Value > IfKeyType
hw::ConstantOp getOrCreateConstant(Location loc, const APInt &value)
std::tuple< Block *, sv::EventControl, Value, sv::ResetType, sv::EventControl, Value > AlwaysKeyType
TypeConverter & typeConverter
llvm::SmallDenseMap< AlwaysKeyType, std::pair< sv::AlwaysOp, sv::IfOp > > alwaysBlocks
llvm::DenseMap< Operation *, llvm::SmallDenseSet< Operation * > > reachableMuxes
llvm::SmallPtrSet< Operation *, 16 > visited
ReachableMuxes(HWModuleOp m)
Definition: sv.py:68
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: hw.py:1
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition: seq.py:21
llvm::filter_iterator< Operation::user_iterator, std::function< bool(const Operation *)> > ValidUsersIterator
static std::function< bool(const Operation *op)> opAllowsReachability
OpUserInfo(Operation *op)
ValidUsersIterator userEnd