15 #include "mlir/Dialect/Func/IR/FuncOps.h"
16 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
17 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
18 #include "mlir/Dialect/SCF/IR/SCF.h"
19 #include "mlir/IR/IRMapping.h"
20 #include "mlir/IR/ImplicitLocOpBuilder.h"
21 #include "mlir/IR/SymbolTable.h"
22 #include "mlir/Pass/Pass.h"
23 #include "mlir/Transforms/TopologicalSortUtils.h"
24 #include "llvm/ADT/TypeSwitch.h"
25 #include "llvm/Support/Debug.h"
27 #define DEBUG_TYPE "arc-lower-state"
31 #define GEN_PASS_DEF_LOWERSTATE
32 #include "circt/Dialect/Arc/ArcPasses.h.inc"
36 using namespace circt;
40 using llvm::SmallDenseSet;
51 Statistics(Pass *parent) : parent(parent) {}
52 using Statistic = Pass::Statistic;
54 Statistic matOpsMoved{parent,
"mat-ops-moved",
55 "Ops moved during value materialization"};
56 Statistic matOpsCloned{parent,
"mat-ops-cloned",
57 "Ops cloned during value materialization"};
58 Statistic opsPruned{parent,
"ops-pruned",
"Ops removed as dead code"};
62 struct ClockLowering {
72 IRMapping materializedValues;
74 DenseMap<std::pair<Value, Value>, Value> andCache;
76 ClockLowering(Value clock, Operation *treeOp, Statistics &stats)
77 : clock(clock), treeOp(treeOp), stats(stats),
builder(treeOp) {
78 assert((isa<ClockTreeOp, PassThroughOp>(treeOp)));
79 builder.setInsertionPointToStart(&treeOp->getRegion(0).front());
82 Value materializeValue(Value
value);
83 Value getOrCreateAnd(Value lhs, Value rhs, Location loc);
86 struct GatedClockLowering {
94 struct ModuleLowering {
99 DenseMap<Value, std::unique_ptr<ClockLowering>> clockLowerings;
100 DenseMap<Value, GatedClockLowering> gatedClockLowerings;
102 OpBuilder clockBuilder;
103 OpBuilder stateBuilder;
105 ModuleLowering(
HWModuleOp moduleOp, Statistics &stats)
106 : moduleOp(moduleOp), stats(stats), context(moduleOp.getContext()),
107 clockBuilder(moduleOp), stateBuilder(moduleOp) {}
109 GatedClockLowering getOrCreateClockLowering(Value clock);
110 ClockLowering &getOrCreatePassThrough();
111 Value replaceValueWithStateRead(Value
value, Value state);
113 void addStorageArg();
114 LogicalResult lowerPrimaryInputs();
115 LogicalResult lowerPrimaryOutputs();
116 LogicalResult lowerStates();
117 LogicalResult lowerState(StateOp stateOp);
118 LogicalResult lowerState(MemoryOp memOp);
119 LogicalResult lowerState(MemoryWritePortOp memWriteOp);
120 LogicalResult lowerState(TapOp tapOp);
121 LogicalResult lowerExtModules(SymbolTable &symtbl);
122 LogicalResult lowerExtModule(InstanceOp instOp);
124 LogicalResult cleanup();
136 if (
auto stateOp = dyn_cast<StateOp>(op); stateOp && stateOp.getLatency() > 0)
139 if (isa<MemoryOp, AllocStateOp, AllocMemoryOp, AllocStorageOp, ClockTreeOp,
140 PassThroughOp, RootInputOp, RootOutputOp, StateWriteOp,
141 MemoryWritePortOp, igraph::InstanceOpInterface>(op))
151 auto *op =
value.getDefiningOp();
160 Value ClockLowering::materializeValue(Value
value) {
163 if (
auto mapped = materializedValues.lookupOrNull(
value))
170 SmallVector<Value, 2> operands;
171 WorkItem(Operation *op) : op(op) {}
174 SmallPtrSet<Operation *, 8> seen;
175 SmallVector<WorkItem> worklist;
177 auto addToWorklist = [&](Operation *outerOp) {
178 SmallDenseSet<Value> seenOperands;
179 auto &workItem = worklist.emplace_back(outerOp);
180 outerOp->walk([&](Operation *innerOp) {
181 for (
auto operand : innerOp->getOperands()) {
183 if (!operand.getParentBlock()->getParentOp()->isProperAncestor(outerOp))
187 if (!seenOperands.insert(operand).second)
195 workItem.operands.push_back(operand);
200 seen.insert(
value.getDefiningOp());
201 addToWorklist(
value.getDefiningOp());
203 while (!worklist.empty()) {
204 auto &workItem = worklist.back();
205 if (!workItem.operands.empty()) {
206 auto operand = workItem.operands.pop_back_val();
209 auto *defOp = operand.getDefiningOp();
210 if (!seen.insert(defOp).second) {
211 defOp->emitError(
"combinational loop detected");
214 addToWorklist(defOp);
216 builder.clone(*workItem.op, materializedValues);
217 seen.erase(workItem.op);
222 return materializedValues.lookup(
value);
228 Value ClockLowering::getOrCreateAnd(Value lhs, Value rhs, Location loc) {
233 auto &slot = andCache[std::make_pair(lhs, rhs)];
243 GatedClockLowering ModuleLowering::getOrCreateClockLowering(Value clock) {
245 if (
auto ckgOp = clock.getDefiningOp<ClockGateOp>()) {
247 if (
auto it = gatedClockLowerings.find(clock);
248 it != gatedClockLowerings.end())
255 auto info = getOrCreateClockLowering(ckgOp.getInput());
256 auto ckgEnable = info.clock.materializeValue(ckgOp.getEnable());
258 info.clock.getOrCreateAnd(info.enable, ckgEnable, ckgOp.getLoc());
259 gatedClockLowerings.insert({clock, info});
264 auto &slot = clockLowerings[clock];
267 clockBuilder.createOrFold<seq::FromClockOp>(clock.getLoc(), clock);
270 auto oldClockStorage = stateBuilder.create<AllocStateOp>(
271 clock.getLoc(),
StateType::get(stateBuilder.getI1Type()), storageArg);
273 clockBuilder.create<StateReadOp>(clock.getLoc(), oldClockStorage);
274 clockBuilder.create<StateWriteOp>(clock.getLoc(), oldClockStorage, newClock,
276 Value trigger = clockBuilder.create<comb::ICmpOp>(
277 clock.getLoc(), comb::ICmpPredicate::ne, oldClock, newClock);
279 clockBuilder.create<
comb::AndOp>(clock.getLoc(), trigger, newClock);
282 auto treeOp = clockBuilder.create<ClockTreeOp>(clock.getLoc(), trigger);
283 treeOp.getBody().emplaceBlock();
284 slot = std::make_unique<ClockLowering>(clock, treeOp, stats);
286 return GatedClockLowering{*slot, Value{}};
289 ClockLowering &ModuleLowering::getOrCreatePassThrough() {
290 auto &slot = clockLowerings[Value{}];
292 auto treeOp = clockBuilder.create<PassThroughOp>(moduleOp.getLoc());
293 treeOp.getBody().emplaceBlock();
294 slot = std::make_unique<ClockLowering>(Value{}, treeOp, stats);
300 Value ModuleLowering::replaceValueWithStateRead(Value
value, Value state) {
301 OpBuilder
builder(state.getContext());
302 builder.setInsertionPointAfterValue(state);
303 Value readOp =
builder.create<StateReadOp>(
value.getLoc(), state);
304 if (isa<seq::ClockType>(
value.getType()))
305 readOp =
builder.createOrFold<seq::ToClockOp>(
value.getLoc(), readOp);
306 value.replaceAllUsesWith(readOp);
311 void ModuleLowering::addStorageArg() {
313 storageArg = moduleOp.getBodyBlock()->addArgument(
319 LogicalResult ModuleLowering::lowerPrimaryInputs() {
320 for (
auto blockArg : moduleOp.getBodyBlock()->getArguments()) {
321 if (blockArg == storageArg)
323 auto name = moduleOp.getArgName(blockArg.getArgNumber());
324 auto argTy = blockArg.getType();
326 if (argTy.isa<seq::ClockType>()) {
328 }
else if (
auto intType = argTy.dyn_cast<IntegerType>()) {
331 return mlir::emitError(blockArg.getLoc(),
"input ")
332 << name <<
" is of non-integer type " << blockArg.getType();
334 auto state = stateBuilder.create<RootInputOp>(
336 replaceValueWithStateRead(blockArg, state);
343 LogicalResult ModuleLowering::lowerPrimaryOutputs() {
344 auto outputOp = cast<hw::OutputOp>(moduleOp.getBodyBlock()->getTerminator());
345 if (outputOp.getNumOperands() > 0) {
346 auto outputOperands = SmallVector<Value>(outputOp.getOperands());
347 outputOp->dropAllReferences();
348 auto &passThrough = getOrCreatePassThrough();
349 for (
auto [outputArg, name] :
350 llvm::zip(outputOperands, moduleOp.getOutputNames())) {
352 if (outputArg.getType().isa<seq::ClockType>()) {
354 }
else if (
auto intType = outputArg.getType().dyn_cast<IntegerType>()) {
357 return mlir::emitError(outputOp.getLoc(),
"output ")
358 << name <<
" is of non-integer type " << outputArg.getType();
360 auto value = passThrough.materializeValue(outputArg);
361 auto state = stateBuilder.create<RootOutputOp>(
362 outputOp.getLoc(),
StateType::get(innerTy), name.cast<StringAttr>(),
364 if (isa<seq::ClockType>(
value.getType()))
365 value = passThrough.builder.createOrFold<seq::FromClockOp>(
366 outputOp.getLoc(),
value);
367 passThrough.builder.create<StateWriteOp>(outputOp.getLoc(), state,
value,
375 LogicalResult ModuleLowering::lowerStates() {
376 SmallVector<Operation *> opsToLower;
377 for (
auto &op : *moduleOp.getBodyBlock()) {
378 auto stateOp = dyn_cast<StateOp>(&op);
379 if ((stateOp && stateOp.getLatency() > 0) ||
380 isa<MemoryOp, MemoryWritePortOp, TapOp>(&op))
381 opsToLower.push_back(&op);
384 for (
auto *op : opsToLower) {
385 LLVM_DEBUG(
llvm::dbgs() <<
"- Lowering " << *op <<
"\n");
386 auto result = TypeSwitch<Operation *, LogicalResult>(op)
387 .Case<StateOp, MemoryOp, MemoryWritePortOp, TapOp>(
388 [&](
auto op) {
return lowerState(op); })
396 LogicalResult ModuleLowering::lowerState(StateOp stateOp) {
398 if (stateOp.getLatency() == 0)
403 if (stateOp.getLatency() > 1)
404 return stateOp.emitError(
"state with latency > 1 not supported");
409 auto stateClock = stateOp.getClock();
410 auto stateEnable = stateOp.getEnable();
411 auto stateReset = stateOp.getReset();
412 auto stateInputs = SmallVector<Value>(stateOp.getInputs());
413 stateOp->dropAllReferences();
418 auto info = getOrCreateClockLowering(stateClock);
419 info.enable = info.clock.getOrCreateAnd(
420 info.enable, info.clock.materializeValue(stateEnable), stateOp.getLoc());
423 SmallVector<Value> allocatedStates;
424 for (
unsigned stateIdx = 0; stateIdx < stateOp.getNumResults(); ++stateIdx) {
425 auto type = stateOp.getResult(stateIdx).getType();
426 auto intType = dyn_cast<IntegerType>(type);
428 return stateOp.emitOpError(
"result ")
429 << stateIdx <<
" has non-integer type " << type
430 <<
"; only integer types are supported";
432 auto state = stateBuilder.create<AllocStateOp>(stateOp.getLoc(), stateType,
434 if (
auto names = stateOp->getAttrOfType<ArrayAttr>(
"names"))
435 state->setAttr(
"name", names[stateIdx]);
436 allocatedStates.push_back(state);
442 SmallVector<Value> materializedOperands;
443 materializedOperands.reserve(stateInputs.size());
445 for (
auto input : stateInputs)
446 materializedOperands.push_back(info.clock.materializeValue(input));
448 OpBuilder nonResetBuilder = info.clock.builder;
450 auto materializedReset = info.clock.materializeValue(stateReset);
451 auto ifOp = info.clock.builder.create<scf::IfOp>(stateOp.getLoc(),
452 materializedReset,
true);
454 for (
auto [alloc, resTy] :
455 llvm::zip(allocatedStates, stateOp.getResultTypes())) {
456 if (!resTy.isa<IntegerType>())
457 stateOp->emitOpError(
"Non-integer result not supported yet!");
459 auto thenBuilder = ifOp.getThenBodyBuilder();
462 thenBuilder.
create<StateWriteOp>(stateOp.getLoc(), alloc, constZero,
466 nonResetBuilder = ifOp.getElseBodyBuilder();
469 auto newStateOp = nonResetBuilder.create<StateOp>(
470 stateOp.getLoc(), stateOp.getArcAttr(), stateOp.getResultTypes(), Value{},
471 Value{}, 0, materializedOperands);
475 for (
auto [alloc, result] :
476 llvm::zip(allocatedStates, newStateOp.getResults()))
477 nonResetBuilder.create<StateWriteOp>(stateOp.getLoc(), alloc, result,
481 for (
auto [alloc, result] : llvm::zip(allocatedStates, stateOp.getResults()))
482 replaceValueWithStateRead(result, alloc);
487 LogicalResult ModuleLowering::lowerState(MemoryOp memOp) {
488 auto allocMemOp = stateBuilder.create<AllocMemoryOp>(
489 memOp.getLoc(), memOp.getType(), storageArg, memOp->getAttrs());
490 memOp.replaceAllUsesWith(allocMemOp.getResult());
495 LogicalResult ModuleLowering::lowerState(MemoryWritePortOp memWriteOp) {
496 if (memWriteOp.getLatency() > 1)
497 return memWriteOp->emitOpError(
"latencies > 1 not supported yet");
502 auto info = getOrCreateClockLowering(memWriteOp.getClock());
507 auto writeMemory = memWriteOp.getMemory();
508 auto writeInputs = SmallVector<Value>(memWriteOp.getInputs());
509 auto arcResultTypes = memWriteOp.getArcResultTypes();
510 memWriteOp->dropAllReferences();
512 SmallVector<Value> materializedInputs;
513 for (
auto input : writeInputs)
514 materializedInputs.push_back(info.clock.materializeValue(input));
517 .create<CallOp>(memWriteOp.getLoc(), arcResultTypes,
518 memWriteOp.getArc(), materializedInputs)
522 memWriteOp.getEnable() ? results[memWriteOp.getEnableIdx()] : Value();
524 info.clock.getOrCreateAnd(info.enable, enable, memWriteOp.getLoc());
528 auto address = results[memWriteOp.getAddressIdx()];
529 auto data = results[memWriteOp.getDataIdx()];
530 if (memWriteOp.getMask()) {
531 Value
mask = results[memWriteOp.getMaskIdx(
static_cast<bool>(enable))];
532 Value oldData = info.clock.builder.create<arc::MemoryReadOp>(
533 mask.getLoc(),
data.getType(), writeMemory, address);
535 mask.getLoc(), oldData.getType(), -1);
537 mask.getLoc(),
mask, allOnes,
true);
538 Value maskedOldData = info.clock.builder.create<
comb::AndOp>(
539 mask.getLoc(), negatedMask, oldData,
true);
540 Value maskedNewData =
543 maskedNewData,
true);
545 info.clock.builder.create<MemoryWriteOp>(memWriteOp.getLoc(), writeMemory,
546 address, info.enable,
data);
552 LogicalResult ModuleLowering::lowerState(TapOp tapOp) {
553 auto intType = tapOp.getValue().getType().dyn_cast<IntegerType>();
555 return mlir::emitError(tapOp.getLoc(),
"tapped value ")
556 << tapOp.getNameAttr() <<
" is of non-integer type "
557 << tapOp.getValue().getType();
561 auto tapValue = tapOp.getValue();
562 tapOp->dropAllReferences();
564 auto &passThrough = getOrCreatePassThrough();
565 auto materializedValue = passThrough.materializeValue(tapValue);
566 auto state = stateBuilder.create<AllocStateOp>(
568 state->setAttr(
"name", tapOp.getNameAttr());
569 passThrough.builder.create<StateWriteOp>(tapOp.getLoc(), state,
570 materializedValue, Value{});
577 LogicalResult ModuleLowering::lowerExtModules(SymbolTable &symtbl) {
578 auto instOps = SmallVector<InstanceOp>(moduleOp.getOps<InstanceOp>());
579 for (
auto op : instOps)
580 if (isa<HWModuleExternOp>(symtbl.lookup(op.getModuleNameAttr().getAttr())))
581 if (failed(lowerExtModule(op)))
586 LogicalResult ModuleLowering::lowerExtModule(InstanceOp instOp) {
587 LLVM_DEBUG(
llvm::dbgs() <<
"- Lowering extmodule "
588 << instOp.getInstanceNameAttr() <<
"\n");
590 SmallString<32> baseName(instOp.getInstanceName());
591 auto baseNameLen = baseName.size();
594 for (
auto [operand, name] :
595 llvm::zip(instOp.getOperands(), instOp.getArgNames())) {
597 <<
" - Input " << name <<
" : " << operand.getType() <<
"\n");
598 auto intType = operand.getType().dyn_cast<IntegerType>();
600 return mlir::emitError(operand.getLoc(),
"input ")
601 << name <<
" of extern module " << instOp.getModuleNameAttr()
602 <<
" instance " << instOp.getInstanceNameAttr()
603 <<
" is of non-integer type " << operand.getType();
604 baseName.resize(baseNameLen);
606 baseName += cast<StringAttr>(name).getValue();
607 auto &passThrough = getOrCreatePassThrough();
608 auto state = stateBuilder.create<AllocStateOp>(
610 state->setAttr(
"name", stateBuilder.getStringAttr(baseName));
611 passThrough.builder.create<StateWriteOp>(
612 instOp.getLoc(), state, passThrough.materializeValue(operand), Value{});
616 for (
auto [result, name] :
617 llvm::zip(instOp.getResults(), instOp.getResultNames())) {
619 <<
" - Output " << name <<
" : " << result.getType() <<
"\n");
620 auto intType = result.getType().dyn_cast<IntegerType>();
622 return mlir::emitError(result.getLoc(),
"output ")
623 << name <<
" of extern module " << instOp.getModuleNameAttr()
624 <<
" instance " << instOp.getInstanceNameAttr()
625 <<
" is of non-integer type " << result.getType();
626 baseName.resize(baseNameLen);
628 baseName += cast<StringAttr>(name).getValue();
629 auto state = stateBuilder.create<AllocStateOp>(
631 state->setAttr(
"name", stateBuilder.getStringAttr(baseName));
632 replaceValueWithStateRead(result, state);
639 LogicalResult ModuleLowering::cleanup() {
641 SetVector<Operation *> erasureWorklist;
642 auto isDead = [](Operation *op) {
643 if (isOpTriviallyDead(op))
645 if (!op->use_empty())
647 if (
auto stateOp = dyn_cast<StateOp>(op))
648 return stateOp.getLatency() == 0;
651 for (
auto &op : *moduleOp.getBodyBlock())
653 erasureWorklist.insert(&op);
654 while (!erasureWorklist.empty()) {
655 auto *op = erasureWorklist.pop_back_val();
658 op->walk([&](Operation *innerOp) {
659 for (
auto operand : innerOp->getOperands())
660 if (
auto *defOp = operand.getDefiningOp())
661 if (!op->isProperAncestor(defOp))
662 erasureWorklist.insert(defOp);
671 DenseMap<Operation *, unsigned> opOrder;
672 SmallVector<StateReadOp, 0> readsToSink;
673 moduleOp.walk([&](Operation *op) {
674 opOrder.insert({op, opOrder.size()});
675 if (
auto readOp = dyn_cast<StateReadOp>(op))
676 readsToSink.push_back(readOp);
678 for (
auto readToSink : readsToSink) {
680 for (
auto &use : llvm::make_early_inc_range(readToSink->getUses())) {
681 auto *user = use.getOwner();
682 auto userOrder = opOrder.lookup(user);
683 auto &localRead = readsByBlock[user->getBlock()];
684 if (!localRead.first) {
685 if (user->getBlock() == readToSink->getBlock()) {
686 localRead.first = readToSink;
687 readToSink->moveBefore(user);
689 localRead.first = OpBuilder(user).cloneWithoutRegions(readToSink);
691 localRead.second = userOrder;
692 }
else if (userOrder < localRead.second) {
693 localRead.first->moveBefore(user);
694 localRead.second = userOrder;
696 use.set(localRead.first);
698 if (readToSink.use_empty())
709 struct LowerStatePass :
public arc::impl::LowerStateBase<LowerStatePass> {
710 LowerStatePass() =
default;
711 LowerStatePass(
const LowerStatePass &pass) : LowerStatePass() {}
713 void runOnOperation()
override;
714 LogicalResult runOnModule(
HWModuleOp moduleOp, SymbolTable &symtbl);
716 Statistics stats{
this};
720 void LowerStatePass::runOnOperation() {
721 auto &symtbl = getAnalysis<SymbolTable>();
722 SmallVector<HWModuleExternOp> extModules;
723 for (
auto &op : llvm::make_early_inc_range(getOperation().getOps())) {
724 if (
auto moduleOp = dyn_cast<HWModuleOp>(&op)) {
725 if (failed(runOnModule(moduleOp, symtbl)))
726 return signalPassFailure();
727 }
else if (
auto extModuleOp = dyn_cast<HWModuleExternOp>(&op)) {
728 extModules.push_back(extModuleOp);
731 for (
auto op : extModules)
740 SetVector<DefineOp> arcsToLower;
741 OpBuilder
builder(getOperation());
742 getOperation()->walk([&](MemoryReadPortOp memReadOp) {
743 if (
auto defOp = memReadOp->getParentOfType<DefineOp>())
744 arcsToLower.insert(defOp);
746 builder.setInsertionPoint(memReadOp);
747 Value newRead =
builder.create<MemoryReadOp>(
748 memReadOp.getLoc(), memReadOp.getMemory(), memReadOp.getAddress());
749 memReadOp.replaceAllUsesWith(newRead);
753 SymbolTableCollection symbolTable;
754 mlir::SymbolUserMap userMap(symbolTable, getOperation());
755 for (
auto defOp : arcsToLower) {
756 auto *terminator = defOp.getBodyBlock().getTerminator();
757 builder.setInsertionPoint(terminator);
758 builder.create<func::ReturnOp>(terminator->getLoc(),
759 terminator->getOperands());
761 builder.setInsertionPoint(defOp);
762 auto funcOp =
builder.create<func::FuncOp>(defOp.getLoc(), defOp.getName(),
763 defOp.getFunctionType());
764 funcOp->setAttr(
"llvm.linkage",
766 LLVM::linkage::Linkage::Internal));
767 funcOp.getBody().takeBody(defOp.getBody());
769 for (
auto *user : userMap.getUsers(defOp)) {
770 builder.setInsertionPoint(user);
772 .create<func::CallOp>(
773 user->getLoc(), funcOp,
774 cast<CallOpInterface>(user).getArgOperands())
776 user->replaceAllUsesWith(results);
784 LogicalResult LowerStatePass::runOnModule(
HWModuleOp moduleOp,
785 SymbolTable &symtbl) {
786 LLVM_DEBUG(
llvm::dbgs() <<
"Lowering state in `" << moduleOp.getModuleName()
788 ModuleLowering lowering(moduleOp, stats);
791 lowering.stateBuilder.setInsertionPointToStart(moduleOp.getBodyBlock());
793 Operation *stateSentinel =
794 lowering.stateBuilder.create<hw::OutputOp>(moduleOp.getLoc());
795 Operation *clockSentinel =
796 lowering.stateBuilder.create<hw::OutputOp>(moduleOp.getLoc());
798 lowering.stateBuilder.setInsertionPoint(stateSentinel);
799 lowering.clockBuilder.setInsertionPoint(clockSentinel);
801 lowering.addStorageArg();
802 if (failed(lowering.lowerPrimaryInputs()))
804 if (failed(lowering.lowerPrimaryOutputs()))
806 if (failed(lowering.lowerStates()))
808 if (failed(lowering.lowerExtModules(symtbl)))
814 if (failed(lowering.cleanup()))
818 stateSentinel->erase();
819 clockSentinel->erase();
822 moduleOp.getBodyBlock()->eraseArguments(
823 [&](
auto arg) {
return arg != lowering.storageArg; });
824 ImplicitLocOpBuilder
builder(moduleOp.getLoc(), moduleOp);
826 builder.create<ModelOp>(moduleOp.getLoc(), moduleOp.getModuleNameAttr());
827 modelOp.getBody().takeBody(moduleOp.getBody());
829 sortTopologically(&modelOp.getBodyBlock());
835 return std::make_unique<LowerStatePass>();
assert(baseType &&"element must be base type")
static bool shouldMaterialize(Operation *op)
def create(data_type, value)
std::unique_ptr< mlir::Pass > createLowerStatePass()
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()