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 DenseMap<std::pair<Value, Value>, Value> orCache;
78 ClockLowering(Value clock, Operation *treeOp, Statistics &stats)
79 : clock(clock), treeOp(treeOp), stats(stats),
builder(treeOp) {
80 assert((isa<ClockTreeOp, PassThroughOp>(treeOp)));
81 builder.setInsertionPointToStart(&treeOp->getRegion(0).front());
84 Value materializeValue(Value value);
85 Value getOrCreateAnd(Value lhs, Value rhs, Location loc);
86 Value getOrCreateOr(Value lhs, Value rhs, Location loc);
89 struct GatedClockLowering {
97 struct ModuleLowering {
101 MLIRContext *context;
102 DenseMap<Value, std::unique_ptr<ClockLowering>> clockLowerings;
103 DenseMap<Value, GatedClockLowering> gatedClockLowerings;
105 OpBuilder clockBuilder;
106 OpBuilder stateBuilder;
108 ModuleLowering(
HWModuleOp moduleOp, Statistics &stats)
109 : moduleOp(moduleOp), stats(stats), context(moduleOp.getContext()),
110 clockBuilder(moduleOp), stateBuilder(moduleOp) {}
112 GatedClockLowering getOrCreateClockLowering(Value clock);
113 ClockLowering &getOrCreatePassThrough();
114 Value replaceValueWithStateRead(Value value, Value state);
116 void addStorageArg();
117 LogicalResult lowerPrimaryInputs();
118 LogicalResult lowerPrimaryOutputs();
119 LogicalResult lowerStates();
120 LogicalResult lowerState(StateOp stateOp);
121 LogicalResult lowerState(MemoryOp memOp);
122 LogicalResult lowerState(MemoryWritePortOp memWriteOp);
123 LogicalResult lowerState(TapOp tapOp);
124 LogicalResult lowerExtModules(SymbolTable &symtbl);
125 LogicalResult lowerExtModule(InstanceOp instOp);
127 LogicalResult cleanup();
139 return !isa<MemoryOp, AllocStateOp, AllocMemoryOp, AllocStorageOp,
140 ClockTreeOp, PassThroughOp, RootInputOp, RootOutputOp,
141 StateWriteOp, MemoryWritePortOp, igraph::InstanceOpInterface,
149 auto *op = value.getDefiningOp();
158 Value ClockLowering::materializeValue(Value value) {
161 if (
auto mapped = materializedValues.lookupOrNull(value))
168 SmallVector<Value, 2> operands;
169 WorkItem(Operation *op) : op(op) {}
172 SmallPtrSet<Operation *, 8> seen;
173 SmallVector<WorkItem> worklist;
175 auto addToWorklist = [&](Operation *outerOp) {
176 SmallDenseSet<Value> seenOperands;
177 auto &workItem = worklist.emplace_back(outerOp);
178 outerOp->walk([&](Operation *innerOp) {
179 for (
auto operand : innerOp->getOperands()) {
181 if (!operand.getParentBlock()->getParentOp()->isProperAncestor(outerOp))
185 if (!seenOperands.insert(operand).second)
193 workItem.operands.push_back(operand);
198 seen.insert(value.getDefiningOp());
199 addToWorklist(value.getDefiningOp());
201 while (!worklist.empty()) {
202 auto &workItem = worklist.back();
203 if (!workItem.operands.empty()) {
204 auto operand = workItem.operands.pop_back_val();
207 auto *defOp = operand.getDefiningOp();
208 if (!seen.insert(defOp).second) {
209 defOp->emitError(
"combinational loop detected");
212 addToWorklist(defOp);
214 builder.clone(*workItem.op, materializedValues);
215 seen.erase(workItem.op);
220 return materializedValues.lookup(value);
226 Value ClockLowering::getOrCreateAnd(Value lhs, Value rhs, Location loc) {
231 auto &slot = andCache[std::make_pair(lhs, rhs)];
240 Value ClockLowering::getOrCreateOr(Value lhs, Value rhs, Location loc) {
245 auto &slot = orCache[std::make_pair(lhs, rhs)];
255 GatedClockLowering ModuleLowering::getOrCreateClockLowering(Value clock) {
257 if (
auto ckgOp = clock.getDefiningOp<seq::ClockGateOp>()) {
259 if (
auto it = gatedClockLowerings.find(clock);
260 it != gatedClockLowerings.end())
267 auto info = getOrCreateClockLowering(ckgOp.getInput());
268 auto ckgEnable = info.clock.materializeValue(ckgOp.getEnable());
269 auto ckgTestEnable = info.clock.materializeValue(ckgOp.getTestEnable());
270 info.enable = info.clock.getOrCreateAnd(
272 info.clock.getOrCreateOr(ckgEnable, ckgTestEnable, ckgOp.getLoc()),
274 gatedClockLowerings.insert({clock, info});
279 auto &slot = clockLowerings[clock];
282 clockBuilder.createOrFold<seq::FromClockOp>(clock.getLoc(), clock);
285 auto oldClockStorage = stateBuilder.create<AllocStateOp>(
286 clock.getLoc(),
StateType::get(stateBuilder.getI1Type()), storageArg);
288 clockBuilder.create<StateReadOp>(clock.getLoc(), oldClockStorage);
289 clockBuilder.create<StateWriteOp>(clock.getLoc(), oldClockStorage, newClock,
291 Value trigger = clockBuilder.create<comb::ICmpOp>(
292 clock.getLoc(), comb::ICmpPredicate::ne, oldClock, newClock);
294 clockBuilder.create<
comb::AndOp>(clock.getLoc(), trigger, newClock);
297 auto treeOp = clockBuilder.create<ClockTreeOp>(clock.getLoc(), trigger);
298 treeOp.getBody().emplaceBlock();
299 slot = std::make_unique<ClockLowering>(clock, treeOp, stats);
301 return GatedClockLowering{*slot, Value{}};
304 ClockLowering &ModuleLowering::getOrCreatePassThrough() {
305 auto &slot = clockLowerings[Value{}];
307 auto treeOp = clockBuilder.create<PassThroughOp>(moduleOp.getLoc());
308 treeOp.getBody().emplaceBlock();
309 slot = std::make_unique<ClockLowering>(Value{}, treeOp, stats);
315 Value ModuleLowering::replaceValueWithStateRead(Value value, Value state) {
316 OpBuilder
builder(state.getContext());
317 builder.setInsertionPointAfterValue(state);
318 Value readOp =
builder.create<StateReadOp>(value.getLoc(), state);
319 if (isa<seq::ClockType>(value.getType()))
320 readOp =
builder.createOrFold<seq::ToClockOp>(value.getLoc(), readOp);
321 value.replaceAllUsesWith(readOp);
326 void ModuleLowering::addStorageArg() {
328 storageArg = moduleOp.getBodyBlock()->addArgument(
334 LogicalResult ModuleLowering::lowerPrimaryInputs() {
335 for (
auto blockArg : moduleOp.getBodyBlock()->getArguments()) {
336 if (blockArg == storageArg)
338 auto name = moduleOp.getArgName(blockArg.getArgNumber());
339 auto argTy = blockArg.getType();
341 if (isa<seq::ClockType>(argTy)) {
343 }
else if (
auto intType = dyn_cast<IntegerType>(argTy)) {
346 return mlir::emitError(blockArg.getLoc(),
"input ")
347 << name <<
" is of non-integer type " << blockArg.getType();
349 auto state = stateBuilder.create<RootInputOp>(
351 replaceValueWithStateRead(blockArg, state);
358 LogicalResult ModuleLowering::lowerPrimaryOutputs() {
359 auto outputOp = cast<hw::OutputOp>(moduleOp.getBodyBlock()->getTerminator());
360 if (outputOp.getNumOperands() > 0) {
361 auto outputOperands = SmallVector<Value>(outputOp.getOperands());
362 outputOp->dropAllReferences();
363 auto &passThrough = getOrCreatePassThrough();
364 for (
auto [outputArg, name] :
365 llvm::zip(outputOperands, moduleOp.getOutputNames())) {
367 if (isa<seq::ClockType>(outputArg.getType())) {
369 }
else if (
auto intType = dyn_cast<IntegerType>(outputArg.getType())) {
372 return mlir::emitError(outputOp.getLoc(),
"output ")
373 << name <<
" is of non-integer type " << outputArg.getType();
375 auto value = passThrough.materializeValue(outputArg);
376 auto state = stateBuilder.create<RootOutputOp>(
377 outputOp.getLoc(),
StateType::get(innerTy), cast<StringAttr>(name),
379 if (isa<seq::ClockType>(value.getType()))
380 value = passThrough.builder.createOrFold<seq::FromClockOp>(
381 outputOp.getLoc(), value);
382 passThrough.builder.create<StateWriteOp>(outputOp.getLoc(), state, value,
390 LogicalResult ModuleLowering::lowerStates() {
391 SmallVector<Operation *> opsToLower;
392 for (
auto &op : *moduleOp.getBodyBlock())
393 if (isa<StateOp, MemoryOp, MemoryWritePortOp, TapOp>(&op))
394 opsToLower.push_back(&op);
396 for (
auto *op : opsToLower) {
397 LLVM_DEBUG(llvm::dbgs() <<
"- Lowering " << *op <<
"\n");
398 auto result = TypeSwitch<Operation *, LogicalResult>(op)
399 .Case<StateOp, MemoryOp, MemoryWritePortOp, TapOp>(
400 [&](
auto op) {
return lowerState(op); })
408 LogicalResult ModuleLowering::lowerState(StateOp stateOp) {
411 if (stateOp.getLatency() > 1)
412 return stateOp.emitError(
"state with latency > 1 not supported");
417 auto stateClock = stateOp.getClock();
418 auto stateEnable = stateOp.getEnable();
419 auto stateReset = stateOp.getReset();
420 auto stateInputs = SmallVector<Value>(stateOp.getInputs());
425 auto info = getOrCreateClockLowering(stateClock);
426 info.enable = info.clock.getOrCreateAnd(
427 info.enable, info.clock.materializeValue(stateEnable), stateOp.getLoc());
430 SmallVector<Value> allocatedStates;
431 for (
unsigned stateIdx = 0; stateIdx < stateOp.getNumResults(); ++stateIdx) {
432 auto type = stateOp.getResult(stateIdx).getType();
433 auto intType = dyn_cast<IntegerType>(type);
435 return stateOp.emitOpError(
"result ")
436 << stateIdx <<
" has non-integer type " << type
437 <<
"; only integer types are supported";
439 auto state = stateBuilder.create<AllocStateOp>(stateOp.getLoc(), stateType,
441 if (
auto names = stateOp->getAttrOfType<ArrayAttr>(
"names"))
442 state->setAttr(
"name", names[stateIdx]);
443 allocatedStates.push_back(state);
449 SmallVector<Value> materializedOperands;
450 materializedOperands.reserve(stateInputs.size());
452 for (
auto input : stateInputs)
453 materializedOperands.push_back(info.clock.materializeValue(input));
455 OpBuilder nonResetBuilder = info.clock.builder;
457 auto materializedReset = info.clock.materializeValue(stateReset);
458 auto ifOp = info.clock.builder.create<scf::IfOp>(stateOp.getLoc(),
459 materializedReset,
true);
461 for (
auto [alloc, resTy] :
462 llvm::zip(allocatedStates, stateOp.getResultTypes())) {
463 if (!isa<IntegerType>(resTy))
464 stateOp->emitOpError(
"Non-integer result not supported yet!");
466 auto thenBuilder = ifOp.getThenBodyBuilder();
469 thenBuilder.
create<StateWriteOp>(stateOp.getLoc(), alloc, constZero,
473 nonResetBuilder = ifOp.getElseBodyBuilder();
476 stateOp->dropAllReferences();
478 auto newStateOp = nonResetBuilder.create<CallOp>(
479 stateOp.getLoc(), stateOp.getResultTypes(), stateOp.getArcAttr(),
480 materializedOperands);
484 for (
auto [alloc, result] :
485 llvm::zip(allocatedStates, newStateOp.getResults()))
486 nonResetBuilder.create<StateWriteOp>(stateOp.getLoc(), alloc, result,
490 for (
auto [alloc, result] : llvm::zip(allocatedStates, stateOp.getResults()))
491 replaceValueWithStateRead(result, alloc);
496 LogicalResult ModuleLowering::lowerState(MemoryOp memOp) {
497 auto allocMemOp = stateBuilder.create<AllocMemoryOp>(
498 memOp.getLoc(), memOp.getType(), storageArg, memOp->getAttrs());
499 memOp.replaceAllUsesWith(allocMemOp.getResult());
504 LogicalResult ModuleLowering::lowerState(MemoryWritePortOp memWriteOp) {
505 if (memWriteOp.getLatency() > 1)
506 return memWriteOp->emitOpError(
"latencies > 1 not supported yet");
511 auto info = getOrCreateClockLowering(memWriteOp.getClock());
516 auto writeMemory = memWriteOp.getMemory();
517 auto writeInputs = SmallVector<Value>(memWriteOp.getInputs());
518 auto arcResultTypes = memWriteOp.getArcResultTypes();
519 memWriteOp->dropAllReferences();
521 SmallVector<Value> materializedInputs;
522 for (
auto input : writeInputs)
523 materializedInputs.push_back(info.clock.materializeValue(input));
526 .create<CallOp>(memWriteOp.getLoc(), arcResultTypes,
527 memWriteOp.getArc(), materializedInputs)
531 memWriteOp.getEnable() ? results[memWriteOp.getEnableIdx()] : Value();
533 info.clock.getOrCreateAnd(info.enable, enable, memWriteOp.getLoc());
537 auto address = results[memWriteOp.getAddressIdx()];
538 auto data = results[memWriteOp.getDataIdx()];
539 if (memWriteOp.getMask()) {
540 Value
mask = results[memWriteOp.getMaskIdx(
static_cast<bool>(enable))];
541 Value oldData = info.clock.builder.create<arc::MemoryReadOp>(
542 mask.getLoc(),
data.getType(), writeMemory, address);
544 mask.getLoc(), oldData.getType(), -1);
546 mask.getLoc(),
mask, allOnes,
true);
547 Value maskedOldData = info.clock.builder.create<
comb::AndOp>(
548 mask.getLoc(), negatedMask, oldData,
true);
549 Value maskedNewData =
552 maskedNewData,
true);
554 info.clock.builder.create<MemoryWriteOp>(memWriteOp.getLoc(), writeMemory,
555 address, info.enable,
data);
561 LogicalResult ModuleLowering::lowerState(TapOp tapOp) {
562 auto intType = dyn_cast<IntegerType>(tapOp.getValue().getType());
564 return mlir::emitError(tapOp.getLoc(),
"tapped value ")
565 << tapOp.getNameAttr() <<
" is of non-integer type "
566 << tapOp.getValue().getType();
570 auto tapValue = tapOp.getValue();
571 tapOp->dropAllReferences();
573 auto &passThrough = getOrCreatePassThrough();
574 auto materializedValue = passThrough.materializeValue(tapValue);
575 auto state = stateBuilder.create<AllocStateOp>(
577 state->setAttr(
"name", tapOp.getNameAttr());
578 passThrough.builder.create<StateWriteOp>(tapOp.getLoc(), state,
579 materializedValue, Value{});
586 LogicalResult ModuleLowering::lowerExtModules(SymbolTable &symtbl) {
587 auto instOps = SmallVector<InstanceOp>(moduleOp.getOps<InstanceOp>());
588 for (
auto op : instOps)
589 if (isa<HWModuleExternOp>(symtbl.lookup(op.getModuleNameAttr().getAttr())))
590 if (failed(lowerExtModule(op)))
595 LogicalResult ModuleLowering::lowerExtModule(InstanceOp instOp) {
596 LLVM_DEBUG(llvm::dbgs() <<
"- Lowering extmodule "
597 << instOp.getInstanceNameAttr() <<
"\n");
599 SmallString<32> baseName(instOp.getInstanceName());
600 auto baseNameLen = baseName.size();
603 for (
auto [operand, name] :
604 llvm::zip(instOp.getOperands(), instOp.getArgNames())) {
605 LLVM_DEBUG(llvm::dbgs()
606 <<
" - Input " << name <<
" : " << operand.getType() <<
"\n");
607 auto intType = dyn_cast<IntegerType>(operand.getType());
609 return mlir::emitError(operand.getLoc(),
"input ")
610 << name <<
" of extern module " << instOp.getModuleNameAttr()
611 <<
" instance " << instOp.getInstanceNameAttr()
612 <<
" is of non-integer type " << operand.getType();
613 baseName.resize(baseNameLen);
615 baseName += cast<StringAttr>(name).getValue();
616 auto &passThrough = getOrCreatePassThrough();
617 auto state = stateBuilder.create<AllocStateOp>(
619 state->setAttr(
"name", stateBuilder.getStringAttr(baseName));
620 passThrough.builder.create<StateWriteOp>(
621 instOp.getLoc(), state, passThrough.materializeValue(operand), Value{});
625 for (
auto [result, name] :
626 llvm::zip(instOp.getResults(), instOp.getResultNames())) {
627 LLVM_DEBUG(llvm::dbgs()
628 <<
" - Output " << name <<
" : " << result.getType() <<
"\n");
629 auto intType = dyn_cast<IntegerType>(result.getType());
631 return mlir::emitError(result.getLoc(),
"output ")
632 << name <<
" of extern module " << instOp.getModuleNameAttr()
633 <<
" instance " << instOp.getInstanceNameAttr()
634 <<
" is of non-integer type " << result.getType();
635 baseName.resize(baseNameLen);
637 baseName += cast<StringAttr>(name).getValue();
638 auto state = stateBuilder.create<AllocStateOp>(
640 state->setAttr(
"name", stateBuilder.getStringAttr(baseName));
641 replaceValueWithStateRead(result, state);
648 LogicalResult ModuleLowering::cleanup() {
650 SetVector<Operation *> erasureWorklist;
651 auto isDead = [](Operation *op) {
652 if (isOpTriviallyDead(op))
654 if (!op->use_empty())
658 for (
auto &op : *moduleOp.getBodyBlock())
660 erasureWorklist.insert(&op);
661 while (!erasureWorklist.empty()) {
662 auto *op = erasureWorklist.pop_back_val();
665 op->walk([&](Operation *innerOp) {
666 for (
auto operand : innerOp->getOperands())
667 if (
auto *defOp = operand.getDefiningOp())
668 if (!op->isProperAncestor(defOp))
669 erasureWorklist.insert(defOp);
678 DenseMap<Operation *, unsigned> opOrder;
679 SmallVector<StateReadOp, 0> readsToSink;
680 moduleOp.walk([&](Operation *op) {
681 opOrder.insert({op, opOrder.size()});
682 if (
auto readOp = dyn_cast<StateReadOp>(op))
683 readsToSink.push_back(readOp);
685 for (
auto readToSink : readsToSink) {
687 for (
auto &use : llvm::make_early_inc_range(readToSink->getUses())) {
688 auto *user = use.getOwner();
689 auto userOrder = opOrder.lookup(user);
690 auto &localRead = readsByBlock[user->getBlock()];
691 if (!localRead.first) {
692 if (user->getBlock() == readToSink->getBlock()) {
693 localRead.first = readToSink;
694 readToSink->moveBefore(user);
696 localRead.first = OpBuilder(user).cloneWithoutRegions(readToSink);
698 localRead.second = userOrder;
699 }
else if (userOrder < localRead.second) {
700 localRead.first->moveBefore(user);
701 localRead.second = userOrder;
703 use.set(localRead.first);
705 if (readToSink.use_empty())
716 struct LowerStatePass :
public arc::impl::LowerStateBase<LowerStatePass> {
717 LowerStatePass() =
default;
718 LowerStatePass(
const LowerStatePass &pass) : LowerStatePass() {}
720 void runOnOperation()
override;
721 LogicalResult runOnModule(
HWModuleOp moduleOp, SymbolTable &symtbl);
723 Statistics stats{
this};
727 void LowerStatePass::runOnOperation() {
728 auto &symtbl = getAnalysis<SymbolTable>();
729 SmallVector<HWModuleExternOp> extModules;
730 for (
auto &op : llvm::make_early_inc_range(getOperation().getOps())) {
731 if (
auto moduleOp = dyn_cast<HWModuleOp>(&op)) {
732 if (failed(runOnModule(moduleOp, symtbl)))
733 return signalPassFailure();
734 }
else if (
auto extModuleOp = dyn_cast<HWModuleExternOp>(&op)) {
735 extModules.push_back(extModuleOp);
738 for (
auto op : extModules)
747 SetVector<DefineOp> arcsToLower;
748 OpBuilder
builder(getOperation());
749 getOperation()->walk([&](MemoryReadPortOp memReadOp) {
750 if (
auto defOp = memReadOp->getParentOfType<DefineOp>())
751 arcsToLower.insert(defOp);
753 builder.setInsertionPoint(memReadOp);
754 Value newRead =
builder.create<MemoryReadOp>(
755 memReadOp.getLoc(), memReadOp.getMemory(), memReadOp.getAddress());
756 memReadOp.replaceAllUsesWith(newRead);
760 SymbolTableCollection symbolTable;
761 mlir::SymbolUserMap userMap(symbolTable, getOperation());
762 for (
auto defOp : arcsToLower) {
763 auto *terminator = defOp.getBodyBlock().getTerminator();
764 builder.setInsertionPoint(terminator);
765 builder.create<func::ReturnOp>(terminator->getLoc(),
766 terminator->getOperands());
768 builder.setInsertionPoint(defOp);
769 auto funcOp =
builder.create<func::FuncOp>(defOp.getLoc(), defOp.getName(),
770 defOp.getFunctionType());
771 funcOp->setAttr(
"llvm.linkage",
773 LLVM::linkage::Linkage::Internal));
774 funcOp.getBody().takeBody(defOp.getBody());
776 for (
auto *user : userMap.getUsers(defOp)) {
777 builder.setInsertionPoint(user);
779 .create<func::CallOp>(
780 user->getLoc(), funcOp,
781 cast<CallOpInterface>(user).getArgOperands())
783 user->replaceAllUsesWith(results);
791 LogicalResult LowerStatePass::runOnModule(
HWModuleOp moduleOp,
792 SymbolTable &symtbl) {
793 LLVM_DEBUG(llvm::dbgs() <<
"Lowering state in `" << moduleOp.getModuleName()
795 ModuleLowering lowering(moduleOp, stats);
798 lowering.stateBuilder.setInsertionPointToStart(moduleOp.getBodyBlock());
800 Operation *stateSentinel =
801 lowering.stateBuilder.create<hw::OutputOp>(moduleOp.getLoc());
802 Operation *clockSentinel =
803 lowering.stateBuilder.create<hw::OutputOp>(moduleOp.getLoc());
805 lowering.stateBuilder.setInsertionPoint(stateSentinel);
806 lowering.clockBuilder.setInsertionPoint(clockSentinel);
808 lowering.addStorageArg();
809 if (failed(lowering.lowerPrimaryInputs()))
811 if (failed(lowering.lowerPrimaryOutputs()))
813 if (failed(lowering.lowerStates()))
815 if (failed(lowering.lowerExtModules(symtbl)))
821 if (failed(lowering.cleanup()))
825 stateSentinel->erase();
826 clockSentinel->erase();
829 moduleOp.getBodyBlock()->eraseArguments(
830 [&](
auto arg) {
return arg != lowering.storageArg; });
831 ImplicitLocOpBuilder
builder(moduleOp.getLoc(), moduleOp);
833 builder.create<ModelOp>(moduleOp.getLoc(), moduleOp.getModuleNameAttr(),
835 modelOp.getBody().takeBody(moduleOp.getBody());
837 sortTopologically(&modelOp.getBodyBlock());
843 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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.