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"
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())
128 OpBuilder builder(outputOp);
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())
151 resetCond = comb::AndOp::create(builder, stateOp.getEnable(), resetCond);
153 if (stateOp.getReset())
154 resetCond = comb::OrOp::create(builder, stateOp.getReset(), resetCond);
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()] =
199 enableCond = comb::XorOp::create(builder, enableCond, one);
201 inputs[enableInfos[0].condition.getArgNumber()] = one;
204 if (stateOp.getEnable())
205 enableCond = comb::AndOp::create(builder, stateOp.getEnable(), enableCond);
207 stateOp.getEnableMutable().assign(enableCond);
209 for (
size_t i = 0, e = outputOp.getOutputs().size(); i < e; ++i) {
210 if (enableInfos[i].selfArg.hasOneUse())
212 builder, stateOp.getLoc(), enableInfos[i].selfArg.getType(), 0);
215 stateOp.getInputsMutable().assign(inputs);
231 assert(isa<arc::OutputOp>(output.getOwner()) &&
232 "value has to be returned by the arc");
234 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
238 if (!mux.getResult().hasOneUse())
241 if (
auto condArg = dyn_cast<BlockArgument>(mux.getCond()))
242 return ResetInfo(mux.getFalseValue(), condArg,
true);
254 assert(isa<arc::OutputOp>(output.getOwner()) &&
255 "value has to be returned by the arc");
257 if (
auto andOp = output.get().getDefiningOp<
comb::AndOp>()) {
258 if (!andOp.getResult().getType().isInteger(1))
261 if (!andOp.getResult().hasOneUse())
264 for (
auto &operand : andOp->getOpOperands()) {
265 if (
auto xorOp = operand.get().getDefiningOp<
comb::XorOp>();
266 xorOp && xorOp->getNumOperands() == 2 &&
267 xorOp.getResult().hasOneUse()) {
268 if (
auto condArg = dyn_cast<BlockArgument>(xorOp.getInputs()[0])) {
269 if (xorOp.getInputs().size() != 2 ||
273 const unsigned condOutputNumber = operand.getOperandNumber();
274 auto inputConstructor = [=](OpBuilder &builder) -> Value {
275 if (andOp->getNumOperands() > 2) {
276 builder.setInsertionPoint(andOp);
277 auto copy = cast<comb::AndOp>(builder.clone(*andOp));
278 copy.getInputsMutable().erase(condOutputNumber);
279 return copy->getResult(0);
282 return andOp->getOperand(!condOutputNumber);
285 return ResetInfo(inputConstructor, condArg,
true);
299 Value cond,
unsigned outputNr,
301 if (
auto trueArg = dyn_cast<BlockArgument>(selfArg)) {
302 if (stateOp.getInputs()[trueArg.getArgNumber()] !=
303 stateOp.getResult(outputNr))
306 if (
auto condArg = dyn_cast<BlockArgument>(cond))
307 return EnableInfo(selfArg, condArg, trueArg, isDisable);
318 assert(isa<arc::OutputOp>(output.getOwner()) &&
319 "value has to be returned by the arc");
321 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
322 if (!mux.getResult().hasOneUse())
326 output.getOperandNumber(),
false);
338 assert(isa<arc::OutputOp>(output.getOwner()) &&
339 "value has to be returned by the arc");
341 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
342 if (!mux.getResult().hasOneUse())
346 output.getOperandNumber(),
true);
381struct InferStatePropertiesPass
382 :
public impl::InferStatePropertiesBase<InferStatePropertiesPass> {
383 using InferStatePropertiesBase::InferStatePropertiesBase;
385 void runOnOperation()
override;
386 void runOnStateOp(arc::StateOp stateOp, arc::DefineOp arc,
387 DenseMap<arc::DefineOp, unsigned> &resetConditionMap);
391void InferStatePropertiesPass::runOnOperation() {
392 SymbolTableCollection symbolTable;
394 DenseMap<arc::DefineOp, unsigned> resetConditionMap;
395 getOperation()->walk([&](arc::StateOp stateOp) {
397 cast<arc::DefineOp>(cast<mlir::CallOpInterface>(stateOp.getOperation())
398 .resolveCallableInTable(&symbolTable));
399 runOnStateOp(stateOp, arc, resetConditionMap);
403void InferStatePropertiesPass::runOnStateOp(
404 arc::StateOp stateOp, arc::DefineOp arc,
405 DenseMap<arc::DefineOp, unsigned> &resetConditionMap) {
407 auto outputOp = cast<arc::OutputOp>(arc.getBodyBlock().getTerminator());
408 static constexpr unsigned visitedNoChange = -1;
413 if (!resetConditionMap.count(arc)) {
414 SmallVector<ResetInfo> resetInfos;
416 for (
auto &output : outputOp->getOpOperands()) {
418 resetInfos.push_back(resetInfo);
425 if ((succeeded(result) && resetInfos[0]))
426 resetConditionMap[arc] = resetInfos[0].condition.getArgNumber();
428 resetConditionMap[arc] = visitedNoChange;
431 missedResets += numResets;
435 if (resetConditionMap.count(arc) &&
436 resetConditionMap[arc] != visitedNoChange) {
444 SmallVector<EnableInfo> enableInfos;
446 for (OpOperand &output : outputOp->getOpOperands()) {
448 enableInfos.push_back(enableInfo);
457 missedEnables += numEnables;
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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.