14#include "mlir/Analysis/Liveness.h"
15#include "mlir/Dialect/Arith/IR/Arith.h"
16#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
17#include "mlir/IR/Dominance.h"
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/GenericIteratedDominanceFrontier.h"
22#define DEBUG_TYPE "llhd-mem2reg"
26#define GEN_PASS_DEF_MEM2REGPASS
27#include "circt/Dialect/LLHD/LLHDPasses.h.inc"
35using llvm::PointerIntPair;
36using llvm::SmallDenseSet;
38using llvm::SpecificBumpPtrAllocator;
42 if (
auto timeOp = value.getDefiningOp<ConstantTimeOp>()) {
43 auto t = timeOp.getValue();
44 return t.getTime() == 0 && t.getDelta() == 0 && t.getEpsilon() == 1;
51 if (
auto timeOp = value.getDefiningOp<ConstantTimeOp>()) {
52 auto t = timeOp.getValue();
53 return t.getTime() == 0 && t.getDelta() == 0 && t.getEpsilon() == 0;
60 if (
auto timeOp = value.getDefiningOp<ConstantTimeOp>()) {
61 auto t = timeOp.getValue();
62 return t.getTime() == 0 && t.getDelta() == 1 && t.getEpsilon() == 0;
70 if (
auto driveOp = dyn_cast<DriveOp>(op))
78 if (
auto driveOp = dyn_cast<DriveOp>(op))
92struct DriveCondition {
93 static DriveCondition never() {
return ConditionAndMode(Value{},
Never); }
94 static DriveCondition always() {
return ConditionAndMode(Value{}, Always); }
95 static DriveCondition conditional(Value condition = {}) {
96 return ConditionAndMode(condition, Conditional);
99 bool isNever()
const {
return conditionAndMode.getInt() ==
Never; }
100 bool isAlways()
const {
return conditionAndMode.getInt() == Always; }
101 bool isConditional()
const {
102 return conditionAndMode.getInt() == Conditional;
105 Value getCondition()
const {
return conditionAndMode.getPointer(); }
106 void setCondition(Value condition) { conditionAndMode.setPointer(condition); }
108 bool operator==(
const DriveCondition &other)
const {
109 return conditionAndMode == other.conditionAndMode;
111 bool operator!=(
const DriveCondition &other)
const {
112 return conditionAndMode != other.conditionAndMode;
121 typedef PointerIntPair<Value, 2> ConditionAndMode;
122 ConditionAndMode conditionAndMode;
124 DriveCondition(ConditionAndMode conditionAndMode)
125 : conditionAndMode(conditionAndMode) {}
126 friend DenseMapInfo<DriveCondition>;
138 DriveCondition condition;
139 bool valueIsPlaceholder =
false;
140 bool conditionIsPlaceholder =
false;
142 Def(Value value, DriveCondition condition)
143 : block(value.getParentBlock()), type(value.getType()), value(value),
144 condition(condition) {}
145 Def(Block *block, Type type, DriveCondition condition)
146 : block(block), type(type), condition(condition) {}
148 Value getValueOrPlaceholder();
149 Value getConditionOrPlaceholder();
155Value Def::getValueOrPlaceholder() {
157 auto builder = OpBuilder::atBlockBegin(block);
158 value = UnrealizedConversionCastOp::create(builder, builder.getUnknownLoc(),
161 valueIsPlaceholder =
true;
170Value Def::getConditionOrPlaceholder() {
171 if (!condition.getCondition()) {
172 auto builder = OpBuilder::atBlockBegin(block);
174 if (condition.isNever()) {
176 builder.getI1Type(), 0);
177 }
else if (condition.isAlways()) {
179 builder.getI1Type(), 1);
182 UnrealizedConversionCastOp::create(builder, builder.getUnknownLoc(),
183 builder.getI1Type(), ValueRange{})
185 conditionIsPlaceholder =
true;
187 condition.setCondition(value);
189 return condition.getCondition();
199 static bool isEqual(DriveCondition lhs, DriveCondition rhs) {
217 return cast<RefType>(slot.getType()).getNestedType();
225 if (
auto intTy = dyn_cast<IntegerType>(type))
226 return intTy.getWidth();
227 if (
auto floatTy = dyn_cast<FloatType>(type))
228 return floatTy.getWidth();
230 auto bitWidth = hw::getBitWidth(type);
233 return static_cast<unsigned>(bitWidth);
238 return bitWidth && *bitWidth <= IntegerType::kMaxWidth;
242 if (isa<FloatType>(type))
243 return arith::ConstantOp::create(builder, loc, builder.getZeroAttr(type));
246 assert(bitWidth &&
"cannot create zero value for unpromotable slot type");
247 auto flatType = builder.getIntegerType(*bitWidth);
249 if (type != flatType)
270 LatticeNode *nodeBefore =
nullptr;
271 LatticeNode *nodeAfter =
nullptr;
273 Def *blockingReachingDef =
nullptr;
274 Def *delayedReachingDef =
nullptr;
277 Def *getReachingDef(
bool delayed)
const {
278 return delayed ? delayedReachingDef : blockingReachingDef;
280 void setReachingDef(
bool delayed, Def *def) {
281 (delayed ? delayedReachingDef : blockingReachingDef) = def;
286 enum class Kind { BlockEntry, BlockExit, Probe, Drive, Signal };
290 LatticeNode(Kind kind) : kind(kind) {}
293struct BlockEntry :
public LatticeNode {
295 LatticeValue *valueAfter;
296 SmallVector<BlockExit *, 2> predecessors;
300 Def *insertedProbe =
nullptr;
303 Def *blockingMerged =
nullptr;
304 Def *delayedMerged =
nullptr;
306 BlockEntry(Block *block, LatticeValue *valueAfter)
307 : LatticeNode(Kind::BlockEntry), block(block), valueAfter(valueAfter) {
308 assert(!valueAfter->nodeBefore);
309 valueAfter->nodeBefore =
this;
312 Def *getMerged(
bool delayed)
const {
313 return delayed ? delayedMerged : blockingMerged;
315 void setMerged(
bool delayed, Def *def) {
316 (delayed ? delayedMerged : blockingMerged) = def;
319 static bool classof(
const LatticeNode *n) {
320 return n->kind == Kind::BlockEntry;
324struct BlockExit :
public LatticeNode {
326 LatticeValue *valueBefore;
327 SmallVector<BlockEntry *, 2> successors;
328 Operation *terminator;
331 BlockExit(Block *block, LatticeValue *valueBefore)
332 : LatticeNode(Kind::BlockExit), block(block), valueBefore(valueBefore),
333 terminator(block->getTerminator()),
334 suspends(isa<HaltOp, WaitOp>(terminator)) {
335 assert(!valueBefore->nodeAfter);
336 valueBefore->nodeAfter =
this;
339 static bool classof(
const LatticeNode *n) {
340 return n->kind == Kind::BlockExit;
344struct OpNode :
public LatticeNode {
346 LatticeValue *valueBefore;
347 LatticeValue *valueAfter;
349 OpNode(Kind kind, Operation *op, LatticeValue *valueBefore,
350 LatticeValue *valueAfter)
351 : LatticeNode(kind), op(op), valueBefore(valueBefore),
352 valueAfter(valueAfter) {
353 assert(!valueBefore->nodeAfter);
354 assert(!valueAfter->nodeBefore);
355 valueBefore->nodeAfter =
this;
356 valueAfter->nodeBefore =
this;
359 static bool classof(
const LatticeNode *n) {
360 return isa<ProbeNode, DriveNode, SignalNode>(n);
364struct ProbeNode :
public OpNode {
367 ProbeNode(ProbeOp op, Value slot, LatticeValue *valueBefore,
368 LatticeValue *valueAfter)
369 : OpNode(Kind::Probe, op, valueBefore, valueAfter), slot(slot) {}
371 static bool classof(
const LatticeNode *n) {
return n->kind == Kind::Probe; }
374struct DriveNode :
public OpNode {
378 DriveNode(DriveOp op, Value slot, Def *def, LatticeValue *valueBefore,
379 LatticeValue *valueAfter)
380 : OpNode(Kind::Drive, op, valueBefore, valueAfter),
388 bool drivesProjection()
const {
return op->getOperand(0) !=
getSlot(slot); }
391 DriveOp getDriveOp()
const {
return cast<DriveOp>(op); }
393 static bool classof(
const LatticeNode *n) {
return n->kind == Kind::Drive; }
396struct SignalNode :
public OpNode {
399 SignalNode(SignalOp op, Def *def, LatticeValue *valueBefore,
400 LatticeValue *valueAfter)
401 : OpNode(Kind::Signal, op, valueBefore, valueAfter), def(def) {}
403 SignalOp getSignalOp()
const {
return cast<SignalOp>(op); }
406 static bool classof(
const LatticeNode *n) {
return n->kind == Kind::Signal; }
413 LatticeValue *createValue() {
414 auto *value =
new (valueAllocator.Allocate()) LatticeValue();
415 values.push_back(value);
420 template <
class T,
typename... Args>
421 T *createNode(Args... args) {
423 new (getAllocator<T>().Allocate()) T(std::forward<Args>(args)...);
424 nodes.push_back(node);
429 template <
typename... Args>
430 Def *createDef(Args... args) {
431 auto *def =
new (defAllocator.Allocate()) Def(std::forward<Args>(args)...);
437 Def *createDef(Value value, DriveCondition mode) {
438 auto &slot = defsForValues[{value, mode}];
440 slot =
new (defAllocator.Allocate()) Def(value, mode);
441 defs.push_back(slot);
447 void dump(llvm::raw_ostream &os = llvm::dbgs());
451 std::vector<LatticeNode *> nodes;
453 std::vector<LatticeValue *> values;
455 std::vector<Def *> defs;
459 DenseMap<std::pair<Value, DriveCondition>, Def *> defsForValues;
462 SpecificBumpPtrAllocator<LatticeValue> valueAllocator;
463 SpecificBumpPtrAllocator<Def> defAllocator;
464 SpecificBumpPtrAllocator<BlockEntry> blockEntryAllocator;
465 SpecificBumpPtrAllocator<BlockExit> blockExitAllocator;
466 SpecificBumpPtrAllocator<ProbeNode> probeAllocator;
467 SpecificBumpPtrAllocator<DriveNode> driveAllocator;
468 SpecificBumpPtrAllocator<SignalNode> signalAllocator;
472 SpecificBumpPtrAllocator<T> &getAllocator();
478SpecificBumpPtrAllocator<BlockEntry> &Lattice::getAllocator() {
479 return blockEntryAllocator;
482SpecificBumpPtrAllocator<BlockExit> &Lattice::getAllocator() {
483 return blockExitAllocator;
486SpecificBumpPtrAllocator<ProbeNode> &Lattice::getAllocator() {
487 return probeAllocator;
490SpecificBumpPtrAllocator<DriveNode> &Lattice::getAllocator() {
491 return driveAllocator;
494SpecificBumpPtrAllocator<SignalNode> &Lattice::getAllocator() {
495 return signalAllocator;
502void Lattice::dump(llvm::raw_ostream &os) {
508 auto blockName = [&](
Block *block) {
509 unsigned id = blockNames.insert({block, blockNames.size()}).first->second;
510 return std::string(
"bb") + llvm::utostr(
id);
513 auto memName = [&](
DefSlot value) {
515 memNames.insert({
getSlot(value), memNames.size()}).first->second;
516 return std::string(
"mem") + llvm::utostr(
id) +
520 auto defName = [&](Def *def) {
521 unsigned id = defNames.insert({def, defNames.size()}).first->second;
522 return std::string(
"def") + llvm::utostr(
id);
526 for (
auto *node : nodes)
527 if (auto *entry = dyn_cast<BlockEntry>(node))
528 blockName(entry->block);
532 for (
auto *node : nodes) {
533 auto *entry = dyn_cast<BlockEntry>(node);
538 os <<
" " << blockName(entry->block) <<
":";
539 if (entry->predecessors.empty()) {
540 os <<
" // no predecessors";
543 for (
auto *node : entry->predecessors)
544 os <<
" " << blockName(node->block);
549 auto *value = entry->valueAfter;
554 auto printDef = [&](
bool delayed, Def *def) {
557 os <<
" -> def (" << (delayed ?
"delayed" :
"blocking")
558 <<
")=" << defName(def);
559 if (def->condition.isNever())
561 else if (def->condition.isAlways())
567 printDef(
false, value->blockingReachingDef);
568 printDef(
true, value->delayedReachingDef);
569 if (isa<BlockExit>(value->nodeAfter))
573 if (
auto *node = dyn_cast<ProbeNode>(value->nodeAfter))
574 os <<
" probe " << memName(
blockingSlot(node->slot)) <<
"\n";
575 else if (
auto *node = dyn_cast<DriveNode>(value->nodeAfter))
576 os <<
" drive " << memName(node->slot) <<
"\n";
577 else if (
auto *node = dyn_cast<SignalNode>(value->nodeAfter))
578 os <<
" signal " << memName(node->getSlot()) <<
"\n";
583 value = cast<OpNode>(value->nodeAfter)->valueAfter;
587 auto *exit = cast<BlockExit>(value->nodeAfter);
588 if (isa<WaitOp>(exit->terminator))
590 else if (exit->successors.empty())
594 for (
auto *node : exit->successors)
595 os <<
" " << blockName(node->block);
597 os <<
" // suspends";
602 for (
auto [mem,
id] : memNames)
603 os <<
" mem" << id <<
": " << mem <<
"\n";
637 while (fromSignal != toSlot) {
638 auto *op = cast<OpResult>(fromSignal).getOwner();
639 stack.push_back({op, Value()});
640 fromSignal = op->getOperand(0);
653 for (
auto &projection : llvm::reverse(projections)) {
654 projection.into = value;
655 value = TypeSwitch<Operation *, Value>(projection.op)
656 .Case<SigArrayGetOp>([&](
auto op) {
658 op.getLoc(), value, op.getIndex());
660 .Case<SigStructExtractOp>([&](
auto op) {
663 if (isa<hw::UnionType>(value.getType()))
664 return builder.createOrFold<hw::UnionExtractOp>(
665 op.getLoc(), value, op.getFieldAttr());
667 op.getLoc(), value, op.getFieldAttr());
669 .Case<SigExtractOp>([&](
auto op) {
670 auto type = cast<RefType>(op.getType()).getNestedType();
671 auto width = type.getIntOrFloatBitWidth();
672 return comb::createDynamicExtract(builder, op.getLoc(), value,
673 op.getLowBit(), width);
693 for (
auto projection : projections) {
694 value = TypeSwitch<Operation *, Value>(projection.op)
695 .Case<SigArrayGetOp>([&](
auto op) {
696 return builder.createOrFold<hw::ArrayInjectOp>(
697 op.getLoc(), projection.into, op.getIndex(), value);
699 .Case<SigStructExtractOp>([&](
auto op) {
703 dyn_cast<hw::UnionType>(projection.into.getType()))
704 return builder.createOrFold<hw::UnionCreateOp>(
705 op.getLoc(), unionTy, op.getFieldAttr(), value);
706 return builder.createOrFold<hw::StructInjectOp>(
707 op.getLoc(), projection.into, op.getFieldAttr(), value);
709 .Case<SigExtractOp>([&](
auto op) {
710 return comb::createDynamicInject(builder, op.getLoc(),
712 op.getLowBit(), value);
725 Promoter(Region ®ion) : region(region) {}
726 LogicalResult promote();
728 void findPromotableSlots();
729 Value resolveSlot(Value projectionOrSlot);
730 void populateSlotOps();
732 void captureAcrossWait();
733 void captureAcrossWait(Value value, ArrayRef<WaitOp> waitOps,
734 Liveness &liveness, DominanceInfo &dominance);
736 void constructLattice();
737 void propagateBackward();
738 void propagateBackward(LatticeNode *node);
739 void propagateForward();
740 void propagateForward(
bool optimisticMerges, DominanceInfo &dominance);
741 void propagateForward(LatticeNode *node,
bool optimisticMerges,
742 DominanceInfo &dominance);
743 void markDirty(LatticeNode *node);
745 void insertProbeBlocks();
747 void insertProbes(BlockEntry *node);
749 void insertDriveBlocks();
751 void insertDrives(BlockExit *node);
752 void insertDrives(DriveNode *node);
754 void resolveDefinitions();
755 void resolveDefinitions(ProbeNode *node);
756 void resolveDefinitions(DriveNode *node);
757 void resolveDefinitionValue(DriveNode *node);
758 void resolveDefinitionCondition(DriveNode *node);
760 void insertBlockArgs();
761 bool insertBlockArgs(BlockEntry *node);
762 void replaceValueWith(Value oldValue, Value newValue);
766 void removeUnusedLocalSignal(SignalOp signalOp);
777 SmallVector<Value> slots;
782 SmallDenseSet<Value> promotable;
791 DenseMap<Block *, ConstantTimeOp> blockingTimeCache;
792 DenseMap<Block *, ConstantTimeOp> delayedTimeCache;
797 std::optional<Lattice> lattice;
799 SmallVector<LatticeNode *> dirtyNodes;
806 DenseMap<Value, SmallVector<Operation *>> slotOps;
810LogicalResult Promoter::promote() {
814 findPromotableSlots();
829 for (
auto slot : slots) {
842void Promoter::promoteSlot() {
843 assert(currentSlot &&
"currentSlot must be set before promoteSlot()");
847 LLVM_DEBUG(llvm::dbgs() <<
"Promoting slot " << currentSlot <<
"\n");
851 llvm::dbgs() <<
"Initial lattice:\n";
858 llvm::dbgs() <<
"After backward propagation:\n";
866 llvm::dbgs() <<
"After probe insertion:\n";
873 llvm::dbgs() <<
"After forward propagation:\n";
878 resolveDefinitions();
884 llvm::dbgs() <<
"After def resolution and drive insertion:\n";
893 if (
auto signalOp = currentSlot.getDefiningOp<SignalOp>())
894 if (signalOp->getParentRegion() == ®ion)
895 removeUnusedLocalSignal(signalOp);
903void Promoter::findPromotableSlots() {
904 SmallPtrSet<Value, 8> seenSlots;
905 SmallPtrSet<Operation *, 8> checkedUsers;
906 SmallVector<Operation *, 8> userWorklist;
908 region.walk([&](Operation *op) {
909 for (
auto operand : op->getOperands()) {
910 if (!seenSlots.insert(operand).second)
916 if (!operand.getDefiningOp<llhd::SignalOp>())
920 bool hasProjection =
false;
921 bool hasBlockingDrive =
false;
922 bool hasDeltaDrive =
false;
923 auto checkUser = [&](Operation *user) ->
bool {
925 if (region.isProperAncestor(user->getParentRegion()))
928 if (user->getParentRegion() != ®ion)
934 if (isa<SigArrayGetOp, SigExtractOp, SigStructExtractOp>(user)) {
935 hasProjection =
true;
936 for (
auto *projectionUser : user->getUsers()) {
937 if (isa<SigArrayGetOp, SigExtractOp, SigStructExtractOp>(
939 projectionUser->getBlock() != user->getBlock())
943 if (checkedUsers.insert(projectionUser).second)
944 userWorklist.push_back(projectionUser);
946 projections.insert({user->getResult(0), operand});
954 checkedUsers.clear();
955 if (!llvm::all_of(operand.getUsers(), [&](
auto *user) {
957 if (checkedUsers.insert(user).second)
958 userWorklist.push_back(user);
959 while (!userWorklist.empty() && allOk)
960 allOk &= checkUser(userWorklist.pop_back_val());
961 userWorklist.clear();
969 if (hasProjection && hasBlockingDrive && hasDeltaDrive)
977 slots.push_back(operand);
982 promotable.insert(slots.begin(), slots.end());
983 projections.remove_if([&](
auto elem) {
984 auto [projection, slot] = elem;
985 return !promotable.contains(slot);
987 for (
auto [projection, slot] : projections)
988 promotable.insert(projection);
990 LLVM_DEBUG(llvm::dbgs() <<
"Found " << slots.size() <<
" promotable slots, "
991 << promotable.size() <<
" promotable values\n");
996Value Promoter::resolveSlot(Value projectionOrSlot) {
997 if (
auto slot = projections.lookup(projectionOrSlot))
999 return projectionOrSlot;
1006void Promoter::captureAcrossWait() {
1007 if (region.hasOneBlock())
1010 SmallVector<WaitOp> waitOps;
1011 for (
auto &block : region)
1012 if (auto waitOp = dyn_cast<WaitOp>(block.getTerminator()))
1013 waitOps.push_back(waitOp);
1015 DominanceInfo dominance(region.getParentOp());
1016 Liveness liveness(region.getParentOp());
1018 llvm::DenseSet<Value> alreadyCaptured;
1020 auto isDefinedInRegion = [&](Value v) {
1021 return v.getParentRegion() == ®ion;
1024 for (
auto waitOp : waitOps) {
1025 Block *waitBlock = waitOp->getBlock();
1026 const auto &liveOutValues = liveness.getLiveOut(waitBlock);
1028 for (Value v : liveOutValues) {
1029 if (!isDefinedInRegion(v))
1032 if (!alreadyCaptured.insert(v).second)
1035 captureAcrossWait(v, waitOps, liveness, dominance);
1044void Promoter::captureAcrossWait(Value value, ArrayRef<WaitOp> waitOps,
1045 Liveness &liveness, DominanceInfo &dominance) {
1052 if (
auto *defOp = value.getDefiningOp())
1053 if (defOp->hasTrait<OpTrait::ConstantLike>())
1056 SmallVector<WaitOp> capturedWaitOps;
1057 for (
auto waitOp : waitOps) {
1058 auto *waitBlock = waitOp->getBlock();
1059 auto *blockLiveness = liveness.getLiveness(waitBlock);
1060 if (!blockLiveness || !blockLiveness->isLiveOut(value))
1062 if (!dominance.dominates(value, waitOp.getOperation()))
1064 capturedWaitOps.push_back(waitOp);
1066 if (capturedWaitOps.empty())
1070 llvm::dbgs() <<
"Capture " << value <<
"\n";
1071 for (
auto waitOp : capturedWaitOps)
1072 llvm::dbgs() <<
"- Across " << waitOp <<
"\n";
1077 auto &domTree = dominance.getDomTree(®ion);
1078 llvm::IDFCalculatorBase<Block, false> idfCalculator(domTree);
1082 SmallPtrSet<Block *, 4> definingBlocks;
1083 definingBlocks.insert(value.getParentBlock());
1084 for (
auto waitOp : capturedWaitOps)
1085 definingBlocks.insert(waitOp.getDest());
1086 idfCalculator.setDefiningBlocks(definingBlocks);
1089 SmallPtrSet<Block *, 16> liveInBlocks;
1090 for (
auto &block : region)
1091 if (liveness.getLiveness(&block)->isLiveIn(value))
1092 liveInBlocks.insert(&block);
1093 idfCalculator.setLiveInBlocks(liveInBlocks);
1097 SmallVector<Block *> mergePointsVec;
1098 idfCalculator.calculate(mergePointsVec);
1099 SmallPtrSet<Block *, 16> mergePoints(mergePointsVec.begin(),
1100 mergePointsVec.end());
1101 for (
auto waitOp : capturedWaitOps)
1102 mergePoints.insert(waitOp.getDest());
1103 LLVM_DEBUG(llvm::dbgs() <<
"- " << mergePoints.size() <<
" merge points\n");
1108 struct WorklistItem {
1109 DominanceInfoNode *domNode;
1112 SmallVector<WorklistItem> worklist;
1113 worklist.push_back({domTree.getNode(value.getParentBlock()), value});
1115 while (!worklist.empty()) {
1116 auto item = worklist.pop_back_val();
1117 auto *block = item.domNode->getBlock();
1120 if (mergePoints.contains(block))
1121 item.reachingDef = block->addArgument(value.getType(), value.getLoc());
1125 for (
auto &op : *block)
1126 op.replaceUsesOfWith(value, item.reachingDef);
1130 if (
auto branchOp = dyn_cast<BranchOpInterface>(block->getTerminator())) {
1131 for (
auto &blockOperand : branchOp->getBlockOperands())
1132 if (mergePoints.contains(blockOperand.
get()))
1133 branchOp.getSuccessorOperands(blockOperand.getOperandNumber())
1134 .
append(item.reachingDef);
1135 }
else if (
auto waitOp = dyn_cast<WaitOp>(block->getTerminator())) {
1136 if (mergePoints.contains(waitOp.getDest()))
1137 waitOp.getDestOperandsMutable().append(item.reachingDef);
1140 for (
auto *child : item.domNode->children())
1141 worklist.push_back({child, item.reachingDef});
1153void Promoter::populateSlotOps() {
1154 for (
auto &block : region) {
1155 for (
auto &op : block.without_terminator()) {
1156 Value slot = TypeSwitch<Operation *, Value>(&op)
1157 .Case<ProbeOp, DriveOp>([&](
auto op) {
1158 if (promotable.contains(op.getSignal()))
1159 return resolveSlot(op.getSignal());
1162 .Case([&](SignalOp op) {
return op.getResult(); })
1163 .Default([&](Operation *) {
return Value(); });
1165 slotOps[slot].push_back(&op);
1174void Promoter::constructLattice() {
1175 assert(currentSlot &&
"constructLattice requires currentSlot");
1179 ArrayRef<Operation *> currentSlotOps = slotOps[currentSlot];
1183 for (
auto &block : region) {
1185 lattice->createNode<BlockEntry>(&block, lattice->createValue());
1186 blockEntries.insert({&block, entry});
1190 for (
auto &block : region) {
1191 auto *valueBefore = blockEntries.lookup(&block)->valueAfter;
1195 ArrayRef<Operation *> blockOps = currentSlotOps.take_while(
1196 [&](Operation *op) {
return op->getBlock() == █ });
1197 currentSlotOps = currentSlotOps.drop_front(blockOps.size());
1199 for (Operation *op : blockOps) {
1201 if (
auto probeOp = dyn_cast<ProbeOp>(op)) {
1202 if (!promotable.contains(probeOp.getSignal()))
1204 if (resolveSlot(probeOp.getSignal()) != currentSlot)
1206 auto *node = lattice->createNode<ProbeNode>(
1207 probeOp, currentSlot, valueBefore, lattice->createValue());
1208 valueBefore = node->valueAfter;
1213 if (
auto driveOp = dyn_cast<DriveOp>(op)) {
1216 if (!promotable.contains(driveOp.getSignal()))
1218 if (resolveSlot(driveOp.getSignal()) != currentSlot)
1220 auto condition = DriveCondition::always();
1221 if (
auto enable = driveOp.getEnable())
1222 condition = DriveCondition::conditional(enable);
1227 driveOp.getSignal() == currentSlot
1228 ? lattice->createDef(driveOp.getValue(), condition)
1229 : lattice->createDef(driveOp->getBlock(),
1231 auto *node = lattice->createNode<DriveNode>(
1232 driveOp, currentSlot, def, valueBefore, lattice->createValue());
1233 valueBefore = node->valueAfter;
1239 if (
auto signalOp = dyn_cast<SignalOp>(op)) {
1240 if (signalOp.getResult() != currentSlot)
1243 lattice->createDef(signalOp.getInit(), DriveCondition::never());
1244 auto *node = lattice->createNode<SignalNode>(signalOp, def, valueBefore,
1245 lattice->createValue());
1246 valueBefore = node->valueAfter;
1252 auto *exit = lattice->createNode<BlockExit>(&block, valueBefore);
1253 for (
auto *otherBlock : exit->terminator->getSuccessors()) {
1254 auto *otherEntry = blockEntries.lookup(otherBlock);
1255 exit->successors.push_back(otherEntry);
1256 otherEntry->predecessors.push_back(exit);
1263void Promoter::propagateBackward() {
1264 for (
auto *node : lattice->nodes)
1265 propagateBackward(node);
1266 SmallVector<LatticeNode *> nodes;
1267 while (!dirtyNodes.empty()) {
1268 std::swap(dirtyNodes, nodes);
1269 for (
auto *node : nodes) {
1270 node->dirty =
false;
1271 propagateBackward(node);
1279void Promoter::propagateBackward(LatticeNode *node) {
1280 auto update = [&](LatticeValue *value,
bool needed) {
1281 if (value->needed != needed) {
1282 value->needed = needed;
1283 markDirty(value->nodeBefore);
1288 if (
auto *probe = dyn_cast<ProbeNode>(node)) {
1289 update(probe->valueBefore,
true);
1299 if (
auto *drive = dyn_cast<DriveNode>(node)) {
1300 bool needed = drive->valueAfter->needed;
1301 if (drive->drivesProjection())
1303 else if (!
isDelayed(drive->slot) && !drive->getDriveOp().getEnable())
1305 update(drive->valueBefore, needed);
1312 if (isa<SignalNode>(node)) {
1313 auto *signal = cast<SignalNode>(node);
1314 update(signal->valueBefore,
false);
1319 if (
auto *entry = dyn_cast<BlockEntry>(node)) {
1320 for (
auto *predecessor : entry->predecessors)
1321 markDirty(predecessor);
1326 if (
auto *exit = dyn_cast<BlockExit>(node)) {
1329 bool needed =
false;
1330 for (
auto *successor : exit->successors)
1331 needed |= successor->valueAfter->needed;
1332 update(exit->valueBefore, needed);
1336 assert(
false &&
"unhandled node in backward propagation");
1339void Promoter::propagateForward() {
1340 DominanceInfo dominance(region.getParentOp());
1341 propagateForward(
true, dominance);
1342 propagateForward(
false, dominance);
1353void Promoter::propagateForward(
bool optimisticMerges,
1354 DominanceInfo &dominance) {
1355 for (
auto *node : lattice->nodes)
1356 propagateForward(node, optimisticMerges, dominance);
1357 SmallVector<LatticeNode *> nodes;
1358 while (!dirtyNodes.empty()) {
1359 std::swap(dirtyNodes, nodes);
1360 for (
auto *node : nodes) {
1361 node->dirty =
false;
1362 propagateForward(node, optimisticMerges, dominance);
1371void Promoter::propagateForward(LatticeNode *node,
bool optimisticMerges,
1372 DominanceInfo &dominance) {
1373 auto update = [&](LatticeValue *value, Def *blocking, Def *delayed) {
1374 if (value->blockingReachingDef != blocking ||
1375 value->delayedReachingDef != delayed) {
1376 value->blockingReachingDef = blocking;
1377 value->delayedReachingDef = delayed;
1378 markDirty(value->nodeAfter);
1383 if (
auto *probe = dyn_cast<ProbeNode>(node)) {
1384 update(probe->valueAfter, probe->valueBefore->blockingReachingDef,
1385 probe->valueBefore->delayedReachingDef);
1399 if (
auto *drive = dyn_cast<DriveNode>(node)) {
1400 Def *blocking = drive->valueBefore->blockingReachingDef;
1401 Def *delayed = drive->valueBefore->delayedReachingDef;
1402 bool driveDelayed =
isDelayed(drive->slot);
1408 if (drive->drivesProjection() || drive->getDriveOp().getEnable()) {
1409 Def *inDef = driveDelayed ? delayed : blocking;
1411 if (drive->def->value != inDef->value)
1412 drive->def->value = {};
1413 if (inDef->condition.isAlways() || drive->def->condition.isAlways())
1414 drive->def->condition = DriveCondition::always();
1415 else if (drive->def->condition != inDef->condition)
1416 drive->def->condition = DriveCondition::conditional();
1421 delayed = drive->def;
1423 blocking = drive->def;
1427 update(drive->valueAfter, blocking, delayed);
1433 if (
auto *signal = dyn_cast<SignalNode>(node)) {
1434 update(signal->valueAfter, signal->def,
nullptr);
1440 if (
auto *entry = dyn_cast<BlockEntry>(node)) {
1443 if (entry->insertedProbe) {
1444 update(entry->valueAfter, entry->insertedProbe, entry->insertedProbe);
1451 Block *slotBlock = currentSlot.getDefiningOp()->getBlock();
1452 bool slotDominates = dominance.dominates(slotBlock, entry->block);
1453 bool anyPredSuspends =
1454 llvm::any_of(entry->predecessors, [](
auto *p) { return p->suspends; });
1456 auto mergeFlavor = [&](
bool delayed) -> Def * {
1457 if (!slotDominates || anyPredSuspends)
1461 if (llvm::all_of(entry->predecessors, [&](
auto *p) {
1462 return !p->valueBefore->getReachingDef(delayed);
1468 Def *common =
nullptr;
1469 DriveCondition cond = DriveCondition::never();
1471 for (
auto *pred : entry->predecessors) {
1472 Def *predDef = pred->valueBefore->getReachingDef(delayed);
1473 if (!predDef && optimisticMerges)
1475 DriveCondition predCond =
1476 predDef ? predDef->condition : DriveCondition::never();
1483 if (common != predDef)
1485 if (cond != predCond)
1486 cond = DriveCondition::conditional();
1497 Def *&merged = delayed ? entry->delayedMerged : entry->blockingMerged;
1499 merged->condition = cond;
1510 merged = lattice->createDef(entry->block,
getStoredType(slot), cond);
1514 Def *newBlocking = mergeFlavor(
false);
1515 Def *newDelayed = mergeFlavor(
true);
1516 update(entry->valueAfter, newBlocking, newDelayed);
1521 if (
auto *exit = dyn_cast<BlockExit>(node)) {
1522 for (
auto *successor : exit->successors)
1523 markDirty(successor);
1527 assert(
false &&
"unhandled node in forward propagation");
1531void Promoter::markDirty(LatticeNode *node) {
1536 dirtyNodes.push_back(node);
1547void Promoter::insertProbeBlocks() {
1551 SmallDenseSet<std::pair<BlockExit *, BlockEntry *>, 1> worklist;
1552 for (
auto *node : lattice->nodes) {
1553 auto *entry = dyn_cast<BlockEntry>(node);
1554 if (!entry || !entry->valueAfter->needed)
1556 unsigned numIncoming = 0;
1557 for (
auto *predecessor : entry->predecessors)
1558 if (predecessor->valueBefore->needed)
1560 if (numIncoming == 0 || numIncoming == entry->predecessors.size())
1562 for (
auto *predecessor : entry->predecessors)
1563 if (!predecessor->valueBefore->needed)
1564 worklist.insert({predecessor, entry});
1568 for (
auto [predecessor, successor] : worklist) {
1569 LLVM_DEBUG(llvm::dbgs() <<
"- Inserting probe block towards " << successor
1570 <<
" after " << *predecessor->terminator <<
"\n");
1571 OpBuilder builder(predecessor->terminator);
1572 auto *newBlock = builder.createBlock(successor->block);
1573 for (
auto oldArg : successor->block->getArguments())
1574 newBlock->addArgument(oldArg.getType(), oldArg.
getLoc());
1575 cf::BranchOp::create(builder, predecessor->terminator->getLoc(),
1576 successor->block, newBlock->getArguments());
1577 for (
auto &blockOp : predecessor->terminator->getBlockOperands())
1578 if (blockOp.
get() == successor->block)
1579 blockOp.set(newBlock);
1582 auto *value = lattice->createValue();
1583 value->needed = successor->valueAfter->needed;
1584 auto *newEntry = lattice->createNode<BlockEntry>(newBlock, value);
1585 auto *newExit = lattice->createNode<BlockExit>(newBlock, value);
1586 newEntry->predecessors.push_back(predecessor);
1587 newExit->successors.push_back(successor);
1588 llvm::replace(successor->predecessors, predecessor, newExit);
1589 llvm::replace(predecessor->successors, successor, newEntry);
1596void Promoter::insertProbes() {
1597 for (
auto *node : lattice->nodes) {
1598 if (
auto *entry = dyn_cast<BlockEntry>(node))
1599 insertProbes(entry);
1605void Promoter::insertProbes(BlockEntry *node) {
1606 if (!node->valueAfter->needed)
1608 if (!node->predecessors.empty() &&
1609 llvm::all_of(node->predecessors, [](
auto *predecessor) {
1610 return predecessor->valueBefore->needed;
1613 LLVM_DEBUG(llvm::dbgs() <<
"- Inserting probe for " << currentSlot
1614 <<
" in block " << node->block <<
"\n");
1615 auto builder = OpBuilder::atBlockBegin(node->block);
1617 if (Operation *op = currentSlot.getDefiningOp())
1618 if (op->getBlock() == node->block)
1619 builder.setInsertionPointAfterValue(currentSlot);
1620 auto value = ProbeOp::create(builder, currentSlot.getLoc(), currentSlot);
1621 auto *def = lattice->createDef(value, DriveCondition::never());
1622 node->insertedProbe = def;
1627void Promoter::insertDriveBlocks() {
1631 auto partialAt = [](LatticeValue *before, LatticeValue *after,
bool delayed,
1632 unsigned totalSuccessors) {
1633 Def *def = before->getReachingDef(delayed);
1634 if (!def || def->condition.isNever())
1636 (void)totalSuccessors;
1637 return !after->getReachingDef(delayed);
1640 SmallDenseSet<std::pair<BlockExit *, BlockEntry *>, 1> worklist;
1641 for (
auto *node : lattice->nodes) {
1642 auto *exit = dyn_cast<BlockExit>(node);
1648 for (
bool delayed : {
false,
true}) {
1649 Def *def = exit->valueBefore->getReachingDef(delayed);
1650 if (!def || def->condition.isNever())
1652 unsigned numContinues = 0;
1653 for (
auto *successor : exit->successors)
1654 if (successor->valueAfter->getReachingDef(delayed))
1656 if (numContinues == 0 || numContinues == exit->successors.size())
1658 for (
auto *successor : exit->successors)
1659 if (partialAt(exit->valueBefore, successor->valueAfter, delayed,
1660 exit->successors.size()))
1661 worklist.insert({exit, successor});
1666 for (
auto [predecessor, successor] : worklist) {
1667 LLVM_DEBUG(llvm::dbgs() <<
"- Inserting drive block towards " << successor
1668 <<
" after " << *predecessor->terminator <<
"\n");
1669 OpBuilder builder(predecessor->terminator);
1670 auto *newBlock = builder.createBlock(successor->block);
1671 for (
auto oldArg : successor->block->getArguments())
1672 newBlock->addArgument(oldArg.getType(), oldArg.
getLoc());
1673 cf::BranchOp::create(builder, predecessor->terminator->getLoc(),
1674 successor->block, newBlock->getArguments());
1675 for (
auto &blockOp : predecessor->terminator->getBlockOperands())
1676 if (blockOp.
get() == successor->block)
1677 blockOp.set(newBlock);
1682 auto *value = lattice->createValue();
1683 value->needed = successor->valueAfter->needed;
1684 value->blockingReachingDef = predecessor->valueBefore->blockingReachingDef;
1685 value->delayedReachingDef = predecessor->valueBefore->delayedReachingDef;
1686 auto *newEntry = lattice->createNode<BlockEntry>(newBlock, value);
1687 auto *newExit = lattice->createNode<BlockExit>(newBlock, value);
1688 newEntry->predecessors.push_back(predecessor);
1689 newExit->successors.push_back(successor);
1690 llvm::replace(successor->predecessors, predecessor, newExit);
1691 llvm::replace(predecessor->successors, successor, newEntry);
1698void Promoter::insertDrives() {
1699 for (
auto *node : lattice->nodes) {
1700 if (
auto *exit = dyn_cast<BlockExit>(node))
1702 else if (
auto *drive = dyn_cast<DriveNode>(node))
1703 insertDrives(drive);
1709void Promoter::insertDrives(BlockExit *node) {
1710 auto builder = OpBuilder::atBlockTerminator(node->block);
1715 auto getTime = [&](
bool delta) -> ConstantTimeOp {
1716 auto &cached = (delta ? delayedTimeCache : blockingTimeCache)[node->block];
1718 cached = ConstantTimeOp::create(builder, node->terminator->getLoc(), 0,
1719 "ns", delta ? 1 : 0, delta ? 0 : 1);
1723 auto insertDriveForSlot = [&](
bool delayed) {
1724 Def *reachingDef = node->valueBefore->getReachingDef(delayed);
1725 if (!reachingDef || reachingDef->condition.isNever())
1727 if (!node->suspends && !node->successors.empty() &&
1728 llvm::all_of(node->successors, [&](
auto *successor) {
1729 return successor->valueAfter->getReachingDef(delayed) != nullptr;
1732 LLVM_DEBUG(llvm::dbgs() <<
"- Inserting drive for " << currentSlot <<
" "
1733 << (delayed ?
"(delayed)" :
"(blocking)")
1734 <<
" before " << *node->terminator <<
"\n");
1735 auto time = getTime(delayed);
1736 auto value = reachingDef->getValueOrPlaceholder();
1737 auto enable = reachingDef->condition.isConditional()
1738 ? reachingDef->getConditionOrPlaceholder()
1740 DriveOp::create(builder, currentSlot.getLoc(), currentSlot, value, time,
1744 insertDriveForSlot(
false);
1745 insertDriveForSlot(
true);
1750void Promoter::insertDrives(DriveNode *node) {
1751 LLVM_DEBUG(llvm::dbgs() <<
"- Removing drive " << *node->op <<
"\n");
1752 pruner.eraseNow(node->op);
1761void Promoter::resolveDefinitions() {
1762 for (
auto *node : lattice->nodes) {
1763 if (
auto *probe = dyn_cast<ProbeNode>(node))
1764 resolveDefinitions(probe);
1765 else if (
auto *drive = dyn_cast<DriveNode>(node))
1766 resolveDefinitions(drive);
1771void Promoter::resolveDefinitions(ProbeNode *node) {
1772 Def *def = node->valueBefore->blockingReachingDef;
1773 assert(def &&
"no definition reaches probe");
1776 auto projections =
getProjections(node->op->getOperand(0), node->slot);
1779 auto builder = OpBuilder(node->op);
1780 auto value = def->getValueOrPlaceholder();
1784 LLVM_DEBUG(llvm::dbgs() <<
"- Replacing " << *node->op <<
" with " << value
1786 replaceValueWith(node->op->getResult(0), value);
1787 pruner.eraseNow(node->op);
1793void Promoter::resolveDefinitions(DriveNode *node) {
1798 if (!node->def->value || node->def->valueIsPlaceholder)
1799 resolveDefinitionValue(node);
1800 if (node->def->condition.isConditional() &&
1801 (!node->def->condition.getCondition() ||
1802 node->def->conditionIsPlaceholder))
1803 resolveDefinitionCondition(node);
1806void Promoter::resolveDefinitionValue(DriveNode *node) {
1809 Def *inDef = node->valueBefore->getReachingDef(
isDelayed(node->slot));
1810 assert(inDef &&
"no definition reaches drive");
1811 auto driveOp = node->getDriveOp();
1812 LLVM_DEBUG(llvm::dbgs() <<
"- Injecting value for " << driveOp <<
"\n");
1818 auto builder = OpBuilder(driveOp);
1819 auto value = inDef->getValueOrPlaceholder();
1823 pruner.eraseLaterIfUnused(value);
1824 if (!driveOp.getEnable())
1825 value = driveOp.getValue();
1828 driveOp.getLoc(), driveOp.getEnable(), driveOp.getValue(), value);
1834 if (node->def->valueIsPlaceholder) {
1835 auto *placeholder = node->def->value.getDefiningOp();
1836 assert(isa_and_nonnull<UnrealizedConversionCastOp>(placeholder) &&
1837 "placeholder replaced but valueIsPlaceholder still set");
1838 replaceValueWith(placeholder->getResult(0), value);
1839 pruner.eraseNow(placeholder);
1840 node->def->valueIsPlaceholder =
false;
1842 node->def->value = value;
1845void Promoter::resolveDefinitionCondition(DriveNode *node) {
1848 Def *inDef = node->valueBefore->getReachingDef(
isDelayed(node->slot));
1849 assert(inDef &&
"no definition reaches drive");
1850 auto driveOp = node->getDriveOp();
1851 LLVM_DEBUG(llvm::dbgs() <<
"- Mutating condition for " << driveOp <<
"\n");
1852 OpBuilder builder(driveOp);
1857 if (inDef->condition.isNever())
1858 condition = driveOp.getEnable();
1861 builder.createOrFold<
comb::OrOp>(driveOp.getLoc(), driveOp.getEnable(),
1862 inDef->getConditionOrPlaceholder());
1865 if (node->def->conditionIsPlaceholder) {
1866 auto *placeholder = node->def->condition.getCondition().getDefiningOp();
1867 assert(isa_and_nonnull<UnrealizedConversionCastOp>(placeholder) &&
1868 "placeholder replaced but conditionIsPlaceholder still set");
1869 replaceValueWith(placeholder->getResult(0), condition);
1870 pruner.eraseNow(placeholder);
1871 node->def->conditionIsPlaceholder =
false;
1873 node->def->condition.setCondition(condition);
1881void Promoter::insertBlockArgs() {
1882 bool anyArgsInserted =
true;
1883 while (anyArgsInserted) {
1884 anyArgsInserted =
false;
1885 for (
auto *node : lattice->nodes)
1886 if (auto *entry = dyn_cast<BlockEntry>(node))
1887 anyArgsInserted |= insertBlockArgs(entry);
1899bool Promoter::insertBlockArgs(BlockEntry *node) {
1905 enum class Which { Value, Condition };
1906 SmallVector<std::pair<DefSlot, Which>> neededSlots;
1907 auto addNeededSlot = [&](
DefSlot slot) {
1908 auto *def = node->getMerged(
isDelayed(slot));
1911 if (!node->valueAfter->getReachingDef(
isDelayed(slot)))
1913 if (def->valueIsPlaceholder)
1914 neededSlots.push_back({slot, Which::Value});
1915 if (def->conditionIsPlaceholder)
1916 neededSlots.push_back({slot, Which::Condition});
1920 if (neededSlots.empty())
1922 LLVM_DEBUG(llvm::dbgs() <<
"- Adding " << neededSlots.size()
1923 <<
" args to block " << node->block <<
"\n");
1926 for (
auto [slot, which] : neededSlots) {
1927 auto *def = node->getMerged(
isDelayed(slot));
1930 case Which::Value: {
1933 auto *placeholder = def->value.getDefiningOp();
1934 assert(isa_and_nonnull<UnrealizedConversionCastOp>(placeholder) &&
1935 "placeholder replaced but valueIsPlaceholder still set");
1937 replaceValueWith(placeholder->getResult(0), arg);
1938 pruner.eraseNow(placeholder);
1940 def->valueIsPlaceholder =
false;
1943 case Which::Condition: {
1947 auto *placeholder = def->condition.getCondition().getDefiningOp();
1948 assert(isa_and_nonnull<UnrealizedConversionCastOp>(placeholder) &&
1949 "placeholder replaced but conditionIsPlaceholder still set");
1950 auto conditionArg = node->block->addArgument(
1951 IntegerType::get(region.getContext(), 1),
getLoc(slot));
1952 replaceValueWith(placeholder->getResult(0), conditionArg);
1953 pruner.eraseNow(placeholder);
1954 def->condition.setCondition(conditionArg);
1955 def->conditionIsPlaceholder =
false;
1962 SmallPtrSet<BlockExit *, 4> updatedPredecessors;
1963 for (
auto *predecessor : node->predecessors) {
1971 if (!updatedPredecessors.insert(predecessor).second)
1975 SmallVector<Value> args;
1976 for (
auto [slot, which] : neededSlots) {
1977 Def *def = predecessor->valueBefore->getReachingDef(
isDelayed(slot));
1978 auto builder = OpBuilder::atBlockTerminator(predecessor->block);
1982 args.push_back(def->getValueOrPlaceholder());
1988 case Which::Condition:
1990 args.push_back(def->getConditionOrPlaceholder());
1993 builder.getI1Type(), 0));
2002 if (
auto branchOp = dyn_cast<BranchOpInterface>(predecessor->terminator)) {
2003 SmallVector<unsigned> successorOperandNumbers;
2004 for (
auto &blockOperand : branchOp->getBlockOperands())
2005 if (blockOperand.
get() == node->block)
2006 successorOperandNumbers.push_back(blockOperand.getOperandNumber());
2007 for (
auto operandNumber : successorOperandNumbers)
2008 branchOp.getSuccessorOperands(operandNumber).
append(args);
2011 if (
auto waitOp = dyn_cast<WaitOp>(predecessor->terminator)) {
2012 if (waitOp.getDest() == node->block)
2013 waitOp.getDestOperandsMutable().append(args);
2017 "mem2reg predecessor terminator has no successor operands");
2025void Promoter::replaceValueWith(Value oldValue, Value newValue) {
2026 oldValue.replaceAllUsesWith(newValue);
2027 for (
auto *def : lattice->defs) {
2028 if (def->value == oldValue)
2029 def->value = newValue;
2030 if (def->condition.isConditional() &&
2031 def->condition.getCondition() == oldValue)
2032 def->condition.setCondition(newValue);
2043void Promoter::removeUnusedLocalSignal(SignalOp signalOp) {
2047 SmallVector<Operation *> worklist;
2048 worklist.push_back(signalOp);
2049 while (!worklist.empty()) {
2050 auto *op = worklist.pop_back_val();
2051 if (!isa<SignalOp, DriveOp, SigArrayGetOp, SigArraySliceOp, SigExtractOp,
2052 SigStructExtractOp>(op))
2054 for (
auto *user : op->getUsers())
2055 if (users.insert(user))
2056 worklist.push_back(user);
2061 LLVM_DEBUG(llvm::dbgs() <<
"- Removing local signal " << *signalOp <<
"\n");
2062 for (
auto *op :
llvm::reverse(users))
2063 pruner.eraseNow(op);
2071struct Mem2RegPass :
public llhd::impl::Mem2RegPassBase<Mem2RegPass> {
2072 void runOnOperation()
override;
2076void Mem2RegPass::runOnOperation() {
2077 SmallVector<Region *> regions;
2078 getOperation()->walk<WalkOrder::PreOrder>([&](Operation *op) {
2079 if (isa<ProcessOp, FinalOp, CombinationalOp, CoroutineOp>(op)) {
2080 auto ®ion = op->getRegion(0);
2081 if (!region.empty())
2082 regions.push_back(®ion);
2083 return WalkResult::skip();
2085 return WalkResult::advance();
2087 for (
auto *region : regions)
2088 if (failed(Promoter(*region).promote()))
2089 return signalPassFailure();
static bool isAlways(Attribute attr, bool expected)
assert(baseType &&"element must be base type")
static void dump(DIModule &module, raw_indented_ostream &os)
static std::optional< unsigned > getPromotableSlotBitWidth(Type type)
static bool isDelayed(DefSlot slot)
static bool isZeroDelay(Value value)
Check whether a value is defined by llhd.constant_time <0ns, 0d, 0e>.
static bool isPromotableSlotType(Type type)
static Value packProjections(OpBuilder &builder, Value value, const ProjectionStack &projections)
Undo a stack of projections by taking the value of the projected field and injecting it into the surr...
static Location getLoc(DefSlot slot)
static bool isDeltaDrive(Operation *op)
Check whether an operation is a llhd.drive with a delta delay.
static ProjectionStack getProjections(Value fromSignal, Value toSlot)
Collect the llhd.sig.
static Value createZeroValue(OpBuilder &builder, Location loc, Type type)
static bool isDeltaDelay(Value value)
Check whether a value is defined by llhd.constant_time <0ns, 1d, 0e>.
static DefSlot blockingSlot(Value slot)
static Value unpackProjections(OpBuilder &builder, Value value, ProjectionStack &projections)
Resolve a stack of projections by taking a value and descending into its subelements until the final ...
static DefSlot delayedSlot(Value slot)
static Value getSlot(DefSlot slot)
SmallVector< Projection > ProjectionStack
A stack of projection operations.
static bool isBlockingDrive(Operation *op)
Check whether an operation is a llhd.drive with an epsilon delay.
static Type getStoredType(Value slot)
static bool isEpsilonDelay(Value value)
Check whether a value is defined by llhd.constant_time <0ns, 0d, 1e>.
PointerIntPair< Value, 1 > DefSlot
The slot a reaching definition specifies a value for, alongside a bit indicating whether the definiti...
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
static bool operator==(const ModulePort &a, const ModulePort &b)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
bool operator!=(uint64_t a, const FVInt &b)
Utility that tracks operations that have potentially become unused and allows them to be cleaned up a...
static bool isEqual(DriveCondition lhs, DriveCondition rhs)
static unsigned getHashValue(DriveCondition d)