nir: Add a deref instruction type
This commit adds a new instruction type to NIR for handling derefs. Nothing uses it yet but this adds the data structure as well as all of the code to validate, print, clone, and [de]serialize them. Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com> Acked-by: Rob Clark <robdclark@gmail.com> Acked-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> Acked-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
@@ -473,6 +473,26 @@ nir_alu_instr_create(nir_shader *shader, nir_op op)
|
|||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nir_deref_instr *
|
||||||
|
nir_deref_instr_create(nir_shader *shader, nir_deref_type deref_type)
|
||||||
|
{
|
||||||
|
nir_deref_instr *instr =
|
||||||
|
rzalloc_size(shader, sizeof(nir_deref_instr));
|
||||||
|
|
||||||
|
instr_init(&instr->instr, nir_instr_type_deref);
|
||||||
|
|
||||||
|
instr->deref_type = deref_type;
|
||||||
|
if (deref_type != nir_deref_type_var)
|
||||||
|
src_init(&instr->parent);
|
||||||
|
|
||||||
|
if (deref_type == nir_deref_type_array)
|
||||||
|
src_init(&instr->arr.index);
|
||||||
|
|
||||||
|
dest_init(&instr->dest);
|
||||||
|
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
nir_jump_instr *
|
nir_jump_instr *
|
||||||
nir_jump_instr_create(nir_shader *shader, nir_jump_type type)
|
nir_jump_instr_create(nir_shader *shader, nir_jump_type type)
|
||||||
{
|
{
|
||||||
@@ -1201,6 +1221,12 @@ visit_alu_dest(nir_alu_instr *instr, nir_foreach_dest_cb cb, void *state)
|
|||||||
return cb(&instr->dest.dest, state);
|
return cb(&instr->dest.dest, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
visit_deref_dest(nir_deref_instr *instr, nir_foreach_dest_cb cb, void *state)
|
||||||
|
{
|
||||||
|
return cb(&instr->dest, state);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
visit_intrinsic_dest(nir_intrinsic_instr *instr, nir_foreach_dest_cb cb,
|
visit_intrinsic_dest(nir_intrinsic_instr *instr, nir_foreach_dest_cb cb,
|
||||||
void *state)
|
void *state)
|
||||||
@@ -1242,6 +1268,8 @@ nir_foreach_dest(nir_instr *instr, nir_foreach_dest_cb cb, void *state)
|
|||||||
switch (instr->type) {
|
switch (instr->type) {
|
||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
return visit_alu_dest(nir_instr_as_alu(instr), cb, state);
|
return visit_alu_dest(nir_instr_as_alu(instr), cb, state);
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
return visit_deref_dest(nir_instr_as_deref(instr), cb, state);
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
return visit_intrinsic_dest(nir_instr_as_intrinsic(instr), cb, state);
|
return visit_intrinsic_dest(nir_instr_as_intrinsic(instr), cb, state);
|
||||||
case nir_instr_type_tex:
|
case nir_instr_type_tex:
|
||||||
@@ -1287,6 +1315,7 @@ nir_foreach_ssa_def(nir_instr *instr, nir_foreach_ssa_def_cb cb, void *state)
|
|||||||
{
|
{
|
||||||
switch (instr->type) {
|
switch (instr->type) {
|
||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
|
case nir_instr_type_deref:
|
||||||
case nir_instr_type_tex:
|
case nir_instr_type_tex:
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
case nir_instr_type_phi:
|
case nir_instr_type_phi:
|
||||||
@@ -1352,6 +1381,23 @@ visit_alu_src(nir_alu_instr *instr, nir_foreach_src_cb cb, void *state)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
visit_deref_instr_src(nir_deref_instr *instr,
|
||||||
|
nir_foreach_src_cb cb, void *state)
|
||||||
|
{
|
||||||
|
if (instr->deref_type != nir_deref_type_var) {
|
||||||
|
if (!visit_src(&instr->parent, cb, state))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instr->deref_type == nir_deref_type_array) {
|
||||||
|
if (!visit_src(&instr->arr.index, cb, state))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
visit_tex_src(nir_tex_instr *instr, nir_foreach_src_cb cb, void *state)
|
visit_tex_src(nir_tex_instr *instr, nir_foreach_src_cb cb, void *state)
|
||||||
{
|
{
|
||||||
@@ -1440,6 +1486,10 @@ nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state)
|
|||||||
if (!visit_alu_src(nir_instr_as_alu(instr), cb, state))
|
if (!visit_alu_src(nir_instr_as_alu(instr), cb, state))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
if (!visit_deref_instr_src(nir_instr_as_deref(instr), cb, state))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
if (!visit_intrinsic_src(nir_instr_as_intrinsic(instr), cb, state))
|
if (!visit_intrinsic_src(nir_instr_as_intrinsic(instr), cb, state))
|
||||||
return false;
|
return false;
|
||||||
|
@@ -429,6 +429,7 @@ typedef struct nir_register {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
nir_instr_type_alu,
|
nir_instr_type_alu,
|
||||||
|
nir_instr_type_deref,
|
||||||
nir_instr_type_call,
|
nir_instr_type_call,
|
||||||
nir_instr_type_tex,
|
nir_instr_type_tex,
|
||||||
nir_instr_type_intrinsic,
|
nir_instr_type_intrinsic,
|
||||||
@@ -898,7 +899,9 @@ bool nir_alu_srcs_equal(const nir_alu_instr *alu1, const nir_alu_instr *alu2,
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
nir_deref_type_var,
|
nir_deref_type_var,
|
||||||
nir_deref_type_array,
|
nir_deref_type_array,
|
||||||
nir_deref_type_struct
|
nir_deref_type_array_wildcard,
|
||||||
|
nir_deref_type_struct,
|
||||||
|
nir_deref_type_cast,
|
||||||
} nir_deref_type;
|
} nir_deref_type;
|
||||||
|
|
||||||
typedef struct nir_deref {
|
typedef struct nir_deref {
|
||||||
@@ -957,6 +960,56 @@ nir_deref_tail(nir_deref *deref)
|
|||||||
return deref;
|
return deref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
nir_instr instr;
|
||||||
|
|
||||||
|
/** The type of this deref instruction */
|
||||||
|
nir_deref_type deref_type;
|
||||||
|
|
||||||
|
/** The mode of the underlying variable */
|
||||||
|
nir_variable_mode mode;
|
||||||
|
|
||||||
|
/** The dereferenced type of the resulting pointer value */
|
||||||
|
const struct glsl_type *type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
/** Variable being dereferenced if deref_type is a deref_var */
|
||||||
|
nir_variable *var;
|
||||||
|
|
||||||
|
/** Parent deref if deref_type is not deref_var */
|
||||||
|
nir_src parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Additional deref parameters */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
nir_src index;
|
||||||
|
} arr;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned index;
|
||||||
|
} strct;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Destination to store the resulting "pointer" */
|
||||||
|
nir_dest dest;
|
||||||
|
} nir_deref_instr;
|
||||||
|
|
||||||
|
NIR_DEFINE_CAST(nir_instr_as_deref, nir_instr, nir_deref_instr, instr,
|
||||||
|
type, nir_instr_type_deref)
|
||||||
|
|
||||||
|
static inline nir_deref_instr *
|
||||||
|
nir_src_as_deref(nir_src src)
|
||||||
|
{
|
||||||
|
if (!src.is_ssa)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (src.ssa->parent_instr->type != nir_instr_type_deref)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return nir_instr_as_deref(src.ssa->parent_instr);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nir_instr instr;
|
nir_instr instr;
|
||||||
|
|
||||||
@@ -2121,6 +2174,9 @@ void nir_metadata_preserve(nir_function_impl *impl, nir_metadata preserved);
|
|||||||
/** creates an instruction with default swizzle/writemask/etc. with NULL registers */
|
/** creates an instruction with default swizzle/writemask/etc. with NULL registers */
|
||||||
nir_alu_instr *nir_alu_instr_create(nir_shader *shader, nir_op op);
|
nir_alu_instr *nir_alu_instr_create(nir_shader *shader, nir_op op);
|
||||||
|
|
||||||
|
nir_deref_instr *nir_deref_instr_create(nir_shader *shader,
|
||||||
|
nir_deref_type deref_type);
|
||||||
|
|
||||||
nir_jump_instr *nir_jump_instr_create(nir_shader *shader, nir_jump_type type);
|
nir_jump_instr *nir_jump_instr_create(nir_shader *shader, nir_jump_type type);
|
||||||
|
|
||||||
nir_load_const_instr *nir_load_const_instr_create(nir_shader *shader,
|
nir_load_const_instr *nir_load_const_instr_create(nir_shader *shader,
|
||||||
|
@@ -346,6 +346,46 @@ clone_alu(clone_state *state, const nir_alu_instr *alu)
|
|||||||
return nalu;
|
return nalu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nir_deref_instr *
|
||||||
|
clone_deref_instr(clone_state *state, const nir_deref_instr *deref)
|
||||||
|
{
|
||||||
|
nir_deref_instr *nderef =
|
||||||
|
nir_deref_instr_create(state->ns, deref->deref_type);
|
||||||
|
|
||||||
|
__clone_dst(state, &nderef->instr, &nderef->dest, &deref->dest);
|
||||||
|
|
||||||
|
nderef->mode = deref->mode;
|
||||||
|
nderef->type = deref->type;
|
||||||
|
|
||||||
|
if (deref->deref_type == nir_deref_type_var) {
|
||||||
|
nderef->var = remap_var(state, deref->var);
|
||||||
|
return nderef;
|
||||||
|
}
|
||||||
|
|
||||||
|
__clone_src(state, &nderef->instr, &nderef->parent, &deref->parent);
|
||||||
|
|
||||||
|
switch (deref->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
nderef->strct.index = deref->strct.index;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array:
|
||||||
|
__clone_src(state, &nderef->instr,
|
||||||
|
&nderef->arr.index, &deref->arr.index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
case nir_deref_type_cast:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid instruction deref type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return nderef;
|
||||||
|
}
|
||||||
|
|
||||||
static nir_intrinsic_instr *
|
static nir_intrinsic_instr *
|
||||||
clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr)
|
clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr)
|
||||||
{
|
{
|
||||||
@@ -502,6 +542,8 @@ clone_instr(clone_state *state, const nir_instr *instr)
|
|||||||
switch (instr->type) {
|
switch (instr->type) {
|
||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
return &clone_alu(state, nir_instr_as_alu(instr))->instr;
|
return &clone_alu(state, nir_instr_as_alu(instr))->instr;
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
return &clone_deref_instr(state, nir_instr_as_deref(instr))->instr;
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
return &clone_intrinsic(state, nir_instr_as_intrinsic(instr))->instr;
|
return &clone_intrinsic(state, nir_instr_as_intrinsic(instr))->instr;
|
||||||
case nir_instr_type_load_const:
|
case nir_instr_type_load_const:
|
||||||
|
@@ -78,6 +78,40 @@ hash_alu(uint32_t hash, const nir_alu_instr *instr)
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
hash_deref(uint32_t hash, const nir_deref_instr *instr)
|
||||||
|
{
|
||||||
|
hash = HASH(hash, instr->deref_type);
|
||||||
|
hash = HASH(hash, instr->mode);
|
||||||
|
hash = HASH(hash, instr->type);
|
||||||
|
|
||||||
|
if (instr->deref_type == nir_deref_type_var)
|
||||||
|
return HASH(hash, instr->var);
|
||||||
|
|
||||||
|
hash = hash_src(hash, &instr->parent);
|
||||||
|
|
||||||
|
switch (instr->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
hash = HASH(hash, instr->strct.index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array:
|
||||||
|
hash = hash_src(hash, &instr->arr.index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_var:
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
case nir_deref_type_cast:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid instruction deref type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
hash_load_const(uint32_t hash, const nir_load_const_instr *instr)
|
hash_load_const(uint32_t hash, const nir_load_const_instr *instr)
|
||||||
{
|
{
|
||||||
@@ -182,6 +216,9 @@ hash_instr(const void *data)
|
|||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
hash = hash_alu(hash, nir_instr_as_alu(instr));
|
hash = hash_alu(hash, nir_instr_as_alu(instr));
|
||||||
break;
|
break;
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
hash = hash_deref(hash, nir_instr_as_deref(instr));
|
||||||
|
break;
|
||||||
case nir_instr_type_load_const:
|
case nir_instr_type_load_const:
|
||||||
hash = hash_load_const(hash, nir_instr_as_load_const(instr));
|
hash = hash_load_const(hash, nir_instr_as_load_const(instr));
|
||||||
break;
|
break;
|
||||||
@@ -289,6 +326,43 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case nir_instr_type_deref: {
|
||||||
|
nir_deref_instr *deref1 = nir_instr_as_deref(instr1);
|
||||||
|
nir_deref_instr *deref2 = nir_instr_as_deref(instr2);
|
||||||
|
|
||||||
|
if (deref1->deref_type != deref2->deref_type ||
|
||||||
|
deref1->mode != deref2->mode ||
|
||||||
|
deref1->type != deref2->type)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (deref1->deref_type == nir_deref_type_var)
|
||||||
|
return deref1->var == deref2->var;
|
||||||
|
|
||||||
|
if (!nir_srcs_equal(deref1->parent, deref2->parent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (deref1->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
if (deref1->strct.index != deref2->strct.index)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array:
|
||||||
|
if (!nir_srcs_equal(deref1->arr.index, deref2->arr.index))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_var:
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
case nir_deref_type_cast:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid instruction deref type");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case nir_instr_type_tex: {
|
case nir_instr_type_tex: {
|
||||||
nir_tex_instr *tex1 = nir_instr_as_tex(instr1);
|
nir_tex_instr *tex1 = nir_instr_as_tex(instr1);
|
||||||
nir_tex_instr *tex2 = nir_instr_as_tex(instr2);
|
nir_tex_instr *tex2 = nir_instr_as_tex(instr2);
|
||||||
@@ -430,6 +504,7 @@ instr_can_rewrite(nir_instr *instr)
|
|||||||
|
|
||||||
switch (instr->type) {
|
switch (instr->type) {
|
||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
|
case nir_instr_type_deref:
|
||||||
case nir_instr_type_load_const:
|
case nir_instr_type_load_const:
|
||||||
case nir_instr_type_phi:
|
case nir_instr_type_phi:
|
||||||
return true;
|
return true;
|
||||||
@@ -468,6 +543,9 @@ nir_instr_get_dest_ssa_def(nir_instr *instr)
|
|||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
assert(nir_instr_as_alu(instr)->dest.dest.is_ssa);
|
assert(nir_instr_as_alu(instr)->dest.dest.is_ssa);
|
||||||
return &nir_instr_as_alu(instr)->dest.dest.ssa;
|
return &nir_instr_as_alu(instr)->dest.dest.ssa;
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
assert(nir_instr_as_deref(instr)->dest.is_ssa);
|
||||||
|
return &nir_instr_as_deref(instr)->dest.ssa;
|
||||||
case nir_instr_type_load_const:
|
case nir_instr_type_load_const:
|
||||||
return &nir_instr_as_load_const(instr)->def;
|
return &nir_instr_as_load_const(instr)->def;
|
||||||
case nir_instr_type_phi:
|
case nir_instr_type_phi:
|
||||||
|
@@ -98,6 +98,22 @@ is_swizzleless_move(nir_alu_instr *instr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_trivial_deref_cast(nir_deref_instr *cast)
|
||||||
|
{
|
||||||
|
if (cast->deref_type != nir_deref_type_cast)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
nir_deref_instr *parent = nir_src_as_deref(cast->parent);
|
||||||
|
if (!parent)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return cast->mode == parent->mode &&
|
||||||
|
cast->type == parent->type &&
|
||||||
|
cast->dest.ssa.num_components == parent->dest.ssa.num_components &&
|
||||||
|
cast->dest.ssa.bit_size == parent->dest.ssa.bit_size;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if,
|
copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if,
|
||||||
unsigned num_components)
|
unsigned num_components)
|
||||||
@@ -109,9 +125,8 @@ copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nir_instr *src_instr = src->ssa->parent_instr;
|
nir_instr *src_instr = src->ssa->parent_instr;
|
||||||
if (src_instr->type != nir_instr_type_alu)
|
nir_ssa_def *copy_def;
|
||||||
return false;
|
if (src_instr->type == nir_instr_type_alu) {
|
||||||
|
|
||||||
nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
|
nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr);
|
||||||
if (!is_swizzleless_move(alu_instr))
|
if (!is_swizzleless_move(alu_instr))
|
||||||
return false;
|
return false;
|
||||||
@@ -119,13 +134,22 @@ copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if,
|
|||||||
if (alu_instr->src[0].src.ssa->num_components != num_components)
|
if (alu_instr->src[0].src.ssa->num_components != num_components)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
copy_def= alu_instr->src[0].src.ssa;
|
||||||
|
} else if (src_instr->type == nir_instr_type_deref) {
|
||||||
|
nir_deref_instr *deref_instr = nir_instr_as_deref(src_instr);
|
||||||
|
if (!is_trivial_deref_cast(deref_instr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
copy_def = deref_instr->parent.ssa;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (parent_instr) {
|
if (parent_instr) {
|
||||||
nir_instr_rewrite_src(parent_instr, src,
|
nir_instr_rewrite_src(parent_instr, src, nir_src_for_ssa(copy_def));
|
||||||
nir_src_for_ssa(alu_instr->src[0].src.ssa));
|
|
||||||
} else {
|
} else {
|
||||||
assert(src == &parent_if->condition);
|
assert(src == &parent_if->condition);
|
||||||
nir_if_rewrite_condition(parent_if,
|
nir_if_rewrite_condition(parent_if, nir_src_for_ssa(copy_def));
|
||||||
nir_src_for_ssa(alu_instr->src[0].src.ssa));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -234,6 +258,24 @@ copy_prop_instr(nir_instr *instr)
|
|||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case nir_instr_type_deref: {
|
||||||
|
nir_deref_instr *deref = nir_instr_as_deref(instr);
|
||||||
|
|
||||||
|
if (deref->deref_type != nir_deref_type_var) {
|
||||||
|
assert(deref->dest.is_ssa);
|
||||||
|
const unsigned comps = deref->dest.ssa.num_components;
|
||||||
|
while (copy_prop_src(&deref->parent, instr, NULL, comps))
|
||||||
|
progress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deref->deref_type == nir_deref_type_array) {
|
||||||
|
while (copy_prop_src(&deref->arr.index, instr, NULL, 1))
|
||||||
|
progress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
case nir_instr_type_tex: {
|
case nir_instr_type_tex: {
|
||||||
nir_tex_instr *tex = nir_instr_as_tex(instr);
|
nir_tex_instr *tex = nir_instr_as_tex(instr);
|
||||||
for (unsigned i = 0; i < tex->num_srcs; i++) {
|
for (unsigned i = 0; i < tex->num_srcs; i++) {
|
||||||
|
@@ -52,6 +52,7 @@ static void
|
|||||||
init_instr(nir_instr *instr, nir_instr_worklist *worklist)
|
init_instr(nir_instr *instr, nir_instr_worklist *worklist)
|
||||||
{
|
{
|
||||||
nir_alu_instr *alu_instr;
|
nir_alu_instr *alu_instr;
|
||||||
|
nir_deref_instr *deref_instr;
|
||||||
nir_intrinsic_instr *intrin_instr;
|
nir_intrinsic_instr *intrin_instr;
|
||||||
nir_tex_instr *tex_instr;
|
nir_tex_instr *tex_instr;
|
||||||
|
|
||||||
@@ -73,6 +74,12 @@ init_instr(nir_instr *instr, nir_instr_worklist *worklist)
|
|||||||
mark_and_push(worklist, instr);
|
mark_and_push(worklist, instr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
deref_instr = nir_instr_as_deref(instr);
|
||||||
|
if (!deref_instr->dest.is_ssa)
|
||||||
|
mark_and_push(worklist, instr);
|
||||||
|
break;
|
||||||
|
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
intrin_instr = nir_instr_as_intrinsic(instr);
|
intrin_instr = nir_instr_as_intrinsic(instr);
|
||||||
if (nir_intrinsic_infos[intrin_instr->intrinsic].flags &
|
if (nir_intrinsic_infos[intrin_instr->intrinsic].flags &
|
||||||
|
@@ -393,7 +393,7 @@ print_constant(nir_constant *c, const struct glsl_type *type, print_state *state
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
get_variable_mode_str(nir_variable_mode mode)
|
get_variable_mode_str(nir_variable_mode mode, bool want_local_global_mode)
|
||||||
{
|
{
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case nir_var_shader_in:
|
case nir_var_shader_in:
|
||||||
@@ -410,7 +410,9 @@ get_variable_mode_str(nir_variable_mode mode)
|
|||||||
return "shared";
|
return "shared";
|
||||||
case nir_var_param:
|
case nir_var_param:
|
||||||
case nir_var_global:
|
case nir_var_global:
|
||||||
|
return want_local_global_mode ? "global" : "";
|
||||||
case nir_var_local:
|
case nir_var_local:
|
||||||
|
return want_local_global_mode ? "local" : "";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -428,7 +430,7 @@ print_var_decl(nir_variable *var, print_state *state)
|
|||||||
const char *const patch = (var->data.patch) ? "patch " : "";
|
const char *const patch = (var->data.patch) ? "patch " : "";
|
||||||
const char *const inv = (var->data.invariant) ? "invariant " : "";
|
const char *const inv = (var->data.invariant) ? "invariant " : "";
|
||||||
fprintf(fp, "%s%s%s%s%s %s ",
|
fprintf(fp, "%s%s%s%s%s %s ",
|
||||||
cent, samp, patch, inv, get_variable_mode_str(var->data.mode),
|
cent, samp, patch, inv, get_variable_mode_str(var->data.mode, false),
|
||||||
glsl_interp_mode_name(var->data.interpolation));
|
glsl_interp_mode_name(var->data.interpolation));
|
||||||
|
|
||||||
const char *const coher = (var->data.image.coherent) ? "coherent " : "";
|
const char *const coher = (var->data.image.coherent) ? "coherent " : "";
|
||||||
@@ -517,6 +519,128 @@ print_var_decl(nir_variable *var, print_state *state)
|
|||||||
print_annotation(state, var);
|
print_annotation(state, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_deref_link(nir_deref_instr *instr, bool whole_chain, print_state *state)
|
||||||
|
{
|
||||||
|
FILE *fp = state->fp;
|
||||||
|
|
||||||
|
if (instr->deref_type == nir_deref_type_var) {
|
||||||
|
fprintf(fp, "%s", get_var_name(instr->var, state));
|
||||||
|
return;
|
||||||
|
} else if (instr->deref_type == nir_deref_type_cast) {
|
||||||
|
fprintf(fp, "(%s *)", glsl_get_type_name(instr->type));
|
||||||
|
print_src(&instr->parent, state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(instr->parent.is_ssa);
|
||||||
|
nir_deref_instr *parent =
|
||||||
|
nir_instr_as_deref(instr->parent.ssa->parent_instr);
|
||||||
|
|
||||||
|
/* Is the parent we're going to print a bare cast? */
|
||||||
|
const bool is_parent_cast =
|
||||||
|
whole_chain && parent->deref_type == nir_deref_type_cast;
|
||||||
|
|
||||||
|
/* If we're not printing the whole chain, the parent we print will be a SSA
|
||||||
|
* value that represents a pointer. The only deref type that naturally
|
||||||
|
* gives a pointer is a cast.
|
||||||
|
*/
|
||||||
|
const bool is_parent_pointer =
|
||||||
|
!whole_chain || parent->deref_type == nir_deref_type_cast;
|
||||||
|
|
||||||
|
/* Struct derefs have a nice syntax that works on pointers, arrays derefs
|
||||||
|
* do not.
|
||||||
|
*/
|
||||||
|
const bool need_deref =
|
||||||
|
is_parent_pointer && instr->deref_type != nir_deref_type_struct;
|
||||||
|
|
||||||
|
/* Cast need extra parens and so * dereferences */
|
||||||
|
if (is_parent_cast || need_deref)
|
||||||
|
fprintf(fp, "(");
|
||||||
|
|
||||||
|
if (need_deref)
|
||||||
|
fprintf(fp, "*");
|
||||||
|
|
||||||
|
if (whole_chain) {
|
||||||
|
print_deref_link(parent, whole_chain, state);
|
||||||
|
} else {
|
||||||
|
print_src(&instr->parent, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_parent_cast || need_deref)
|
||||||
|
fprintf(fp, ")");
|
||||||
|
|
||||||
|
switch (instr->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
fprintf(fp, "%s%s", is_parent_pointer ? "->" : ".",
|
||||||
|
glsl_get_struct_elem_name(parent->type, instr->strct.index));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array: {
|
||||||
|
nir_const_value *const_index = nir_src_as_const_value(instr->arr.index);
|
||||||
|
if (const_index) {
|
||||||
|
fprintf(fp, "[%u]", const_index->u32[0]);
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "[");
|
||||||
|
print_src(&instr->arr.index, state);
|
||||||
|
fprintf(fp, "]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
fprintf(fp, "[*]");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid deref instruction type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_deref_instr(nir_deref_instr *instr, print_state *state)
|
||||||
|
{
|
||||||
|
FILE *fp = state->fp;
|
||||||
|
|
||||||
|
print_dest(&instr->dest, state);
|
||||||
|
|
||||||
|
switch (instr->deref_type) {
|
||||||
|
case nir_deref_type_var:
|
||||||
|
fprintf(fp, " = deref_var ");
|
||||||
|
break;
|
||||||
|
case nir_deref_type_array:
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
fprintf(fp, " = deref_array ");
|
||||||
|
break;
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
fprintf(fp, " = deref_struct ");
|
||||||
|
break;
|
||||||
|
case nir_deref_type_cast:
|
||||||
|
fprintf(fp, " = deref_cast ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unreachable("Invalid deref instruction type");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only casts naturally return a pointer type */
|
||||||
|
if (instr->deref_type != nir_deref_type_cast)
|
||||||
|
fprintf(fp, "&");
|
||||||
|
|
||||||
|
print_deref_link(instr, false, state);
|
||||||
|
|
||||||
|
fprintf(fp, " (%s %s) ",
|
||||||
|
get_variable_mode_str(instr->mode, true),
|
||||||
|
glsl_get_type_name(instr->type));
|
||||||
|
|
||||||
|
if (instr->deref_type != nir_deref_type_var &&
|
||||||
|
instr->deref_type != nir_deref_type_cast) {
|
||||||
|
/* Print the entire chain as a comment */
|
||||||
|
fprintf(fp, "/* &");
|
||||||
|
print_deref_link(instr, true, state);
|
||||||
|
fprintf(fp, " */");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_var(nir_variable *var, print_state *state)
|
print_var(nir_variable *var, print_state *state)
|
||||||
{
|
{
|
||||||
@@ -965,6 +1089,10 @@ print_instr(const nir_instr *instr, print_state *state, unsigned tabs)
|
|||||||
print_alu_instr(nir_instr_as_alu(instr), state);
|
print_alu_instr(nir_instr_as_alu(instr), state);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
print_deref_instr(nir_instr_as_deref(instr), state);
|
||||||
|
break;
|
||||||
|
|
||||||
case nir_instr_type_call:
|
case nir_instr_type_call:
|
||||||
print_call_instr(nir_instr_as_call(instr), state);
|
print_call_instr(nir_instr_as_call(instr), state);
|
||||||
break;
|
break;
|
||||||
|
@@ -478,6 +478,81 @@ read_alu(read_ctx *ctx)
|
|||||||
return alu;
|
return alu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_deref(write_ctx *ctx, const nir_deref_instr *deref)
|
||||||
|
{
|
||||||
|
blob_write_uint32(ctx->blob, deref->deref_type);
|
||||||
|
|
||||||
|
blob_write_uint32(ctx->blob, deref->mode);
|
||||||
|
encode_type_to_blob(ctx->blob, deref->type);
|
||||||
|
|
||||||
|
write_dest(ctx, &deref->dest);
|
||||||
|
|
||||||
|
if (deref->deref_type == nir_deref_type_var) {
|
||||||
|
write_object(ctx, deref->var);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_src(ctx, &deref->parent);
|
||||||
|
|
||||||
|
switch (deref->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
blob_write_uint32(ctx->blob, deref->strct.index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array:
|
||||||
|
write_src(ctx, &deref->arr.index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
case nir_deref_type_cast:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid deref type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static nir_deref_instr *
|
||||||
|
read_deref(read_ctx *ctx)
|
||||||
|
{
|
||||||
|
nir_deref_type deref_type = blob_read_uint32(ctx->blob);
|
||||||
|
nir_deref_instr *deref = nir_deref_instr_create(ctx->nir, deref_type);
|
||||||
|
|
||||||
|
deref->mode = blob_read_uint32(ctx->blob);
|
||||||
|
deref->type = decode_type_from_blob(ctx->blob);
|
||||||
|
|
||||||
|
read_dest(ctx, &deref->dest, &deref->instr);
|
||||||
|
|
||||||
|
if (deref_type == nir_deref_type_var) {
|
||||||
|
deref->var = read_object(ctx);
|
||||||
|
return deref;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_src(ctx, &deref->parent, &deref->instr);
|
||||||
|
|
||||||
|
switch (deref->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
deref->strct.index = blob_read_uint32(ctx->blob);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array:
|
||||||
|
read_src(ctx, &deref->arr.index, &deref->instr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
case nir_deref_type_cast:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid deref type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return deref;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_intrinsic(write_ctx *ctx, const nir_intrinsic_instr *intrin)
|
write_intrinsic(write_ctx *ctx, const nir_intrinsic_instr *intrin)
|
||||||
{
|
{
|
||||||
@@ -803,6 +878,9 @@ write_instr(write_ctx *ctx, const nir_instr *instr)
|
|||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
write_alu(ctx, nir_instr_as_alu(instr));
|
write_alu(ctx, nir_instr_as_alu(instr));
|
||||||
break;
|
break;
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
write_deref(ctx, nir_instr_as_deref(instr));
|
||||||
|
break;
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
write_intrinsic(ctx, nir_instr_as_intrinsic(instr));
|
write_intrinsic(ctx, nir_instr_as_intrinsic(instr));
|
||||||
break;
|
break;
|
||||||
@@ -840,6 +918,9 @@ read_instr(read_ctx *ctx, nir_block *block)
|
|||||||
case nir_instr_type_alu:
|
case nir_instr_type_alu:
|
||||||
instr = &read_alu(ctx)->instr;
|
instr = &read_alu(ctx)->instr;
|
||||||
break;
|
break;
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
instr = &read_deref(ctx)->instr;
|
||||||
|
break;
|
||||||
case nir_instr_type_intrinsic:
|
case nir_instr_type_intrinsic:
|
||||||
instr = &read_intrinsic(ctx)->instr;
|
instr = &read_intrinsic(ctx)->instr;
|
||||||
break;
|
break;
|
||||||
|
@@ -462,6 +462,85 @@ validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *s
|
|||||||
validate_deref_chain(&deref->deref, deref->var->data.mode, state);
|
validate_deref_chain(&deref->deref, deref->var->data.mode, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
validate_deref_instr(nir_deref_instr *instr, validate_state *state)
|
||||||
|
{
|
||||||
|
if (instr->deref_type == nir_deref_type_var) {
|
||||||
|
/* Variable dereferences are stupid simple. */
|
||||||
|
validate_assert(state, instr->mode == instr->var->data.mode);
|
||||||
|
validate_assert(state, instr->type == instr->var->type);
|
||||||
|
validate_var_use(instr->var, state);
|
||||||
|
} else if (instr->deref_type == nir_deref_type_cast) {
|
||||||
|
/* For cast, we simply have to trust the instruction. It's up to
|
||||||
|
* lowering passes and front/back-ends to make them sane.
|
||||||
|
*/
|
||||||
|
validate_src(&instr->parent, state, 0, 0);
|
||||||
|
|
||||||
|
/* We just validate that the type and mode are there */
|
||||||
|
validate_assert(state, instr->mode);
|
||||||
|
validate_assert(state, instr->type);
|
||||||
|
} else {
|
||||||
|
/* We require the parent to be SSA. This may be lifted in the future */
|
||||||
|
validate_assert(state, instr->parent.is_ssa);
|
||||||
|
|
||||||
|
/* The parent pointer value must have the same number of components
|
||||||
|
* as the destination.
|
||||||
|
*/
|
||||||
|
validate_src(&instr->parent, state, nir_dest_bit_size(instr->dest),
|
||||||
|
nir_dest_num_components(instr->dest));
|
||||||
|
|
||||||
|
nir_instr *parent_instr = instr->parent.ssa->parent_instr;
|
||||||
|
|
||||||
|
/* The parent must come from another deref instruction */
|
||||||
|
validate_assert(state, parent_instr->type == nir_instr_type_deref);
|
||||||
|
|
||||||
|
nir_deref_instr *parent = nir_instr_as_deref(parent_instr);
|
||||||
|
|
||||||
|
validate_assert(state, instr->mode == parent->mode);
|
||||||
|
|
||||||
|
switch (instr->deref_type) {
|
||||||
|
case nir_deref_type_struct:
|
||||||
|
validate_assert(state, glsl_type_is_struct(parent->type));
|
||||||
|
validate_assert(state,
|
||||||
|
instr->strct.index < glsl_get_length(parent->type));
|
||||||
|
validate_assert(state, instr->type ==
|
||||||
|
glsl_get_struct_field(parent->type, instr->strct.index));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nir_deref_type_array:
|
||||||
|
case nir_deref_type_array_wildcard:
|
||||||
|
if (instr->mode == nir_var_shared) {
|
||||||
|
/* Shared variables have a bit more relaxed rules because we need
|
||||||
|
* to be able to handle array derefs on vectors. Fortunately,
|
||||||
|
* nir_lower_io handles these just fine.
|
||||||
|
*/
|
||||||
|
validate_assert(state, glsl_type_is_array(parent->type) ||
|
||||||
|
glsl_type_is_matrix(parent->type) ||
|
||||||
|
glsl_type_is_vector(parent->type));
|
||||||
|
} else {
|
||||||
|
/* Most of NIR cannot handle array derefs on vectors */
|
||||||
|
validate_assert(state, glsl_type_is_array(parent->type) ||
|
||||||
|
glsl_type_is_matrix(parent->type));
|
||||||
|
}
|
||||||
|
validate_assert(state,
|
||||||
|
instr->type == glsl_get_array_element(parent->type));
|
||||||
|
|
||||||
|
if (instr->deref_type == nir_deref_type_array)
|
||||||
|
validate_src(&instr->arr.index, state, 32, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable("Invalid deref instruction type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We intentionally don't validate the size of the destination because we
|
||||||
|
* want to let other compiler components such as SPIR-V decide how big
|
||||||
|
* pointers should be.
|
||||||
|
*/
|
||||||
|
validate_dest(&instr->dest, state, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state)
|
validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state)
|
||||||
{
|
{
|
||||||
@@ -610,6 +689,10 @@ validate_instr(nir_instr *instr, validate_state *state)
|
|||||||
validate_alu_instr(nir_instr_as_alu(instr), state);
|
validate_alu_instr(nir_instr_as_alu(instr), state);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nir_instr_type_deref:
|
||||||
|
validate_deref_instr(nir_instr_as_deref(instr), state);
|
||||||
|
break;
|
||||||
|
|
||||||
case nir_instr_type_call:
|
case nir_instr_type_call:
|
||||||
validate_call_instr(nir_instr_as_call(instr), state);
|
validate_call_instr(nir_instr_as_call(instr), state);
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user