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())
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 = builder.create<
comb::AndOp>(stateOp.getEnable(), resetCond);
153 if (stateOp.getReset())
154 resetCond = builder.create<
comb::OrOp>(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()];
195 Value one = builder.create<
hw::ConstantOp>(builder.getI1Type(), -1);
196 if (enableInfos[0].isDisable) {
197 inputs[enableInfos[0].condition.getArgNumber()] =
201 inputs[enableInfos[0].condition.getArgNumber()] = one;
204 if (stateOp.getEnable())
205 enableCond = builder.create<
comb::AndOp>(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())
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 = dyn_cast<BlockArgument>(mux.getCond()))
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 = dyn_cast<BlockArgument>(xorOp.getInputs()[0])) {
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 = dyn_cast<BlockArgument>(selfArg)) {
303 if (stateOp.getInputs()[trueArg.getArgNumber()] !=
304 stateOp.getResult(outputNr))
307 if (
auto condArg = dyn_cast<BlockArgument>(cond))
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 impl::InferStatePropertiesBase<InferStatePropertiesPass> {
384 using InferStatePropertiesBase::InferStatePropertiesBase;
386 void runOnOperation()
override;
387 void runOnStateOp(arc::StateOp stateOp, arc::DefineOp arc,
388 DenseMap<arc::DefineOp, unsigned> &resetConditionMap);
392 void InferStatePropertiesPass::runOnOperation() {
393 SymbolTableCollection symbolTable;
395 DenseMap<arc::DefineOp, unsigned> resetConditionMap;
396 getOperation()->walk([&](arc::StateOp stateOp) {
398 cast<arc::DefineOp>(cast<mlir::CallOpInterface>(stateOp.getOperation())
399 .resolveCallableInTable(&symbolTable));
400 runOnStateOp(stateOp, arc, resetConditionMap);
404 void InferStatePropertiesPass::runOnStateOp(
405 arc::StateOp stateOp, arc::DefineOp arc,
406 DenseMap<arc::DefineOp, unsigned> &resetConditionMap) {
408 auto outputOp = cast<arc::OutputOp>(arc.getBodyBlock().getTerminator());
409 static constexpr
unsigned visitedNoChange = -1;
414 if (!resetConditionMap.count(arc)) {
415 SmallVector<ResetInfo> resetInfos;
417 for (
auto &output : outputOp->getOpOperands()) {
419 resetInfos.push_back(resetInfo);
426 if ((succeeded(result) && resetInfos[0]))
427 resetConditionMap[arc] = resetInfos[0].condition.getArgNumber();
429 resetConditionMap[arc] = visitedNoChange;
432 missedResets += numResets;
436 if (resetConditionMap.count(arc) &&
437 resetConditionMap[arc] != visitedNoChange) {
445 SmallVector<EnableInfo> enableInfos;
447 for (OpOperand &output : outputOp->getOpOperands()) {
449 enableInfos.push_back(enableInfo);
458 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.
def create(data_type, value)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.