10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
12
13
+ #include < ranges>
14
+
13
15
#include " circt/Dialect/Verif/VerifOps.h"
14
16
#include " circt/Dialect/Verif/VerifPasses.h"
15
17
#include " mlir/IR/IRMapping.h"
@@ -53,10 +55,6 @@ Operation *replaceContractOp(OpBuilder &builder, RequireLike op,
53
55
return nullptr ;
54
56
}
55
57
56
- LogicalResult cloneFanIn (OpBuilder &builder, Operation *opToClone,
57
- IRMapping &mapping, DenseSet<Operation *> &seen,
58
- bool assumeContract);
59
-
60
58
LogicalResult cloneContractOp (OpBuilder &builder, Operation *opToClone,
61
59
IRMapping &mapping, bool assumeContract) {
62
60
Operation *clonedOp;
@@ -78,6 +76,10 @@ LogicalResult cloneContractOp(OpBuilder &builder, Operation *opToClone,
78
76
return llvm::success ();
79
77
}
80
78
79
+ LogicalResult cloneFanIn (OpBuilder &builder, Operation *opToClone,
80
+ IRMapping &mapping, DenseSet<Operation *> &seen,
81
+ bool assumeContract);
82
+
81
83
LogicalResult cloneContractBody (ContractOp &contract, OpBuilder &builder,
82
84
IRMapping &mapping, DenseSet<Operation *> &seen,
83
85
bool assumeContract, bool shouldCloneFanIn) {
@@ -105,57 +107,84 @@ LogicalResult inlineContract(ContractOp &contract, OpBuilder &builder,
105
107
shouldCloneFanIn);
106
108
}
107
109
108
- LogicalResult cloneOperands (OpBuilder &builder, Operation *opToClone,
109
- IRMapping &mapping, DenseSet<Operation *> &seen,
110
- bool assumeContract, Operation *parent = nullptr ) {
111
- for (auto operand : opToClone->getOperands ()) {
110
+ void buildOpsToClone (OpBuilder &builder, IRMapping &mapping, Operation *op,
111
+ SmallVector<Operation *> &opsToClone,
112
+ std::queue<Operation *> &workList,
113
+ DenseSet<Operation *> &seen, Operation *parent = nullptr ) {
114
+ if (auto contract = dyn_cast<ContractOp>(*op)) {
115
+ for (auto result : contract.getResults ()) {
116
+ auto sym =
117
+ builder.create <SymbolicValueOp>(result.getLoc (), result.getType ());
118
+ mapping.map (result, sym);
119
+ }
120
+ // Assume it holds
121
+ // TODO: merge w/ parent/walk logic?
122
+ auto &contractOps = contract.getBody ().front ().getOperations ();
123
+ for (auto it = contractOps.rbegin (); it != contractOps.rend (); ++it) {
124
+ if (!seen.contains (&*it)) {
125
+ workList.push (&*it);
126
+ }
127
+ }
128
+ return ;
129
+ }
130
+ for (auto operand : op->getOperands ()) {
112
131
if (mapping.contains (operand))
113
132
continue ;
114
-
133
+ // Don't need to clone if defining op is within parent op
134
+ if (parent && parent->isAncestor (operand.getParentBlock ()->getParentOp ()))
135
+ continue ;
115
136
if (auto *definingOp = operand.getDefiningOp ()) {
116
- // Don't need to clone if defining op is within parent op
117
- if (parent && parent->isAncestor (operand.getParentBlock ()->getParentOp ()))
118
- continue ;
119
- // Recurse and clone defining op
120
- if (failed (
121
- cloneFanIn (builder, definingOp, mapping, seen, assumeContract)))
122
- return failure ();
137
+ if (!seen.contains (definingOp)) {
138
+ workList.push (definingOp);
139
+ }
123
140
} else {
124
141
// Create symbolic values for arguments
125
142
auto sym = builder.create <verif::SymbolicValueOp>(operand.getLoc (),
126
143
operand.getType ());
127
144
mapping.map (operand, sym);
128
145
}
129
146
}
130
- return success ();
131
147
}
132
148
133
149
LogicalResult cloneFanIn (OpBuilder &builder, Operation *opToClone,
134
150
IRMapping &mapping, DenseSet<Operation *> &seen,
135
151
bool assumeContract) {
136
- if (seen.contains (opToClone))
137
- return llvm::success ();
138
- seen.insert (opToClone);
139
-
140
- if (failed (cloneOperands (builder, opToClone, mapping, seen, assumeContract)))
141
- return failure ();
142
- // Ensure all operands have been mapped
143
- if (opToClone
144
- ->walk ([&](Operation *nestedOp) {
145
- if (failed (cloneOperands (builder, nestedOp, mapping, seen,
146
- assumeContract, opToClone)))
147
- return WalkResult::interrupt ();
148
- return WalkResult::advance ();
149
- })
150
- .wasInterrupted ())
151
- return failure ();
152
-
153
- if (auto contract = dyn_cast<ContractOp>(opToClone)) {
154
- // Assume it holds
155
- return inlineContract (contract, builder, mapping, seen, true );
152
+ SmallVector<Operation *> opsToClone;
153
+ std::queue<Operation *> workList;
154
+ workList.push (opToClone);
155
+ while (!workList.empty ()) {
156
+ auto *currentOp = workList.front ();
157
+ workList.pop ();
158
+ if (seen.contains (currentOp))
159
+ continue ;
160
+ seen.insert (currentOp);
161
+ buildOpsToClone (builder, mapping, currentOp, opsToClone, workList, seen);
162
+ if (auto contract = dyn_cast<ContractOp>(*currentOp))
163
+ continue ;
164
+ currentOp->walk ([&](Operation *nestedOp) {
165
+ buildOpsToClone (builder, mapping, nestedOp, opsToClone, workList, seen,
166
+ currentOp);
167
+ });
168
+ opsToClone.push_back (currentOp);
156
169
}
157
170
158
- return cloneContractOp (builder, opToClone, mapping, assumeContract);
171
+ for (auto it = opsToClone.rbegin (); it != opsToClone.rend (); ++it) {
172
+ Operation *op = *it;
173
+ Operation *clonedOp;
174
+ if (auto requireLike = dyn_cast<RequireLike>(*op)) {
175
+ clonedOp =
176
+ replaceContractOp (builder, requireLike, mapping, assumeContract);
177
+ if (!clonedOp) {
178
+ return failure ();
179
+ }
180
+ } else {
181
+ clonedOp = builder.clone (*op, mapping);
182
+ }
183
+ for (auto [x, y] : llvm::zip (op->getResults (), clonedOp->getResults ())) {
184
+ mapping.map (x, y);
185
+ }
186
+ }
187
+ return success ();
159
188
}
160
189
161
190
LogicalResult runOnHWModule (HWModuleOp hwModule, ModuleOp mlirModule) {
@@ -186,7 +215,7 @@ LogicalResult runOnHWModule(HWModuleOp hwModule, ModuleOp mlirModule) {
186
215
// Clone fan in cone for contract operands
187
216
for (auto operand : contract.getOperands ()) {
188
217
auto *definingOp = operand.getDefiningOp ();
189
- if (failed (cloneFanIn (formalBuilder, definingOp, mapping, seen, false )))
218
+ if (failed (cloneFanIn (formalBuilder, definingOp, mapping, seen, true )))
190
219
return failure ();
191
220
}
192
221
0 commit comments