diff --git a/src/compiler/nir/nir_intrinsics.py b/src/compiler/nir/nir_intrinsics.py index beb2fa6b555..bb40fab9d02 100644 --- a/src/compiler/nir/nir_intrinsics.py +++ b/src/compiler/nir/nir_intrinsics.py @@ -214,6 +214,20 @@ index("unsigned", "stack_size") index("unsigned", "align_mul") index("unsigned", "align_offset") +# For load/store intrinsics that take an offset, the amount the offset is +# shifted left to calculate the final byte offset: +# +# offset = (offset_src + base) << offset_shift +# +# It is unspecified how overflows due to offset_shift are handled: they may +# either be treated as out-of-bounds, or wrap around and generate an in-bounds +# offset. NIR passes may implement either behavior and may not be consistent +# about it. +# +# This is useful for backends that have memory operations that use offset units +# other than bytes (i.e., where the shift is implicit). +index("unsigned", "offset_shift") + # The Vulkan descriptor type for a vulkan_resource_[re]index intrinsic. index("unsigned", "desc_type") diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c index 12f1b60ef64..bd02c35d61f 100644 --- a/src/compiler/nir/nir_validate.c +++ b/src/compiler/nir/nir_validate.c @@ -809,6 +809,12 @@ validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state) (state->shader->info.stage == MESA_SHADER_FRAGMENT && instr->intrinsic == nir_intrinsic_load_input_vertex)); } + + if (nir_intrinsic_has_offset_shift(instr) && + nir_intrinsic_has_align(instr)) { + unsigned min_align = 1 << nir_intrinsic_offset_shift(instr); + validate_assert(state, nir_intrinsic_align(instr) >= min_align); + } } static void