void LoopNestVisitor::GenerateLoopsOld()

in libraries/value/src/loopnests/LoopNestVisitor.cpp [207:355]


        void LoopNestVisitor::GenerateLoopsOld(const RecursionState& state, const LoopVisitSchedule& schedule) const
        {
            // Loop-unswitching / duplicating rules:
            //
            // Need to duplicate the outermost loop involving an index used to compute the constraint index
            // Only the innermost loop involving an index used to compute the constraint index needs to start from `1` for the body case
            // If all the loops with indices used to compute the constraint index are contiguous, and the kernel is run in the innermost of these loops,
            //   then we can omit the 'body' from the prologue (/epilogue) fragment, and allow the body loop to start from `0`
            //   (really, we can have the prologue (/epilogue) fragment contain only the constrained kernel)

            if (schedule.IsDone())
            {
                return;
            }

            // We're descending into the heart of the loop

            // If the index we're looping over in this loop has any prologue / epilogue kernels, we have to (potentially) break up the range
            // into prologue / body / epilogue sections
            auto currentDimension = schedule.CurrentDimension();

            // Find the active range for the current loop dimension and reduce our end amount if it exceeds the active range (boundary case)
            auto activeRangeIt = state.activeDimensionRanges.find(currentDimension);
            auto loopRange = schedule.LoopRange();
            int begin = loopRange.Begin();
            int end = loopRange.End();
            int increment = schedule.LoopIncrement();
            if (activeRangeIt != state.activeDimensionRanges.end())
            {
                auto activeRange = activeRangeIt->second;
                if (end > activeRange.End())
                {
                    end = activeRange.End();
                    loopRange = Range{ begin, end, increment };
                }
            }

            int nonBoundaryEnd = GetMainBodyLoopEnd(state, schedule, loopRange);

            // These mean "split current loop for this fragment type"
            auto currentLoopHasPrologue = schedule.CurrentLoopHasFragment(state.activeKernels, LoopFragmentType::prologue);
            auto currentLoopHasEpilogue = schedule.CurrentLoopHasFragment(state.activeKernels, LoopFragmentType::epilogue);

            // check if we need to emit an epilogue section to handle the end boundary for this loop
            auto currentLoopHasEndBoundary = schedule.CurrentIndexEndBoundarySize() != 0;

            auto futureLoopHasPrologue = schedule.FutureLoopHasFragmentForThisIndex(state.activeKernels, LoopFragmentType::prologue);
            auto futureLoopHasEpilogue = schedule.FutureLoopHasFragmentForThisIndex(state.activeKernels, LoopFragmentType::epilogue);

            LoopFragmentFlags bodyFlags = state.currentFragment;
            bodyFlags.SetFlag(LoopFragmentType::boundary, false);

            bool bodyInPrologue = !schedule.FragmentCanRunAlone(state.activeKernels, LoopFragmentType::prologue);
            bool bodyInEpilogue = !schedule.FragmentCanRunAlone(state.activeKernels, LoopFragmentType::epilogue);

            bool generatePrologueFragment = currentLoopHasPrologue || futureLoopHasPrologue;
            bool generateEpilogueFragment = currentLoopHasEpilogue || futureLoopHasEpilogue;

            std::vector<LoopRange> ranges;
            auto prologueBegin = begin;
            auto prologueEnd = begin + increment;

            if (generatePrologueFragment)
            {
                if (bodyInPrologue)
                {
                    begin += increment;
                }
                else
                {
                    bodyFlags.SetFlag(LoopFragmentType::prologue, false);
                }
            }

            // adjust loop boundary to unswitch last loop iteration if we have an epilogue kernel
            auto epilogueBegin = end - increment;
            auto epilogueEnd = end;
            if (generateEpilogueFragment)
            {
                if (bodyInEpilogue)
                {
                    if (currentLoopHasEndBoundary)
                    {
                        epilogueBegin = nonBoundaryEnd;
                    }
                    else
                    {
                        end -= increment;
                        nonBoundaryEnd -= increment;
                    }
                }
                else
                {
                    bodyFlags.SetFlag(LoopFragmentType::epilogue, false);
                }
            }

            // Add prologue section
            if (generatePrologueFragment)
            {
                LoopFragmentFlags flags = bodyInPrologue ? LoopFragmentType::prologue | LoopFragmentType::body : LoopFragmentType::prologue;
                ranges.push_back({ prologueBegin, prologueEnd, increment, flags, LoopFragmentType::prologue });
            }

            // Add main body section
            if (nonBoundaryEnd > begin)
            {
                ranges.push_back({ begin, nonBoundaryEnd, increment, bodyFlags, LoopFragmentType::body });
            }

            // Add boundary case (unless epilogue case already handles it)
            if (currentLoopHasEndBoundary && !(generateEpilogueFragment && bodyInEpilogue) && (end - nonBoundaryEnd > 0))
            {
                ranges.push_back({ nonBoundaryEnd, end, increment, bodyFlags | LoopFragmentType::boundary, LoopFragmentType::body });
            }

            // Add epilogue case
            if (generateEpilogueFragment)
            {
                LoopFragmentFlags flags = bodyInEpilogue ? LoopFragmentType::epilogue | LoopFragmentType::body : LoopFragmentType::epilogue;
                if (currentLoopHasEndBoundary)
                {
                    flags.SetFlag(LoopFragmentType::boundary, true);
                }
                ranges.push_back({ epilogueBegin, epilogueEnd, increment, flags, LoopFragmentType::epilogue });
            }

            for (auto r : ranges)
            {
                std::function<void(Scalar)> codegenFn = GetCodegenFnOld(r, state, schedule);
                const int startInt = r.start.Get<int>();
                const int stopInt = r.stop.Get<int>();
                const int stepInt = r.step.Get<int>();
                auto numIterations = CeilDiv(stopInt - startInt, stepInt);

                if (numIterations == 0)
                {
                    // throw?
                }
                else if (numIterations == 1)
                {
                    codegenFn(r.start);
                }
                else
                {
                    GenerateLoopRangeOld(r, state, schedule, codegenFn);
                }
            }
        }