nir: Introduce nir_debug_info_instr

Adds a new instruction type that stores metadata that might be useful
for debugging purposes. Passes must ignore these instructions when
making decisions.

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18903>
This commit is contained in:
Konstantin Seurer 2024-05-19 17:29:21 +02:00 committed by Marge Bot
parent a70968c62f
commit ce24486ee4
19 changed files with 280 additions and 0 deletions

View file

@ -1315,6 +1315,9 @@ v3d_instr_delay_cb(nir_instr *instr, void *data)
case nir_instr_type_tex:
return 5;
case nir_instr_type_debug_info:
return 0;
}
return 0;

View file

@ -880,6 +880,26 @@ nir_parallel_copy_instr_create(nir_shader *shader)
return instr;
}
nir_debug_info_instr *
nir_debug_info_instr_create(nir_shader *shader, nir_debug_info_type type,
uint32_t string_length)
{
uint32_t additional_size = 0;
if (type == nir_debug_info_string)
additional_size = string_length + 1;
nir_debug_info_instr *instr = gc_zalloc_size(
shader->gctx, sizeof(nir_debug_info_instr) + additional_size, 1);
instr_init(&instr->instr, nir_instr_type_debug_info);
instr->type = type;
if (type == nir_debug_info_string)
instr->string_length = string_length;
return instr;
}
nir_undef_instr *
nir_undef_instr_create(nir_shader *shader,
unsigned num_components,
@ -1331,6 +1351,7 @@ nir_instr_def(nir_instr *instr)
case nir_instr_type_call:
case nir_instr_type_jump:
case nir_instr_type_debug_info:
return NULL;
}
@ -1401,6 +1422,16 @@ nir_src_as_const_value(nir_src src)
return load->value;
}
const char *
nir_src_as_string(nir_src src)
{
nir_debug_info_instr *di = nir_src_as_debug_info(src);
if (di && di->type == nir_debug_info_string)
return di->string;
return NULL;
}
/**
* Returns true if the source is known to be always uniform. Otherwise it
* returns false which means it may or may not be uniform but it can't be

View file

@ -959,6 +959,7 @@ typedef enum ENUM_PACKED {
nir_instr_type_undef,
nir_instr_type_phi,
nir_instr_type_parallel_copy,
nir_instr_type_debug_info,
} nir_instr_type;
typedef struct nir_instr {
@ -2760,6 +2761,41 @@ typedef struct {
struct exec_list entries;
} nir_parallel_copy_instr;
typedef enum nir_debug_info_type {
nir_debug_info_src_loc,
nir_debug_info_string,
} nir_debug_info_type;
typedef enum nir_debug_info_source {
nir_debug_info_spirv,
nir_debug_info_nir,
} nir_debug_info_source;
typedef struct nir_debug_info_instr {
nir_instr instr;
nir_debug_info_type type;
union {
struct {
nir_src filename;
/* 0 if only the spirv_offset is available. */
uint32_t line;
uint32_t column;
uint32_t spirv_offset;
nir_debug_info_source source;
} src_loc;
uint16_t string_length;
};
nir_def def;
char string[];
} nir_debug_info_instr;
NIR_DEFINE_CAST(nir_instr_as_alu, nir_instr, nir_alu_instr, instr,
type, nir_instr_type_alu)
NIR_DEFINE_CAST(nir_instr_as_deref, nir_instr, nir_deref_instr, instr,
@ -2781,6 +2817,9 @@ NIR_DEFINE_CAST(nir_instr_as_phi, nir_instr, nir_phi_instr, instr,
NIR_DEFINE_CAST(nir_instr_as_parallel_copy, nir_instr,
nir_parallel_copy_instr, instr,
type, nir_instr_type_parallel_copy)
NIR_DEFINE_CAST(nir_instr_as_debug_info, nir_instr,
nir_debug_info_instr, instr,
type, nir_instr_type_debug_info)
#define NIR_DEFINE_SRC_AS_CONST(type, suffix) \
static inline type \
@ -4584,6 +4623,10 @@ nir_phi_src *nir_phi_instr_add_src(nir_phi_instr *instr,
nir_parallel_copy_instr *nir_parallel_copy_instr_create(nir_shader *shader);
nir_debug_info_instr *nir_debug_info_instr_create(nir_shader *shader,
nir_debug_info_type type,
uint32_t string_length);
nir_undef_instr *nir_undef_instr_create(nir_shader *shader,
unsigned num_components,
unsigned bit_size);
@ -4893,6 +4936,9 @@ NIR_SRC_AS_(alu_instr, nir_alu_instr, nir_instr_type_alu, nir_instr_as_alu)
NIR_SRC_AS_(intrinsic, nir_intrinsic_instr,
nir_instr_type_intrinsic, nir_instr_as_intrinsic)
NIR_SRC_AS_(deref, nir_deref_instr, nir_instr_type_deref, nir_instr_as_deref)
NIR_SRC_AS_(debug_info, nir_debug_info_instr, nir_instr_type_debug_info, nir_instr_as_debug_info)
const char *nir_src_as_string(nir_src src);
bool nir_src_is_always_uniform(nir_src src);
bool nir_srcs_equal(nir_src src1, nir_src src2);

View file

@ -312,6 +312,17 @@ nir_build_tex_deref_instr(nir_builder *build, nir_texop op,
return &tex->def;
}
nir_def *
nir_build_string(nir_builder *build, const char *value)
{
nir_debug_info_instr *instr =
nir_debug_info_instr_create(build->shader, nir_debug_info_string, strlen(value));
memcpy(instr->string, value, instr->string_length);
nir_def_init(&instr->instr, &instr->def, 1, nir_get_ptr_bitsize(build->shader));
nir_builder_instr_insert(build, &instr->instr);
return &instr->def;
}
nir_def *
nir_vec_scalars(nir_builder *build, nir_scalar *comp, unsigned num_components)
{

View file

@ -2262,6 +2262,9 @@ nir_discard_if(nir_builder *build, nir_def *src)
nir_terminate_if(build, src);
}
nir_def *
nir_build_string(nir_builder *build, const char *value);
/*
* Call a given nir_function * with a variadic number of nir_def * arguments.
*

View file

@ -424,6 +424,30 @@ clone_call(clone_state *state, const nir_call_instr *call)
return ncall;
}
static nir_debug_info_instr *
clone_debug_info(clone_state *state, nir_debug_info_instr *di)
{
nir_debug_info_instr *instr =
nir_debug_info_instr_create(state->ns, di->type, di->string_length);
switch (di->type) {
case nir_debug_info_src_loc:
if (di->src_loc.line)
__clone_src(state, instr, &instr->src_loc.filename, &di->src_loc.filename);
instr->src_loc.line = di->src_loc.line;
instr->src_loc.column = di->src_loc.column;
instr->src_loc.spirv_offset = di->src_loc.spirv_offset;
instr->src_loc.source = di->src_loc.source;
return instr;
case nir_debug_info_string:
memcpy(instr->string, di->string, di->string_length);
__clone_def(state, &instr->instr, &instr->def, &di->def);
return instr;
}
unreachable("Unimplemented nir_debug_info_type");
}
static nir_instr *
clone_instr(clone_state *state, const nir_instr *instr)
{
@ -446,6 +470,8 @@ clone_instr(clone_state *state, const nir_instr *instr)
return &clone_jump(state, nir_instr_as_jump(instr))->instr;
case nir_instr_type_call:
return &clone_call(state, nir_instr_as_call(instr))->instr;
case nir_instr_type_debug_info:
return &clone_debug_info(state, nir_instr_as_debug_info(instr))->instr;
case nir_instr_type_parallel_copy:
unreachable("Cannot clone parallel copies");
default:

View file

@ -979,6 +979,8 @@ update_instr_divergence(nir_instr *instr, struct divergence_state *state)
return visit_def(&nir_instr_as_undef(instr)->def, state);
case nir_instr_type_deref:
return visit_deref(state->shader, nir_instr_as_deref(instr), state);
case nir_instr_type_debug_info:
return false;
case nir_instr_type_jump:
case nir_instr_type_phi:
case nir_instr_type_call:

View file

@ -32,6 +32,13 @@ _nir_foreach_def(nir_instr *instr, nir_foreach_def_cb cb, void *state)
case nir_instr_type_undef:
return cb(&nir_instr_as_undef(instr)->def, state);
case nir_instr_type_debug_info: {
nir_debug_info_instr *di = nir_instr_as_debug_info(instr);
if (di->type == nir_debug_info_string)
return cb(&di->def, state);
return true;
}
case nir_instr_type_call:
case nir_instr_type_jump:
return true;
@ -132,6 +139,15 @@ nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state)
return true;
}
case nir_instr_type_debug_info: {
nir_debug_info_instr *di = nir_instr_as_debug_info(instr);
if (di->type == nir_debug_info_src_loc && di->src_loc.line) {
if (!_nir_visit_src(&di->src_loc.filename, cb, state))
return false;
}
return true;
}
case nir_instr_type_load_const:
case nir_instr_type_undef:
return true;

View file

@ -62,6 +62,8 @@ instr_can_rewrite(const nir_instr *instr)
return nir_intrinsic_can_reorder(intr);
}
}
case nir_instr_type_debug_info:
return nir_instr_as_debug_info(instr)->type == nir_debug_info_string;
case nir_instr_type_call:
case nir_instr_type_jump:
case nir_instr_type_undef:
@ -265,6 +267,13 @@ hash_tex(uint32_t hash, const nir_tex_instr *instr)
return hash;
}
static uint32_t
hash_debug_info(uint32_t hash, const nir_debug_info_instr *instr)
{
assert(instr->type == nir_debug_info_string);
return XXH32(instr->string, instr->string_length, hash);
}
/* Computes a hash of an instruction for use in a hash table. Note that this
* will only work for instructions where instr_can_rewrite() returns true, and
* it should return identical hashes for two instructions that are the same
@ -296,6 +305,9 @@ hash_instr(const void *data)
case nir_instr_type_tex:
hash = hash_tex(hash, nir_instr_as_tex(instr));
break;
case nir_instr_type_debug_info:
hash = hash_debug_info(hash, nir_instr_as_debug_info(instr));
break;
default:
unreachable("Invalid instruction type");
}
@ -707,6 +719,16 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2)
return true;
}
case nir_instr_type_debug_info: {
nir_debug_info_instr *di1 = nir_instr_as_debug_info(instr1);
nir_debug_info_instr *di2 = nir_instr_as_debug_info(instr2);
assert(di1->type == nir_debug_info_string);
assert(di2->type == nir_debug_info_string);
return di1->string_length == di2->string_length &&
!memcmp(di1->string, di2->string, di1->string_length);
}
case nir_instr_type_call:
case nir_instr_type_jump:
case nir_instr_type_undef:
@ -734,6 +756,8 @@ nir_instr_get_def_def(nir_instr *instr)
return &nir_instr_as_intrinsic(instr)->def;
case nir_instr_type_tex:
return &nir_instr_as_tex(instr)->def;
case nir_instr_type_debug_info:
return &nir_instr_as_debug_info(instr)->def;
default:
unreachable("We never ask for any of these");
}

View file

@ -96,6 +96,16 @@ is_live(BITSET_WORD *defs_live, nir_instr *instr)
}
return false;
}
case nir_instr_type_debug_info: {
nir_debug_info_instr *di = nir_instr_as_debug_info(instr);
if (di->type == nir_debug_info_src_loc) {
nir_instr *next = nir_instr_next(instr);
return !next || next->type != nir_instr_type_debug_info;
} else if (di->type == nir_debug_info_string) {
return is_def_live(&di->def, defs_live);
}
return true;
}
default:
unreachable("unexpected instr type");
}

View file

@ -144,6 +144,7 @@ opt_move_discards_to_top_impl(nir_function_impl *impl)
case nir_instr_type_load_const:
case nir_instr_type_undef:
case nir_instr_type_phi:
case nir_instr_type_debug_info:
/* These are all safe */
continue;

View file

@ -73,6 +73,7 @@ block_check_for_allowed_instrs(nir_block *block, unsigned *count,
case nir_instr_type_phi:
case nir_instr_type_undef:
case nir_instr_type_tex:
case nir_instr_type_debug_info:
break;
case nir_instr_type_intrinsic: {
@ -270,6 +271,9 @@ block_check_for_allowed_instrs(nir_block *block, unsigned *count,
break;
}
case nir_instr_type_debug_info:
break;
default:
return false;
}

View file

@ -1972,6 +1972,24 @@ print_parallel_copy_instr(nir_parallel_copy_instr *instr, print_state *state)
}
}
static void
print_debug_info_instr(nir_debug_info_instr *instr, print_state *state)
{
FILE *fp = state->fp;
switch (instr->type) {
case nir_debug_info_src_loc:
fprintf(fp, "// 0x%x", instr->src_loc.spirv_offset);
if (instr->src_loc.line)
fprintf(fp, " %s:%u:%u", nir_src_as_string(instr->src_loc.filename), instr->src_loc.line, instr->src_loc.column);
return;
case nir_debug_info_string:
return; /* Strings are printed for their uses. */
}
unreachable("Unimplemented nir_debug_info_type");
}
static void
print_instr(const nir_instr *instr, print_state *state, unsigned tabs)
{
@ -2019,6 +2037,10 @@ print_instr(const nir_instr *instr, print_state *state, unsigned tabs)
print_parallel_copy_instr(nir_instr_as_parallel_copy(instr), state);
break;
case nir_instr_type_debug_info:
print_debug_info_instr(nir_instr_as_debug_info(instr), state);
break;
default:
unreachable("Invalid instruction type");
break;
@ -2054,6 +2076,7 @@ block_has_instruction_with_dest(nir_block *block)
case nir_instr_type_jump:
case nir_instr_type_call:
case nir_instr_type_debug_info:
/* Doesn't define a new value. */
break;
}

View file

@ -126,6 +126,7 @@ propagate_invariant_instr(nir_instr *instr, struct set *invariants)
case nir_instr_type_jump:
case nir_instr_type_undef:
case nir_instr_type_load_const:
case nir_instr_type_debug_info:
break; /* Nothing to do */
case nir_instr_type_phi: {

View file

@ -460,6 +460,7 @@ nir_schedule_calculate_deps(nir_deps_state *state, nir_schedule_node *n)
case nir_instr_type_load_const:
case nir_instr_type_alu:
case nir_instr_type_deref:
case nir_instr_type_debug_info:
break;
case nir_instr_type_tex:
@ -1093,6 +1094,7 @@ nir_schedule_get_delay(nir_schedule_scoreboard *scoreboard, nir_instr *instr)
case nir_instr_type_parallel_copy:
case nir_instr_type_call:
case nir_instr_type_phi:
case nir_instr_type_debug_info:
return 1;
case nir_instr_type_intrinsic:

View file

@ -587,6 +587,12 @@ union packed_instr {
unsigned type : 2;
unsigned _pad : 26;
} jump;
struct {
unsigned instr_type : 4;
unsigned type : 4;
unsigned string_length : 16;
unsigned def : 8;
} debug_info;
};
/* Write "lo24" as low 24 bits in the first uint32. */
@ -1592,6 +1598,63 @@ read_call(read_ctx *ctx)
return call;
}
static void
write_debug_info(write_ctx *ctx, const nir_debug_info_instr *di)
{
union packed_instr header;
header.u32 = 0;
header.debug_info.instr_type = nir_instr_type_debug_info;
header.debug_info.type = di->type;
header.debug_info.string_length = di->string_length;
switch (di->type) {
case nir_debug_info_src_loc:
blob_write_uint32(ctx->blob, header.u32);
blob_write_uint32(ctx->blob, di->src_loc.line);
blob_write_uint32(ctx->blob, di->src_loc.column);
blob_write_uint32(ctx->blob, di->src_loc.spirv_offset);
blob_write_uint8(ctx->blob, di->src_loc.source);
if (di->src_loc.line)
write_src(ctx, &di->src_loc.filename);
return;
case nir_debug_info_string:
write_def(ctx, &di->def, header, di->instr.type);
blob_write_bytes(ctx->blob, di->string, di->string_length);
return;
}
unreachable("Unimplemented nir_debug_info_type");
}
static nir_debug_info_instr *
read_debug_info(read_ctx *ctx, union packed_instr header)
{
nir_debug_info_type type = header.debug_info.type;
switch (type) {
case nir_debug_info_src_loc: {
nir_debug_info_instr *di = nir_debug_info_instr_create(ctx->nir, type, 0);
di->src_loc.line = blob_read_uint32(ctx->blob);
di->src_loc.column = blob_read_uint32(ctx->blob);
di->src_loc.spirv_offset = blob_read_uint32(ctx->blob);
di->src_loc.source = blob_read_uint8(ctx->blob);
if (di->src_loc.line)
read_src(ctx, &di->src_loc.filename);
return di;
}
case nir_debug_info_string: {
nir_debug_info_instr *di =
nir_debug_info_instr_create(ctx->nir, type, header.debug_info.string_length);
read_def(ctx, &di->def, &di->instr, header);
memcpy(di->string, blob_read_bytes(ctx->blob, di->string_length), di->string_length);
return di;
}
}
unreachable("Unimplemented nir_debug_info_type");
}
static void
write_instr(write_ctx *ctx, const nir_instr *instr)
{
@ -1627,6 +1690,9 @@ write_instr(write_ctx *ctx, const nir_instr *instr)
blob_write_uint32(ctx->blob, instr->type);
write_call(ctx, nir_instr_as_call(instr));
break;
case nir_instr_type_debug_info:
write_debug_info(ctx, nir_instr_as_debug_info(instr));
break;
case nir_instr_type_parallel_copy:
unreachable("Cannot write parallel copies");
default:
@ -1677,6 +1743,9 @@ read_instr(read_ctx *ctx, nir_block *block)
case nir_instr_type_call:
instr = &read_call(ctx)->instr;
break;
case nir_instr_type_debug_info:
instr = &read_debug_info(ctx, header)->instr;
break;
case nir_instr_type_parallel_copy:
unreachable("Cannot read parallel copies");
default:

View file

@ -1145,6 +1145,9 @@ validate_instr(nir_instr *instr, validate_state *state)
validate_jump_instr(nir_instr_as_jump(instr), state);
break;
case nir_instr_type_debug_info:
break;
default:
validate_assert(state, !"Invalid ALU instruction type");
break;

View file

@ -4102,6 +4102,7 @@ emit_instr(struct ir3_context *ctx, nir_instr *instr)
break;
case nir_instr_type_call:
case nir_instr_type_parallel_copy:
case nir_instr_type_debug_info:
ir3_context_error(ctx, "Unhandled NIR instruction type: %d\n",
instr->type);
break;
@ -4278,6 +4279,7 @@ instr_can_be_predicated(nir_instr *instr)
return true;
case nir_instr_type_call:
case nir_instr_type_jump:
case nir_instr_type_debug_info:
return false;
case nir_instr_type_intrinsic: {
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);

View file

@ -4122,6 +4122,9 @@ emit_block(struct ntv_context *ctx, struct nir_block *block)
case nir_instr_type_deref:
emit_deref(ctx, nir_instr_as_deref(instr));
break;
case nir_instr_type_debug_info:
unreachable("nir_instr_type_debug_info not supported");
break;
}
}
}