glsl/nir: Handle unlowered SSBO atomic and array_length intrinsics
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 14 Mar 2019 17:00:04 +0000 (12:00 -0500)
committerJason Ekstrand <jason@jlekstrand.net>
Fri, 15 Mar 2019 01:02:19 +0000 (01:02 +0000)
We didn't have any of these before because all NIR consumers always
called lower_ubo_references.  Soon, we want to pass the derefs straight
through to NIR so we need to handle these intrinsics directly.

Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
src/compiler/glsl/glsl_to_nir.cpp

index b70a7eddd057b341e5bb668d0a1d5ab45e2038b2..9084803adf134f5ffb44c11ffca3bc6ac295162f 100644 (file)
@@ -826,6 +826,49 @@ nir_visitor::visit(ir_call *ir)
       nir_intrinsic_op op;
 
       switch (ir->callee->intrinsic_id) {
+      case ir_intrinsic_generic_atomic_add:
+         op = ir->return_deref->type->is_integer_32_64()
+            ? nir_intrinsic_deref_atomic_add : nir_intrinsic_deref_atomic_fadd;
+         break;
+      case ir_intrinsic_generic_atomic_and:
+         op = nir_intrinsic_deref_atomic_and;
+         break;
+      case ir_intrinsic_generic_atomic_or:
+         op = nir_intrinsic_deref_atomic_or;
+         break;
+      case ir_intrinsic_generic_atomic_xor:
+         op = nir_intrinsic_deref_atomic_xor;
+         break;
+      case ir_intrinsic_generic_atomic_min:
+         assert(ir->return_deref);
+         if (ir->return_deref->type == glsl_type::int_type)
+            op = nir_intrinsic_deref_atomic_imin;
+         else if (ir->return_deref->type == glsl_type::uint_type)
+            op = nir_intrinsic_deref_atomic_umin;
+         else if (ir->return_deref->type == glsl_type::float_type)
+            op = nir_intrinsic_deref_atomic_fmin;
+         else
+            unreachable("Invalid type");
+         break;
+      case ir_intrinsic_generic_atomic_max:
+         assert(ir->return_deref);
+         if (ir->return_deref->type == glsl_type::int_type)
+            op = nir_intrinsic_deref_atomic_imax;
+         else if (ir->return_deref->type == glsl_type::uint_type)
+            op = nir_intrinsic_deref_atomic_umax;
+         else if (ir->return_deref->type == glsl_type::float_type)
+            op = nir_intrinsic_deref_atomic_fmax;
+         else
+            unreachable("Invalid type");
+         break;
+      case ir_intrinsic_generic_atomic_exchange:
+         op = nir_intrinsic_deref_atomic_exchange;
+         break;
+      case ir_intrinsic_generic_atomic_comp_swap:
+         op = ir->return_deref->type->is_integer_32_64()
+            ? nir_intrinsic_deref_atomic_comp_swap
+            : nir_intrinsic_deref_atomic_fcomp_swap;
+         break;
       case ir_intrinsic_atomic_counter_read:
          op = nir_intrinsic_atomic_counter_read_deref;
          break;
@@ -1049,6 +1092,63 @@ nir_visitor::visit(ir_call *ir)
       nir_ssa_def *ret = &instr->dest.ssa;
 
       switch (op) {
+      case nir_intrinsic_deref_atomic_add:
+      case nir_intrinsic_deref_atomic_imin:
+      case nir_intrinsic_deref_atomic_umin:
+      case nir_intrinsic_deref_atomic_imax:
+      case nir_intrinsic_deref_atomic_umax:
+      case nir_intrinsic_deref_atomic_and:
+      case nir_intrinsic_deref_atomic_or:
+      case nir_intrinsic_deref_atomic_xor:
+      case nir_intrinsic_deref_atomic_exchange:
+      case nir_intrinsic_deref_atomic_comp_swap:
+      case nir_intrinsic_deref_atomic_fadd:
+      case nir_intrinsic_deref_atomic_fmin:
+      case nir_intrinsic_deref_atomic_fmax:
+      case nir_intrinsic_deref_atomic_fcomp_swap: {
+         int param_count = ir->actual_parameters.length();
+         assert(param_count == 2 || param_count == 3);
+
+         /* Deref */
+         exec_node *param = ir->actual_parameters.get_head();
+         ir_rvalue *rvalue = (ir_rvalue *) param;
+         ir_dereference *deref = rvalue->as_dereference();
+         ir_swizzle *swizzle = NULL;
+         if (!deref) {
+            /* We may have a swizzle to pick off a single vec4 component */
+            swizzle = rvalue->as_swizzle();
+            assert(swizzle && swizzle->type->vector_elements == 1);
+            deref = swizzle->val->as_dereference();
+            assert(deref);
+         }
+         nir_deref_instr *nir_deref = evaluate_deref(deref);
+         if (swizzle) {
+            nir_deref = nir_build_deref_array_imm(&b, nir_deref,
+                                                  swizzle->mask.x);
+         }
+         instr->src[0] = nir_src_for_ssa(&nir_deref->dest.ssa);
+
+         /* data1 parameter (this is always present) */
+         param = param->get_next();
+         ir_instruction *inst = (ir_instruction *) param;
+         instr->src[1] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue()));
+
+         /* data2 parameter (only with atomic_comp_swap) */
+         if (param_count == 3) {
+            assert(op == nir_intrinsic_deref_atomic_comp_swap ||
+                   op == nir_intrinsic_deref_atomic_fcomp_swap);
+            param = param->get_next();
+            inst = (ir_instruction *) param;
+            instr->src[2] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue()));
+         }
+
+         /* Atomic result */
+         assert(ir->return_deref);
+         nir_ssa_dest_init(&instr->instr, &instr->dest,
+                           ir->return_deref->type->vector_elements, 32, NULL);
+         nir_builder_instr_insert(&b, &instr->instr);
+         break;
+      }
       case nir_intrinsic_atomic_counter_read_deref:
       case nir_intrinsic_atomic_counter_inc_deref:
       case nir_intrinsic_atomic_counter_pre_dec_deref:
@@ -1738,6 +1838,18 @@ nir_visitor::visit(ir_expression *ir)
       return;
    }
 
+   case ir_unop_ssbo_unsized_array_length: {
+      nir_intrinsic_instr *intrin =
+         nir_intrinsic_instr_create(b.shader,
+                                    nir_intrinsic_deref_buffer_array_length);
+
+      ir_dereference *deref = ir->operands[0]->as_dereference();
+      intrin->src[0] = nir_src_for_ssa(&evaluate_deref(deref)->dest.ssa);
+
+      add_instr(&intrin->instr, 1, 32);
+      return;
+   }
+
    default:
       break;
    }