nir/lower_io: Eliminate oob writes and return zero for oob reads
authorDanylo Piliaiev <danylo.piliaiev@globallogic.com>
Fri, 21 Aug 2020 10:42:55 +0000 (13:42 +0300)
committerMarge Bot <eric+marge@anholt.net>
Tue, 22 Sep 2020 09:06:52 +0000 (09:06 +0000)
Out-of-bounds writes could be eliminated per spec:

Section 5.11 (Out-of-Bounds Accesses) of the GLSL 4.60 spec says:

 "In the subsections described above for array, vector, matrix and
  structure accesses, any out-of-bounds access produced undefined
  behavior....
  Out-of-bounds writes may be discarded or overwrite
  other variables of the active program.
  Out-of-bounds reads return undefined values, which
  include values from other variables of the active program or zero."

GL_KHR_robustness and GL_ARB_robustness encourage us to return zero
for reads.

Otherwise get_io_offset would return out-of-bound offset which may
result in out-of-bound loading/storing of inputs/outputs,
that could cause issues in drivers down the line.

E.g. this fixes such dereference:
 int vue_slot = vue_map->varying_to_slot[intrin->const_index[0]];
in brw_nir.c

CC: <mesa-stable@lists.freedesktop.org>
Signed-off-by: Danylo Piliaiev <danylo.piliaiev@globallogic.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6428>

src/compiler/nir/nir_lower_io.c

index 986c4c0..c90119b 100644 (file)
@@ -636,6 +636,37 @@ nir_lower_io_block(nir_block *block,
                                 mode == nir_var_shader_out ||
                                 var->data.bindless;
 
+     if (nir_deref_instr_is_known_out_of_bounds(deref)) {
+        /* Section 5.11 (Out-of-Bounds Accesses) of the GLSL 4.60 spec says:
+         *
+         *    In the subsections described above for array, vector, matrix and
+         *    structure accesses, any out-of-bounds access produced undefined
+         *    behavior....
+         *    Out-of-bounds reads return undefined values, which
+         *    include values from other variables of the active program or zero.
+         *    Out-of-bounds writes may be discarded or overwrite
+         *    other variables of the active program.
+         *
+         * GL_KHR_robustness and GL_ARB_robustness encourage us to return zero
+         * for reads.
+         *
+         * Otherwise get_io_offset would return out-of-bound offset which may
+         * result in out-of-bound loading/storing of inputs/outputs,
+         * that could cause issues in drivers down the line.
+         */
+         if (intrin->intrinsic != nir_intrinsic_store_deref) {
+            nir_ssa_def *zero =
+               nir_imm_zero(b, intrin->dest.ssa.num_components,
+                             intrin->dest.ssa.bit_size);
+            nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
+                                  nir_src_for_ssa(zero));
+         }
+
+         nir_instr_remove(&intrin->instr);
+         progress = true;
+         continue;
+      }
+
       offset = get_io_offset(b, deref, per_vertex ? &vertex_index : NULL,
                              state->type_size, &component_offset,
                              bindless_type_size);