mesa/src/amd/vulkan/nir/radv_nir_lower_io.c
Antonio Ospite ddf2aa3a4d build: avoid redefining unreachable() which is standard in C23
In the C23 standard unreachable() is now a predefined function-like
macro in <stddef.h>

See https://android.googlesource.com/platform/bionic/+/HEAD/docs/c23.md#is-now-a-predefined-function_like-macro-in

And this causes build errors when building for C23:

-----------------------------------------------------------------------
In file included from ../src/util/log.h:30,
                 from ../src/util/log.c:30:
../src/util/macros.h:123:9: warning: "unreachable" redefined
  123 | #define unreachable(str)    \
      |         ^~~~~~~~~~~
In file included from ../src/util/macros.h:31:
/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h:456:9: note: this is the location of the previous definition
  456 | #define unreachable() (__builtin_unreachable ())
      |         ^~~~~~~~~~~
-----------------------------------------------------------------------

So don't redefine it with the same name, but use the name UNREACHABLE()
to also signify it's a macro.

Using a different name also makes sense because the behavior of the
macro was extending the one of __builtin_unreachable() anyway, and it
also had a different signature, accepting one argument, compared to the
standard unreachable() with no arguments.

This change improves the chances of building mesa with the C23 standard,
which for instance is the default in recent AOSP versions.

All the instances of the macro, including the definition, were updated
with the following command line:

  git grep -l '[^_]unreachable(' -- "src/**" | sort | uniq | \
  while read file; \
  do \
    sed -e 's/\([^_]\)unreachable(/\1UNREACHABLE(/g' -i "$file"; \
  done && \
  sed -e 's/#undef unreachable/#undef UNREACHABLE/g' -i src/intel/isl/isl_aux_info.c

Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36437>
2025-07-31 17:49:42 +00:00

295 lines
11 KiB
C

/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
* Copyright © 2023 Valve Corporation
*
* SPDX-License-Identifier: MIT
*/
#include "ac_nir.h"
#include "nir.h"
#include "nir_builder.h"
#include "nir_tcs_info.h"
#include "radv_device.h"
#include "radv_nir.h"
#include "radv_physical_device.h"
#include "radv_shader.h"
static int
type_size_vec4(const struct glsl_type *type, bool bindless)
{
return glsl_count_attribute_slots(type, false);
}
void
radv_nir_lower_io_vars_to_scalar(nir_shader *nir, nir_variable_mode mask)
{
bool progress = false;
NIR_PASS(progress, nir, nir_lower_io_vars_to_scalar, mask);
if (progress) {
/* Optimize the new vector code and then remove dead vars */
NIR_PASS(_, nir, nir_copy_prop);
NIR_PASS(_, nir, nir_opt_shrink_vectors, true);
if (mask & nir_var_shader_out) {
/* Optimize swizzled movs of load_const for nir_link_opt_varyings's constant propagation. */
NIR_PASS(_, nir, nir_opt_constant_folding);
/* For nir_link_opt_varyings's duplicate input opt */
NIR_PASS(_, nir, nir_opt_cse);
}
/* Run copy-propagation to help remove dead output variables (some shaders have useless copies
* to/from an output), so compaction later will be more effective.
*
* This will have been done earlier but it might not have worked because the outputs were
* vector.
*/
if (nir->info.stage == MESA_SHADER_TESS_CTRL)
NIR_PASS(_, nir, nir_opt_copy_prop_vars);
NIR_PASS(_, nir, nir_opt_dce);
NIR_PASS(_, nir, nir_remove_dead_variables, nir_var_function_temp | nir_var_shader_in | nir_var_shader_out, NULL);
}
}
typedef struct {
uint64_t always_per_vertex;
uint64_t potentially_per_primitive;
uint64_t always_per_primitive;
unsigned num_always_per_vertex;
unsigned num_potentially_per_primitive;
} radv_recompute_fs_input_bases_state;
static bool
radv_recompute_fs_input_bases_callback(UNUSED nir_builder *b, nir_intrinsic_instr *intrin, void *data)
{
const radv_recompute_fs_input_bases_state *s = (const radv_recompute_fs_input_bases_state *)data;
/* Filter possible FS input intrinsics */
switch (intrin->intrinsic) {
case nir_intrinsic_load_input:
case nir_intrinsic_load_per_primitive_input:
case nir_intrinsic_load_interpolated_input:
case nir_intrinsic_load_input_vertex:
break;
default:
return false;
}
const nir_io_semantics sem = nir_intrinsic_io_semantics(intrin);
const uint64_t location_bit = BITFIELD64_BIT(sem.location);
const uint64_t location_mask = BITFIELD64_MASK(sem.location);
const unsigned old_base = nir_intrinsic_base(intrin);
unsigned new_base = 0;
if (location_bit & s->always_per_vertex) {
new_base = util_bitcount64(s->always_per_vertex & location_mask);
} else if (location_bit & s->potentially_per_primitive) {
new_base = s->num_always_per_vertex;
switch (location_bit) {
case VARYING_BIT_VIEWPORT:
break;
case VARYING_BIT_PRIMITIVE_ID:
new_base += !!(s->potentially_per_primitive & VARYING_BIT_VIEWPORT);
break;
}
} else if (location_bit & s->always_per_primitive) {
new_base = s->num_always_per_vertex + s->num_potentially_per_primitive +
util_bitcount64(s->always_per_primitive & location_mask);
} else {
UNREACHABLE("invalid FS input");
}
if (new_base != old_base) {
nir_intrinsic_set_base(intrin, new_base);
return true;
}
return false;
}
bool
radv_recompute_fs_input_bases(nir_shader *nir)
{
const uint64_t always_per_vertex = nir->info.inputs_read & ~nir->info.per_primitive_inputs &
~(VARYING_BIT_PRIMITIVE_ID | VARYING_BIT_VIEWPORT | VARYING_BIT_LAYER);
const uint64_t potentially_per_primitive = nir->info.inputs_read & (VARYING_BIT_PRIMITIVE_ID | VARYING_BIT_VIEWPORT);
const uint64_t always_per_primitive = nir->info.inputs_read & nir->info.per_primitive_inputs &
~(VARYING_BIT_PRIMITIVE_ID | VARYING_BIT_VIEWPORT | VARYING_BIT_LAYER);
radv_recompute_fs_input_bases_state s = {
.always_per_vertex = always_per_vertex,
.potentially_per_primitive = potentially_per_primitive,
.always_per_primitive = always_per_primitive,
.num_always_per_vertex = util_bitcount64(always_per_vertex),
.num_potentially_per_primitive = util_bitcount64(potentially_per_primitive),
};
return nir_shader_intrinsics_pass(nir, radv_recompute_fs_input_bases_callback, nir_metadata_control_flow, &s);
}
void
radv_nir_lower_io(struct radv_device *device, nir_shader *nir)
{
const struct radv_physical_device *pdev = radv_device_physical(device);
/* The nir_lower_io pass currently cannot handle array deref of vectors.
* Call this here to make sure there are no such derefs left in the shader.
*/
NIR_PASS(_, nir, nir_lower_array_deref_of_vec, nir_var_shader_in | nir_var_shader_out, NULL,
nir_lower_direct_array_deref_of_vec_load | nir_lower_indirect_array_deref_of_vec_load |
nir_lower_direct_array_deref_of_vec_store | nir_lower_indirect_array_deref_of_vec_store);
if (nir->info.stage == MESA_SHADER_TESS_CTRL) {
NIR_PASS(_, nir, nir_lower_tess_level_array_vars_to_vec);
}
if (nir->info.stage == MESA_SHADER_VERTEX) {
NIR_PASS(_, nir, nir_lower_io, nir_var_shader_in, type_size_vec4, 0);
NIR_PASS(_, nir, nir_lower_io, nir_var_shader_out, type_size_vec4, nir_lower_io_lower_64bit_to_32);
} else {
NIR_PASS(_, nir, nir_lower_io, nir_var_shader_in | nir_var_shader_out, type_size_vec4,
nir_lower_io_lower_64bit_to_32 | nir_lower_io_use_interpolated_input_intrinsics);
}
/* This pass needs actual constants */
NIR_PASS(_, nir, nir_opt_constant_folding);
NIR_PASS(_, nir, nir_io_add_const_offset_to_base, nir_var_shader_in | nir_var_shader_out);
if (nir->xfb_info) {
NIR_PASS(_, nir, nir_io_add_intrinsic_xfb_info);
if (pdev->use_ngg_streamout) {
/* The total number of shader outputs is required for computing the pervertex LDS size for
* VS/TES when lowering NGG streamout.
*/
nir_assign_io_var_locations(nir, nir_var_shader_out, &nir->num_outputs, nir->info.stage);
}
}
if (nir->info.stage == MESA_SHADER_FRAGMENT) {
/* Lower explicit input load intrinsics to sysvals for the layer ID. */
NIR_PASS(_, nir, nir_lower_system_values);
/* Recompute FS input intrinsic bases to assign a location to each FS input.
* The computed base will match the index of each input in SPI_PS_INPUT_CNTL_n.
*/
radv_recompute_fs_input_bases(nir);
}
NIR_PASS(_, nir, nir_opt_dce);
NIR_PASS(_, nir, nir_remove_dead_variables, nir_var_shader_in | nir_var_shader_out, NULL);
}
/* IO slot layout for stages that aren't linked. */
enum {
RADV_IO_SLOT_POS = 0,
RADV_IO_SLOT_CLIP_DIST0,
RADV_IO_SLOT_CLIP_DIST1,
RADV_IO_SLOT_PSIZ,
RADV_IO_SLOT_VAR0, /* 0..31 */
};
unsigned
radv_map_io_driver_location(unsigned semantic)
{
if ((semantic >= VARYING_SLOT_PATCH0 && semantic < VARYING_SLOT_TESS_MAX) ||
semantic == VARYING_SLOT_TESS_LEVEL_INNER || semantic == VARYING_SLOT_TESS_LEVEL_OUTER)
return ac_shader_io_get_unique_index_patch(semantic);
switch (semantic) {
case VARYING_SLOT_POS:
return RADV_IO_SLOT_POS;
case VARYING_SLOT_CLIP_DIST0:
return RADV_IO_SLOT_CLIP_DIST0;
case VARYING_SLOT_CLIP_DIST1:
return RADV_IO_SLOT_CLIP_DIST1;
case VARYING_SLOT_PSIZ:
return RADV_IO_SLOT_PSIZ;
default:
assert(semantic >= VARYING_SLOT_VAR0 && semantic <= VARYING_SLOT_VAR31);
return RADV_IO_SLOT_VAR0 + (semantic - VARYING_SLOT_VAR0);
}
}
bool
radv_nir_lower_io_to_mem(struct radv_device *device, struct radv_shader_stage *stage)
{
const struct radv_physical_device *pdev = radv_device_physical(device);
const struct radv_shader_info *info = &stage->info;
ac_nir_map_io_driver_location map_input = info->inputs_linked ? NULL : radv_map_io_driver_location;
ac_nir_map_io_driver_location map_output = info->outputs_linked ? NULL : radv_map_io_driver_location;
nir_shader *nir = stage->nir;
if (nir->info.stage == MESA_SHADER_VERTEX) {
if (info->vs.as_ls) {
NIR_PASS(_, nir, ac_nir_lower_ls_outputs_to_mem, map_output, pdev->info.gfx_level, info->vs.tcs_in_out_eq,
info->vs.tcs_inputs_via_temp, info->vs.tcs_inputs_via_lds);
return true;
} else if (info->vs.as_es) {
NIR_PASS(_, nir, ac_nir_lower_es_outputs_to_mem, map_output, pdev->info.gfx_level, info->esgs_itemsize,
info->gs_inputs_read);
return true;
}
} else if (nir->info.stage == MESA_SHADER_TESS_CTRL) {
NIR_PASS(_, nir, ac_nir_lower_hs_inputs_to_mem, map_input, pdev->info.gfx_level, info->vs.tcs_in_out_eq,
info->vs.tcs_inputs_via_temp, info->vs.tcs_inputs_via_lds);
nir_tcs_info tcs_info;
nir_gather_tcs_info(nir, &tcs_info, nir->info.tess._primitive_mode, nir->info.tess.spacing);
ac_nir_tess_io_info tess_io_info;
ac_nir_get_tess_io_info(nir, &tcs_info, info->tcs.tes_inputs_read, info->tcs.tes_patch_inputs_read, map_output,
true, &tess_io_info);
NIR_PASS(_, nir, ac_nir_lower_hs_outputs_to_mem, &tcs_info, &tess_io_info, map_output, pdev->info.gfx_level,
info->wave_size);
return true;
} else if (nir->info.stage == MESA_SHADER_TESS_EVAL) {
NIR_PASS(_, nir, ac_nir_lower_tes_inputs_to_mem, map_input);
if (info->tes.as_es) {
NIR_PASS(_, nir, ac_nir_lower_es_outputs_to_mem, map_output, pdev->info.gfx_level, info->esgs_itemsize,
info->gs_inputs_read);
}
return true;
} else if (nir->info.stage == MESA_SHADER_GEOMETRY) {
NIR_PASS(_, nir, ac_nir_lower_gs_inputs_to_mem, map_input, pdev->info.gfx_level, false);
return true;
} else if (nir->info.stage == MESA_SHADER_TASK) {
ac_nir_lower_task_outputs_to_mem(nir, pdev->task_info.payload_entry_size, pdev->task_info.num_entries,
info->cs.has_query);
return true;
} else if (nir->info.stage == MESA_SHADER_MESH) {
ac_nir_lower_mesh_inputs_to_mem(nir, pdev->task_info.payload_entry_size, pdev->task_info.num_entries);
return true;
}
return false;
}
static bool
radv_nir_lower_draw_id_to_zero_callback(struct nir_builder *b, nir_intrinsic_instr *intrin, UNUSED void *state)
{
if (intrin->intrinsic != nir_intrinsic_load_draw_id)
return false;
nir_def *replacement = nir_imm_zero(b, intrin->def.num_components, intrin->def.bit_size);
nir_def_replace(&intrin->def, replacement);
nir_instr_free(&intrin->instr);
return true;
}
bool
radv_nir_lower_draw_id_to_zero(nir_shader *shader)
{
return nir_shader_intrinsics_pass(shader, radv_nir_lower_draw_id_to_zero_callback, nir_metadata_control_flow, NULL);
}