Struct naga::back::spv::BlockContext

source ·
struct BlockContext<'w> {
    writer: &'w mut Writer,
    ir_module: &'w Module,
    ir_function: &'w Function,
    fun_info: &'w FunctionInfo,
    function: &'w mut Function,
    cached: CachedExpressions,
    temp_list: Vec<Word>,
    expression_constness: ExpressionConstnessTracker,
}
Expand description

General information needed to emit SPIR-V for Naga statements.

Fields§

§writer: &'w mut Writer

The writer handling the module to which this code belongs.

§ir_module: &'w Module

The Module for which we’re generating code.

§ir_function: &'w Function

The Function for which we’re generating code.

§fun_info: &'w FunctionInfo

Information module validation produced about ir_function.

§function: &'w mut Function

The spv::Function to which we are contributing SPIR-V instructions.

§cached: CachedExpressions

SPIR-V ids for expressions we’ve evaluated.

§temp_list: Vec<Word>

The Writer’s temporary vector, for convenience.

§expression_constness: ExpressionConstnessTracker

Tracks the constness of Expressions residing in self.ir_function.expressions

Implementations§

source§

impl BlockContext<'_>

source

pub(super) fn cache_expression_value( &mut self, expr_handle: Handle<Expression>, block: &mut Block, ) -> Result<(), Error>

Cache an expression for a value.

source

fn write_access_chain( &mut self, expr_handle: Handle<Expression>, block: &mut Block, type_adjustment: AccessTypeAdjustment, ) -> Result<ExpressionPointer, Error>

Build an OpAccessChain instruction.

Emit any needed bounds-checking expressions to block.

Give the OpAccessChain a result type based on expr_handle, adjusted according to type_adjustment; see the documentation for AccessTypeAdjustment for details.

On success, the return value is an ExpressionPointer value; see the documentation for that type.

source

fn is_nonuniform_binding_array_access( &mut self, base: Handle<Expression>, index: Handle<Expression>, ) -> bool

source

fn write_access_chain_index( &mut self, base: Handle<Expression>, index: GuardedIndex, accumulated_checks: &mut Option<Word>, block: &mut Block, ) -> Result<Word, Error>

Compute a single index operand to an OpAccessChain instruction.

Given that we are indexing base with index, apply the appropriate bounds check policies, emitting code to block to clamp index or determine whether it’s in bounds. Return the SPIR-V instruction id of the index value we should actually use.

Extend accumulated_checks to include the results of any needed bounds checks. See BlockContext::extend_bounds_check_condition_chain.

source

fn extend_bounds_check_condition_chain( &mut self, chain: &mut Option<Word>, comparison_id: Word, block: &mut Block, )

Add a condition to a chain of bounds checks.

As we build an OpAccessChain instruction govered by BoundsCheckPolicy::ReadZeroSkipWrite, we accumulate a chain of dynamic bounds checks, one for each index in the chain, which must all be true for that OpAccessChain’s execution to be well-defined. This function adds the boolean instruction id comparison_id to chain.

If chain is None, that means there are no bounds checks in the chain yet. If chain is Some(id), then id is the conjunction of all the bounds checks in the chain.

When we have multiple bounds checks, we combine them with OpLogicalAnd, not a short-circuit branch. This means we might do comparisons we don’t need to, but we expect these checks to almost always succeed, and keeping branches to a minimum is essential.

source

fn write_checked_load( &mut self, pointer: Handle<Expression>, block: &mut Block, access_type_adjustment: AccessTypeAdjustment, result_type_id: Word, ) -> Result<Word, Error>

source

fn spill_to_internal_variable( &mut self, base: Handle<Expression>, block: &mut Block, )

source

fn maybe_access_spilled_composite( &mut self, access: Handle<Expression>, block: &mut Block, result_type_id: Word, ) -> Result<Word, Error>

Generate an access to a spilled temporary, if necessary.

Given access, an Access or AccessIndex expression that refers to a component of a composite value that has been spilled to a temporary variable, determine whether other expressions are going to use access’s value:

  • If so, perform the access and cache that as the value of access.

  • Otherwise, generate no code and cache no value for access.

Return Ok(0) if no value was fetched, or Ok(id) if we loaded it into the instruction given by id.

source

fn write_matrix_matrix_column_op( &mut self, block: &mut Block, result_id: Word, result_type_id: Word, left_id: Word, right_id: Word, columns: VectorSize, rows: VectorSize, width: u8, op: Op, )

Build the instructions for matrix - matrix column operations

source

fn write_vector_scalar_mult( &mut self, block: &mut Block, result_id: Word, result_type_id: Word, vector_id: Word, scalar_id: Word, vector: &TypeInner, )

Build the instructions for vector - scalar multiplication

source

fn write_dot_product( &mut self, result_id: Word, result_type_id: Word, arg0_id: Word, arg1_id: Word, size: u32, block: &mut Block, )

Build the instructions for the arithmetic expression of a dot product

source

fn write_block( &mut self, label_id: Word, naga_block: &Block, exit: BlockExit, loop_context: LoopContext, debug_info: Option<&DebugInfoInner<'_>>, ) -> Result<BlockExitDisposition, Error>

Generate one or more SPIR-V blocks for naga_block.

Use label_id as the label for the SPIR-V entry point block.

If control reaches the end of the SPIR-V block, terminate it according to exit. This function’s return value indicates whether it acted on this parameter or not; see BlockExitDisposition.

If the block contains Break or Continue statements, loop_context supplies the labels of the SPIR-V blocks to jump to. If either of these labels are None, then it should have been a Naga validation error for the corresponding statement to occur in this context.

source

pub(super) fn write_function_body( &mut self, entry_id: Word, debug_info: Option<&DebugInfoInner<'_>>, ) -> Result<(), Error>

source§

impl BlockContext<'_>

source

fn write_image_coordinates( &mut self, coordinates: Handle<Expression>, array_index: Option<Handle<Expression>>, block: &mut Block, ) -> Result<ImageCoordinates, Error>

Extend image coordinates with an array index, if necessary.

Whereas Expression::ImageLoad and ImageSample treat the array index as a separate operand from the coordinates, SPIR-V image access instructions include the array index in the coordinates operand. This function builds a SPIR-V coordinate vector from a Naga coordinate vector and array index, if one is supplied, and returns a ImageCoordinates struct describing what it built.

If array_index is Some(expr), then this function constructs a new vector that is coordinates with array_index concatenated onto the end: a vec2 becomes a vec3, a scalar becomes a vec2, and so on.

If array_index is None, then the return value uses coordinates unchanged. Note that, when indexing a non-arrayed 1D image, this will be a scalar value.

If needed, this function generates code to convert the array index, always an integer scalar, to match the component type of coordinates. Naga’s ImageLoad and SPIR-V’s OpImageRead, OpImageFetch, and OpImageWrite all use integer coordinates, while Naga’s ImageSample and SPIR-V’s OpImageSample... instructions all take floating-point coordinate vectors.

source

pub(super) fn get_handle_id(&mut self, expr_handle: Handle<Expression>) -> Word

source

fn write_coordinate_one( &mut self, coordinates: &ImageCoordinates, ) -> Result<Word, Error>

Generate a vector or scalar ‘one’ for arithmetic on coordinates.

If coordinates is a scalar, return a scalar one. Otherwise, return a vector of ones.

source

fn restrict_scalar( &mut self, type_id: Word, input_id: Word, size_id: Word, block: &mut Block, ) -> Result<Word, Error>

Generate code to restrict input to fall between zero and one less than size_id.

Both must be 32-bit scalar integer values, whose type is given by type_id. The computed value is also of type type_id.

source

fn write_coordinate_bounds( &mut self, type_id: Word, image_id: Word, level_id: Option<Word>, block: &mut Block, ) -> Word

Write instructions to query the size of an image.

This takes care of selecting the right instruction depending on whether a level of detail parameter is present.

source

fn write_restricted_coordinates( &mut self, image_id: Word, coordinates: ImageCoordinates, level_id: Option<Word>, sample_id: Option<Word>, block: &mut Block, ) -> Result<(Word, Option<Word>, Option<Word>), Error>

Write code to restrict coordinates for an image reference.

First, clamp the level of detail or sample index to fall within bounds. Then, obtain the image size, possibly using the clamped level of detail. Finally, use an unsigned minimum instruction to force all coordinates into range.

Return a triple (COORDS, LEVEL, SAMPLE), where COORDS is a coordinate vector (including the array index, if any), LEVEL is an optional level of detail, and SAMPLE is an optional sample index, all guaranteed to be in-bounds for image_id.

The result is usually a vector, but it is a scalar when indexing non-arrayed 1D images.

source

fn write_conditional_image_access<A: Access>( &mut self, image_id: Word, coordinates: ImageCoordinates, level_id: Option<Word>, sample_id: Option<Word>, block: &mut Block, access: &A, ) -> Result<A::Output, Error>

source

pub(super) fn write_image_load( &mut self, result_type_id: Word, image: Handle<Expression>, coordinate: Handle<Expression>, array_index: Option<Handle<Expression>>, level: Option<Handle<Expression>>, sample: Option<Handle<Expression>>, block: &mut Block, ) -> Result<Word, Error>

Generate code for an ImageLoad expression.

The arguments are the components of an Expression::ImageLoad variant.

source

pub(super) fn write_image_sample( &mut self, result_type_id: Word, image: Handle<Expression>, sampler: Handle<Expression>, gather: Option<SwizzleComponent>, coordinate: Handle<Expression>, array_index: Option<Handle<Expression>>, offset: Option<Handle<Expression>>, level: SampleLevel, depth_ref: Option<Handle<Expression>>, block: &mut Block, ) -> Result<Word, Error>

Generate code for an ImageSample expression.

The arguments are the components of an Expression::ImageSample variant.

source

pub(super) fn write_image_query( &mut self, result_type_id: Word, image: Handle<Expression>, query: ImageQuery, block: &mut Block, ) -> Result<Word, Error>

Generate code for an ImageQuery expression.

The arguments are the components of an Expression::ImageQuery variant.

source

pub(super) fn write_image_store( &mut self, image: Handle<Expression>, coordinate: Handle<Expression>, array_index: Option<Handle<Expression>>, value: Handle<Expression>, block: &mut Block, ) -> Result<(), Error>

source§

impl BlockContext<'_>

source

pub(super) fn write_runtime_array_length( &mut self, array: Handle<Expression>, block: &mut Block, ) -> Result<Word, Error>

Emit code to compute the length of a run-time array.

Given array, an expression referring a runtime-sized array, return the instruction id for the array’s length.

Runtime-sized arrays may only appear in the values of global variables, which must have one of the following Naga types:

  1. A runtime-sized array.
  2. A struct whose last member is a runtime-sized array.
  3. A binding array of 2.

Thus, the expression array has the form of:

The generated SPIR-V takes into account wrapped globals; see back::spv::GlobalVariable for details.

source

fn write_sequence_length( &mut self, sequence: Handle<Expression>, block: &mut Block, ) -> Result<MaybeKnown<u32>, Error>

Compute the length of a subscriptable value.

Given sequence, an expression referring to some indexable type, return its length. The result may either be computed by SPIR-V instructions, or known at shader translation time.

sequence may be a Vector, Matrix, or Array, a Pointer to any of those, or a ValuePointer. An array may be fixed-size, dynamically sized, or use a specializable constant as its length.

source

fn write_sequence_max_index( &mut self, sequence: Handle<Expression>, block: &mut Block, ) -> Result<MaybeKnown<u32>, Error>

Compute the maximum valid index of a subscriptable value.

Given sequence, an expression referring to some indexable type, return its maximum valid index - one less than its length. The result may either be computed, or known at shader translation time.

sequence may be a Vector, Matrix, or Array, a Pointer to any of those, or a ValuePointer. An array may be fixed-size, dynamically sized, or use a specializable constant as its length.

source

pub(super) fn write_restricted_index( &mut self, sequence: Handle<Expression>, index: GuardedIndex, block: &mut Block, ) -> Result<BoundsCheckResult, Error>

Restrict an index to be in range for a vector, matrix, or array.

This is used to implement BoundsCheckPolicy::Restrict. An in-bounds index is left unchanged. An out-of-bounds index is replaced with some arbitrary in-bounds index. Note,this is not necessarily clamping; for example, negative indices might be changed to refer to the last element of the sequence, not the first, as clamping would do.

Either return the restricted index value, if known, or add instructions to block to compute it, and return the id of the result. See the documentation for BoundsCheckResult for details.

The sequence expression may be a Vector, Matrix, or Array, a Pointer to any of those, or a ValuePointer. An array may be fixed-size, dynamically sized, or use a specializable constant as its length.

source

fn write_index_comparison( &mut self, sequence: Handle<Expression>, index: GuardedIndex, block: &mut Block, ) -> Result<BoundsCheckResult, Error>

Write an index bounds comparison to block, if needed.

This is used to implement BoundsCheckPolicy::ReadZeroSkipWrite.

If we’re able to determine statically that index is in bounds for sequence, return KnownInBounds(value), where value is the actual value of the index. (In principle, one could know that the index is in bounds without knowing its specific value, but in our simple-minded situation, we always know it.)

If instead we must generate code to perform the comparison at run time, return Conditional(comparison_id), where comparison_id is an instruction producing a boolean value that is true if index is in bounds for sequence.

The sequence expression may be a Vector, Matrix, or Array, a Pointer to any of those, or a ValuePointer. An array may be fixed-size, dynamically sized, or use a specializable constant as its length.

source

pub(super) fn write_conditional_indexed_load<F>( &mut self, result_type: Word, condition: Word, block: &mut Block, emit_load: F, ) -> Word
where F: FnOnce(&mut IdGenerator, &mut Block) -> Word,

Emit a conditional load for BoundsCheckPolicy::ReadZeroSkipWrite.

Generate code to load a value of result_type if condition is true, and generate a null value of that type if it is false. Call emit_load to emit the instructions to perform the load. Return the id of the merged value of the two branches.

source

pub(super) fn write_bounds_check( &mut self, base: Handle<Expression>, index: GuardedIndex, block: &mut Block, ) -> Result<BoundsCheckResult, Error>

Emit code for bounds checks for an array, vector, or matrix access.

This tries to handle all the critical steps for bounds checks:

  • First, select the appropriate bounds check policy for base, depending on its address space.

  • Next, analyze index to see if its value is known at compile time, in which case we can decide statically whether the index is in bounds.

  • If the index’s value is not known at compile time, emit code to:

Return a BoundsCheckResult indicating how the index should be consumed. See that type’s documentation for details.

source

pub(super) fn write_vector_access( &mut self, expr_handle: Handle<Expression>, base: Handle<Expression>, index: Handle<Expression>, block: &mut Block, ) -> Result<Word, Error>

Emit code to subscript a vector by value with a computed index.

Return the id of the element value.

source§

impl BlockContext<'_>

source

pub(super) fn write_ray_query_function( &mut self, query: Handle<Expression>, function: &RayQueryFunction, block: &mut Block, )

source

pub(super) fn write_ray_query_get_intersection( &mut self, query: Handle<Expression>, block: &mut Block, is_committed: bool, ) -> Word

source§

impl BlockContext<'_>

source

pub(super) fn write_subgroup_ballot( &mut self, predicate: &Option<Handle<Expression>>, result: Handle<Expression>, block: &mut Block, ) -> Result<(), Error>

source

pub(super) fn write_subgroup_operation( &mut self, op: &SubgroupOperation, collective_op: &CollectiveOperation, argument: Handle<Expression>, result: Handle<Expression>, block: &mut Block, ) -> Result<(), Error>

source

pub(super) fn write_subgroup_gather( &mut self, mode: &GatherMode, argument: Handle<Expression>, result: Handle<Expression>, block: &mut Block, ) -> Result<(), Error>

source§

impl BlockContext<'_>

source

fn gen_id(&mut self) -> Word

source

fn get_type_id(&mut self, lookup_type: LookupType) -> Word

source

fn get_expression_type_id(&mut self, tr: &TypeResolution) -> Word

source

fn get_index_constant(&mut self, index: Word) -> Word

source

fn get_scope_constant(&mut self, scope: Word) -> Word

source

fn get_pointer_id(&mut self, handle: Handle<Type>, class: StorageClass) -> Word

Auto Trait Implementations§

§

impl<'w> Freeze for BlockContext<'w>

§

impl<'w> RefUnwindSafe for BlockContext<'w>

§

impl<'w> Send for BlockContext<'w>

§

impl<'w> Sync for BlockContext<'w>

§

impl<'w> Unpin for BlockContext<'w>

§

impl<'w> !UnwindSafe for BlockContext<'w>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.