i965: fix unsigned long overflows for i386
[mesa.git] / src / vulkan / anv_nir_apply_dynamic_offsets.c
index afb3313ccb4750b81030b7b7628e1b7daf54e625..6837a80460de0da5114fe14c9ab22c25dcebaf6b 100644 (file)
@@ -28,7 +28,6 @@ struct apply_dynamic_offsets_state {
    nir_shader *shader;
    nir_builder builder;
 
-   VkShaderStage stage;
    struct anv_pipeline_layout *layout;
 
    uint32_t indices_start;
@@ -50,22 +49,24 @@ apply_dynamic_offsets_block(nir_block *block, void *void_state)
 
       unsigned block_idx_src;
       switch (intrin->intrinsic) {
-      case nir_intrinsic_load_ubo_vk:
-      case nir_intrinsic_load_ubo_vk_indirect:
-      case nir_intrinsic_load_ssbo_vk:
-      case nir_intrinsic_load_ssbo_vk_indirect:
+      case nir_intrinsic_load_ubo:
+      case nir_intrinsic_load_ssbo:
          block_idx_src = 0;
          break;
-      case nir_intrinsic_store_ssbo_vk:
-      case nir_intrinsic_store_ssbo_vk_indirect:
+      case nir_intrinsic_store_ssbo:
          block_idx_src = 1;
          break;
       default:
          continue; /* the loop */
       }
 
-      unsigned set = intrin->const_index[0];
-      unsigned binding = intrin->const_index[1];
+      nir_instr *res_instr = intrin->src[block_idx_src].ssa->parent_instr;
+      assert(res_instr->type == nir_instr_type_intrinsic);
+      nir_intrinsic_instr *res_intrin = nir_instr_as_intrinsic(res_instr);
+      assert(res_intrin->intrinsic == nir_intrinsic_vulkan_resource_index);
+
+      unsigned set = res_intrin->const_index[0];
+      unsigned binding = res_intrin->const_index[1];
 
       set_layout = state->layout->set[set].layout;
       if (set_layout->binding[binding].dynamic_offset_index < 0)
@@ -73,104 +74,62 @@ apply_dynamic_offsets_block(nir_block *block, void *void_state)
 
       b->cursor = nir_before_instr(&intrin->instr);
 
-      int indirect_src;
-      switch (intrin->intrinsic) {
-      case nir_intrinsic_load_ubo_vk_indirect:
-      case nir_intrinsic_load_ssbo_vk_indirect:
-         indirect_src = 1;
-         break;
-      case nir_intrinsic_store_ssbo_vk_indirect:
-         indirect_src = 2;
-         break;
-      default:
-         indirect_src = -1;
-         break;
-      }
-
       /* First, we need to generate the uniform load for the buffer offset */
       uint32_t index = state->layout->set[set].dynamic_offset_start +
                        set_layout->binding[binding].dynamic_offset_index;
 
-      nir_const_value *const_arr_idx =
-         nir_src_as_const_value(intrin->src[block_idx_src]);
-
-      nir_intrinsic_op offset_load_op;
-      if (const_arr_idx)
-         offset_load_op = nir_intrinsic_load_uniform;
-      else
-         offset_load_op = nir_intrinsic_load_uniform_indirect;
-
       nir_intrinsic_instr *offset_load =
-         nir_intrinsic_instr_create(state->shader, offset_load_op);
-      offset_load->num_components = 1;
-      offset_load->const_index[0] = state->indices_start + index;
-
-      if (const_arr_idx) {
-         offset_load->const_index[1] = const_arr_idx->u[0];
-      } else {
-         offset_load->const_index[1] = 0;
-         nir_src_copy(&offset_load->src[0], &intrin->src[0], &intrin->instr);
-      }
+         nir_intrinsic_instr_create(state->shader, nir_intrinsic_load_uniform);
+      offset_load->num_components = 2;
+      offset_load->const_index[0] = state->indices_start + index * 8;
+      offset_load->src[0] = nir_src_for_ssa(nir_imul(b, res_intrin->src[0].ssa,
+                                                     nir_imm_int(b, 8)));
 
-      nir_ssa_dest_init(&offset_load->instr, &offset_load->dest, 1, NULL);
+      nir_ssa_dest_init(&offset_load->instr, &offset_load->dest, 2, NULL);
       nir_builder_instr_insert(b, &offset_load->instr);
 
-      nir_ssa_def *offset = &offset_load->dest.ssa;
-      if (indirect_src >= 0) {
-         assert(intrin->src[indirect_src].is_ssa);
-         offset = nir_iadd(b, intrin->src[indirect_src].ssa, offset);
-      }
-
-      /* Now we can modify the load/store intrinsic */
-
-      if (indirect_src < 0) {
-         /* The original intrinsic is not an indirect variant.  We need to
-          * create a new one and copy the old data over first.
-          */
-
-         nir_intrinsic_op indirect_op;
-         switch (intrin->intrinsic) {
-         case nir_intrinsic_load_ubo_vk:
-            indirect_op = nir_intrinsic_load_ubo_vk_indirect;
-            break;
-         case nir_intrinsic_load_ssbo_vk:
-            indirect_op = nir_intrinsic_load_ssbo_vk_indirect;
-            break;
-         case nir_intrinsic_store_ssbo_vk:
-            indirect_op = nir_intrinsic_store_ssbo_vk_indirect;
-            break;
-         default:
-            unreachable("Invalid direct load/store intrinsic");
-         }
-
-         nir_intrinsic_instr *copy =
-            nir_intrinsic_instr_create(state->shader, indirect_op);
-         copy->num_components = intrin->num_components;
-
-         for (unsigned i = 0; i < 4; i++)
-            copy->const_index[i] = intrin->const_index[i];
-
-         /* The indirect is always the last source */
-         indirect_src = nir_intrinsic_infos[intrin->intrinsic].num_srcs;
-
-         for (unsigned i = 0; i < (unsigned)indirect_src; i++)
-            nir_src_copy(&copy->src[i], &intrin->src[i], &copy->instr);
-
-         copy->src[indirect_src] = nir_src_for_ssa(offset);
-         nir_ssa_dest_init(&copy->instr, &copy->dest,
-                           intrin->dest.ssa.num_components,
-                           intrin->dest.ssa.name);
-         nir_builder_instr_insert(b, &copy->instr);
+      nir_src *offset_src = nir_get_io_offset_src(intrin);
+      nir_ssa_def *new_offset = nir_iadd(b, offset_src->ssa,
+                                         &offset_load->dest.ssa);
+
+      /* In order to avoid out-of-bounds access, we predicate */
+      nir_ssa_def *pred = nir_uge(b, nir_channel(b, &offset_load->dest.ssa, 1),
+                                  offset_src->ssa);
+      nir_if *if_stmt = nir_if_create(b->shader);
+      if_stmt->condition = nir_src_for_ssa(pred);
+      nir_cf_node_insert(b->cursor, &if_stmt->cf_node);
+
+      nir_instr_remove(&intrin->instr);
+      *offset_src = nir_src_for_ssa(new_offset);
+      nir_instr_insert_after_cf_list(&if_stmt->then_list, &intrin->instr);
+
+      if (intrin->intrinsic != nir_intrinsic_store_ssbo) {
+         /* It's a load, we need a phi node */
+         nir_phi_instr *phi = nir_phi_instr_create(b->shader);
+         nir_ssa_dest_init(&phi->instr, &phi->dest,
+                           intrin->num_components, NULL);
+
+         nir_phi_src *src1 = ralloc(phi, nir_phi_src);
+         struct exec_node *tnode = exec_list_get_tail(&if_stmt->then_list);
+         src1->pred = exec_node_data(nir_block, tnode, cf_node.node);
+         src1->src = nir_src_for_ssa(&intrin->dest.ssa);
+         exec_list_push_tail(&phi->srcs, &src1->node);
+
+         b->cursor = nir_after_cf_list(&if_stmt->else_list);
+         nir_ssa_def *zero = nir_build_imm(b, intrin->num_components,
+            (nir_const_value) { .u = { 0, 0, 0, 0 } });
+
+         nir_phi_src *src2 = ralloc(phi, nir_phi_src);
+         struct exec_node *enode = exec_list_get_tail(&if_stmt->else_list);
+         src2->pred = exec_node_data(nir_block, enode, cf_node.node);
+         src2->src = nir_src_for_ssa(zero);
+         exec_list_push_tail(&phi->srcs, &src2->node);
 
          assert(intrin->dest.is_ssa);
          nir_ssa_def_rewrite_uses(&intrin->dest.ssa,
-                                  nir_src_for_ssa(&copy->dest.ssa));
+                                  nir_src_for_ssa(&phi->dest.ssa));
 
-         nir_instr_remove(&intrin->instr);
-      } else {
-         /* It's already indirect, so we can just rewrite the one source */
-         nir_instr_rewrite_src(&intrin->instr, &intrin->src[indirect_src],
-                               nir_src_for_ssa(offset));
+         nir_instr_insert_after_cf(&if_stmt->cf_node, &phi->instr);
       }
    }
 
@@ -184,27 +143,29 @@ anv_nir_apply_dynamic_offsets(struct anv_pipeline *pipeline,
 {
    struct apply_dynamic_offsets_state state = {
       .shader = shader,
-      .stage = anv_vk_shader_stage_for_mesa_stage(shader->stage),
       .layout = pipeline->layout,
       .indices_start = shader->num_uniforms,
    };
 
-   if (!state.layout || !state.layout->stage[state.stage].has_dynamic_offsets)
+   if (!state.layout || !state.layout->stage[shader->stage].has_dynamic_offsets)
       return;
 
-   nir_foreach_overload(shader, overload) {
-      if (overload->impl) {
-         nir_builder_init(&state.builder, overload->impl);
-         nir_foreach_block(overload->impl, apply_dynamic_offsets_block, &state);
-         nir_metadata_preserve(overload->impl, nir_metadata_block_index |
+   nir_foreach_function(shader, function) {
+      if (function->impl) {
+         nir_builder_init(&state.builder, function->impl);
+         nir_foreach_block(function->impl, apply_dynamic_offsets_block, &state);
+         nir_metadata_preserve(function->impl, nir_metadata_block_index |
                                                nir_metadata_dominance);
       }
    }
 
    struct anv_push_constants *null_data = NULL;
-   for (unsigned i = 0; i < MAX_DYNAMIC_BUFFERS; i++)
-      prog_data->param[i + shader->num_uniforms] =
-         (const gl_constant_value *)&null_data->dynamic_offsets[i];
+   for (unsigned i = 0; i < MAX_DYNAMIC_BUFFERS; i++) {
+      prog_data->param[i * 2 + shader->num_uniforms] =
+         (const union gl_constant_value *)&null_data->dynamic[i].offset;
+      prog_data->param[i * 2 + 1 + shader->num_uniforms] =
+         (const union gl_constant_value *)&null_data->dynamic[i].range;
+   }
 
-   shader->num_uniforms += MAX_DYNAMIC_BUFFERS;
+   shader->num_uniforms += MAX_DYNAMIC_BUFFERS * 8;
 }