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"
44using llvm::SmallDenseSet;
47enum class Phase { Initial, Old, New, Final };
53 return os <<
"initial";
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);
125struct 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);
187LogicalResult ModuleLowering::run() {
188 LLVM_DEBUG(llvm::dbgs() <<
"Lowering module `" << moduleOp.getModuleName()
193 ModelOp::create(builder, moduleOp.getLoc(), moduleOp.getModuleNameAttr(),
194 TypeAttr::get(moduleOp.getModuleType()),
195 FlatSymbolRefAttr{}, FlatSymbolRefAttr{});
196 auto &modelBlock = modelOp.getBody().emplaceBlock();
197 storageArg = modelBlock.addArgument(
198 StorageType::get(builder.getContext(), {}), modelOp.getLoc());
199 builder.setInsertionPointToStart(&modelBlock);
203 auto initialOp = InitialOp::create(builder, moduleOp.getLoc());
204 initialBuilder.setInsertionPointToStart(&initialOp.getBody().emplaceBlock());
207 auto finalOp = FinalOp::create(builder, 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());
218 RootInputOp::create(allocBuilder, arg.getLoc(),
219 StateType::get(arg.getType()), name, storageArg);
220 allocatedInputs.push_back(state);
224 for (
auto &op : moduleOp.getOps()) {
225 if (mlir::isMemoryEffectFree(&op) && !isa<hw::OutputOp>(op))
227 if (isa<MemoryReadPortOp, MemoryWritePortOp>(op))
229 if (failed(lowerOp(&op)))
235 for (
auto &op :
llvm::make_early_inc_range(
llvm::reverse(modelBlock)))
236 if (
mlir::isOpTriviallyDead(&op))
243LogicalResult ModuleLowering::lowerOp(Operation *op) {
244 LLVM_DEBUG(llvm::dbgs() <<
"- Handling " << *op <<
"\n");
247 SmallVector<Phase, 2> phases = {Phase::New};
248 if (isa<seq::InitialOp>(op))
249 phases = {Phase::Initial};
250 if (isa<llhd::FinalOp>(op))
251 phases = {Phase::Final};
252 if (isa<StateOp>(op))
253 phases = {Phase::Initial, Phase::New};
255 for (
auto phase : phases) {
256 if (loweredOps.contains({op, phase}))
258 opsWorklist.push_back(OpLowering(op, phase, *
this));
259 opsSeen.insert({op, phase});
262 auto dumpWorklist = [&] {
263 for (
auto &opLowering :
llvm::reverse(opsWorklist))
264 opLowering.op->emitRemark()
265 <<
"computing " << opLowering.phase <<
" phase here";
268 while (!opsWorklist.empty()) {
269 auto &opLowering = opsWorklist.back();
272 if (opLowering.initial) {
273 if (failed(opLowering.lower())) {
277 std::reverse(opLowering.pending.begin(), opLowering.pending.end());
278 opLowering.initial =
false;
282 if (!opLowering.pending.empty()) {
283 auto [defOp, phase] = opLowering.pending.pop_back_val();
284 if (loweredOps.contains({defOp, phase}))
286 if (!opsSeen.insert({defOp, phase}).second) {
287 defOp->emitOpError(
"is on a combinational loop");
291 opsWorklist.push_back(OpLowering(defOp, phase, *
this));
297 LLVM_DEBUG(llvm::dbgs() <<
" - Lowering " << opLowering.phase <<
" "
298 << *opLowering.op <<
"\n");
299 if (failed(opLowering.lower())) {
303 loweredOps.insert({opLowering.op, opLowering.phase});
304 opsSeen.erase({opLowering.op, opLowering.phase});
305 opsWorklist.pop_back();
313Value ModuleLowering::getAllocatedState(OpResult result) {
314 if (
auto alloc = allocatedStates.lookup(result))
318 if (
auto memOp = dyn_cast<MemoryOp>(result.getOwner())) {
320 AllocMemoryOp::create(allocBuilder, memOp.getLoc(), memOp.getType(),
321 storageArg, memOp->getAttrs());
322 allocatedStates.insert({result, alloc});
328 AllocStateOp::create(allocBuilder, result.getLoc(),
329 StateType::get(result.getType()), storageArg);
330 allocatedStates.insert({result, alloc});
335 if (
auto instOp = dyn_cast<InstanceOp>(result.getOwner()))
337 "name", builder.getStringAttr(
338 instOp.getInstanceName() +
"/" +
339 instOp.getOutputName(result.getResultNumber()).getValue()));
344 if (isa<StateOp, sim::DPICallOp>(result.getOwner()))
345 if (
auto names = result.getOwner()->getAttrOfType<ArrayAttr>(
"names"))
346 if (result.getResultNumber() < names.size())
347 alloc->setAttr(
"name", names[result.getResultNumber()]);
354Value ModuleLowering::detectPosedge(Value clock) {
355 auto loc = clock.getLoc();
356 if (isa<seq::ClockType>(clock.getType()))
357 clock = seq::FromClockOp::create(builder, loc, clock);
360 auto oldStorage = AllocStateOp::create(
361 allocBuilder, loc, StateType::get(builder.getI1Type()), storageArg);
365 auto oldClock = StateReadOp::create(builder, loc, oldStorage);
366 StateWriteOp::create(builder, loc, oldStorage, clock, Value{});
369 auto edge = comb::XorOp::create(builder, loc, oldClock, clock);
370 return comb::AndOp::create(builder, loc, edge, clock);
374OpBuilder &ModuleLowering::getBuilder(Phase phase) {
377 return initialBuilder;
387Value ModuleLowering::requireLoweredValue(Value value, Phase phase,
389 if (
auto lowered = loweredValues.lookup({value, phase}))
391 auto d = emitError(value.getLoc()) <<
"value has not been lowered";
392 d.attachNote(useLoc) <<
"value used here";
404 if (
auto ip = builder.getInsertionPoint(); ip != builder.getBlock()->begin())
405 if (
auto ifOp = dyn_cast<scf::IfOp>(*std::prev(ip)))
406 if (ifOp.getCondition() == condition)
408 return scf::IfOp::create(builder, condition.getLoc(), condition, withElse);
415LogicalResult OpLowering::lower() {
416 return TypeSwitch<Operation *, LogicalResult>(op)
418 .Case<StateOp, sim::DPICallOp, MemoryOp, TapOp, InstanceOp, hw::OutputOp,
419 seq::InitialOp, llhd::FinalOp>([&](
auto op) {
return lower(op); })
423 .Case<MemoryWritePortOp, MemoryReadPortOp>([&](
auto op) {
424 assert(
false &&
"ports must be lowered by memory op");
429 .Default([&](
auto) {
return lowerDefault(); });
434LogicalResult OpLowering::lowerDefault() {
437 auto anyFailed =
false;
438 op->walk([&](Operation *nestedOp) {
439 for (
auto operand : nestedOp->getOperands()) {
440 if (op->isAncestor(operand.getParentBlock()->getParentOp()))
442 auto lowered = lowerValue(operand, phase);
445 mapping.map(operand, lowered);
454 auto *clonedOp =
module.getBuilder(phase).clone(*op, mapping);
457 for (
auto [oldResult, newResult] :
458 llvm::zip(op->getResults(), clonedOp->getResults()))
459 module.loweredValues[{oldResult, phase}] = newResult;
468LogicalResult OpLowering::lower(StateOp op) {
470 if (phase == Phase::Initial) {
473 for (
auto initial : op.getInitials())
474 lowerValue(initial, Phase::Initial);
479 if (op.getInitials().empty())
481 for (
auto [initial, result] :
482 llvm::zip(op.getInitials(), op.getResults())) {
483 auto value = lowerValue(initial, Phase::Initial);
486 auto state =
module.getAllocatedState(result);
489 StateWriteOp::create(module.initialBuilder, value.getLoc(), state, value,
495 assert(phase == Phase::New);
499 return op.emitOpError() <<
"must have a clock";
500 if (op.getLatency() > 1)
501 return op.emitOpError(
"latencies > 1 not supported yet");
504 return lowerStateful(op.getClock(), op.getEnable(), op.getReset(),
505 op.getInputs(), op.getResults(), [&](ValueRange inputs) {
506 return CallOp::create(module.builder, op.getLoc(),
507 op.getResultTypes(), op.getArc(),
517LogicalResult OpLowering::lower(sim::DPICallOp op) {
519 if (!op.getClock()) {
521 SmallVector<Value> inputs;
522 for (
auto operand : op.getInputs())
523 inputs.push_back(lowerValue(operand, phase));
526 if (llvm::is_contained(inputs, Value{}))
529 return op.emitOpError() <<
"without clock cannot have an enable";
533 func::CallOp::create(module.getBuilder(phase), op.getLoc(),
534 op.getCalleeAttr(), op.getResultTypes(), inputs);
535 for (
auto [oldResult, newResult] :
536 llvm::zip(op.getResults(), callOp.getResults()))
537 module.loweredValues[{oldResult, phase}] = newResult;
541 assert(phase == Phase::New);
543 return lowerStateful(op.getClock(), op.getEnable(), {},
544 op.getInputs(), op.getResults(), [&](ValueRange inputs) {
545 return func::CallOp::create(
546 module.builder, op.getLoc(),
547 op.getCalleeAttr(), op.getResultTypes(),
557LogicalResult OpLowering::lowerStateful(
558 Value clock, Value enable, Value reset, ValueRange inputs,
560 llvm::function_ref<ValueRange(ValueRange)> createMapping) {
566 lowerValue(clock, Phase::New);
568 lowerValue(enable, Phase::Old);
570 lowerValue(reset, Phase::Old);
571 for (
auto input : inputs)
572 lowerValue(input, Phase::Old);
578 auto ifClockOp = createIfClockOp(clock);
581 OpBuilder::InsertionGuard guard(module.builder);
582 module.builder.setInsertionPoint(ifClockOp.thenYield());
586 SmallVector<Value> states;
587 for (
auto result : results) {
588 auto state =
module.getAllocatedState(result);
591 states.push_back(state);
597 auto &[unloweredReset, loweredReset] =
module.prevReset;
598 if (unloweredReset != reset ||
599 loweredReset.getParentBlock() != module.builder.getBlock()) {
600 unloweredReset = reset;
601 loweredReset = lowerValue(reset, Phase::Old);
609 module.builder.setInsertionPoint(ifResetOp.thenYield());
612 for (
auto state : states) {
613 auto type = cast<StateType>(state.getType()).getType();
615 module.builder, loweredReset.getLoc(),
616 module.builder.getIntegerType(hw::getBitWidth(type)), 0);
617 if (value.getType() != type)
620 StateWriteOp::create(module.builder, loweredReset.getLoc(), state, value,
623 module.builder.setInsertionPoint(ifResetOp.elseYield());
629 auto &[unloweredEnable, loweredEnable] =
module.prevEnable;
630 if (unloweredEnable != enable ||
631 loweredEnable.getParentBlock() != module.builder.getBlock()) {
632 unloweredEnable = enable;
633 loweredEnable = lowerValue(enable, Phase::Old);
640 auto ifEnableOp =
createOrReuseIf(module.builder, loweredEnable,
false);
641 module.builder.setInsertionPoint(ifEnableOp.thenYield());
645 SmallVector<Value> loweredInputs;
646 for (
auto input : inputs) {
647 auto lowered = lowerValue(input, Phase::Old);
650 loweredInputs.push_back(lowered);
654 auto loweredResults = createMapping(loweredInputs);
655 for (
auto [state, value] :
llvm::zip(states, loweredResults))
656 StateWriteOp::create(module.builder, value.
getLoc(), state, value, Value{});
661 module.builder.setInsertionPoint(ifClockOp);
662 for (
auto [state, result] :
llvm::zip(states, results)) {
663 auto oldValue = StateReadOp::create(module.builder, result.getLoc(), state);
664 module.loweredValues[{result, Phase::Old}] = oldValue;
673LogicalResult OpLowering::lower(MemoryOp op) {
674 assert(phase == Phase::New);
677 SmallVector<MemoryReadPortOp> reads;
678 SmallVector<MemoryWritePortOp> writes;
680 for (
auto *user : op->getUsers()) {
681 if (
auto read = dyn_cast<MemoryReadPortOp>(user)) {
682 reads.push_back(read);
683 }
else if (
auto write = dyn_cast<MemoryWritePortOp>(user)) {
684 writes.push_back(write);
686 auto d = op.emitOpError()
687 <<
"users must all be memory read or write port ops";
688 d.attachNote(user->getLoc())
689 <<
"but found " << user->getName() <<
" user here";
696 for (
auto read : reads)
697 lowerValue(read, Phase::Old);
698 for (
auto write : writes) {
699 if (write.getClock())
700 lowerValue(write.getClock(), Phase::New);
701 for (
auto input : write.getInputs())
702 lowerValue(input, Phase::Old);
708 auto state =
module.getAllocatedState(op->getResult(0));
712 for (
auto read : reads) {
713 auto oldValue = lowerValue(read, Phase::Old);
716 module.loweredValues[{read, Phase::Old}] = oldValue;
720 for (
auto write : writes) {
721 if (!write.getClock())
722 return write.emitOpError() <<
"must have a clock";
723 if (write.getLatency() > 1)
724 return write.emitOpError(
"latencies > 1 not supported yet");
727 auto ifClockOp = createIfClockOp(write.getClock());
730 OpBuilder::InsertionGuard guard(module.builder);
731 module.builder.setInsertionPoint(ifClockOp.thenYield());
734 SmallVector<Value> inputs;
735 for (
auto input : write.getInputs()) {
736 auto lowered = lowerValue(input, Phase::Old);
739 inputs.push_back(lowered);
742 CallOp::create(module.builder, write.getLoc(),
743 write.getArcResultTypes(), write.getArc(), inputs);
746 if (write.getEnable()) {
748 module.builder, callOp.getResult(write.getEnableIdx()),
false);
749 module.builder.setInsertionPoint(ifEnableOp.thenYield());
754 auto address = callOp.getResult(write.getAddressIdx());
755 auto data = callOp.getResult(write.getDataIdx());
756 if (write.getMask()) {
757 auto mask = callOp.getResult(write.getMaskIdx(write.getEnable()));
758 auto maskInv =
module.builder.createOrFold<comb::XorOp>(
759 write.getLoc(), mask,
760 ConstantOp::create(module.builder, write.getLoc(), mask.getType(),
764 MemoryReadOp::create(module.builder, write.getLoc(), state, address);
765 auto oldMasked = comb::AndOp::create(module.builder, write.getLoc(),
766 maskInv, oldData,
true);
768 comb::AndOp::create(module.builder, write.getLoc(), mask, data,
true);
769 data = comb::OrOp::create(module.builder, write.getLoc(), oldMasked,
774 MemoryWriteOp::create(module.builder, write.getLoc(), state, address,
783LogicalResult OpLowering::lower(TapOp op) {
784 assert(phase == Phase::New);
786 auto value = lowerValue(op.getValue(), phase);
792 auto &state =
module.allocatedTaps[op];
794 auto alloc = AllocStateOp::create(module.allocBuilder, op.getLoc(),
795 StateType::get(value.getType()),
796 module.storageArg,
true);
797 alloc->setAttr(
"name", op.getNameAttr());
800 StateWriteOp::create(module.builder, op.getLoc(), state, value, Value{});
807LogicalResult OpLowering::lower(InstanceOp op) {
808 assert(phase == Phase::New);
811 SmallVector<Value> values;
812 for (
auto operand : op.getOperands())
813 values.push_back(lowerValue(operand, Phase::New));
816 if (llvm::is_contained(values, Value{}))
821 for (
auto [value, name] :
llvm::zip(values, op.getArgNames())) {
822 auto state = AllocStateOp::create(module.allocBuilder, value.getLoc(),
823 StateType::get(value.getType()),
825 state->setAttr(
"name", module.builder.getStringAttr(
826 op.getInstanceName() +
"/" +
827 cast<StringAttr>(name).getValue()));
828 StateWriteOp::create(module.builder, value.getLoc(), state, value, Value{});
835 for (
auto result : op.getResults())
836 module.getAllocatedState(result);
843LogicalResult OpLowering::lower(hw::OutputOp op) {
844 assert(phase == Phase::New);
847 SmallVector<Value> values;
848 for (
auto operand : op.getOperands())
849 values.push_back(lowerValue(operand, Phase::New));
852 if (llvm::is_contained(values, Value{}))
856 for (
auto [value, name] :
857 llvm::zip(values, module.moduleOp.getOutputNames())) {
858 auto state = RootOutputOp::create(
859 module.allocBuilder, value.getLoc(), StateType::get(value.getType()),
860 cast<StringAttr>(name), module.storageArg);
861 StateWriteOp::create(module.builder, value.getLoc(), state, value, Value{});
867LogicalResult OpLowering::lower(seq::InitialOp op) {
868 assert(phase == Phase::Initial);
871 SmallVector<Value> operands;
872 for (
auto operand : op.getOperands())
873 operands.push_back(lowerValue(operand, Phase::Initial));
876 if (llvm::is_contained(operands, Value{}))
880 for (
auto [arg, operand] :
llvm::zip(op.getBody().getArguments(), operands))
881 module.loweredValues[{arg, Phase::Initial}] = operand;
884 for (
auto &bodyOp : op.getOps()) {
885 if (isa<seq::YieldOp>(bodyOp))
889 auto *clonedOp =
module.initialBuilder.clone(bodyOp);
890 auto result = clonedOp->walk([&](Operation *nestedClonedOp) {
891 for (
auto &operand : nestedClonedOp->getOpOperands()) {
892 if (clonedOp->isAncestor(operand.get().getParentBlock()->getParentOp()))
894 auto value =
module.requireLoweredValue(operand.get(), Phase::Initial,
895 nestedClonedOp->getLoc());
897 return WalkResult::interrupt();
900 return WalkResult::advance();
902 if (result.wasInterrupted())
906 for (
auto [result, lowered] :
907 llvm::zip(bodyOp.getResults(), clonedOp->getResults()))
908 module.loweredValues[{result, Phase::Initial}] = lowered;
912 auto *terminator = op.getBodyBlock()->getTerminator();
913 for (
auto [result, operand] :
914 llvm::zip(op.getResults(), terminator->getOperands())) {
915 auto value =
module.requireLoweredValue(operand, Phase::Initial,
916 terminator->getLoc());
919 module.loweredValues[{result, Phase::Initial}] = value;
926LogicalResult OpLowering::lower(llhd::FinalOp op) {
927 assert(phase == Phase::Final);
930 SmallVector<Value> externalOperands;
931 op.walk([&](Operation *nestedOp) {
932 for (
auto value : nestedOp->getOperands())
933 if (!op->
isAncestor(value.getParentBlock()->getParentOp()))
934 externalOperands.push_back(value);
939 for (
auto operand : externalOperands) {
940 auto lowered = lowerValue(operand, Phase::Final);
941 if (!initial && !lowered)
943 mapping.map(operand, lowered);
950 if (op.getBody().hasOneBlock()) {
951 for (
auto &bodyOp : op.getBody().front().without_terminator())
952 module.finalBuilder.clone(bodyOp, mapping);
958 auto executeOp = scf::ExecuteRegionOp::create(module.finalBuilder,
959 op.getLoc(), TypeRange{});
960 module.finalBuilder.cloneRegionBefore(op.getBody(), executeOp.getRegion(),
961 executeOp.getRegion().begin(), mapping);
962 executeOp.walk([&](llhd::HaltOp op) {
963 auto builder = OpBuilder(op);
964 scf::YieldOp::create(builder, op.getLoc());
975scf::IfOp OpLowering::createIfClockOp(Value clock) {
976 auto &posedge =
module.loweredPosedges[clock];
978 auto loweredClock = lowerValue(clock, Phase::New);
981 posedge =
module.detectPosedge(loweredClock);
994Value OpLowering::lowerValue(Value value, Phase phase) {
996 if (
auto arg = dyn_cast<BlockArgument>(value)) {
999 auto state =
module.allocatedInputs[arg.getArgNumber()];
1000 return StateReadOp::create(module.getBuilder(phase), arg.getLoc(), state);
1004 if (
auto lowered = module.loweredValues.lookup({value, phase}))
1009 auto result = cast<OpResult>(value);
1010 auto *op = result.getOwner();
1013 if (
auto instOp = dyn_cast<InstanceOp>(op))
1014 return lowerValue(instOp, result, phase);
1015 if (
auto stateOp = dyn_cast<StateOp>(op))
1016 return lowerValue(stateOp, result, phase);
1017 if (
auto dpiOp = dyn_cast<sim::DPICallOp>(op); dpiOp && dpiOp.getClock())
1018 return lowerValue(dpiOp, result, phase);
1019 if (
auto readOp = dyn_cast<MemoryReadPortOp>(op))
1020 return lowerValue(readOp, result, phase);
1021 if (
auto initialOp = dyn_cast<seq::InitialOp>(op))
1022 return lowerValue(initialOp, result, phase);
1023 if (
auto castOp = dyn_cast<seq::FromImmutableOp>(op))
1024 return lowerValue(castOp, result, phase);
1030 addPending(op, phase);
1033 emitError(result.getLoc()) <<
"value has not been lowered";
1039Value OpLowering::lowerValue(InstanceOp op, OpResult result, Phase phase) {
1042 auto state =
module.getAllocatedState(result);
1043 return StateReadOp::create(module.getBuilder(phase), result.getLoc(), state);
1050Value OpLowering::lowerValue(StateOp op, OpResult result, Phase phase) {
1054 if (phase == Phase::New || phase == Phase::Initial)
1055 addPending(op, phase);
1060 if (phase == Phase::Old)
1061 assert(!module.loweredOps.contains({op, Phase::New}) &&
1062 "need old value but new value already written");
1064 auto state =
module.getAllocatedState(result);
1065 return StateReadOp::create(module.getBuilder(phase), result.getLoc(), state);
1072Value OpLowering::lowerValue(sim::DPICallOp op, OpResult result, Phase phase) {
1076 if (phase == Phase::New || phase == Phase::Initial)
1077 addPending(op, phase);
1082 if (phase == Phase::Old)
1083 assert(!module.loweredOps.contains({op, Phase::New}) &&
1084 "need old value but new value already written");
1086 auto state =
module.getAllocatedState(result);
1087 return StateReadOp::create(module.getBuilder(phase), result.getLoc(), state);
1093Value OpLowering::lowerValue(MemoryReadPortOp op, OpResult result,
1095 auto memOp = op.getMemory().getDefiningOp<MemoryOp>();
1098 op->emitOpError() <<
"memory must be defined locally";
1102 auto address = lowerValue(op.getAddress(), phase);
1105 if (phase == Phase::New)
1106 addPending(memOp.getOperation(), Phase::New);
1112 if (phase == Phase::Old) {
1114 assert(!module.loweredOps.contains({memOp, Phase::New}) &&
1115 "need old memory value but new value already written");
1117 assert(phase == Phase::New);
1120 auto state =
module.getAllocatedState(memOp->getResult(0));
1121 return MemoryReadOp::create(module.getBuilder(phase), result.getLoc(), state,
1128Value OpLowering::lowerValue(seq::InitialOp op, OpResult result, Phase phase) {
1131 addPending(op, Phase::Initial);
1134 auto value =
module.loweredValues.lookup({result, Phase::Initial});
1136 emitError(result.getLoc()) <<
"value has not been lowered";
1142 if (phase == Phase::Initial)
1147 auto &state =
module.allocatedInitials[result];
1149 state = AllocStateOp::create(module.allocBuilder, value.getLoc(),
1150 StateType::get(value.getType()),
1152 OpBuilder::InsertionGuard guard(module.initialBuilder);
1153 module.initialBuilder.setInsertionPointAfterValue(value);
1154 StateWriteOp::create(module.initialBuilder, value.getLoc(), state, value,
1159 return StateReadOp::create(module.getBuilder(phase), state.getLoc(), state);
1163Value OpLowering::lowerValue(seq::FromImmutableOp op, OpResult result,
1165 return lowerValue(op.getInput(), phase);
1169void OpLowering::addPending(Value value, Phase phase) {
1170 auto *defOp = value.getDefiningOp();
1171 assert(defOp &&
"block args should never be marked as a dependency");
1172 addPending(defOp, phase);
1177void OpLowering::addPending(Operation *op, Phase phase) {
1178 auto pair = std::make_pair(op, phase);
1179 if (!module.loweredOps.contains(pair))
1180 if (!llvm::is_contained(pending, pair))
1181 pending.push_back(pair);
1189struct LowerStatePass :
public arc::impl::LowerStatePassBase<LowerStatePass> {
1190 using LowerStatePassBase::LowerStatePassBase;
1191 void runOnOperation()
override;
1195void LowerStatePass::runOnOperation() {
1196 auto op = getOperation();
1197 for (
auto moduleOp :
llvm::make_early_inc_range(op.getOps<
HWModuleOp>())) {
1198 if (failed(ModuleLowering(moduleOp).
run()))
1199 return signalPassFailure();
1203 SymbolTable symbolTable(op);
1204 for (
auto extModuleOp :
1208 auto uses = symbolTable.getSymbolUses(extModuleOp, op);
1209 if (!uses->empty()) {
1210 extModuleOp->emitError(
"Failed to remove external module because it is "
1211 "still referenced/instantiated");
1212 return signalPassFailure();
1214 extModuleOp.erase();
assert(baseType &&"element must be base type")
static bool isAncestor(Block *block, Block *other)
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...
static Location getLoc(DefSlot slot)
static Block * getBodyBlock(FModuleLike mod)
OS & operator<<(OS &os, const InnerSymTarget &target)
Printing InnerSymTarget's.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)