@@ -486,17 +486,38 @@ FirRegLower::tryRestoringSubaccess(OpBuilder &builder, Value reg, Value term,
486486
487487void FirRegLower::createTree (OpBuilder &builder, Value reg, Value term,
488488 Value next) {
489- // If term and next values are equivalent, we don't have to create an
490- // assignment.
491- if (areEquivalentValues (term, next))
492- return ;
493- auto mux = next.getDefiningOp <comb::MuxOp>();
494- if (mux && mux.getTwoState ()) {
495- addToIfBlock (
496- builder, mux.getCond (),
497- [&]() { createTree (builder, reg, term, mux.getTrueValue ()); },
498- [&]() { createTree (builder, reg, term, mux.getFalseValue ()); });
499- } else {
489+
490+ SmallVector<std::tuple<Block *, Value, Value, Value>> worklist;
491+ auto addToWorklist = [&](Value reg, Value term, Value next) {
492+ worklist.push_back ({builder.getBlock (), reg, term, next});
493+ };
494+
495+ auto getArrayIndex = [&](Value reg, Value idx) {
496+ // Create an array index op just after `reg`.
497+ OpBuilder::InsertionGuard guard (builder);
498+ builder.setInsertionPointAfterValue (reg);
499+ return builder.create <sv::ArrayIndexInOutOp>(reg.getLoc (), reg, idx);
500+ };
501+
502+ SmallVector<Value, 8 > opsToDelete;
503+ addToWorklist (reg, term, next);
504+ while (!worklist.empty ()) {
505+ OpBuilder::InsertionGuard guard (builder);
506+ Block *block;
507+ Value reg, term, next;
508+ std::tie (block, reg, term, next) = worklist.pop_back_val ();
509+ builder.setInsertionPointToEnd (block);
510+ if (areEquivalentValues (term, next))
511+ continue ;
512+
513+ auto mux = next.getDefiningOp <comb::MuxOp>();
514+ if (mux && mux.getTwoState ()) {
515+ addToIfBlock (
516+ builder, mux.getCond (),
517+ [&]() { addToWorklist (reg, term, mux.getTrueValue ()); },
518+ [&]() { addToWorklist (reg, term, mux.getFalseValue ()); });
519+ continue ;
520+ }
500521 // If the next value is an array creation, split the value into
501522 // invidial elements and construct trees recursively.
502523 if (auto array = next.getDefiningOp <hw::ArrayCreateOp>()) {
@@ -508,54 +529,53 @@ void FirRegLower::createTree(OpBuilder &builder, Value reg, Value term,
508529 addToIfBlock (
509530 builder, cond,
510531 [&]() {
511- Value nextReg;
512- {
513- // Create an array index op just after `reg`.
514- OpBuilder::InsertionGuard guard (builder);
515- builder.setInsertionPointAfterValue (reg);
516- nextReg = builder.create <sv::ArrayIndexInOutOp>(reg.getLoc (),
517- reg, index);
518- }
532+ Value nextReg = getArrayIndex (reg, index);
533+ // Create a value to use for equivalence checking in the
534+ // recursive calls. Add the value to `opsToDelete` so that it can
535+ // be deleted afterwards.
519536 auto termElement =
520537 builder.create <hw::ArrayGetOp>(term.getLoc (), term, index);
521- createTree (builder, nextReg, termElement, trueValue );
522- termElement. erase ( );
538+ opsToDelete. push_back ( termElement);
539+ addToWorklist (nextReg, termElement, trueValue );
523540 },
524541 []() {});
525542 ++numSubaccessRestored;
526- return ;
543+ continue ;
527544 }
528545 // Compat fix for GCC12's libstdc++, cannot use
529546 // llvm::enumerate(llvm::reverse(OperandRange)). See #4900.
530- SmallVector<Value> reverseOpValues (llvm::reverse (array.getOperands ()));
531- for (auto [idx, value] : llvm::enumerate (reverseOpValues )) {
532-
547+ // SmallVector<Value> reverseOpValues(llvm::reverse(array.getOperands()));
548+ for (auto [idx, value] : llvm::enumerate (array. getOperands () )) {
549+ idx = array. getOperands (). size () - idx - 1 ;
533550 // Create an index constant.
534551 auto idxVal = getOrCreateConstant (
535552 array.getLoc (),
536553 APInt (std::max (1u , llvm::Log2_64_Ceil (array.getOperands ().size ())),
537554 idx));
538555
539556 auto &index = arrayIndexCache[{reg, idx}];
540- if (!index) {
541- // Create an array index op just after `reg`.
542- OpBuilder::InsertionGuard guard (builder);
543- builder.setInsertionPointAfterValue (reg);
544- index =
545- builder.create <sv::ArrayIndexInOutOp>(reg.getLoc (), reg, idxVal);
546- }
557+ if (!index)
558+ index = getArrayIndex (reg, idxVal);
547559
560+ // Create a value to use for equivalence checking in the
561+ // recursive calls. Add the value to `opsToDelete` so that it can
562+ // be deleted afterwards.
548563 auto termElement =
549564 builder.create <hw::ArrayGetOp>(term.getLoc (), term, idxVal);
550- createTree (builder, index, termElement, value);
551- // This value was used to check the equivalence of elements so useless
552- // anymore.
553- termElement.erase ();
565+ opsToDelete.push_back (termElement);
566+ addToWorklist (index, termElement, value);
554567 }
555- return ;
568+ continue ;
556569 }
570+
557571 builder.create <sv::PAssignOp>(term.getLoc (), reg, next);
558572 }
573+
574+ while (!opsToDelete.empty ()) {
575+ auto value = opsToDelete.pop_back_val ();
576+ assert (value.use_empty ());
577+ value.getDefiningOp ()->erase ();
578+ }
559579}
560580
561581FirRegLower::RegLowerInfo FirRegLower::lower (FirRegOp reg) {
0 commit comments