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) {
175 if (info.selfArg.hasOneUse() &&
hw::getBitWidth(info.selfArg.getType()) < 0)
182 if (!enableInfos.empty() &&
183 (info.condition != enableInfos.back().condition ||
184 info.isDisable != enableInfos.back().isDisable))
188 if (enableInfos.empty())
191 if (!enableInfos[0].condition.hasOneUse())
194 ImplicitLocOpBuilder builder(stateOp.getLoc(), stateOp);
195 SmallVector<Value> inputs(stateOp.getInputs());
198 stateOp.getInputs()[enableInfos[0].condition.getArgNumber()];
200 if (enableInfos[0].isDisable) {
201 inputs[enableInfos[0].condition.getArgNumber()] =
203 enableCond = comb::XorOp::create(builder, enableCond, one);
205 inputs[enableInfos[0].condition.getArgNumber()] = one;
208 if (stateOp.getEnable())
209 enableCond = comb::AndOp::create(builder, stateOp.getEnable(), enableCond);
211 stateOp.getEnableMutable().assign(enableCond);
213 for (
size_t i = 0, e = outputOp.getOutputs().size(); i < e; ++i) {
214 if (enableInfos[i].selfArg.hasOneUse()) {
217 auto type = enableInfos[i].selfArg.getType();
219 builder, stateOp.getLoc(),
221 if (zero.getType() != type)
223 inputs[enableInfos[i].selfArg.getArgNumber()] = zero;
227 stateOp.getInputsMutable().assign(inputs);
243 assert(isa<arc::OutputOp>(output.getOwner()) &&
244 "value has to be returned by the arc");
246 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
250 if (!mux.getResult().hasOneUse())
253 if (
auto condArg = dyn_cast<BlockArgument>(mux.getCond()))
254 return ResetInfo(mux.getFalseValue(), condArg,
true);
266 assert(isa<arc::OutputOp>(output.getOwner()) &&
267 "value has to be returned by the arc");
269 if (
auto andOp = output.get().getDefiningOp<
comb::AndOp>()) {
270 if (!andOp.getResult().getType().isInteger(1))
273 if (!andOp.getResult().hasOneUse())
276 for (
auto &operand : andOp->getOpOperands()) {
277 if (
auto xorOp = operand.get().getDefiningOp<
comb::XorOp>();
278 xorOp && xorOp->getNumOperands() == 2 &&
279 xorOp.getResult().hasOneUse()) {
280 if (
auto condArg = dyn_cast<BlockArgument>(xorOp.getInputs()[0])) {
281 if (xorOp.getInputs().size() != 2 ||
285 const unsigned condOutputNumber = operand.getOperandNumber();
286 auto inputConstructor = [=](OpBuilder &builder) -> Value {
287 if (andOp->getNumOperands() > 2) {
288 builder.setInsertionPoint(andOp);
289 auto copy = cast<comb::AndOp>(builder.clone(*andOp));
290 copy.getInputsMutable().erase(condOutputNumber);
291 return copy->getResult(0);
294 return andOp->getOperand(!condOutputNumber);
297 return ResetInfo(inputConstructor, condArg,
true);
311 Value cond,
unsigned outputNr,
313 if (
auto trueArg = dyn_cast<BlockArgument>(selfArg)) {
314 if (stateOp.getInputs()[trueArg.getArgNumber()] !=
315 stateOp.getResult(outputNr))
318 if (
auto condArg = dyn_cast<BlockArgument>(cond))
319 return EnableInfo(selfArg, condArg, trueArg, isDisable);
330 assert(isa<arc::OutputOp>(output.getOwner()) &&
331 "value has to be returned by the arc");
333 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
334 if (!mux.getResult().hasOneUse())
338 output.getOperandNumber(),
false);
350 assert(isa<arc::OutputOp>(output.getOwner()) &&
351 "value has to be returned by the arc");
353 if (
auto mux = output.get().getDefiningOp<
comb::MuxOp>()) {
354 if (!mux.getResult().hasOneUse())
358 output.getOperandNumber(),
true);
393struct InferStatePropertiesPass
394 :
public impl::InferStatePropertiesBase<InferStatePropertiesPass> {
395 using InferStatePropertiesBase::InferStatePropertiesBase;
397 void runOnOperation()
override;
398 void runOnStateOp(arc::StateOp stateOp, arc::DefineOp arc,
399 DenseMap<arc::DefineOp, unsigned> &resetConditionMap);
403void InferStatePropertiesPass::runOnOperation() {
404 SymbolTableCollection symbolTable;
406 DenseMap<arc::DefineOp, unsigned> resetConditionMap;
407 getOperation()->walk([&](arc::StateOp stateOp) {
409 cast<arc::DefineOp>(cast<mlir::CallOpInterface>(stateOp.getOperation())
410 .resolveCallableInTable(&symbolTable));
411 runOnStateOp(stateOp, arc, resetConditionMap);
415void InferStatePropertiesPass::runOnStateOp(
416 arc::StateOp stateOp, arc::DefineOp arc,
417 DenseMap<arc::DefineOp, unsigned> &resetConditionMap) {
419 auto outputOp = cast<arc::OutputOp>(arc.getBodyBlock().getTerminator());
420 static constexpr unsigned visitedNoChange = -1;
425 if (!resetConditionMap.count(arc)) {
426 SmallVector<ResetInfo> resetInfos;
428 for (
auto &output : outputOp->getOpOperands()) {
430 resetInfos.push_back(resetInfo);
437 if ((succeeded(result) && resetInfos[0]))
438 resetConditionMap[arc] = resetInfos[0].condition.getArgNumber();
440 resetConditionMap[arc] = visitedNoChange;
443 missedResets += numResets;
447 if (resetConditionMap.count(arc) &&
448 resetConditionMap[arc] != visitedNoChange) {
456 SmallVector<EnableInfo> enableInfos;
458 for (OpOperand &output : outputOp->getOpOperands()) {
460 enableInfos.push_back(enableInfo);
469 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.
false return failure()
Parse an optional keyword or string and set instance into 'result'.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.