+ if (vertex_index_out != NULL || vertex_index_ref != NULL) {
+ tail = tail->child;
+ nir_deref_array *deref_array = nir_deref_as_array(tail);
+ if (vertex_index_out)
+ *vertex_index_out = deref_array->base_offset;
+
+ if (vertex_index_ref) {
+ LLVMValueRef vtx = LLVMConstInt(ctx->i32, deref_array->base_offset, false);
+ if (deref_array->deref_array_type == nir_deref_array_type_indirect) {
+ vtx = LLVMBuildAdd(ctx->builder, vtx, get_src(ctx, deref_array->indirect), "");
+ }
+ *vertex_index_ref = vtx;
+ }
+ }
+
+ if (deref->var->data.compact) {
+ assert(tail->child->deref_type == nir_deref_type_array);
+ assert(glsl_type_is_scalar(glsl_without_array(deref->var->type)));
+ nir_deref_array *deref_array = nir_deref_as_array(tail->child);
+ /* We always lower indirect dereferences for "compact" array vars. */
+ assert(deref_array->deref_array_type == nir_deref_array_type_direct);
+
+ const_offset = deref_array->base_offset;
+ goto out;
+ }
+
+ while (tail->child != NULL) {
+ const struct glsl_type *parent_type = tail->type;
+ tail = tail->child;
+
+ if (tail->deref_type == nir_deref_type_array) {
+ nir_deref_array *deref_array = nir_deref_as_array(tail);
+ LLVMValueRef index, stride, local_offset;
+ unsigned size = glsl_count_attribute_slots(tail->type, vs_in);
+
+ const_offset += size * deref_array->base_offset;
+ if (deref_array->deref_array_type == nir_deref_array_type_direct)
+ continue;
+
+ assert(deref_array->deref_array_type == nir_deref_array_type_indirect);
+ index = get_src(ctx, deref_array->indirect);
+ stride = LLVMConstInt(ctx->i32, size, 0);
+ local_offset = LLVMBuildMul(ctx->builder, stride, index, "");
+
+ if (offset)
+ offset = LLVMBuildAdd(ctx->builder, offset, local_offset, "");
+ else
+ offset = local_offset;
+ } else if (tail->deref_type == nir_deref_type_struct) {
+ nir_deref_struct *deref_struct = nir_deref_as_struct(tail);
+
+ for (unsigned i = 0; i < deref_struct->index; i++) {
+ const struct glsl_type *ft = glsl_get_struct_field(parent_type, i);
+ const_offset += glsl_count_attribute_slots(ft, vs_in);
+ }
+ } else
+ unreachable("unsupported deref type");
+
+ }
+out:
+ if (const_offset && offset)
+ offset = LLVMBuildAdd(ctx->builder, offset,
+ LLVMConstInt(ctx->i32, const_offset, 0),
+ "");
+
+ *const_out = const_offset;
+ *indir_out = offset;
+}
+
+static LLVMValueRef
+lds_load(struct nir_to_llvm_context *ctx,
+ LLVMValueRef dw_addr)
+{
+ LLVMValueRef value;
+ value = ac_build_indexed_load(&ctx->ac, ctx->lds, dw_addr, false);
+ return value;
+}
+
+static void
+lds_store(struct nir_to_llvm_context *ctx,
+ LLVMValueRef dw_addr, LLVMValueRef value)
+{
+ value = LLVMBuildBitCast(ctx->builder, value, ctx->i32, "");
+ ac_build_indexed_store(&ctx->ac, ctx->lds,
+ dw_addr, value);
+}
+
+/* The offchip buffer layout for TCS->TES is
+ *
+ * - attribute 0 of patch 0 vertex 0
+ * - attribute 0 of patch 0 vertex 1
+ * - attribute 0 of patch 0 vertex 2
+ * ...
+ * - attribute 0 of patch 1 vertex 0
+ * - attribute 0 of patch 1 vertex 1
+ * ...
+ * - attribute 1 of patch 0 vertex 0
+ * - attribute 1 of patch 0 vertex 1
+ * ...
+ * - per patch attribute 0 of patch 0
+ * - per patch attribute 0 of patch 1
+ * ...
+ *
+ * Note that every attribute has 4 components.
+ */
+static LLVMValueRef get_tcs_tes_buffer_address(struct nir_to_llvm_context *ctx,
+ LLVMValueRef vertex_index,
+ LLVMValueRef param_index)
+{
+ LLVMValueRef base_addr, vertices_per_patch, num_patches, total_vertices;
+ LLVMValueRef param_stride, constant16;
+ LLVMValueRef rel_patch_id = get_rel_patch_id(ctx);
+
+ vertices_per_patch = unpack_param(ctx, ctx->tcs_offchip_layout, 9, 6);
+ num_patches = unpack_param(ctx, ctx->tcs_offchip_layout, 0, 9);
+ total_vertices = LLVMBuildMul(ctx->builder, vertices_per_patch,
+ num_patches, "");
+
+ constant16 = LLVMConstInt(ctx->i32, 16, false);
+ if (vertex_index) {
+ base_addr = LLVMBuildMul(ctx->builder, rel_patch_id,
+ vertices_per_patch, "");
+
+ base_addr = LLVMBuildAdd(ctx->builder, base_addr,
+ vertex_index, "");
+
+ param_stride = total_vertices;
+ } else {
+ base_addr = rel_patch_id;
+ param_stride = num_patches;
+ }
+
+ base_addr = LLVMBuildAdd(ctx->builder, base_addr,
+ LLVMBuildMul(ctx->builder, param_index,
+ param_stride, ""), "");
+
+ base_addr = LLVMBuildMul(ctx->builder, base_addr, constant16, "");
+
+ if (!vertex_index) {
+ LLVMValueRef patch_data_offset =
+ unpack_param(ctx, ctx->tcs_offchip_layout, 16, 16);
+
+ base_addr = LLVMBuildAdd(ctx->builder, base_addr,
+ patch_data_offset, "");
+ }
+ return base_addr;
+}
+
+static LLVMValueRef get_tcs_tes_buffer_address_params(struct nir_to_llvm_context *ctx,
+ unsigned param,
+ unsigned const_index,
+ bool is_compact,
+ LLVMValueRef vertex_index,
+ LLVMValueRef indir_index)
+{
+ LLVMValueRef param_index;
+
+ if (indir_index)
+ param_index = LLVMBuildAdd(ctx->builder, LLVMConstInt(ctx->i32, param, false),
+ indir_index, "");
+ else {
+ if (const_index && !is_compact)
+ param += const_index;
+ param_index = LLVMConstInt(ctx->i32, param, false);
+ }
+ return get_tcs_tes_buffer_address(ctx, vertex_index, param_index);
+}
+
+static void
+mark_tess_output(struct nir_to_llvm_context *ctx,
+ bool is_patch, uint32_t param)
+
+{
+ if (is_patch) {
+ ctx->tess_patch_outputs_written |= (1ull << param);
+ } else
+ ctx->tess_outputs_written |= (1ull << param);
+}
+
+static LLVMValueRef
+get_dw_address(struct nir_to_llvm_context *ctx,
+ LLVMValueRef dw_addr,
+ unsigned param,
+ unsigned const_index,
+ bool compact_const_index,
+ LLVMValueRef vertex_index,
+ LLVMValueRef stride,
+ LLVMValueRef indir_index)
+
+{
+
+ if (vertex_index) {
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ LLVMBuildMul(ctx->builder,
+ vertex_index,
+ stride, ""), "");
+ }
+
+ if (indir_index)
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ LLVMBuildMul(ctx->builder, indir_index,
+ LLVMConstInt(ctx->i32, 4, false), ""), "");
+ else if (const_index && !compact_const_index)
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ LLVMConstInt(ctx->i32, const_index, false), "");
+
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ LLVMConstInt(ctx->i32, param * 4, false), "");
+
+ if (const_index && compact_const_index)
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ LLVMConstInt(ctx->i32, const_index, false), "");
+ return dw_addr;
+}
+
+static LLVMValueRef
+load_tcs_input(struct nir_to_llvm_context *ctx,
+ nir_intrinsic_instr *instr)
+{
+ LLVMValueRef dw_addr, stride;
+ unsigned const_index;
+ LLVMValueRef vertex_index;
+ LLVMValueRef indir_index;
+ unsigned param;
+ LLVMValueRef value[4], result;
+ const bool per_vertex = nir_is_per_vertex_io(instr->variables[0]->var, ctx->stage);
+ const bool is_compact = instr->variables[0]->var->data.compact;
+ param = shader_io_get_unique_index(instr->variables[0]->var->data.location);
+ radv_get_deref_offset(ctx, instr->variables[0],
+ false, NULL, per_vertex ? &vertex_index : NULL,
+ &const_index, &indir_index);
+
+ stride = unpack_param(ctx, ctx->tcs_in_layout, 13, 8);
+ dw_addr = get_tcs_in_current_patch_offset(ctx);
+ dw_addr = get_dw_address(ctx, dw_addr, param, const_index, is_compact, vertex_index, stride,
+ indir_index);
+
+ for (unsigned i = 0; i < instr->num_components; i++) {
+ value[i] = lds_load(ctx, dw_addr);
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ ctx->i32one, "");
+ }
+ result = ac_build_gather_values(&ctx->ac, value, instr->num_components);
+ result = LLVMBuildBitCast(ctx->builder, result, get_def_type(ctx, &instr->dest.ssa), "");
+ return result;
+}
+
+static LLVMValueRef
+load_tcs_output(struct nir_to_llvm_context *ctx,
+ nir_intrinsic_instr *instr)
+{
+ LLVMValueRef dw_addr, stride;
+ LLVMValueRef value[4], result;
+ LLVMValueRef vertex_index = NULL;
+ LLVMValueRef indir_index = NULL;
+ unsigned const_index = 0;
+ unsigned param;
+ const bool per_vertex = nir_is_per_vertex_io(instr->variables[0]->var, ctx->stage);
+ const bool is_compact = instr->variables[0]->var->data.compact;
+ param = shader_io_get_unique_index(instr->variables[0]->var->data.location);
+ radv_get_deref_offset(ctx, instr->variables[0],
+ false, NULL, per_vertex ? &vertex_index : NULL,
+ &const_index, &indir_index);
+
+ if (!instr->variables[0]->var->data.patch) {
+ stride = unpack_param(ctx, ctx->tcs_out_layout, 13, 8);
+ dw_addr = get_tcs_out_current_patch_offset(ctx);
+ } else {
+ dw_addr = get_tcs_out_current_patch_data_offset(ctx);
+ }
+
+ dw_addr = get_dw_address(ctx, dw_addr, param, const_index, is_compact, vertex_index, stride,
+ indir_index);
+
+ for (unsigned i = 0; i < instr->num_components; i++) {
+ value[i] = lds_load(ctx, dw_addr);
+ dw_addr = LLVMBuildAdd(ctx->builder, dw_addr,
+ ctx->i32one, "");
+ }
+ result = ac_build_gather_values(&ctx->ac, value, instr->num_components);
+ result = LLVMBuildBitCast(ctx->builder, result, get_def_type(ctx, &instr->dest.ssa), "");
+ return result;
+}
+
+static void
+store_tcs_output(struct nir_to_llvm_context *ctx,
+ nir_intrinsic_instr *instr,
+ LLVMValueRef src,
+ unsigned writemask)
+{
+ LLVMValueRef stride, dw_addr;
+ LLVMValueRef buf_addr = NULL;
+ LLVMValueRef vertex_index = NULL;
+ LLVMValueRef indir_index = NULL;
+ unsigned const_index = 0;
+ unsigned param;
+ const bool per_vertex = nir_is_per_vertex_io(instr->variables[0]->var, ctx->stage);
+ const bool is_compact = instr->variables[0]->var->data.compact;
+
+ radv_get_deref_offset(ctx, instr->variables[0],
+ false, NULL, per_vertex ? &vertex_index : NULL,
+ &const_index, &indir_index);
+
+ param = shader_io_get_unique_index(instr->variables[0]->var->data.location);
+ if (instr->variables[0]->var->data.location == VARYING_SLOT_CLIP_DIST0 &&
+ is_compact && const_index > 3) {
+ const_index -= 3;
+ param++;
+ }
+
+ if (!instr->variables[0]->var->data.patch) {
+ stride = unpack_param(ctx, ctx->tcs_out_layout, 13, 8);
+ dw_addr = get_tcs_out_current_patch_offset(ctx);
+ } else {
+ dw_addr = get_tcs_out_current_patch_data_offset(ctx);