658 Location loc = forOp.getLoc();
660 !FinalClass::getConstantNumberOfIterations(forOp).has_value();
663 OpBuilder builder(newForOp);
664 Type idxTy = FinalClass::getIndexLikeType(builder);
666 Value c0 = FinalClass::emitConst(builder, loc, 0);
667 Value c1 = FinalClass::emitConst(builder, loc, 1);
671 Value numItersV, startV, stepV;
673 startV = FinalClass::materializeLowerBound(builder, loc, forOp, gutils);
674 stepV = FinalClass::materializeStep(builder, loc, forOp, gutils);
676 FinalClass::getNumIterationsValue(builder, loc, forOp, gutils);
677 numItersV = FinalClass::castToType(builder, loc, numItersV, idxTy);
680 FinalClass::getConstantNumberOfIterations(forOp).value();
681 numItersV = FinalClass::emitConst(builder, loc, numIters);
682 startV = FinalClass::emitConst(builder, loc,
683 FinalClass::getConstantStart(forOp));
684 stepV = FinalClass::emitConst(builder, loc,
685 FinalClass::getConstantStep(forOp));
697 Value budgetV = FinalClass::emitMin(
698 builder, loc, FinalClass::emitConst(builder, loc, budget), numItersV);
700 SmallVector<Value> immutableRefs, mutableRefs;
701 FinalClass::splitOutsideRefs(forOp, mutableRefs, immutableRefs);
706 SmallVector<Value> caches;
711 size_t numIterArgs = FinalClass::getNumRegionIterArgs(forOp);
712 SmallVector<Value> stores;
713 for (
auto arg : FinalClass::getInits(newForOp))
715 FinalClass::createStore(builder, loc, budget, arg.getType()));
716 stores.push_back(FinalClass::createStore(builder, loc, budget, idxTy));
717 const size_t idxStore = stores.size() - 1;
718 const bool carriedStores = FinalClass::storesAreLoopCarried();
725 SmallVector<Value> mutBufs;
726 for (
auto ref : mutableRefs) {
727 auto iface = cast<ClonableTypeInterface>(ref.getType());
730 mutBufs.push_back(buf);
735 SmallVector<Value> outerInit;
736 outerInit.push_back(c0);
737 auto newForOpInits = FinalClass::getInits(newForOp);
738 outerInit.append(newForOpInits.begin(), newForOpInits.end());
740 outerInit.append(stores.begin(), stores.end());
741 auto outerFwd = FinalClass::createScaffoldForLoop(builder, loc, c0, budgetV,
743 FinalClass::preserveAttributesButCheckpointing(outerFwd.op, forOp);
745 builder.setInsertionPointToStart(outerFwd.body);
746 Value k = outerFwd.getIV();
747 auto outerArgs = outerFwd.args();
748 Value stepCtr = outerArgs[0];
749 auto state = outerArgs.slice(1, numIterArgs);
753 SmallVector<Value> liveStores(stores);
755 for (
auto &&[i, arg] :
756 llvm::enumerate(outerArgs.slice(1 + numIterArgs, stores.size())))
759 for (
auto &&[i, val] : llvm::enumerate(state))
761 FinalClass::storeSlot(builder, loc, liveStores[i], k, val);
762 liveStores[idxStore] =
763 FinalClass::storeSlot(builder, loc, liveStores[idxStore], k, stepCtr);
765 Value numStepsRem = FinalClass::emitSub(builder, loc, numItersV, stepCtr);
766 Value budgetRem = FinalClass::emitSub(builder, loc, budgetV, k);
769 budgetRem = FinalClass::emitMin(builder, loc, budgetRem, numStepsRem);
770 Value split = enzyme::BinomialProgressOp::create(builder, loc, idxTy,
771 numStepsRem, budgetRem);
776 for (
auto &&[ref, buf] : llvm::zip_equal(mutableRefs, mutBufs)) {
777 auto iface = cast<ClonableTypeInterface>(ref.getType());
778 iface.copyValue(builder,
785 auto innerFwd = FinalClass::createScaffoldForLoop(
786 builder, loc, c0, split, c1,
787 SmallVector<Value>(state.begin(), state.end()));
788 FinalClass::preserveAttributesButCheckpointing(innerFwd.op, forOp);
790 builder.setInsertionPointToStart(innerFwd.body);
791 Value i = innerFwd.getIV();
792 Value globalStep = FinalClass::emitAdd(builder, loc, stepCtr, i);
794 FinalClass::castToType(builder, loc, globalStep, stepV.getType());
795 Value iv = FinalClass::emitAdd(
796 builder, loc, startV,
797 FinalClass::emitMul(builder, loc, stepV, globalStep));
799 Block *newForOpBody = FinalClass::getBodyBlock(newForOp);
800 for (
auto &&[oldArg, newArg] : llvm::zip_equal(
801 newForOpBody->getArguments().drop_front(), innerFwd.args()))
802 mapping.map(oldArg, newArg);
803 mapping.map(FinalClass::getInductionVar(newForOp), iv);
807 SmallVector<Value> innerYields;
808 for (
auto operand : FinalClass::getCarriedTerminatorOperands(
809 newForOpBody->getTerminator()))
810 innerYields.push_back(mapping.lookupOrDefault(operand));
811 FinalClass::finalizeScaffoldLoop(builder, loc, innerFwd, innerYields);
813 FinalClass::setInsertionPointToBodyEnd(builder, outerFwd.body);
814 SmallVector<Value> outerYields;
815 outerYields.push_back(FinalClass::emitAdd(builder, loc, stepCtr, split));
816 auto innerResults = innerFwd.results();
817 outerYields.append(innerResults.begin(), innerResults.end());
819 outerYields.append(liveStores.begin(), liveStores.end());
820 FinalClass::finalizeScaffoldLoop(builder, loc, outerFwd, outerYields);
822 builder.setInsertionPointAfter(outerFwd.op);
826 auto outerResults = outerFwd.results();
827 SmallVector<Value> finalStores(stores);
829 for (
auto &&[i, res] :
830 llvm::enumerate(outerResults.slice(1 + numIterArgs, stores.size())))
831 finalStores[i] = res;
834 for (
auto store : finalStores)
840 for (
auto &&[r, ref] : llvm::enumerate(mutableRefs)) {
842 if (layout.mutableActive[r])
847 for (
auto ref : immutableRefs)
859 assert(caches.size() == layout.size() &&
"binomial cache layout mismatch");
863 forOp, FinalClass::getPrimalResults(builder, loc, forOp,
864 outerResults.slice(1, numIterArgs),
866 gutils->
erase(newForOp);
898 SmallVector<Value> caches,
899 ArrayRef<bool> operandsActive,
900 ArrayRef<Value> incomingGradients) {
901 Location loc = forOp.getLoc();
903 !FinalClass::getConstantNumberOfIterations(forOp).has_value();
904 auto numIterArgs = FinalClass::getNumRegionIterArgs(forOp);
906 SmallVector<Value> immutableRefs, mutableRefs;
907 FinalClass::splitOutsideRefs(forOp, mutableRefs, immutableRefs);
910 assert(caches.size() == layout.size() &&
"binomial cache layout mismatch");
918 SmallVector<std::pair<Value, Value>> savedMutableShadows;
919 for (
auto ref : mutableRefs)
920 savedMutableShadows.emplace_back(
922 auto restoreMutableShadows = llvm::scope_exit([&]() {
923 for (
auto &[ref, prev] : savedMutableShadows) {
933 SmallVector<Value> stores;
934 for (
size_t j = 0; j < numIterArgs; ++j)
935 stores.push_back(gutils->
popCache(caches[layout.ckptBuf(j)], builder));
936 stores.push_back(gutils->
popCache(caches[layout.idxBuf()], builder));
937 const size_t idxStore = stores.size() - 1;
938 const bool carriedStores = FinalClass::storesAreLoopCarried();
940 SmallVector<Value> immutableRefsCaches;
941 for (
auto &&[i, ref] : llvm::enumerate(immutableRefs)) {
942 Value
cached = gutils->
popCache(caches[layout.immutable(i)], builder);
944 immutableRefsCaches.push_back(
cached);
947 Value c0 = FinalClass::emitConst(builder, loc, 0);
948 Value c1 = FinalClass::emitConst(builder, loc, 1);
953 Value numItersV, startV, stepV;
955 numItersV = gutils->
popCache(caches[layout.numIters()], builder);
956 startV = gutils->
popCache(caches[layout.start()], builder);
957 stepV = gutils->
popCache(caches[layout.step()], builder);
960 FinalClass::getConstantNumberOfIterations(forOp).value();
961 numItersV = FinalClass::emitConst(builder, loc, numIters);
962 startV = FinalClass::emitConst(builder, loc,
963 FinalClass::getConstantStart(forOp));
964 stepV = FinalClass::emitConst(builder, loc,
965 FinalClass::getConstantStep(forOp));
970 Value budgetV = FinalClass::emitMin(
971 builder, loc, FinalClass::emitConst(builder, loc, budget), numItersV);
978 SmallVector<Value> mutBufs, workClones;
979 for (
auto &&[r, ref] : llvm::enumerate(mutableRefs)) {
980 auto iface = cast<ClonableTypeInterface>(ref.getType());
981 mutBufs.push_back(gutils->
popCache(caches[layout.cloneBuf(r)], builder));
982 workClones.push_back(
984 mapping.map(ref, workClones.back());
985 if (layout.mutableActive[r])
987 ref, gutils->
popCache(caches[layout.shadow(r)], builder));
991 SmallVector<Value> outerInit;
992 outerInit.push_back(budgetV);
993 outerInit.append(incomingGradients.begin(), incomingGradients.end());
995 outerInit.append(stores.begin(), stores.end());
997 auto revOuter = FinalClass::createScaffoldForLoop(builder, loc, c0,
998 numItersV, c1, outerInit);
999 FinalClass::preserveAttributesButCheckpointing(revOuter.op, forOp);
1001 OpBuilder::InsertionGuard guard(builder);
1002 builder.setInsertionPointToStart(revOuter.body);
1004 Value ivO = revOuter.getIV();
1005 auto revOuterArgs = revOuter.args();
1006 Value sp = revOuterArgs[0];
1007 auto adjArgs = revOuterArgs.slice(1, incomingGradients.size());
1009 SmallVector<Value> liveStores(stores);
1011 for (
auto &&[i, arg] : llvm::enumerate(
1012 revOuterArgs.slice(1 + incomingGradients.size(), stores.size())))
1013 liveStores[i] = arg;
1015 Value capo = FinalClass::emitSub(builder, loc, sp, c1);
1016 Value currentRevStep = FinalClass::emitSub(builder, loc, numItersV, ivO);
1019 SmallVector<Value> ckptState;
1020 for (
auto &&[store, arg] : llvm::zip_equal(
1021 ArrayRef<Value>(liveStores).drop_back(),
1022 FinalClass::getBodyBlock(forOp)->getArguments().drop_front()))
1023 ckptState.push_back(
1024 FinalClass::loadSlot(builder, loc, store, capo, arg.getType()));
1026 FinalClass::loadSlot(builder, loc, liveStores[idxStore], capo,
1027 FinalClass::getIndexLikeType(builder));
1032 for (
auto &&[r, ref] : llvm::enumerate(mutableRefs)) {
1033 auto iface = cast<ClonableTypeInterface>(ref.getType());
1034 iface.copyValue(builder, workClones[r],
1036 mutBufs[r], capo, budget));
1041 SmallVector<Value> whileInit;
1042 whileInit.push_back(ckptStep);
1043 whileInit.push_back(capo);
1044 whileInit.append(ckptState.begin(), ckptState.end());
1046 whileInit.append(liveStores.begin(), liveStores.end());
1048 auto revWhile = FinalClass::createScaffoldWhileLoop(
1049 builder, loc, whileInit,
1050 [&](OpBuilder &b, Location l, ValueRange args) {
1051 Value posPlus1 = FinalClass::emitAdd(b, l, args[0], c1);
1052 return FinalClass::emitCmpLT(b, l, posPlus1, currentRevStep);
1055 FinalClass::setInsertionPointToBodyEnd(builder, revWhile.body);
1056 auto wargs = revWhile.args();
1057 Value pos = wargs[0];
1058 Value acapo = wargs[1];
1059 auto astate = wargs.slice(2, numIterArgs);
1061 SmallVector<Value> wStores(liveStores);
1063 for (
auto &&[i, arg] :
1064 llvm::enumerate(wargs.slice(2 + numIterArgs, stores.size())))
1067 Value remaining = FinalClass::emitSub(builder, loc, currentRevStep, pos);
1068 Value budgetRem = FinalClass::emitSub(builder, loc, budgetV, acapo);
1071 budgetRem = FinalClass::emitMin(builder, loc, budgetRem, remaining);
1072 Value split = enzyme::BinomialProgressOp::create(
1073 builder, loc, FinalClass::getIndexLikeType(builder), remaining,
1081 for (
auto &&[i, val] : llvm::enumerate(astate))
1083 FinalClass::storeSlot(builder, loc, wStores[i], acapo, val);
1085 FinalClass::storeSlot(builder, loc, wStores[idxStore], acapo, pos);
1087 for (
auto &&[r, ref] : llvm::enumerate(mutableRefs)) {
1088 auto iface = cast<ClonableTypeInterface>(ref.getType());
1089 iface.copyValue(builder,
1091 mutBufs[r], acapo, budget),
1095 Value posPlusSplit = FinalClass::emitAdd(builder, loc, pos, split);
1097 FinalClass::emitCmpEQ(builder, loc, posPlusSplit, currentRevStep);
1098 Value rematUB = FinalClass::emitSelect(
1099 builder, loc, isLast,
1100 FinalClass::emitSub(builder, loc, posPlusSplit, c1), posPlusSplit);
1103 auto innerRemat = FinalClass::createScaffoldForLoop(
1104 builder, loc, pos, rematUB, c1,
1105 SmallVector<Value>(astate.begin(), astate.end()));
1106 FinalClass::preserveAttributesButCheckpointing(innerRemat.op, forOp);
1109 OpBuilder::InsertionGuard g2(builder);
1110 builder.setInsertionPointToStart(innerRemat.body);
1111 Value idx = FinalClass::castToType(builder, loc, innerRemat.getIV(),
1114 FinalClass::emitAdd(builder, loc, startV,
1115 FinalClass::emitMul(builder, loc, stepV, idx));
1117 Block *origBodyBlock = FinalClass::getBodyBlock(forOp);
1118 for (
auto &&[oldArg, newArg] : llvm::zip_equal(
1119 origBodyBlock->getArguments().drop_front(), innerRemat.args()))
1120 mapping.map(oldArg, newArg);
1121 mapping.map(FinalClass::getInductionVar(forOp), iv);
1125 SmallVector<Value> yields;
1126 for (
auto operand : FinalClass::getCarriedTerminatorOperands(
1127 origBodyBlock->getTerminator()))
1128 yields.push_back(mapping.lookupOrDefault(operand));
1129 FinalClass::finalizeScaffoldLoop(builder, loc, innerRemat, yields);
1132 Value newCapo = FinalClass::emitAdd(builder, loc, acapo, c1);
1133 SmallVector<Value> afterYields;
1134 afterYields.push_back(posPlusSplit);
1135 afterYields.push_back(newCapo);
1136 auto rematResults = innerRemat.results();
1137 afterYields.append(rematResults.begin(), rematResults.end());
1139 afterYields.append(wStores.begin(), wStores.end());
1140 FinalClass::finalizeScaffoldLoop(builder, loc, revWhile, afterYields);
1143 FinalClass::setInsertionPointToBodyEnd(builder, revOuter.body);
1144 auto whileResults = revWhile.results();
1145 Value newSp = whileResults[1];
1146 auto reconState = whileResults.slice(2, numIterArgs);
1148 for (
auto &&[i, res] :
1149 llvm::enumerate(whileResults.slice(2 + numIterArgs, stores.size())))
1150 liveStores[i] = res;
1153 Value stepAdj = FinalClass::emitSub(builder, loc, currentRevStep, c1);
1155 FinalClass::castToType(builder, loc, stepAdj, stepV.getType());
1157 FinalClass::emitAdd(builder, loc, startV,
1158 FinalClass::emitMul(builder, loc, stepV, stepAdjC));
1160 mapping = IRMapping();
1162 for (
auto [ref,
cached] :
1163 llvm::zip_equal(immutableRefs, immutableRefsCaches))
1164 mapping.map(ref,
cached);
1168 for (
auto &&[r, ref] : llvm::enumerate(mutableRefs))
1169 mapping.map(ref, workClones[r]);
1171 for (
auto &&[oldArg, newArg] : llvm::zip_equal(
1172 FinalClass::getBodyBlock(forOp)->getArguments().drop_front(),
1174 mapping.map(oldArg, newArg);
1175 mapping.map(FinalClass::getInductionVar(forOp), ivAdj);
1191 SmallVector<Value> reseededShadowKeys;
1193 OpBuilder::InsertionGuard g4(builder);
1194 FinalClass::getBodyBlock(forOp)->walk([&](Operation *inner) {
1195 for (Value res : inner->getResults()) {
1199 auto iface = dyn_cast<AutoDiffTypeInterface>(shadowTy);
1200 if (!iface || !iface.isMutable())
1202 Value newRes = mapping.lookupOrNull(res);
1205 if (Operation *defOp = newRes.getDefiningOp())
1206 builder.setInsertionPointAfter(defOp);
1210 enzyme::PlaceholderOp::create(builder, res.getLoc(), shadowTy);
1212 reseededShadowKeys.push_back(res);
1224 auto term = FinalClass::getBodyBlock(forOp)->getTerminator();
1225 FinalClass::primeStepGradients(builder, gutils,
1226 FinalClass::getBodyBlock(forOp),
1227 revOuter.body, operandsActive);
1231 unsigned revIdx = 0;
1232 for (
auto &&[active, operand] : llvm::zip_equal(
1233 operandsActive, FinalClass::getCarriedTerminatorOperands(term))) {
1235 gutils->
addToDiffe(operand, adjArgs[revIdx], builder);
1241 auto first = FinalClass::getBodyBlock(forOp)->rbegin();
1243 auto last = FinalClass::getBodyBlock(forOp)->rend();
1248 for (
auto it = first; it != last; ++it)
1260 for (Value orig : reseededShadowKeys) {
1264 auto ph = cur.getDefiningOp<enzyme::PlaceholderOp>();
1265 if (ph && ph->use_empty()) {
1271 SmallVector<Value> newAdjoints;
1272 for (
auto &&[active, arg] : llvm::zip_equal(
1274 FinalClass::getBodyBlock(forOp)->getArguments().drop_front())) {
1276 newAdjoints.push_back(gutils->
diffe(arg, builder));
1282 SmallVector<Value> outerYields;
1283 outerYields.push_back(newSp);
1284 outerYields.append(newAdjoints.begin(), newAdjoints.end());
1286 outerYields.append(liveStores.begin(), liveStores.end());
1287 FinalClass::finalizeScaffoldLoop(builder, loc, revOuter, outerYields);
1289 builder.setInsertionPointAfter(revOuter.op);
1292 auto revOuterResults = revOuter.results();
1293 auto forOpInits = FinalClass::getInits(forOp);
1294 for (
auto &&[active, arg] : llvm::zip_equal(operandsActive, forOpInits)) {
1297 gutils->
addToDiffe(arg, revOuterResults[revIdx + 1], builder);
1304 for (
auto store : stores)
1305 FinalClass::destroyStore(builder, loc, store);
1306 for (
auto &&[r, ref] : llvm::enumerate(mutableRefs)) {
1307 auto iface = cast<ClonableTypeInterface>(ref.getType());
1308 iface.freeClonedValue(builder, workClones[r]);
1312 return success(valid);
1528 OpBuilder cacheBuilder(newOpBase);
1529 Location loc = forOp.getLoc();
1532 if (!FinalClass::getConstantNumberOfIterations(forOp).has_value())
1535 FinalClass::materializeSegmentValues(cacheBuilder, loc, sched);
1537 SmallVector<Value> immutableRefs, mutableRefs;
1538 FinalClass::splitOutsideRefs(forOp, mutableRefs, immutableRefs);
1540 SmallVector<Value> caches;
1542 OpName newForOp = cast<OpName>(newOpBase);
1544 auto newForOpInits = FinalClass::getInits(newForOp);
1545 auto outerFwd = FinalClass::createForwardOuterLoop(cacheBuilder, loc, sched,
1547 FinalClass::preserveAttributesButCheckpointing(outerFwd, forOp);
1549 Block *outerFwdBody = FinalClass::getBodyBlock(outerFwd);
1550 cacheBuilder.setInsertionPointToStart(outerFwdBody);
1556 Value outerFwdIV = FinalClass::getInductionVar(outerFwd);
1564 SmallVector<Value> fwdHint = FinalClass::computeForwardSegmentHint(
1565 cacheBuilder, loc, outerFwdIV, sched);
1567 SmallVector<Value> mutableRefsCaches;
1568 for (
auto ref : mutableRefs) {
1569 auto iface = cast<ClonableTypeInterface>(ref.getType());
1572 mutableRefsCaches.push_back(
1576 auto innerFwd = FinalClass::createForwardSegmentLoop(
1577 cacheBuilder, loc, outerFwdIV, fwdHint, sched,
1578 outerFwdBody->getArguments().drop_front());
1579 FinalClass::preserveAttributesButCheckpointing(innerFwd, forOp);
1581 Block *innerFwdBody = FinalClass::getBodyBlock(innerFwd);
1582 FinalClass::setInsertionPointToBodyEnd(cacheBuilder, innerFwdBody);
1584 Value currentIV = FinalClass::computeForwardSegmentIV(
1585 cacheBuilder, loc, forOp, outerFwdIV,
1586 FinalClass::getInductionVar(innerFwd), sched, fwdHint);
1588 Block *newForOpBody = FinalClass::getBodyBlock(newForOp);
1589 for (
auto [oldArg, newArg] : llvm::zip_equal(newForOpBody->getArguments(),
1590 innerFwdBody->getArguments()))
1591 mapping.map(oldArg, newArg);
1593 mapping.map(FinalClass::getInductionVar(newForOp), currentIV);
1597 Operation *fwdTerm = newForOpBody->getTerminator();
1598 SmallVector<Value> fwdYields;
1599 for (
auto operand : FinalClass::getCarriedTerminatorOperands(fwdTerm))
1600 fwdYields.push_back(mapping.lookupOrDefault(operand));
1601 FinalClass::createScaffoldYield(cacheBuilder, fwdTerm->getLoc(), fwdYields);
1603 FinalClass::setInsertionPointToBodyEnd(cacheBuilder, outerFwdBody);
1604 for (
auto initArg : FinalClass::getInits(innerFwd))
1607 FinalClass::createScaffoldYield(
1609 FinalClass::getBodyBlock(forOp)->getTerminator()->getLoc(),
1610 FinalClass::getCarriedResults(innerFwd));
1612 cacheBuilder.setInsertionPointAfter(outerFwd);
1614 caches.append(mutableRefsCaches);
1616 for (
auto ref : immutableRefs)
1629 cacheBuilder, loc, forOp,
1630 FinalClass::getCarriedResults(outerFwd),
1633 gutils->
erase(newForOp);
1649 SmallVector<Value> caches,
1650 ArrayRef<bool> operandsActive,
1651 ArrayRef<Value> incomingGradients) {
1652 auto numIterArgs = FinalClass::getNumRegionIterArgs(forOp);
1653 Location loc = forOp.getLoc();
1657 SmallVector<Value> immutableRefs, mutableRefs;
1658 FinalClass::splitOutsideRefs(forOp, mutableRefs, immutableRefs);
1662 assert(caches.size() ==
1663 numIterArgs + mutableRefs.size() + immutableRefs.size() +
1664 (FinalClass::getConstantNumberOfIterations(forOp) ? 0 : 3) &&
1665 "periodic cache layout mismatch");
1667 for (
auto [i, ref] : llvm::enumerate(immutableRefs)) {
1669 caches[numIterArgs + mutableRefs.size() + i], builder);
1670 mapping.map(ref, refVal);
1676 if (!FinalClass::getConstantNumberOfIterations(forOp).has_value()) {
1677 size_t base = numIterArgs + mutableRefs.size() + immutableRefs.size();
1682 FinalClass::materializeSegmentValues(builder, loc, sched);
1684 auto revOuter = FinalClass::createReverseOuterLoop(builder, loc, sched,
1686 FinalClass::preserveAttributesButCheckpointing(revOuter, forOp);
1688 OpBuilder::InsertionGuard guard(builder);
1689 Block *revOuterBody = FinalClass::getBodyBlock(revOuter);
1693 Value revOuterIV = FinalClass::getInductionVar(revOuter);
1694 FinalClass::setInsertionPointToBodyEnd(builder, revOuterBody);
1696 SmallVector<Value> cachedOutsideRefs;
1697 for (
auto [i, ref] : llvm::enumerate(mutableRefs)) {
1698 Value refVal = gutils->
popCache(caches[numIterArgs + i], builder);
1699 cachedOutsideRefs.push_back(refVal);
1700 mapping.map(ref, refVal);
1708 SmallVector<Value> revHint =
1709 FinalClass::computeReverseSegmentHint(builder, loc, revOuterIV, sched);
1711 SmallVector<Value> initArgs(numIterArgs,
nullptr);
1712 for (
size_t i = 0; i < numIterArgs; ++i) {
1713 initArgs[i] = gutils->
popCache(caches[i], builder);
1716 auto revInner = FinalClass::createReverseSegmentLoop(
1717 builder, loc, revOuterIV, revHint, sched, initArgs);
1718 FinalClass::preserveAttributesButCheckpointing(revInner, forOp);
1720 Block *revInnerBody = FinalClass::getBodyBlock(revInner);
1721 FinalClass::setInsertionPointToBodyEnd(builder, revInnerBody);
1723 Value currentIV = FinalClass::computeReverseSegmentIV(
1724 builder, loc, forOp, revOuterIV, FinalClass::getInductionVar(revInner),
1727 Block *origBodyBlock = FinalClass::getBodyBlock(forOp);
1728 for (
auto [oldArg, newArg] : llvm::zip_equal(origBodyBlock->getArguments(),
1729 revInnerBody->getArguments()))
1730 mapping.map(oldArg, newArg);
1732 mapping.map(FinalClass::getInductionVar(forOp), currentIV);
1735 Operation *segTerm = origBodyBlock->getTerminator();
1736 SmallVector<Value> segYields;
1737 for (
auto operand : FinalClass::getCarriedTerminatorOperands(segTerm))
1738 segYields.push_back(mapping.lookupOrDefault(operand));
1739 FinalClass::createScaffoldYield(builder, segTerm->getLoc(), segYields);
1741 FinalClass::setInsertionPointToBodyEnd(builder, revOuterBody);
1743 for (
auto outsideRef : cachedOutsideRefs) {
1744 if (
auto cachableT =
1745 dyn_cast<ClonableTypeInterface>(outsideRef.getType())) {
1746 cachableT.freeClonedValue(builder, outsideRef);
1750 auto revLoop = FinalClass::createLoopWithSameBounds(
1751 builder, loc, revInner, revOuterBody->getArguments().drop_front());
1752 FinalClass::preserveAttributesButCheckpointing(revLoop, forOp);
1754 Block *revLoopBody = FinalClass::getBodyBlock(revLoop);
1755 Block *origBody = origBodyBlock;
1757 FinalClass::primeSegmentGradients(builder, gutils, origBody, revLoopBody,
1760 FinalClass::setInsertionPointToBodyEnd(builder, revLoopBody);
1762 for (
auto &&[active, operand] : llvm::zip_equal(
1763 operandsActive, FinalClass::getCarriedTerminatorOperands(
1764 origBody->getTerminator()))) {
1766 gutils->
addToDiffe(operand, revLoopBody->getArgument(revIdx), builder);
1773 auto first = origBody->rbegin();
1776 auto last = origBody->rend();
1783 for (
auto it = first; it != last; ++it) {
1784 Operation *o = &*it;
1789 SmallVector<Value> newResults;
1790 for (
auto &&[active, arg] : llvm::zip_equal(
1791 operandsActive, origBody->getArguments().drop_front())) {
1793 newResults.push_back(gutils->
diffe(arg, builder));
1799 FinalClass::setInsertionPointToBodyEnd(builder, revLoopBody);
1800 FinalClass::createScaffoldYield(
1801 builder, origBody->getTerminator()->getLoc(), newResults);
1803 FinalClass::setInsertionPointToBodyEnd(builder, revOuterBody);
1804 FinalClass::createScaffoldYield(builder,
1805 origBody->getTerminator()->getLoc(),
1806 FinalClass::getCarriedResults(revLoop));
1808 builder.setInsertionPointAfter(revOuter);
1811 auto revOuterResults = FinalClass::getCarriedResults(revOuter);
1812 auto forOpInits = FinalClass::getInits(forOp);
1813 for (
auto &&[active, arg] : llvm::zip_equal(operandsActive, forOpInits)) {
1816 gutils->
addToDiffe(arg, revOuterResults[revIdx], builder);
1822 return success(valid);