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);
}
}
}