TailStrategy#

enum class Halide::TailStrategy#

Different ways to handle a tail case in a split when the factor does not provably divide the extent.

Values:

enumerator RoundUp#

Round up the extent to be a multiple of the split factor.

Not legal for RVars, as it would change the meaning of the algorithm. Pros: generates the simplest, fastest code. Cons: if used on a stage that reads from the input or writes to the output, constrains the input or output size to be a multiple of the split factor.

enumerator GuardWithIf#

Guard the inner loop with an if statement that prevents evaluation beyond the original extent.

Always legal. The if statement is treated like a boundary condition, and factored out into a loop epilogue if possible. Pros: no redundant re-evaluation; does not constrain input our output sizes. Cons: increases code size due to separate tail-case handling; vectorization will scalarize in the tail case to handle the if statement.

enumerator Predicate#

Guard the loads and stores in the loop with an if statement that prevents evaluation beyond the original extent.

Always legal. The if statement is treated like a boundary condition, and factored out into a loop epilogue if possible. Pros: no redundant re-evaluation; does not constrain input or output sizes. Cons: increases code size due to separate tail-case handling.

enumerator PredicateLoads#

Guard the loads in the loop with an if statement that prevents evaluation beyond the original extent.

Only legal for innermost splits. Not legal for RVars, as it would change the meaning of the algorithm. The if statement is treated like a boundary condition, and factored out into a loop epilogue if possible. Pros: does not constrain input sizes, output size constraints are simpler than full predication. Cons: increases code size due to separate tail-case handling, constrains the output size to be a multiple of the split factor.

enumerator PredicateStores#

Guard the stores in the loop with an if statement that prevents evaluation beyond the original extent.

Only legal for innermost splits. Not legal for RVars, as it would change the meaning of the algorithm. The if statement is treated like a boundary condition, and factored out into a loop epilogue if possible. Pros: does not constrain output sizes, input size constraints are simpler than full predication. Cons: increases code size due to separate tail-case handling, constraints the input size to be a multiple of the split factor..

enumerator ShiftInwards#

Prevent evaluation beyond the original extent by shifting the tail case inwards, re-evaluating some points near the end.

Only legal for pure variables in pure definitions. If the inner loop is very simple, the tail case is treated like a boundary condition and factored out into an epilogue.

This is a good trade-off between several factors. Like RoundUp, it supports vectorization well, because the inner loop is always a fixed size with no data-dependent branching. It increases code size slightly for inner loops due to the epilogue handling, but not for outer loops (e.g. loops over tiles). If used on a stage that reads from an input or writes to an output, this strategy only requires that the input/output extent be at least the split factor, instead of a multiple of the split factor as with RoundUp.

enumerator ShiftInwardsAndBlend#

Equivalent to ShiftInwards, but protects values that would be re-evaluated by loading the memory location that would be stored to, modifying only the elements not contained within the overlap, and then storing the blended result.

This tail strategy is useful when you want to use ShiftInwards to vectorize without a scalar tail, but are scheduling a stage where that isn’t legal (e.g. an update definition).

Because this is a read - modify - write, this tail strategy cannot be used on any dimension the stage is parallelized over as it would cause a race condition.

enumerator RoundUpAndBlend#

Equivalent to RoundUp, but protected values that would be written beyond the end by loading the memory location that would be stored to, modifying only the elements within the region being computed, and then storing the blended result.

This tail strategy is useful when vectorizing an update to some sub-region of a larger Func. As with ShiftInwardsAndBlend, it can’t be combined with parallelism.

enumerator Auto#

For pure definitions use ShiftInwards.

For pure vars in update definitions use RoundUp. For RVars in update definitions use GuardWithIf.