glsl: Add operator for .length() method on implicitly-sized arrays
authorYevhenii Kolesnikov <yevhenii.kolesnikov@globallogic.com>
Wed, 14 Jul 2021 17:39:45 +0000 (20:39 +0300)
committerMarge Bot <eric+marge@anholt.net>
Tue, 27 Jul 2021 10:02:50 +0000 (10:02 +0000)
ARB_shader_storage_buffer_object extension (promoted to core in 4.3) allows us
to call .length() method on arrays declared without an explicit size. The length is
determined at link time as a maximum array access.

Fixes: 273f61a0051a ("glsl: Add parser/compiler support for unsized array's length()")
Signed-off-by: Yevhenii Kolesnikov <yevhenii.kolesnikov@globallogic.com>
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11952>

src/compiler/glsl/ir.cpp
src/compiler/glsl/ir_expression_operation.py
src/compiler/glsl/ir_validate.cpp
src/compiler/glsl/linker.cpp
src/mesa/program/ir_to_mesa.cpp
src/mesa/state_tracker/st_glsl_to_tgsi.cpp

index 97b302a..f9e9c32 100644 (file)
@@ -438,6 +438,7 @@ ir_expression::ir_expression(int op, ir_rvalue *op0)
 
    case ir_unop_get_buffer_size:
    case ir_unop_ssbo_unsized_array_length:
+   case ir_unop_implicitly_sized_array_length:
       this->type = glsl_type::int_type;
       break;
 
index 0d8d7a6..c9f9831 100644 (file)
@@ -591,6 +591,11 @@ ir_expression_operation = [
    # of its length.
    operation("ssbo_unsized_array_length", 1),
 
+   # Calculate length of an implicitly sized array.
+   # This opcode is going to be replaced with a constant expression at link
+   # time.
+   operation("implicitly_sized_array_length", 1),
+
    # 64-bit integer packing ops.
    operation("pack_int_2x32", 1, printable_name="packInt2x32", source_types=(int_type,), dest_type=int64_type, c_expression="data.u64[0] = pack_2x32(op[0]->value.u[0], op[0]->value.u[1])", flags=frozenset((horizontal_operation, non_assign_operation))),
    operation("pack_uint_2x32", 1, printable_name="packUint2x32", source_types=(uint_type,), dest_type=uint64_type, c_expression="data.u64[0] = pack_2x32(op[0]->value.u[0], op[0]->value.u[1])", flags=frozenset((horizontal_operation, non_assign_operation))),
index c9d5ca1..c60c36c 100644 (file)
@@ -633,6 +633,11 @@ ir_validate::visit_leave(ir_expression *ir)
       assert(ir->operands[0]->type->is_unsized_array());
       break;
 
+   case ir_unop_implicitly_sized_array_length:
+      assert(ir->type == glsl_type::int_type);
+      assert(ir->operands[0]->type->is_array());
+      break;
+
    case ir_unop_d2f:
       assert(ir->operands[0]->type->is_double());
       assert(ir->type->is_float());
index a5ae7a3..b598b63 100644 (file)
@@ -321,6 +321,39 @@ public:
    }
 };
 
+class array_length_to_const_visitor : public ir_rvalue_visitor {
+public:
+   array_length_to_const_visitor()
+   {
+      this->progress = false;
+   }
+
+   virtual ~array_length_to_const_visitor()
+   {
+      /* empty */
+   }
+
+   bool progress;
+
+   virtual void handle_rvalue(ir_rvalue **rvalue)
+   {
+      if (*rvalue == NULL || (*rvalue)->ir_type != ir_type_expression)
+         return;
+
+      ir_expression *expr = (*rvalue)->as_expression();
+      if (expr) {
+         if (expr->operation == ir_unop_implicitly_sized_array_length) {
+            assert(!expr->operands[0]->type->is_unsized_array());
+            ir_constant *constant = new(expr)
+               ir_constant(expr->operands[0]->type->array_size());
+            if (constant) {
+               *rvalue = constant;
+            }
+         }
+      }
+   }
+};
+
 /**
  * Visitor that determines the highest stream id to which a (geometry) shader
  * emits vertices. It also checks whether End{Stream}Primitive is ever called.
@@ -2540,6 +2573,12 @@ link_intrastage_shaders(void *mem_ctx,
    v.run(linked->ir);
    v.fixup_unnamed_interface_types();
 
+   /* Now that we know the sizes of all the arrays, we can replace .length()
+    * calls with a constant expression.
+    */
+   array_length_to_const_visitor len_v;
+   len_v.run(linked->ir);
+
    /* Link up uniform blocks defined within this stage. */
    link_uniform_blocks(mem_ctx, ctx, prog, linked, &ubo_blocks,
                        &num_ubo_blocks, &ssbo_blocks, &num_ssbo_blocks);
index eaaf8da..96aa399 100644 (file)
@@ -1351,6 +1351,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
       break;
 
    case ir_unop_ssbo_unsized_array_length:
+   case ir_unop_implicitly_sized_array_length:
    case ir_quadop_vector:
       /* This operation should have already been handled.
        */
index 4f62622..3ecdb83 100644 (file)
@@ -2458,6 +2458,7 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op)
    case ir_binop_carry:
    case ir_binop_borrow:
    case ir_unop_ssbo_unsized_array_length:
+   case ir_unop_implicitly_sized_array_length:
    case ir_unop_atan:
    case ir_binop_atan2:
    case ir_unop_clz: