Function naga::proc::index::find_checked_indexes

source ·
pub fn find_checked_indexes(
    module: &Module,
    function: &Function,
    info: &FunctionInfo,
    policies: BoundsCheckPolicies,
) -> HandleSet<Expression>
Expand description

Build a set of expressions used as indices, to cache in temporary variables when emitted.

Given the bounds-check policies policies, construct a HandleSet containing the handle indices of all the expressions in function that are ever used as guarded indices under the ReadZeroSkipWrite policy. The module argument must be the module to which function belongs, and info should be that function’s analysis results.

Such index expressions will be used twice in the generated code: first for the comparison to see if the index is in bounds, and then for the access itself, should the comparison succeed. To avoid computing the expressions twice, the generated code should cache them in temporary variables.

Why do we need to build such a set in advance, instead of just processing access expressions as we encounter them? Whether an expression needs to be cached depends on whether it appears as something like the index operand of an Access expression or the level operand of an ImageLoad expression, and on the index bounds check policies that apply to those accesses. But Emit statements just identify a range of expressions by index; there’s no good way to tell what an expression is used for. The only way to do it is to just iterate over all the expressions looking for relevant Access expressions — which is what this function does.

Simple expressions like variable loads and constants don’t make sense to cache: it’s no better than just re-evaluating them. But constants are not covered by Emit statements, and Loads are always cached to ensure they occur at the right time, so we don’t bother filtering them out from this set.

Fortunately, we don’t need to deal with ImageStore statements here. When we emit code for a statement, the writer isn’t in the middle of an expression, so we can just emit declarations for temporaries, initialized appropriately.

None of these concerns apply for SPIR-V output, since it’s easy to just reuse an instruction ID in two places; that has the same semantics as a temporary variable, and it’s inherent in the design of SPIR-V. This function is more useful for text-based back ends.