14 #include "mlir/Pass/Pass.h"
16 #define DEBUG_TYPE "arc-infer-state-properties"
20 #define GEN_PASS_DEF_INFERSTATEPROPERTIES
21 #include "circt/Dialect/Arc/ArcPasses.h.inc"
25 using namespace circt;
34 return constOp.getValue().isZero();
41 return constOp.getValue().getBitWidth() == 1 &&
42 constOp.getValue().isAllOnes();
55 ResetInfo() =
default;
56 ResetInfo(std::function<Value(OpBuilder &)> &&constructInput,
57 BlockArgument condition,
bool isZeroReset)
58 : constructInput(constructInput), condition(condition),
59 isZeroReset(isZeroReset) {}
61 ResetInfo(Value input, BlockArgument condition,
bool isZeroReset)
62 : ResetInfo([=](OpBuilder &) {
return input; }, condition, isZeroReset) {}
64 std::function<Value(OpBuilder &)> constructInput;
65 BlockArgument condition;
68 operator bool() {
return constructInput && condition; }
74 EnableInfo() =
default;
75 EnableInfo(std::function<Value(OpBuilder &)> &&constructInput,
76 BlockArgument condition, BlockArgument selfArg,
bool isDisable)
77 : constructInput(constructInput), condition(condition), selfArg(selfArg),
78 isDisable(isDisable) {}
80 EnableInfo(Value input, BlockArgument condition, BlockArgument selfArg,
82 : EnableInfo([=](OpBuilder &) {
return input; }, condition, selfArg,
85 std::function<Value(OpBuilder &)> constructInput;
86 BlockArgument condition;
87 BlockArgument selfArg;
90 operator bool() {
return constructInput && condition && selfArg; }
101 ArrayRef<ResetInfo> resetInfos) {
102 auto outputOp = cast<arc::OutputOp>(arcOp.getBodyBlock().getTerminator());
104 assert(outputOp.getOutputs().size() == resetInfos.size() &&
105 "required to pass the same amount of resets as outputs of the arc");
107 for (
auto info : resetInfos) {
115 if (!resetInfos.empty() &&
116 (info.condition != resetInfos.back().condition ||
117 info.isZeroReset != resetInfos.back().isZeroReset))
121 if (!info.isZeroReset)
125 if (resetInfos.empty())
130 for (
size_t i = 0, e = outputOp.getOutputs().size(); i < e; ++i) {
131 auto *defOp = outputOp.getOperands()[i].getDefiningOp();
132 outputOp.getOperands()[i].replaceUsesWithIf(
133 resetInfos[i].constructInput(
builder),
134 [](OpOperand &op) {
return isa<arc::OutputOp>(op.getOwner()); });
136 if (defOp && defOp->getResult(0).use_empty())
146 unsigned resetConditionIndex) {
147 Value resetCond = stateOp.getInputs()[resetConditionIndex];
148 ImplicitLocOpBuilder
builder(stateOp.getLoc(), stateOp);
150 if (stateOp.getEnable())
153 if (stateOp.getReset())
156 stateOp.getResetMutable().assign(resetCond);
164 ArrayRef<EnableInfo> enableInfos) {
165 auto outputOp = cast<arc::OutputOp>(arcOp.getBodyBlock().getTerminator());
167 assert(outputOp.getOutputs().size() == enableInfos.size() &&
168 "required to pass the same amount of enables as outputs of the arc");
170 for (
auto info : enableInfos) {
178 if (!enableInfos.empty() &&
179 (info.condition != enableInfos.back().condition ||
180 info.isDisable != enableInfos.back().isDisable))
184 if (enableInfos.empty())
187 if (!enableInfos[0].condition.hasOneUse())
190 ImplicitLocOpBuilder
builder(stateOp.getLoc(), stateOp);
191 SmallVector<Value>
inputs(stateOp.getInputs());
194 stateOp.getInputs()[enableInfos[0].condition.getArgNumber()];
196 if (enableInfos[0].isDisable) {
197 inputs[enableInfos[0].condition.getArgNumber()] =
201 inputs[enableInfos[0].condition.getArgNumber()] = one;
204 if (stateOp.getEnable())
207 stateOp.getEnableMutable().assign(enableCond);
209 for (
size_t i = 0, e = outputOp.getOutputs().size(); i < e; ++i) {
210 if (enableInfos[i].selfArg.hasOneUse())
211 inputs[enableInfos[i].selfArg.getArgNumber()] =
213 enableInfos[i].selfArg.getType(), 0);
216 stateOp.getInputsMutable().assign(
inputs);
232 assert(isa<arc::OutputOp>(output.getOwner()) &&
233 "value has to be returned by the arc");
235 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
239 if (!mux.getResult().hasOneUse())
242 if (
auto condArg = mux.getCond().dyn_cast<BlockArgument>())
243 return ResetInfo(mux.getFalseValue(), condArg,
true);
255 assert(isa<arc::OutputOp>(output.getOwner()) &&
256 "value has to be returned by the arc");
258 if (
auto andOp = output.get().getDefiningOp<
comb::AndOp>()) {
259 if (!andOp.getResult().getType().isInteger(1))
262 if (!andOp.getResult().hasOneUse())
265 for (
auto &operand : andOp->getOpOperands()) {
266 if (
auto xorOp = operand.get().getDefiningOp<
comb::XorOp>();
267 xorOp && xorOp->getNumOperands() == 2 &&
268 xorOp.getResult().hasOneUse()) {
269 if (
auto condArg = xorOp.getInputs()[0].dyn_cast<BlockArgument>()) {
270 if (xorOp.getInputs().size() != 2 ||
274 const unsigned condOutputNumber = operand.getOperandNumber();
275 auto inputConstructor = [=](OpBuilder &
builder) -> Value {
276 if (andOp->getNumOperands() > 2) {
277 builder.setInsertionPoint(andOp);
278 auto copy = cast<comb::AndOp>(
builder.clone(*andOp));
279 copy.getInputsMutable().erase(condOutputNumber);
280 return copy->getResult(0);
283 return andOp->getOperand(!condOutputNumber);
286 return ResetInfo(inputConstructor, condArg,
true);
300 Value cond,
unsigned outputNr,
302 if (
auto trueArg = selfArg.dyn_cast<BlockArgument>()) {
303 if (stateOp.getInputs()[trueArg.getArgNumber()] !=
304 stateOp.getResult(outputNr))
307 if (
auto condArg = cond.dyn_cast<BlockArgument>())
308 return EnableInfo(selfArg, condArg, trueArg, isDisable);
319 assert(isa<arc::OutputOp>(output.getOwner()) &&
320 "value has to be returned by the arc");
322 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
323 if (!mux.getResult().hasOneUse())
327 output.getOperandNumber(),
false);
339 assert(isa<arc::OutputOp>(output.getOwner()) &&
340 "value has to be returned by the arc");
342 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
343 if (!mux.getResult().hasOneUse())
347 output.getOperandNumber(),
true);
382 struct InferStatePropertiesPass
383 :
public arc::impl::InferStatePropertiesBase<InferStatePropertiesPass> {
384 InferStatePropertiesPass() =
default;
385 InferStatePropertiesPass(
const InferStatePropertiesPass &pass)
386 : InferStatePropertiesPass() {}
388 void runOnOperation()
override;
389 void runOnStateOp(arc::StateOp stateOp, arc::DefineOp arc,
390 DenseMap<arc::DefineOp, unsigned> &resetConditionMap);
392 Statistic addedEnables{
this,
"added-enables",
393 "Enables added explicitly to a StateOp"};
394 Statistic addedResets{
this,
"added-resets",
395 "Resets added explicitly to a StateOp"};
396 Statistic missedEnables{
397 this,
"missed-enables",
398 "Detected enables that could not be added explicitly to a StateOp"};
399 Statistic missedResets{
400 this,
"missed-resets",
401 "Detected resets that could not be added explicitly to a StateOp"};
405 void InferStatePropertiesPass::runOnOperation() {
406 SymbolTableCollection symbolTable;
408 DenseMap<arc::DefineOp, unsigned> resetConditionMap;
409 getOperation()->walk([&](arc::StateOp stateOp) {
411 cast<arc::DefineOp>(cast<mlir::CallOpInterface>(stateOp.getOperation())
412 .resolveCallable(&symbolTable));
413 runOnStateOp(stateOp, arc, resetConditionMap);
417 void InferStatePropertiesPass::runOnStateOp(
418 arc::StateOp stateOp, arc::DefineOp arc,
419 DenseMap<arc::DefineOp, unsigned> &resetConditionMap) {
421 if (stateOp.getLatency() < 1)
424 auto outputOp = cast<arc::OutputOp>(arc.getBodyBlock().getTerminator());
425 const unsigned visitedNoChange = -1;
429 if (!resetConditionMap.count(arc)) {
430 SmallVector<ResetInfo> resetInfos;
433 for (
auto &output : outputOp->getOpOperands()) {
435 resetInfos.push_back(resetInfo);
442 if ((succeeded(result) && resetInfos[0]))
443 resetConditionMap[arc] = resetInfos[0].condition.getArgNumber();
445 resetConditionMap[arc] = visitedNoChange;
448 missedResets += numResets;
452 if (resetConditionMap.count(arc) &&
453 resetConditionMap[arc] != visitedNoChange) {
459 SmallVector<EnableInfo> enableInfos;
461 for (OpOperand &output : outputOp->getOpOperands()) {
463 enableInfos.push_back(enableInfo);
472 missedEnables += numEnables;
476 return std::make_unique<InferStatePropertiesPass>();
assert(baseType &&"element must be base type")
static bool isConstTrue(Value value)
static EnableInfo checkOperandsForEnable(arc::StateOp stateOp, Value selfArg, Value cond, unsigned outputNr, bool isDisable)
Just a helper function for the following two patterns.
static EnableInfo getIfMuxBasedDisable(OpOperand &output, StateOp stateOp)
A negated enable represented by a single mux operation.
static ResetInfo getIfAndBasedReset(OpOperand &output)
A reset represented by an AND and XOR operation for i1 values only.
static LogicalResult applyEnableTransformation(arc::DefineOp arcOp, arc::StateOp stateOp, ArrayRef< EnableInfo > enableInfos)
Take an arc and a detected enable per output value and apply it to the given state if applicable (no ...
static bool isConstZero(Value value)
static LogicalResult applyResetTransformation(arc::DefineOp arcOp, ArrayRef< ResetInfo > resetInfos)
Take an arc and a detected reset per output value and apply it to the arc if applicable (but does not...
EnableInfo computeEnableInfoFromPattern(OpOperand &output, StateOp stateOp)
Combine all the enable patterns to one.
static void setResetOperandOfStateOp(arc::StateOp stateOp, unsigned resetConditionIndex)
Transform the given state operation to match the changes done to the arc in 'applyResetTransformation...
ResetInfo computeResetInfoFromPattern(OpOperand &output)
Combine all the reset patterns to one.
static EnableInfo getIfMuxBasedEnable(OpOperand &output, StateOp stateOp)
An enable represented by a single mux operation.
static ResetInfo getIfMuxBasedReset(OpOperand &output)
A reset represented with a single mux operation.
llvm::SmallVector< StringAttr > inputs
std::unique_ptr< mlir::Pass > createInferStatePropertiesPass()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...