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 Expression
s residing in self.ir_function.expressions
Implementations§
source§impl<'w> BlockContext<'w>
impl<'w> BlockContext<'w>
sourcepub(super) fn cache_expression_value(
&mut self,
expr_handle: Handle<Expression>,
block: &mut Block,
) -> Result<(), Error>
pub(super) fn cache_expression_value( &mut self, expr_handle: Handle<Expression>, block: &mut Block, ) -> Result<(), Error>
Cache an expression for a value.
sourcefn write_expression_pointer(
&mut self,
expr_handle: Handle<Expression>,
block: &mut Block,
type_adjustment: AccessTypeAdjustment,
) -> Result<ExpressionPointer, Error>
fn write_expression_pointer( &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.
fn is_nonuniform_binding_array_access( &mut self, base: Handle<Expression>, index: Handle<Expression>, ) -> bool
sourcefn write_access_chain_index(
&mut self,
base: Handle<Expression>,
index: GuardedIndex,
accumulated_checks: &mut Option<Word>,
block: &mut Block,
) -> Result<Word, Error>
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
.
sourcefn extend_bounds_check_condition_chain(
&mut self,
chain: &mut Option<Word>,
comparison_id: Word,
block: &mut Block,
)
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.
fn write_checked_load( &mut self, pointer: Handle<Expression>, block: &mut Block, access_type_adjustment: AccessTypeAdjustment, result_type_id: Word, ) -> Result<Word, Error>
fn spill_to_internal_variable( &mut self, base: Handle<Expression>, block: &mut Block, )
sourcefn maybe_access_spilled_composite(
&mut self,
access: Handle<Expression>,
block: &mut Block,
result_type_id: Word,
) -> Result<Word, Error>
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
.
sourcefn 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,
)
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
sourcefn write_vector_scalar_mult(
&mut self,
block: &mut Block,
result_id: Word,
result_type_id: Word,
vector_id: Word,
scalar_id: Word,
vector: &TypeInner,
)
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
sourcefn write_dot_product(
&mut self,
result_id: Word,
result_type_id: Word,
arg0_id: Word,
arg1_id: Word,
size: u32,
block: &mut Block,
)
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
sourcefn write_block(
&mut self,
label_id: Word,
naga_block: &Block,
exit: BlockExit,
loop_context: LoopContext,
debug_info: Option<&DebugInfoInner<'_>>,
) -> Result<BlockExitDisposition, Error>
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.
pub(super) fn write_function_body( &mut self, entry_id: Word, debug_info: Option<&DebugInfoInner<'_>>, ) -> Result<(), Error>
source§impl<'w> BlockContext<'w>
impl<'w> BlockContext<'w>
sourcefn write_image_coordinates(
&mut self,
coordinates: Handle<Expression>,
array_index: Option<Handle<Expression>>,
block: &mut Block,
) -> Result<ImageCoordinates, Error>
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.
pub(super) fn get_handle_id(&mut self, expr_handle: Handle<Expression>) -> Word
sourcefn write_coordinate_one(
&mut self,
coordinates: &ImageCoordinates,
) -> Result<Word, Error>
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.
sourcefn restrict_scalar(
&mut self,
type_id: Word,
input_id: Word,
size_id: Word,
block: &mut Block,
) -> Result<Word, Error>
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
.
sourcefn write_coordinate_bounds(
&mut self,
type_id: Word,
image_id: Word,
level_id: Option<Word>,
block: &mut Block,
) -> Word
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.
sourcefn 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>
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.
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>
sourcepub(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>
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.
sourcepub(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>
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.
sourcepub(super) fn write_image_query(
&mut self,
result_type_id: Word,
image: Handle<Expression>,
query: ImageQuery,
block: &mut Block,
) -> Result<Word, Error>
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.
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<'w> BlockContext<'w>
impl<'w> BlockContext<'w>
sourcepub(super) fn write_runtime_array_length(
&mut self,
array: Handle<Expression>,
block: &mut Block,
) -> Result<Word, Error>
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:
- A runtime-sized array.
- A struct whose last member is a runtime-sized array.
- A binding array of 2.
Thus, the expression array
has the form of:
- An optional
AccessIndex
, for case 2, applied to… - An optional
Access
orAccessIndex
, for case 3, applied to… - A
GlobalVariable
.
The generated SPIR-V takes into account wrapped globals; see
back::spv::GlobalVariable
for details.
sourcefn write_sequence_length(
&mut self,
sequence: Handle<Expression>,
block: &mut Block,
) -> Result<MaybeKnown<u32>, Error>
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.
sourcefn write_sequence_max_index(
&mut self,
sequence: Handle<Expression>,
block: &mut Block,
) -> Result<MaybeKnown<u32>, Error>
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.
sourcepub(super) fn write_restricted_index(
&mut self,
sequence: Handle<Expression>,
index: GuardedIndex,
block: &mut Block,
) -> Result<BoundsCheckResult, Error>
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.
sourcefn write_index_comparison(
&mut self,
sequence: Handle<Expression>,
index: GuardedIndex,
block: &mut Block,
) -> Result<BoundsCheckResult, Error>
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.
sourcepub(super) fn write_conditional_indexed_load<F>(
&mut self,
result_type: Word,
condition: Word,
block: &mut Block,
emit_load: F,
) -> Word
pub(super) fn write_conditional_indexed_load<F>( &mut self, result_type: Word, condition: Word, block: &mut Block, emit_load: F, ) -> 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.
sourcepub(super) fn write_bounds_check(
&mut self,
base: Handle<Expression>,
index: GuardedIndex,
block: &mut Block,
) -> Result<BoundsCheckResult, Error>
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:
-
restrict its value (for
BoundsCheckPolicy::Restrict
), or -
check whether it’s in bounds (for
BoundsCheckPolicy::ReadZeroSkipWrite
).
-
Return a BoundsCheckResult
indicating how the index should be
consumed. See that type’s documentation for details.
sourcepub(super) fn write_vector_access(
&mut self,
expr_handle: Handle<Expression>,
base: Handle<Expression>,
index: Handle<Expression>,
block: &mut Block,
) -> Result<Word, Error>
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.