*/
#include "nir.h"
-#include "nir_control_flow_private.h"
+#include "nir_control_flow.h"
/* Secret Decoder Ring:
* clone_foo():
/* True if we are cloning an entire shader. */
bool global_clone;
+ /* If true allows the clone operation to fall back to the original pointer
+ * if no clone pointer is found in the remap table. This allows us to
+ * clone a loop body without having to add srcs from outside the loop to
+ * the remap table. This is useful for loop unrolling.
+ */
+ bool allow_remap_fallback;
+
/* maps orig ptr -> cloned ptr: */
struct hash_table *remap_table;
} clone_state;
static void
-init_clone_state(clone_state *state, bool global)
+init_clone_state(clone_state *state, struct hash_table *remap_table,
+ bool global, bool allow_remap_fallback)
{
state->global_clone = global;
- state->remap_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
- _mesa_key_pointer_equal);
+ state->allow_remap_fallback = allow_remap_fallback;
+
+ if (remap_table) {
+ state->remap_table = remap_table;
+ } else {
+ state->remap_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+ }
+
list_inithead(&state->phi_srcs);
}
return (void *)ptr;
entry = _mesa_hash_table_search(state->remap_table, ptr);
- assert(entry && "Failed to find pointer!");
- if (!entry)
- return NULL;
+ if (!entry) {
+ assert(state->allow_remap_fallback);
+ return (void *)ptr;
+ }
return entry->data;
}
return nc;
}
-/* NOTE: for cloning nir_variable's, bypass nir_variable_create to avoid
+/* NOTE: for cloning nir_variables, bypass nir_variable_create to avoid
* having to deal with locals and globals separately:
*/
nir_variable *
}
nvar->interface_type = var->interface_type;
+ nvar->num_members = var->num_members;
+ if (var->num_members) {
+ nvar->members = ralloc_array(nvar, struct nir_variable_data,
+ var->num_members);
+ memcpy(nvar->members, var->members,
+ var->num_members * sizeof(*var->members));
+ }
+
return nvar;
}
}
}
-/* NOTE: for cloning nir_register's, bypass nir_global/local_reg_create()
+/* NOTE: for cloning nir_registers, bypass nir_global/local_reg_create()
* to avoid having to deal with locals and globals separately:
*/
static nir_register *
}
}
-static nir_deref *clone_deref(clone_state *state, const nir_deref *deref,
- nir_instr *ninstr, nir_deref *parent);
-
-static nir_deref_var *
-clone_deref_var(clone_state *state, const nir_deref_var *dvar,
- nir_instr *ninstr)
-{
- nir_variable *nvar = remap_var(state, dvar->var);
- nir_deref_var *ndvar = nir_deref_var_create(ninstr, nvar);
-
- if (dvar->deref.child)
- ndvar->deref.child = clone_deref(state, dvar->deref.child,
- ninstr, &ndvar->deref);
-
- return ndvar;
-}
-
-static nir_deref_array *
-clone_deref_array(clone_state *state, const nir_deref_array *darr,
- nir_instr *ninstr, nir_deref *parent)
-{
- nir_deref_array *ndarr = nir_deref_array_create(parent);
-
- ndarr->deref.type = darr->deref.type;
- if (darr->deref.child)
- ndarr->deref.child = clone_deref(state, darr->deref.child,
- ninstr, &ndarr->deref);
-
- ndarr->deref_array_type = darr->deref_array_type;
- ndarr->base_offset = darr->base_offset;
- if (ndarr->deref_array_type == nir_deref_array_type_indirect)
- __clone_src(state, ninstr, &ndarr->indirect, &darr->indirect);
-
- return ndarr;
-}
-
-static nir_deref_struct *
-clone_deref_struct(clone_state *state, const nir_deref_struct *dstr,
- nir_instr *ninstr, nir_deref *parent)
-{
- nir_deref_struct *ndstr = nir_deref_struct_create(parent, dstr->index);
-
- ndstr->deref.type = dstr->deref.type;
- if (dstr->deref.child)
- ndstr->deref.child = clone_deref(state, dstr->deref.child,
- ninstr, &ndstr->deref);
-
- return ndstr;
-}
-
-static nir_deref *
-clone_deref(clone_state *state, const nir_deref *dref,
- nir_instr *ninstr, nir_deref *parent)
-{
- switch (dref->deref_type) {
- case nir_deref_type_array:
- return &clone_deref_array(state, nir_deref_as_array(dref),
- ninstr, parent)->deref;
- case nir_deref_type_struct:
- return &clone_deref_struct(state, nir_deref_as_struct(dref),
- ninstr, parent)->deref;
- default:
- unreachable("bad deref type");
- return NULL;
- }
-}
-
static nir_alu_instr *
clone_alu(clone_state *state, const nir_alu_instr *alu)
{
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 *
clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr)
{
nir_intrinsic_instr *nitr =
nir_intrinsic_instr_create(state->ns, itr->intrinsic);
- unsigned num_variables = nir_intrinsic_infos[itr->intrinsic].num_variables;
unsigned num_srcs = nir_intrinsic_infos[itr->intrinsic].num_srcs;
if (nir_intrinsic_infos[itr->intrinsic].has_dest)
nitr->num_components = itr->num_components;
memcpy(nitr->const_index, itr->const_index, sizeof(nitr->const_index));
- for (unsigned i = 0; i < num_variables; i++) {
- nitr->variables[i] = clone_deref_var(state, itr->variables[i],
- &nitr->instr);
- }
-
for (unsigned i = 0; i < num_srcs; i++)
__clone_src(state, &nitr->instr, &nitr->src[i], &itr->src[i]);
ntex->component = tex->component;
ntex->texture_index = tex->texture_index;
- if (tex->texture)
- ntex->texture = clone_deref_var(state, tex->texture, &ntex->instr);
ntex->texture_array_size = tex->texture_array_size;
-
ntex->sampler_index = tex->sampler_index;
- if (tex->sampler)
- ntex->sampler = clone_deref_var(state, tex->sampler, &ntex->instr);
return ntex;
}
nir_call_instr *ncall = nir_call_instr_create(state->ns, ncallee);
for (unsigned i = 0; i < ncall->num_params; i++)
- ncall->params[i] = clone_deref_var(state, call->params[i], &ncall->instr);
-
- ncall->return_deref = clone_deref_var(state, call->return_deref,
- &ncall->instr);
+ __clone_src(state, ncall, &ncall->params[i], &call->params[i]);
return ncall;
}
switch (instr->type) {
case nir_instr_type_alu:
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:
return &clone_intrinsic(state, nir_instr_as_intrinsic(instr))->instr;
case nir_instr_type_load_const:
{
list_for_each_entry_safe(nir_phi_src, src, &state->phi_srcs, src.use_link) {
src->pred = remap_local(state, src->pred);
- assert(src->src.is_ssa);
- src->src.ssa = remap_local(state, src->src.ssa);
- /* Remove from this list and place in the uses of the SSA def */
+ /* Remove from this list */
list_del(&src->src.use_link);
- list_addtail(&src->src.use_link, &src->src.ssa->uses);
+
+ if (src->src.is_ssa) {
+ src->src.ssa = remap_local(state, src->src.ssa);
+ list_addtail(&src->src.use_link, &src->src.ssa->uses);
+ } else {
+ src->src.reg.reg = remap_reg(state, src->src.reg.reg);
+ list_addtail(&src->src.use_link, &src->src.reg.reg->uses);
+ }
}
assert(list_empty(&state->phi_srcs));
}
+void
+nir_cf_list_clone(nir_cf_list *dst, nir_cf_list *src, nir_cf_node *parent,
+ struct hash_table *remap_table)
+{
+ exec_list_make_empty(&dst->list);
+ dst->impl = src->impl;
+
+ if (exec_list_is_empty(&src->list))
+ return;
+
+ clone_state state;
+ init_clone_state(&state, remap_table, false, true);
+
+ /* We use the same shader */
+ state.ns = src->impl->function->shader;
+
+ /* The control-flow code assumes that the list of cf_nodes always starts
+ * and ends with a block. We start by adding an empty block.
+ */
+ nir_block *nblk = nir_block_create(state.ns);
+ nblk->cf_node.parent = parent;
+ exec_list_push_tail(&dst->list, &nblk->cf_node.node);
+
+ clone_cf_list(&state, &dst->list, &src->list);
+
+ fixup_phi_srcs(&state);
+}
+
static nir_function_impl *
clone_function_impl(clone_state *state, const nir_function_impl *fi)
{
clone_reg_list(state, &nfi->registers, &fi->registers);
nfi->reg_alloc = fi->reg_alloc;
- nfi->num_params = fi->num_params;
- nfi->params = ralloc_array(state->ns, nir_variable *, fi->num_params);
- for (unsigned i = 0; i < fi->num_params; i++) {
- nfi->params[i] = clone_variable(state, fi->params[i]);
- }
- if (fi->return_var)
- nfi->return_var = clone_variable(state, fi->return_var);
-
assert(list_empty(&state->phi_srcs));
clone_cf_list(state, &nfi->body, &fi->body);
nir_function_impl_clone(const nir_function_impl *fi)
{
clone_state state;
- init_clone_state(&state, false);
+ init_clone_state(&state, NULL, false, false);
/* We use the same shader */
state.ns = fi->function->shader;
nfxn->params = ralloc_array(state->ns, nir_parameter, fxn->num_params);
memcpy(nfxn->params, fxn->params, sizeof(nir_parameter) * fxn->num_params);
- nfxn->return_type = fxn->return_type;
-
/* At first glance, it looks like we should clone the function_impl here.
* However, call instructions need to be able to reference at least the
- * function and those will get processed as we clone the function_impl's.
+ * function and those will get processed as we clone the function_impls.
* We stop here and do function_impls as a second pass.
*/
nir_shader_clone(void *mem_ctx, const nir_shader *s)
{
clone_state state;
- init_clone_state(&state, true);
+ init_clone_state(&state, NULL, true, false);
- nir_shader *ns = nir_shader_create(mem_ctx, s->stage, s->options, NULL);
+ nir_shader *ns = nir_shader_create(mem_ctx, s->info.stage, s->options, NULL);
state.ns = ns;
clone_var_list(&state, &ns->uniforms, &s->uniforms);
clone_function(&state, fxn, ns);
/* Only after all functions are cloned can we clone the actual function
- * implementations. This is because nir_call_instr's need to reference the
+ * implementations. This is because nir_call_instrs need to reference the
* functions of other functions and we don't know what order the functions
* will have in the list.
*/
clone_reg_list(&state, &ns->registers, &s->registers);
ns->reg_alloc = s->reg_alloc;
- *ns->info = *s->info;
- ns->info->name = ralloc_strdup(ns, ns->info->name);
- if (ns->info->label)
- ns->info->label = ralloc_strdup(ns, ns->info->label);
+ ns->info = s->info;
+ ns->info.name = ralloc_strdup(ns, ns->info.name);
+ if (ns->info.label)
+ ns->info.label = ralloc_strdup(ns, ns->info.label);
ns->num_inputs = s->num_inputs;
ns->num_uniforms = s->num_uniforms;
ns->num_outputs = s->num_outputs;
ns->num_shared = s->num_shared;
+ ns->constant_data_size = s->constant_data_size;
+ if (s->constant_data_size > 0) {
+ ns->constant_data = ralloc_size(ns, s->constant_data_size);
+ memcpy(ns->constant_data, s->constant_data, s->constant_data_size);
+ }
+
free_clone_state(&state);
return ns;