From b2bce9c98a4685a10ca38b6418d2cae2ac905e9c Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Thu, 22 Sep 2022 09:18:18 +0200 Subject: [PATCH] broadcom/compiler: fix robust buffer access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our implemention was bogus, it was only putting a cap on the offset based on the aligned buffer size and this doesn't ensure the access to the buffer happens within its valid range. I think the only reason we have been passing the tests is that we align all buffers sizes to 256B and the tests create buffers with a size that is smaller than that (like 64B). When get the size of the buffer from the shader, we get the actual bound range (so 64B in this case) and by capping to that we don't ensure the access will stay within that range, but we ensure it will stay within the underlying memory bound to the buffer (256B), and this is fine by the spec, however, I think if the actual buffer range was the same as the underlying allocation we would fail the tests. A valid behavior for robust buffer access on an out-of-bounds access is to return any valid bytes within the buffer, so we can just make that offset 0. Reviewed-by: Alejandro PiƱeiro Part-of: --- .../v3d_nir_lower_robust_buffer_access.c | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/broadcom/compiler/v3d_nir_lower_robust_buffer_access.c b/src/broadcom/compiler/v3d_nir_lower_robust_buffer_access.c index 260cfc9f6f2..1e9f190c5e1 100644 --- a/src/broadcom/compiler/v3d_nir_lower_robust_buffer_access.c +++ b/src/broadcom/compiler/v3d_nir_lower_robust_buffer_access.c @@ -27,6 +27,7 @@ static void rewrite_offset(nir_builder *b, nir_intrinsic_instr *instr, + uint32_t type_sz, uint32_t buffer_idx, uint32_t offset_src, nir_intrinsic_op buffer_size_op) @@ -40,13 +41,20 @@ rewrite_offset(nir_builder *b, nir_ssa_dest_init(&size->instr, &size->dest, 1, 32, NULL); nir_builder_instr_insert(b, &size->instr); - /* All out TMU accesses are 32-bit aligned */ - nir_ssa_def *aligned_buffer_size = - nir_iand(b, &size->dest.ssa, nir_imm_int(b, 0xfffffffc)); + /* Compute the maximum offset being accessed and if it is + * out of bounds rewrite it to 0 to ensure the access is + * within bounds. + */ + const uint32_t access_size = instr->num_components * type_sz; + nir_ssa_def *max_access_offset = + nir_iadd(b, instr->src[offset_src].ssa, + nir_imm_int(b, access_size - 1)); + nir_ssa_def *offset = + nir_bcsel(b, nir_uge(b, max_access_offset, &size->dest.ssa), + nir_imm_int(b, 0), + instr->src[offset_src].ssa); /* Rewrite offset */ - nir_ssa_def *offset = - nir_umin(b, instr->src[offset_src].ssa, aligned_buffer_size); nir_instr_rewrite_src(&instr->instr, &instr->src[offset_src], nir_src_for_ssa(offset)); } @@ -56,6 +64,7 @@ lower_load(struct v3d_compile *c, nir_builder *b, nir_intrinsic_instr *instr) { + uint32_t type_sz = nir_dest_bit_size(instr->dest) / 8; uint32_t index = nir_src_comp_as_uint(instr->src[0], 0); nir_intrinsic_op op; @@ -67,7 +76,7 @@ lower_load(struct v3d_compile *c, op = nir_intrinsic_get_ssbo_size; } - rewrite_offset(b, instr, index, 1, op); + rewrite_offset(b, instr, type_sz, index, 1, op); } static void @@ -75,8 +84,9 @@ lower_store(struct v3d_compile *c, nir_builder *b, nir_intrinsic_instr *instr) { + uint32_t type_sz = nir_src_bit_size(instr->src[0]) / 8; uint32_t index = nir_src_comp_as_uint(instr->src[1], 0); - rewrite_offset(b, instr, index, 2, nir_intrinsic_get_ssbo_size); + rewrite_offset(b, instr, type_sz, index, 2, nir_intrinsic_get_ssbo_size); } static void @@ -85,7 +95,7 @@ lower_atomic(struct v3d_compile *c, nir_intrinsic_instr *instr) { uint32_t index = nir_src_comp_as_uint(instr->src[0], 0); - rewrite_offset(b, instr, index, 1, nir_intrinsic_get_ssbo_size); + rewrite_offset(b, instr, 4, index, 1, nir_intrinsic_get_ssbo_size); } static void @@ -93,10 +103,25 @@ lower_shared(struct v3d_compile *c, nir_builder *b, nir_intrinsic_instr *instr) { + uint32_t type_sz; + if (instr->intrinsic == nir_intrinsic_load_shared) { + type_sz = nir_dest_bit_size(instr->dest) / 8; + } else { + /* atomic */ + type_sz = 4; + } + b->cursor = nir_before_instr(&instr->instr); - nir_ssa_def *aligned_size = - nir_imm_int(b, c->s->info.shared_size & 0xfffffffc); - nir_ssa_def *offset = nir_umin(b, instr->src[0].ssa, aligned_size); + const uint32_t access_size = instr->num_components * type_sz; + nir_ssa_def *max_access_offset = + nir_iadd(b, instr->src[0].ssa, + nir_imm_int(b, access_size - 1)); + nir_ssa_def *offset = + nir_bcsel(b, nir_uge(b, max_access_offset, + nir_imm_int(b, c->s->info.shared_size)), + nir_imm_int(b, 0), + instr->src[0].ssa); + nir_instr_rewrite_src(&instr->instr, &instr->src[0], nir_src_for_ssa(offset)); }