Loading [MathJax]/extensions/tex2jax.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
18#include "circt/Support/LLVM.h"
21#include "mlir/IR/Attributes.h"
22#include "llvm/ADT/SmallPtrSet.h"
23
24namespace circt {
25
26using namespace hw;
27// This class computes the set of muxes that are reachable from an op.
28// The heuristic propagates the reachability only through the 3 ops, mux,
29// array_create and array_get. All other ops block the reachability.
30// This analysis is built lazily on every query.
31// The query: is a mux is reachable from a reg, results in a DFS traversal
32// of the IR rooted at the register. This traversal is completed and the
33// result is cached in a Map, for faster retrieval on any future query of any
34// op in this subgraph.
36public:
37 ReachableMuxes(HWModuleOp m) : module(m) {}
38
39 bool isMuxReachableFrom(seq::FirRegOp regOp, comb::MuxOp muxOp);
40
41private:
42 void buildReachabilityFrom(Operation *startNode);
43 HWModuleOp module;
44 llvm::DenseMap<Operation *, llvm::SmallDenseSet<Operation *>> reachableMuxes;
45 llvm::SmallPtrSet<Operation *, 16> visited;
46};
47
48// The op and its users information that needs to be tracked on the stack
49// for an iterative DFS traversal.
50struct OpUserInfo {
51 Operation *op;
53 llvm::filter_iterator<Operation::user_iterator,
54 std::function<bool(const Operation *)>>;
55
57 static std::function<bool(const Operation *op)> opAllowsReachability;
58
59 OpUserInfo(Operation *op)
60 : op(op), userIter(op->getUsers().begin(), op->getUsers().end(),
62 userEnd(op->getUsers().end(), op->getUsers().end(),
64
66 if (unvisited) {
67 unvisited = false;
68 return true;
69 }
70 return false;
71 }
72
73private:
74 bool unvisited = true;
75};
76
77/// Lower FirRegOp to `sv.reg` and `sv.always`.
79public:
80 /// A map sending registers to their paths.
81 using PathTable = DenseMap<seq::FirRegOp, hw::HierPathOp>;
82
83 /// When a register is buried under an ifdef op, the initialization code at
84 /// the footer of the HW module will refer to the register using a
85 /// hierarchical path op. This function creates any necessary hier paths and
86 /// returns a map from buried registers to their hier path ops. HierPathOps
87 /// creation needs to be serialized to keep the symbol creation deterministic,
88 /// so this is done as a pre-pass on the entire MLIR module. The result should
89 /// be passed in to each invocation of FirRefLowering.
90 static PathTable createPaths(mlir::ModuleOp top);
91
92 FirRegLowering(TypeConverter &typeConverter, hw::HWModuleOp module,
93 const PathTable &pathTable,
94 bool disableRegRandomization = false,
95 bool emitSeparateAlwaysBlocks = false);
96
97 void lower();
98 bool needsRegRandomization() const { return needsRandom; }
99
101
102private:
103 /// The conditions under which a register is defined.
105 enum Kind {
106 /// The register is under an ifdef "then" branch.
108 /// The register is under an ifdef "else" branch.
110 };
111 RegCondition(Kind kind, sv::MacroIdentAttr macro) : data(macro, kind) {}
112 Kind getKind() const { return data.getInt(); }
113 sv::MacroIdentAttr getMacro() const {
114 return cast<sv::MacroIdentAttr>(data.getPointer());
115 }
116 llvm::PointerIntPair<Attribute, 1, Kind> data;
117 };
118
121 hw::HierPathOp path;
122 IntegerAttr preset;
125 int64_t randStart;
126 size_t width;
127 };
128
129 void lowerUnderIfDef(sv::IfDefOp ifDefOp);
130 void lowerInBlock(Block *block);
131 void lowerReg(seq::FirRegOp reg);
132 void createInitialBlock();
133
134 void initialize(OpBuilder &builder, RegLowerInfo reg, ArrayRef<Value> rands);
135 void initializeRegisterElements(Location loc, OpBuilder &builder, Value reg,
136 Value rand, unsigned &pos);
137
138 void createTree(OpBuilder &builder, Value reg, Value term, Value next);
139 std::optional<std::tuple<Value, Value, Value>>
140 tryRestoringSubaccess(OpBuilder &builder, Value reg, Value term,
141 hw::ArrayCreateOp nextRegValue);
142
143 void addToAlwaysBlock(Block *block, sv::EventControl clockEdge, Value clock,
144 const std::function<void(OpBuilder &)> &body,
145 sv::ResetType resetStyle = {},
146 sv::EventControl resetEdge = {}, Value reset = {},
147 const std::function<void(OpBuilder &)> &resetBody = {});
148
149 void addToIfBlock(OpBuilder &builder, Value cond,
150 const std::function<void()> &trueSide,
151 const std::function<void()> &falseSide);
152
153 SmallVector<Value> createRandomizationVector(OpBuilder &builder,
154 Location loc);
155 void createRandomInitialization(ImplicitLocOpBuilder &builder);
156 void createPresetInitialization(ImplicitLocOpBuilder &builder);
157 void createAsyncResetInitialization(ImplicitLocOpBuilder &builder);
158
159 hw::ConstantOp getOrCreateConstant(Location loc, const APInt &value) {
160 OpBuilder builder(module.getBody());
161 auto &constant = constantCache[value];
162 if (constant) {
163 constant->setLoc(builder.getFusedLoc({constant->getLoc(), loc}));
164 return constant;
165 }
166
167 constant = builder.create<hw::ConstantOp>(loc, value);
168 return constant;
169 }
170
171 /// Recreate the ifdefs under which `reg` was defined. Leave the builder with
172 /// its insertion point inside the created ifdef guards.
173 void buildRegConditions(OpBuilder &b, sv::RegOp reg);
174
175 using AlwaysKeyType = std::tuple<Block *, sv::EventControl, Value,
176 sv::ResetType, sv::EventControl, Value>;
179
180 using IfKeyType = std::pair<Block *, Value>;
182
185
186 /// The ambient ifdef conditions we have encountered while lowering.
187 std::vector<RegCondition> conditions;
188
189 /// A list of registers discovered, bucketed by initialization style.
190 SmallVector<RegLowerInfo> randomInitRegs, presetInitRegs;
191
192 /// A map from RegOps to the ifdef conditions under which they are defined.
193 /// We only bother recording a list of conditions if there is at least one.
194 DenseMap<sv::RegOp, std::vector<RegCondition>> regConditionTable;
195
196 /// A map from async reset signal to the registers that use it.
197 llvm::MapVector<Value, SmallVector<RegLowerInfo>> asyncResets;
198
199 std::unique_ptr<ReachableMuxes> reachableMuxes;
200
202 TypeConverter &typeConverter;
203 hw::HWModuleOp module;
204
207
208 bool needsRandom = false;
209};
210} // namespace circt
211
212#endif // CONVERSION_SEQTOSV_FIRREGLOWERING_H
Lower FirRegOp to sv.reg and sv.always.
std::unique_ptr< ReachableMuxes > reachableMuxes
bool needsRegRandomization() const
void initialize(OpBuilder &builder, RegLowerInfo reg, ArrayRef< Value > rands)
llvm::SmallDenseMap< std::pair< Value, unsigned >, Value > arrayIndexCache
void createAsyncResetInitialization(ImplicitLocOpBuilder &builder)
llvm::SmallDenseMap< IfKeyType, sv::IfOp > ifCache
static PathTable createPaths(mlir::ModuleOp top)
When a register is buried under an ifdef op, the initialization code at the footer of the HW module w...
DenseMap< seq::FirRegOp, hw::HierPathOp > PathTable
A map sending registers to their paths.
void addToIfBlock(OpBuilder &builder, Value cond, const std::function< void()> &trueSide, const std::function< void()> &falseSide)
std::optional< std::tuple< Value, Value, Value > > tryRestoringSubaccess(OpBuilder &builder, Value reg, Value term, hw::ArrayCreateOp nextRegValue)
llvm::SmallDenseMap< APInt, hw::ConstantOp > constantCache
void createRandomInitialization(ImplicitLocOpBuilder &builder)
void lowerUnderIfDef(sv::IfDefOp ifDefOp)
void lowerInBlock(Block *block)
void buildRegConditions(OpBuilder &b, sv::RegOp reg)
Recreate the ifdefs under which reg was defined.
const PathTable & pathTable
void lowerReg(seq::FirRegOp reg)
std::pair< Block *, Value > IfKeyType
SmallVector< Value > createRandomizationVector(OpBuilder &builder, Location loc)
std::vector< RegCondition > conditions
The ambient ifdef conditions we have encountered while lowering.
void createTree(OpBuilder &builder, Value reg, Value term, Value next)
void createPresetInitialization(ImplicitLocOpBuilder &builder)
hw::ConstantOp getOrCreateConstant(Location loc, const APInt &value)
void addToAlwaysBlock(Block *block, sv::EventControl clockEdge, Value clock, const std::function< void(OpBuilder &)> &body, sv::ResetType resetStyle={}, sv::EventControl resetEdge={}, Value reset={}, const std::function< void(OpBuilder &)> &resetBody={})
SmallVector< RegLowerInfo > randomInitRegs
A list of registers discovered, bucketed by initialization style.
std::tuple< Block *, sv::EventControl, Value, sv::ResetType, sv::EventControl, Value > AlwaysKeyType
llvm::MapVector< Value, SmallVector< RegLowerInfo > > asyncResets
A map from async reset signal to the registers that use it.
void initializeRegisterElements(Location loc, OpBuilder &builder, Value reg, Value rand, unsigned &pos)
DenseMap< sv::RegOp, std::vector< RegCondition > > regConditionTable
A map from RegOps to the ifdef conditions under which they are defined.
TypeConverter & typeConverter
hw::HWModuleOp bool disableRegRandomization
SmallVector< RegLowerInfo > presetInitRegs
llvm::SmallDenseMap< AlwaysKeyType, std::pair< sv::AlwaysOp, sv::IfOp > > alwaysBlocks
void buildReachabilityFrom(Operation *startNode)
llvm::SmallPtrSet< Operation *, 16 > visited
HWModuleOp llvm::DenseMap< Operation *, llvm::SmallDenseSet< Operation * > > reachableMuxes
bool isMuxReachableFrom(seq::FirRegOp regOp, comb::MuxOp muxOp)
ReachableMuxes(HWModuleOp m)
Definition sv.py:68
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
The conditions under which a register is defined.
sv::MacroIdentAttr getMacro() const
RegCondition(Kind kind, sv::MacroIdentAttr macro)
llvm::PointerIntPair< Attribute, 1, Kind > data
@ IfDefThen
The register is under an ifdef "then" branch.
@ IfDefElse
The register is under an ifdef "else" branch.
llvm::filter_iterator< Operation::user_iterator, std::function< bool(const Operation *)> > ValidUsersIterator
static std::function< bool(const Operation *op)> opAllowsReachability
OpUserInfo(Operation *op)
ValidUsersIterator userIter
ValidUsersIterator userEnd