18 #include "mlir/Analysis/TopologicalSortUtils.h"
19 #include "mlir/Dialect/Func/IR/FuncOps.h"
20 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
21 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
22 #include "mlir/Dialect/SCF/IR/SCF.h"
23 #include "mlir/IR/IRMapping.h"
24 #include "mlir/IR/ImplicitLocOpBuilder.h"
25 #include "mlir/IR/SymbolTable.h"
26 #include "mlir/Interfaces/SideEffectInterfaces.h"
27 #include "mlir/Pass/Pass.h"
28 #include "llvm/ADT/TypeSwitch.h"
29 #include "llvm/Support/Debug.h"
31 #define DEBUG_TYPE "arc-lower-state"
35 #define GEN_PASS_DEF_LOWERSTATEPASS
36 #include "circt/Dialect/Arc/ArcPasses.h.inc"
40 using namespace circt;
44 using llvm::SmallDenseSet;
47 enum class Phase { Initial, Old, New, Final };
53 return os <<
"initial";
63 struct ModuleLowering;
82 ModuleLowering &module;
85 SmallVector<std::pair<Operation *, Phase>, 2> pending;
87 OpLowering(Operation *op, Phase phase, ModuleLowering &module)
88 : op(op), phase(phase), module(module) {}
91 LogicalResult lower();
92 LogicalResult lowerDefault();
93 LogicalResult lower(StateOp op);
94 LogicalResult lower(sim::DPICallOp op);
96 lowerStateful(Value clock, Value enable, Value reset, ValueRange inputs,
98 llvm::function_ref<ValueRange(ValueRange)> createMapping);
99 LogicalResult lower(MemoryOp op);
100 LogicalResult lower(TapOp op);
101 LogicalResult lower(InstanceOp op);
102 LogicalResult lower(hw::OutputOp op);
103 LogicalResult lower(seq::InitialOp op);
104 LogicalResult lower(llhd::FinalOp op);
106 scf::IfOp createIfClockOp(Value clock);
112 Value lowerValue(Value value, Phase phase);
113 Value lowerValue(InstanceOp op, OpResult result, Phase phase);
114 Value lowerValue(StateOp op, OpResult result, Phase phase);
115 Value lowerValue(sim::DPICallOp op, OpResult result, Phase phase);
116 Value lowerValue(MemoryReadPortOp op, OpResult result, Phase phase);
117 Value lowerValue(seq::InitialOp op, OpResult result, Phase phase);
118 Value lowerValue(seq::FromImmutableOp op, OpResult result, Phase phase);
120 void addPending(Value value, Phase phase);
121 void addPending(Operation *op, Phase phase);
125 struct ModuleLowering {
131 OpBuilder allocBuilder;
133 OpBuilder initialBuilder;
135 OpBuilder finalBuilder;
141 SmallVector<OpLowering> opsWorklist;
143 SmallDenseSet<std::pair<Operation *, Phase>> opsSeen;
145 DenseSet<std::pair<Operation *, Phase>> loweredOps;
147 DenseMap<std::pair<Value, Phase>, Value> loweredValues;
150 SmallVector<Value> allocatedInputs;
153 DenseMap<Value, Value> allocatedStates;
155 DenseMap<OpOperand *, Value> allocatedOutputs;
157 DenseMap<Value, Value> allocatedInitials;
159 DenseMap<Operation *, Value> allocatedTaps;
163 DenseMap<Value, Value> loweredPosedges;
166 std::pair<Value, Value> prevEnable;
169 std::pair<Value, Value> prevReset;
172 : moduleOp(moduleOp), builder(moduleOp), allocBuilder(moduleOp),
173 initialBuilder(moduleOp), finalBuilder(moduleOp) {}
175 LogicalResult lowerOp(Operation *op);
176 Value getAllocatedState(OpResult result);
177 Value detectPosedge(Value clock);
178 OpBuilder &getBuilder(Phase phase);
179 Value requireLoweredValue(Value value, Phase phase, Location useLoc);
188 LLVM_DEBUG(llvm::dbgs() <<
"Lowering module `" << moduleOp.getModuleName()
193 builder.create<ModelOp>(moduleOp.getLoc(), moduleOp.getModuleNameAttr(),
195 FlatSymbolRefAttr{}, FlatSymbolRefAttr{});
196 auto &modelBlock = modelOp.getBody().emplaceBlock();
197 storageArg = modelBlock.addArgument(
199 builder.setInsertionPointToStart(&modelBlock);
203 auto initialOp = builder.create<InitialOp>(moduleOp.getLoc());
204 initialBuilder.setInsertionPointToStart(&initialOp.getBody().emplaceBlock());
207 auto finalOp = builder.create<FinalOp>(moduleOp.getLoc());
208 finalBuilder.setInsertionPointToStart(&finalOp.getBody().emplaceBlock());
212 allocBuilder.setInsertionPoint(initialOp);
215 for (
auto arg : moduleOp.getBodyBlock()->getArguments()) {
216 auto name = moduleOp.getArgName(arg.getArgNumber());
217 auto state = allocBuilder.create<RootInputOp>(
219 allocatedInputs.push_back(state);
223 for (
auto &op : moduleOp.getOps()) {
224 if (mlir::isMemoryEffectFree(&op) && !isa<hw::OutputOp>(op))
226 if (isa<MemoryReadPortOp, MemoryWritePortOp>(op))
228 if (failed(lowerOp(&op)))
234 for (
auto &op : llvm::make_early_inc_range(llvm::reverse(modelBlock)))
235 if (mlir::isOpTriviallyDead(&op))
242 LogicalResult ModuleLowering::lowerOp(Operation *op) {
243 LLVM_DEBUG(llvm::dbgs() <<
"- Handling " << *op <<
"\n");
246 SmallVector<Phase, 2> phases = {Phase::New};
247 if (isa<seq::InitialOp>(op))
248 phases = {Phase::Initial};
249 if (isa<llhd::FinalOp>(op))
250 phases = {Phase::Final};
251 if (isa<StateOp>(op))
252 phases = {Phase::Initial, Phase::New};
254 for (
auto phase : phases) {
255 if (loweredOps.contains({op, phase}))
257 opsWorklist.push_back(OpLowering(op, phase, *
this));
258 opsSeen.insert({op, phase});
261 auto dumpWorklist = [&] {
262 for (
auto &opLowering : llvm::reverse(opsWorklist))
263 opLowering.op->emitRemark()
264 <<
"computing " << opLowering.phase <<
" phase here";
267 while (!opsWorklist.empty()) {
268 auto &opLowering = opsWorklist.back();
271 if (opLowering.initial) {
272 if (failed(opLowering.lower())) {
276 std::reverse(opLowering.pending.begin(), opLowering.pending.end());
277 opLowering.initial =
false;
281 if (!opLowering.pending.empty()) {
282 auto [defOp, phase] = opLowering.pending.pop_back_val();
283 if (loweredOps.contains({defOp, phase}))
285 if (!opsSeen.insert({defOp, phase}).second) {
286 defOp->emitOpError(
"is on a combinational loop");
290 opsWorklist.push_back(OpLowering(defOp, phase, *
this));
296 LLVM_DEBUG(llvm::dbgs() <<
" - Lowering " << opLowering.phase <<
" "
297 << *opLowering.op <<
"\n");
298 if (failed(opLowering.lower())) {
302 loweredOps.insert({opLowering.op, opLowering.phase});
303 opsSeen.erase({opLowering.op, opLowering.phase});
304 opsWorklist.pop_back();
312 Value ModuleLowering::getAllocatedState(OpResult result) {
313 if (
auto alloc = allocatedStates.lookup(result))
317 if (
auto memOp = dyn_cast<MemoryOp>(result.getOwner())) {
318 auto alloc = allocBuilder.create<AllocMemoryOp>(
319 memOp.getLoc(), memOp.getType(), storageArg, memOp->getAttrs());
320 allocatedStates.insert({result, alloc});
325 auto alloc = allocBuilder.create<AllocStateOp>(
327 allocatedStates.insert({result, alloc});
332 if (
auto instOp = dyn_cast<InstanceOp>(result.getOwner()))
334 "name", builder.getStringAttr(
335 instOp.getInstanceName() +
"/" +
336 instOp.getOutputName(result.getResultNumber()).getValue()));
341 if (isa<StateOp, sim::DPICallOp>(result.getOwner()))
342 if (
auto names = result.getOwner()->getAttrOfType<ArrayAttr>(
"names"))
343 if (result.getResultNumber() < names.size())
344 alloc->setAttr(
"name", names[result.getResultNumber()]);
351 Value ModuleLowering::detectPosedge(Value clock) {
352 auto loc = clock.getLoc();
353 if (isa<seq::ClockType>(clock.getType()))
354 clock = builder.create<seq::FromClockOp>(loc, clock);
357 auto oldStorage = allocBuilder.create<AllocStateOp>(
362 auto oldClock = builder.create<StateReadOp>(loc, oldStorage);
363 builder.create<StateWriteOp>(loc, oldStorage, clock, Value{});
366 auto edge = builder.create<
comb::XorOp>(loc, oldClock, clock);
367 return builder.create<
comb::AndOp>(loc, edge, clock);
371 OpBuilder &ModuleLowering::getBuilder(Phase phase) {
374 return initialBuilder;
384 Value ModuleLowering::requireLoweredValue(Value value, Phase phase,
386 if (
auto lowered = loweredValues.lookup({value, phase}))
388 auto d = emitError(value.getLoc()) <<
"value has not been lowered";
389 d.attachNote(useLoc) <<
"value used here";
401 if (
auto ip = builder.getInsertionPoint(); ip != builder.getBlock()->begin())
402 if (
auto ifOp = dyn_cast<scf::IfOp>(*std::prev(ip)))
403 if (ifOp.getCondition() == condition)
405 return builder.create<scf::IfOp>(condition.getLoc(), condition, withElse);
412 LogicalResult OpLowering::lower() {
413 return TypeSwitch<Operation *, LogicalResult>(op)
415 .Case<StateOp, sim::DPICallOp, MemoryOp, TapOp, InstanceOp, hw::OutputOp,
416 seq::InitialOp, llhd::FinalOp>([&](
auto op) {
return lower(op); })
420 .Case<MemoryWritePortOp, MemoryReadPortOp>([&](
auto op) {
421 assert(
false &&
"ports must be lowered by memory op");
426 .Default([&](
auto) {
return lowerDefault(); });
431 LogicalResult OpLowering::lowerDefault() {
434 auto anyFailed =
false;
435 op->walk([&](Operation *nestedOp) {
436 for (
auto operand : nestedOp->getOperands()) {
437 if (op->isAncestor(operand.getParentBlock()->getParentOp()))
439 auto lowered = lowerValue(operand, phase);
442 mapping.map(operand, lowered);
451 auto *clonedOp = module.getBuilder(phase).clone(*op, mapping);
454 for (
auto [oldResult, newResult] :
455 llvm::zip(op->getResults(), clonedOp->getResults()))
456 module.loweredValues[{oldResult, phase}] = newResult;
465 LogicalResult OpLowering::lower(StateOp op) {
467 if (phase == Phase::Initial) {
470 for (
auto initial : op.getInitials())
471 lowerValue(initial, Phase::Initial);
476 if (op.getInitials().empty())
478 for (
auto [initial, result] :
479 llvm::zip(op.getInitials(), op.getResults())) {
480 auto value = lowerValue(initial, Phase::Initial);
483 auto state = module.getAllocatedState(result);
486 module.initialBuilder.create<StateWriteOp>(value.getLoc(), state, value,
492 assert(phase == Phase::New);
496 return op.emitOpError() <<
"must have a clock";
497 if (op.getLatency() > 1)
498 return op.emitOpError(
"latencies > 1 not supported yet");
501 return lowerStateful(op.getClock(), op.getEnable(), op.getReset(),
502 op.getInputs(), op.getResults(), [&](ValueRange inputs) {
503 return module.builder
504 .create<CallOp>(op.getLoc(), op.getResultTypes(),
514 LogicalResult OpLowering::lower(sim::DPICallOp op) {
516 if (!op.getClock()) {
518 SmallVector<Value> inputs;
519 for (
auto operand : op.getInputs())
520 inputs.push_back(lowerValue(operand, phase));
523 if (llvm::is_contained(inputs, Value{}))
526 return op.emitOpError() <<
"without clock cannot have an enable";
529 auto callOp = module.getBuilder(phase).create<func::CallOp>(
530 op.getLoc(), op.getCalleeAttr(), op.getResultTypes(), inputs);
531 for (
auto [oldResult, newResult] :
532 llvm::zip(op.getResults(), callOp.getResults()))
533 module.loweredValues[{oldResult, phase}] = newResult;
537 assert(phase == Phase::New);
539 return lowerStateful(op.getClock(), op.getEnable(), {},
540 op.getInputs(), op.getResults(), [&](ValueRange inputs) {
541 return module.builder
542 .create<func::CallOp>(op.getLoc(),
544 op.getResultTypes(), inputs)
553 LogicalResult OpLowering::lowerStateful(
554 Value clock, Value enable, Value reset, ValueRange inputs,
556 llvm::function_ref<ValueRange(ValueRange)> createMapping) {
562 lowerValue(clock, Phase::New);
564 lowerValue(enable, Phase::Old);
566 lowerValue(reset, Phase::Old);
567 for (
auto input : inputs)
568 lowerValue(input, Phase::Old);
574 auto ifClockOp = createIfClockOp(clock);
577 OpBuilder::InsertionGuard guard(module.builder);
578 module.builder.setInsertionPoint(ifClockOp.thenYield());
582 SmallVector<Value> states;
583 for (
auto result : results) {
584 auto state = module.getAllocatedState(result);
587 states.push_back(state);
593 auto &[unloweredReset, loweredReset] = module.prevReset;
594 if (unloweredReset != reset ||
595 loweredReset.getParentBlock() != module.builder.getBlock()) {
596 unloweredReset = reset;
597 loweredReset = lowerValue(reset, Phase::Old);
605 module.builder.setInsertionPoint(ifResetOp.thenYield());
608 for (
auto state : states) {
609 auto type = cast<StateType>(state.getType()).getType();
610 Value value = module.builder.create<
ConstantOp>(
611 loweredReset.getLoc(),
613 if (value.getType() != type)
616 module.builder.
create<StateWriteOp>(loweredReset.getLoc(), state, value,
619 module.builder.setInsertionPoint(ifResetOp.elseYield());
625 auto &[unloweredEnable, loweredEnable] = module.prevEnable;
626 if (unloweredEnable != enable ||
627 loweredEnable.getParentBlock() != module.builder.getBlock()) {
628 unloweredEnable = enable;
629 loweredEnable = lowerValue(enable, Phase::Old);
636 auto ifEnableOp =
createOrReuseIf(module.builder, loweredEnable,
false);
637 module.builder.setInsertionPoint(ifEnableOp.thenYield());
641 SmallVector<Value> loweredInputs;
642 for (
auto input : inputs) {
643 auto lowered = lowerValue(input, Phase::Old);
646 loweredInputs.push_back(lowered);
650 auto loweredResults = createMapping(loweredInputs);
651 for (
auto [state, value] : llvm::zip(states, loweredResults))
652 module.builder.create<StateWriteOp>(value.getLoc(), state, value, Value{});
657 module.builder.setInsertionPoint(ifClockOp);
658 for (
auto [state, result] : llvm::zip(states, results)) {
659 auto oldValue = module.builder.create<StateReadOp>(result.getLoc(), state);
660 module.loweredValues[{result, Phase::Old}] = oldValue;
669 LogicalResult OpLowering::lower(MemoryOp op) {
670 assert(phase == Phase::New);
673 SmallVector<MemoryReadPortOp> reads;
674 SmallVector<MemoryWritePortOp> writes;
676 for (
auto *user : op->getUsers()) {
677 if (
auto read = dyn_cast<MemoryReadPortOp>(user)) {
678 reads.push_back(read);
679 }
else if (
auto write = dyn_cast<MemoryWritePortOp>(user)) {
680 writes.push_back(write);
682 auto d = op.emitOpError()
683 <<
"users must all be memory read or write port ops";
684 d.attachNote(user->getLoc())
685 <<
"but found " << user->getName() <<
" user here";
692 for (
auto read : reads)
693 lowerValue(read, Phase::Old);
694 for (
auto write : writes) {
695 if (write.getClock())
696 lowerValue(write.getClock(), Phase::New);
697 for (
auto input : write.getInputs())
698 lowerValue(input, Phase::Old);
704 auto state = module.getAllocatedState(op->getResult(0));
708 for (
auto read : reads) {
709 auto oldValue = lowerValue(read, Phase::Old);
712 module.loweredValues[{read, Phase::Old}] = oldValue;
716 for (
auto write : writes) {
717 if (!write.getClock())
718 return write.emitOpError() <<
"must have a clock";
719 if (write.getLatency() > 1)
720 return write.emitOpError(
"latencies > 1 not supported yet");
723 auto ifClockOp = createIfClockOp(write.getClock());
726 OpBuilder::InsertionGuard guard(module.builder);
727 module.builder.setInsertionPoint(ifClockOp.thenYield());
730 SmallVector<Value> inputs;
731 for (
auto input : write.getInputs()) {
732 auto lowered = lowerValue(input, Phase::Old);
735 inputs.push_back(lowered);
737 auto callOp = module.builder.create<CallOp>(
738 write.getLoc(), write.getArcResultTypes(), write.getArc(), inputs);
741 if (write.getEnable()) {
743 module.builder, callOp.getResult(write.getEnableIdx()),
false);
744 module.builder.setInsertionPoint(ifEnableOp.thenYield());
749 auto address = callOp.getResult(write.getAddressIdx());
750 auto data = callOp.getResult(write.getDataIdx());
751 if (write.getMask()) {
752 auto mask = callOp.getResult(write.getMaskIdx(write.getEnable()));
753 auto maskInv = module.builder.createOrFold<
comb::XorOp>(
754 write.getLoc(),
mask,
755 module.builder.create<
ConstantOp>(write.getLoc(),
mask.getType(), -1),
758 module.builder.create<MemoryReadOp>(write.getLoc(), state, address);
759 auto oldMasked = module.builder.create<
comb::AndOp>(
760 write.getLoc(), maskInv, oldData,
true);
763 data = module.builder.create<
comb::OrOp>(write.getLoc(), oldMasked,
768 module.builder.create<MemoryWriteOp>(write.getLoc(), state, address,
777 LogicalResult OpLowering::lower(TapOp op) {
778 assert(phase == Phase::New);
780 auto value = lowerValue(op.getValue(), phase);
786 auto &state = module.allocatedTaps[op];
788 auto alloc = module.allocBuilder.create<AllocStateOp>(
789 op.getLoc(),
StateType::get(value.getType()), module.storageArg,
true);
790 alloc->setAttr(
"name", op.getNameAttr());
793 module.builder.create<StateWriteOp>(op.getLoc(), state, value, Value{});
800 LogicalResult OpLowering::lower(InstanceOp op) {
801 assert(phase == Phase::New);
804 SmallVector<Value> values;
805 for (
auto operand : op.getOperands())
806 values.push_back(lowerValue(operand, Phase::New));
809 if (llvm::is_contained(values, Value{}))
814 for (
auto [value, name] : llvm::zip(values, op.getArgNames())) {
815 auto state = module.allocBuilder.create<AllocStateOp>(
816 value.getLoc(),
StateType::get(value.getType()), module.storageArg);
817 state->setAttr(
"name", module.builder.getStringAttr(
818 op.getInstanceName() +
"/" +
819 cast<StringAttr>(name).getValue()));
820 module.builder.create<StateWriteOp>(value.getLoc(), state, value, Value{});
827 for (
auto result : op.getResults())
828 module.getAllocatedState(result);
835 LogicalResult OpLowering::lower(hw::OutputOp op) {
836 assert(phase == Phase::New);
839 SmallVector<Value> values;
840 for (
auto operand : op.getOperands())
841 values.push_back(lowerValue(operand, Phase::New));
844 if (llvm::is_contained(values, Value{}))
848 for (
auto [value, name] :
849 llvm::zip(values, module.moduleOp.getOutputNames())) {
850 auto state = module.allocBuilder.create<RootOutputOp>(
851 value.getLoc(),
StateType::get(value.getType()), cast<StringAttr>(name),
853 module.builder.create<StateWriteOp>(value.getLoc(), state, value, Value{});
859 LogicalResult OpLowering::lower(seq::InitialOp op) {
860 assert(phase == Phase::Initial);
863 SmallVector<Value> operands;
864 for (
auto operand : op.getOperands())
865 operands.push_back(lowerValue(operand, Phase::Initial));
868 if (llvm::is_contained(operands, Value{}))
872 for (
auto [arg, operand] : llvm::zip(op.getBody().getArguments(), operands))
873 module.loweredValues[{arg, Phase::Initial}] = operand;
876 for (
auto &bodyOp : op.getOps()) {
877 if (isa<seq::YieldOp>(bodyOp))
881 auto *clonedOp = module.initialBuilder.clone(bodyOp);
882 auto result = clonedOp->walk([&](Operation *nestedClonedOp) {
883 for (
auto &operand : nestedClonedOp->getOpOperands()) {
884 if (clonedOp->isAncestor(operand.get().getParentBlock()->getParentOp()))
886 auto value = module.requireLoweredValue(operand.get(), Phase::Initial,
887 nestedClonedOp->getLoc());
889 return WalkResult::interrupt();
892 return WalkResult::advance();
894 if (result.wasInterrupted())
898 for (
auto [result, lowered] :
899 llvm::zip(bodyOp.getResults(), clonedOp->getResults()))
900 module.loweredValues[{result, Phase::Initial}] = lowered;
904 auto *terminator = op.getBodyBlock()->getTerminator();
905 for (
auto [result, operand] :
906 llvm::zip(op.getResults(), terminator->getOperands())) {
907 auto value = module.requireLoweredValue(operand, Phase::Initial,
908 terminator->getLoc());
911 module.loweredValues[{result, Phase::Initial}] = value;
918 LogicalResult OpLowering::lower(llhd::FinalOp op) {
919 assert(phase == Phase::Final);
922 SmallVector<Value> externalOperands;
923 op.walk([&](Operation *nestedOp) {
924 for (
auto value : nestedOp->getOperands())
925 if (!op->isAncestor(value.getParentBlock()->getParentOp()))
926 externalOperands.push_back(value);
931 for (
auto operand : externalOperands) {
932 auto lowered = lowerValue(operand, Phase::Final);
933 if (!initial && !lowered)
935 mapping.map(operand, lowered);
942 if (op.getBody().hasOneBlock()) {
943 for (
auto &bodyOp : op.getBody().front().without_terminator())
944 module.finalBuilder.clone(bodyOp, mapping);
950 auto executeOp = module.finalBuilder.create<scf::ExecuteRegionOp>(
951 op.getLoc(), TypeRange{});
952 module.finalBuilder.cloneRegionBefore(op.getBody(), executeOp.getRegion(),
953 executeOp.getRegion().begin(), mapping);
954 executeOp.walk([&](llhd::HaltOp op) {
955 OpBuilder(op).create<scf::YieldOp>(op.getLoc());
966 scf::IfOp OpLowering::createIfClockOp(Value clock) {
967 auto &posedge = module.loweredPosedges[clock];
969 auto loweredClock = lowerValue(clock, Phase::New);
972 posedge = module.detectPosedge(loweredClock);
985 Value OpLowering::lowerValue(Value value, Phase phase) {
987 if (
auto arg = dyn_cast<BlockArgument>(value)) {
990 auto state = module.allocatedInputs[arg.getArgNumber()];
991 return module.getBuilder(phase).create<StateReadOp>(arg.getLoc(), state);
995 if (
auto lowered = module.loweredValues.lookup({value, phase}))
1000 auto result = cast<OpResult>(value);
1001 auto *op = result.getOwner();
1004 if (
auto instOp = dyn_cast<InstanceOp>(op))
1005 return lowerValue(instOp, result, phase);
1006 if (
auto stateOp = dyn_cast<StateOp>(op))
1007 return lowerValue(stateOp, result, phase);
1008 if (
auto dpiOp = dyn_cast<sim::DPICallOp>(op); dpiOp && dpiOp.getClock())
1009 return lowerValue(dpiOp, result, phase);
1010 if (
auto readOp = dyn_cast<MemoryReadPortOp>(op))
1011 return lowerValue(readOp, result, phase);
1012 if (
auto initialOp = dyn_cast<seq::InitialOp>(op))
1013 return lowerValue(initialOp, result, phase);
1014 if (
auto castOp = dyn_cast<seq::FromImmutableOp>(op))
1015 return lowerValue(castOp, result, phase);
1021 addPending(op, phase);
1024 emitError(result.getLoc()) <<
"value has not been lowered";
1030 Value OpLowering::lowerValue(InstanceOp op, OpResult result, Phase phase) {
1033 auto state = module.getAllocatedState(result);
1034 return module.getBuilder(phase).create<StateReadOp>(result.getLoc(), state);
1041 Value OpLowering::lowerValue(StateOp op, OpResult result, Phase phase) {
1045 if (phase == Phase::New || phase == Phase::Initial)
1046 addPending(op, phase);
1051 if (phase == Phase::Old)
1052 assert(!module.loweredOps.contains({op, Phase::New}) &&
1053 "need old value but new value already written");
1055 auto state = module.getAllocatedState(result);
1056 return module.getBuilder(phase).create<StateReadOp>(result.getLoc(), state);
1063 Value OpLowering::lowerValue(sim::DPICallOp op, OpResult result, Phase phase) {
1067 if (phase == Phase::New || phase == Phase::Initial)
1068 addPending(op, phase);
1073 if (phase == Phase::Old)
1074 assert(!module.loweredOps.contains({op, Phase::New}) &&
1075 "need old value but new value already written");
1077 auto state = module.getAllocatedState(result);
1078 return module.getBuilder(phase).create<StateReadOp>(result.getLoc(), state);
1084 Value OpLowering::lowerValue(MemoryReadPortOp op, OpResult result,
1086 auto memOp = op.getMemory().getDefiningOp<MemoryOp>();
1089 op->emitOpError() <<
"memory must be defined locally";
1093 auto address = lowerValue(op.getAddress(), phase);
1096 if (phase == Phase::New)
1097 addPending(memOp.getOperation(), Phase::New);
1103 if (phase == Phase::Old) {
1105 assert(!module.loweredOps.contains({memOp, Phase::New}) &&
1106 "need old memory value but new value already written");
1108 assert(phase == Phase::New);
1111 auto state = module.getAllocatedState(memOp->getResult(0));
1112 return module.getBuilder(phase).create<MemoryReadOp>(result.getLoc(), state,
1119 Value OpLowering::lowerValue(seq::InitialOp op, OpResult result, Phase phase) {
1122 addPending(op, Phase::Initial);
1125 auto value = module.loweredValues.lookup({result, Phase::Initial});
1127 emitError(result.getLoc()) <<
"value has not been lowered";
1133 if (phase == Phase::Initial)
1138 auto &state = module.allocatedInitials[result];
1140 state = module.allocBuilder.create<AllocStateOp>(
1141 value.getLoc(),
StateType::get(value.getType()), module.storageArg);
1142 OpBuilder::InsertionGuard guard(module.initialBuilder);
1143 module.initialBuilder.setInsertionPointAfterValue(value);
1144 module.initialBuilder.create<StateWriteOp>(value.getLoc(), state, value,
1149 return module.getBuilder(phase).create<StateReadOp>(state.getLoc(), state);
1153 Value OpLowering::lowerValue(seq::FromImmutableOp op, OpResult result,
1155 return lowerValue(op.getInput(), phase);
1159 void OpLowering::addPending(Value value, Phase phase) {
1160 auto *defOp = value.getDefiningOp();
1161 assert(defOp &&
"block args should never be marked as a dependency");
1162 addPending(defOp, phase);
1167 void OpLowering::addPending(Operation *op, Phase phase) {
1168 auto pair = std::make_pair(op, phase);
1169 if (!module.loweredOps.contains(pair))
1170 if (!llvm::is_contained(pending, pair))
1171 pending.push_back(pair);
1179 struct LowerStatePass :
public arc::impl::LowerStatePassBase<LowerStatePass> {
1180 using LowerStatePassBase::LowerStatePassBase;
1181 void runOnOperation()
override;
1185 void LowerStatePass::runOnOperation() {
1186 auto op = getOperation();
1187 for (
auto moduleOp : llvm::make_early_inc_range(op.getOps<
HWModuleOp>())) {
1188 if (failed(ModuleLowering(moduleOp).
run()))
1189 return signalPassFailure();
1192 for (
auto extModuleOp :
1194 extModuleOp.erase();
assert(baseType &&"element must be base type")
static scf::IfOp createOrReuseIf(OpBuilder &builder, Value condition, bool withElse)
Create a new scf.if operation with the given builder, or reuse a previous scf.if if the builder's ins...
def create(data_type, value)
def create(data_type, value)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
raw_ostream & operator<<(raw_ostream &os, const FVInt &value)
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)