#include "util/hash_table.h"
#include "../list.h"
#include "GL/gl.h" /* GLenum */
+#include "util/list.h"
#include "util/ralloc.h"
#include "util/set.h"
#include "util/bitset.h"
nir_var_global,
nir_var_local,
nir_var_uniform,
+ nir_var_shader_storage,
nir_var_system_value
} nir_variable_mode;
*/
int index;
+ /**
+ * Descriptor set binding for sampler or UBO.
+ */
+ int descriptor_set;
+
/**
* Initial binding point for a sampler or UBO.
*
*/
bool is_packed;
- /**
- * If this pointer is non-NULL then this register has exactly one
- * definition and that definition dominates all of its uses. This is
- * set by the out-of-SSA pass so that backends can get SSA-like
- * information even once they have gone out of SSA.
- */
- struct nir_instr *parent_instr;
-
/** set of nir_instr's where this register is used (read from) */
- struct set *uses;
+ struct list_head uses;
/** set of nir_instr's where this register is defined (written to) */
- struct set *defs;
+ struct list_head defs;
/** set of nir_if's where this register is used as a condition */
- struct set *if_uses;
+ struct list_head if_uses;
} nir_register;
typedef enum {
return exec_node_data(nir_instr, prev, node);
}
+static inline bool
+nir_instr_is_first(nir_instr *instr)
+{
+ return exec_node_is_head_sentinel(exec_node_get_prev(&instr->node));
+}
+
+static inline bool
+nir_instr_is_last(nir_instr *instr)
+{
+ return exec_node_is_tail_sentinel(exec_node_get_next(&instr->node));
+}
+
typedef struct {
/** for debugging only, can be NULL */
const char* name;
nir_instr *parent_instr;
/** set of nir_instr's where this register is used (read from) */
- struct set *uses;
+ struct list_head uses;
/** set of nir_if's where this register is used as a condition */
- struct set *if_uses;
+ struct list_head if_uses;
uint8_t num_components;
} nir_ssa_def;
} nir_reg_src;
typedef struct {
+ nir_instr *parent_instr;
+ struct list_head def_link;
+
nir_register *reg;
struct nir_src *indirect; /** < NULL for no indirect offset */
unsigned base_offset;
/* TODO def-use chain goes here */
} nir_reg_dest;
+struct nir_if;
+
typedef struct nir_src {
+ union {
+ nir_instr *parent_instr;
+ struct nir_if *parent_if;
+ };
+
+ struct list_head use_link;
+
union {
nir_reg_src reg;
nir_ssa_def *ssa;
bool is_ssa;
} nir_src;
+#ifdef __cplusplus
+# define NIR_SRC_INIT nir_src()
+#else
+# define NIR_SRC_INIT (nir_src) { { NULL } }
+#endif
+
+#define nir_foreach_use(reg_or_ssa_def, src) \
+ list_for_each_entry(nir_src, src, &(reg_or_ssa_def)->uses, use_link)
+
+#define nir_foreach_use_safe(reg_or_ssa_def, src) \
+ list_for_each_entry_safe(nir_src, src, &(reg_or_ssa_def)->uses, use_link)
+
+#define nir_foreach_if_use(reg_or_ssa_def, src) \
+ list_for_each_entry(nir_src, src, &(reg_or_ssa_def)->if_uses, use_link)
+
+#define nir_foreach_if_use_safe(reg_or_ssa_def, src) \
+ list_for_each_entry_safe(nir_src, src, &(reg_or_ssa_def)->if_uses, use_link)
+
typedef struct {
union {
nir_reg_dest reg;
bool is_ssa;
} nir_dest;
+#ifdef __cplusplus
+# define NIR_DEST_INIT nir_dest()
+#else
+# define NIR_DEST_INIT (nir_dest) { { { NULL } } }
+#endif
+
+#define nir_foreach_def(reg, dest) \
+ list_for_each_entry(nir_dest, dest, &(reg)->defs, reg.def_link)
+
+#define nir_foreach_def_safe(reg, dest) \
+ list_for_each_entry_safe(nir_dest, dest, &(reg)->defs, reg.def_link)
+
static inline nir_src
nir_src_for_ssa(nir_ssa_def *def)
{
- nir_src src;
+ nir_src src = NIR_SRC_INIT;
src.is_ssa = true;
src.ssa = def;
static inline nir_src
nir_src_for_reg(nir_register *reg)
{
- nir_src src;
+ nir_src src = NIR_SRC_INIT;
src.is_ssa = false;
src.reg.reg = reg;
return src;
}
-static inline nir_instr *
-nir_src_get_parent_instr(const nir_src *src)
-{
- if (src->is_ssa) {
- return src->ssa->parent_instr;
- } else {
- return src->reg.reg->parent_instr;
- }
-}
-
static inline nir_dest
nir_dest_for_reg(nir_register *reg)
{
- nir_dest dest;
+ nir_dest dest = NIR_DEST_INIT;
- dest.is_ssa = false;
dest.reg.reg = reg;
- dest.reg.indirect = NULL;
- dest.reg.base_offset = 0;
return dest;
}
NIR_DEFINE_CAST(nir_deref_as_array, nir_deref, nir_deref_array, deref)
NIR_DEFINE_CAST(nir_deref_as_struct, nir_deref, nir_deref_struct, deref)
+/** Returns the tail of a deref chain */
+static inline nir_deref *
+nir_deref_tail(nir_deref *deref)
+{
+ while (deref->child)
+ deref = deref->child;
+ return deref;
+}
+
typedef struct {
nir_instr instr;
/* gather component selector */
unsigned component : 2;
+ /* The descriptor set containing this texture */
+ unsigned sampler_set;
+
/** The sampler index
*
* If this texture instruction has a nir_tex_src_sampler_offset source,
static inline unsigned
nir_tex_instr_dest_size(nir_tex_instr *instr)
{
- if (instr->op == nir_texop_txs) {
+ switch (instr->op) {
+ case nir_texop_txs: {
unsigned ret;
switch (instr->sampler_dim) {
case GLSL_SAMPLER_DIM_1D:
return ret;
}
- if (instr->op == nir_texop_query_levels)
+ case nir_texop_lod:
return 2;
- if (instr->is_shadow && instr->is_new_style_shadow)
+ case nir_texop_query_levels:
return 1;
- return 4;
+ default:
+ if (instr->is_shadow && instr->is_new_style_shadow)
+ return 1;
+
+ return 4;
+ }
}
static inline unsigned
#define nir_foreach_phi_src(phi, entry) \
foreach_list_typed(nir_phi_src, entry, node, &(phi)->srcs)
+#define nir_foreach_phi_src_safe(phi, entry) \
+ foreach_list_typed_safe(nir_phi_src, entry, node, &(phi)->srcs)
typedef struct {
nir_instr instr;
foreach_list_typed_reverse(nir_instr, instr, node, &(block)->instr_list)
#define nir_foreach_instr_safe(block, instr) \
foreach_list_typed_safe(nir_instr, instr, node, &(block)->instr_list)
+#define nir_foreach_instr_safe_reverse(block, instr) \
+ foreach_list_typed_safe_reverse(nir_instr, instr, node, &(block)->instr_list)
-typedef struct {
+typedef struct nir_if {
nir_cf_node cf_node;
nir_src condition;
struct exec_list body; /** < list of nir_cf_node */
- nir_block *start_block, *end_block;
+ nir_block *end_block;
/** list for all local variables in the function */
struct exec_list locals;
nir_metadata valid_metadata;
} nir_function_impl;
+static inline nir_block *
+nir_start_block(nir_function_impl *impl)
+{
+ return (nir_block *) exec_list_get_head(&impl->body);
+}
+
static inline nir_cf_node *
nir_cf_node_next(nir_cf_node *node)
{
typedef struct nir_shader_compiler_options {
bool lower_ffma;
+ bool lower_fdiv;
bool lower_flrp;
bool lower_fpow;
bool lower_fsat;
bool lower_fsqrt;
/** lowers fneg and ineg to fsub and isub. */
bool lower_negate;
+ /** lowers fsub and isub to fadd+fneg and iadd+ineg. */
+ bool lower_sub;
/* lower {slt,sge,seq,sne} to {flt,fge,feq,fne} + b2f: */
bool lower_scmp;
* access plus one
*/
unsigned num_inputs, num_uniforms, num_outputs;
+
+ /** The shader stage, such as MESA_SHADER_VERTEX. */
+ gl_shader_stage stage;
} nir_shader;
#define nir_foreach_overload(shader, overload) \
&(func)->overload_list)
nir_shader *nir_shader_create(void *mem_ctx,
+ gl_shader_stage stage,
const nir_shader_compiler_options *options);
/** creates a register, including assigning it an index and adding it to the list */
nir_function_impl *nir_cf_node_get_function(nir_cf_node *node);
-/** puts a control flow node immediately after another control flow node */
-void nir_cf_node_insert_after(nir_cf_node *node, nir_cf_node *after);
-
-/** puts a control flow node immediately before another control flow node */
-void nir_cf_node_insert_before(nir_cf_node *node, nir_cf_node *before);
-
-/** puts a control flow node at the beginning of a list from an if, loop, or function */
-void nir_cf_node_insert_begin(struct exec_list *list, nir_cf_node *node);
-
-/** puts a control flow node at the end of a list from an if, loop, or function */
-void nir_cf_node_insert_end(struct exec_list *list, nir_cf_node *node);
-
-/** removes a control flow node, doing any cleanup necessary */
-void nir_cf_node_remove(nir_cf_node *node);
-
/** requests that the given pieces of metadata be generated */
void nir_metadata_require(nir_function_impl *impl, nir_metadata required);
/** dirties all but the preserved metadata */
nir_deref *nir_copy_deref(void *mem_ctx, nir_deref *deref);
-void nir_instr_insert_before(nir_instr *instr, nir_instr *before);
-void nir_instr_insert_after(nir_instr *instr, nir_instr *after);
+nir_load_const_instr *
+nir_deref_get_const_initializer_load(nir_shader *shader, nir_deref_var *deref);
-void nir_instr_insert_before_block(nir_block *block, nir_instr *before);
-void nir_instr_insert_after_block(nir_block *block, nir_instr *after);
+/**
+ * NIR Cursors and Instruction Insertion API
+ * @{
+ *
+ * A tiny struct representing a point to insert/extract instructions or
+ * control flow nodes. Helps reduce the combinatorial explosion of possible
+ * points to insert/extract.
+ *
+ * \sa nir_control_flow.h
+ */
+typedef enum {
+ nir_cursor_before_block,
+ nir_cursor_after_block,
+ nir_cursor_before_instr,
+ nir_cursor_after_instr,
+} nir_cursor_option;
-void nir_instr_insert_before_cf(nir_cf_node *node, nir_instr *before);
-void nir_instr_insert_after_cf(nir_cf_node *node, nir_instr *after);
+typedef struct {
+ nir_cursor_option option;
+ union {
+ nir_block *block;
+ nir_instr *instr;
+ };
+} nir_cursor;
-void nir_instr_insert_before_cf_list(struct exec_list *list, nir_instr *before);
-void nir_instr_insert_after_cf_list(struct exec_list *list, nir_instr *after);
+static inline nir_block *
+nir_cursor_current_block(nir_cursor cursor)
+{
+ if (cursor.option == nir_cursor_before_instr ||
+ cursor.option == nir_cursor_after_instr) {
+ return cursor.instr->block;
+ } else {
+ return cursor.block;
+ }
+}
+
+static inline nir_cursor
+nir_before_block(nir_block *block)
+{
+ nir_cursor cursor;
+ cursor.option = nir_cursor_before_block;
+ cursor.block = block;
+ return cursor;
+}
+
+static inline nir_cursor
+nir_after_block(nir_block *block)
+{
+ nir_cursor cursor;
+ cursor.option = nir_cursor_after_block;
+ cursor.block = block;
+ return cursor;
+}
+
+static inline nir_cursor
+nir_before_instr(nir_instr *instr)
+{
+ nir_cursor cursor;
+ cursor.option = nir_cursor_before_instr;
+ cursor.instr = instr;
+ return cursor;
+}
+
+static inline nir_cursor
+nir_after_instr(nir_instr *instr)
+{
+ nir_cursor cursor;
+ cursor.option = nir_cursor_after_instr;
+ cursor.instr = instr;
+ return cursor;
+}
+
+static inline nir_cursor
+nir_after_block_before_jump(nir_block *block)
+{
+ nir_instr *last_instr = nir_block_last_instr(block);
+ if (last_instr && last_instr->type == nir_instr_type_jump) {
+ return nir_before_instr(last_instr);
+ } else {
+ return nir_after_block(block);
+ }
+}
+
+static inline nir_cursor
+nir_before_cf_node(nir_cf_node *node)
+{
+ if (node->type == nir_cf_node_block)
+ return nir_before_block(nir_cf_node_as_block(node));
+
+ return nir_after_block(nir_cf_node_as_block(nir_cf_node_prev(node)));
+}
+
+static inline nir_cursor
+nir_after_cf_node(nir_cf_node *node)
+{
+ if (node->type == nir_cf_node_block)
+ return nir_after_block(nir_cf_node_as_block(node));
+
+ return nir_before_block(nir_cf_node_as_block(nir_cf_node_next(node)));
+}
+
+static inline nir_cursor
+nir_before_cf_list(struct exec_list *cf_list)
+{
+ nir_cf_node *first_node = exec_node_data(nir_cf_node,
+ exec_list_get_head(cf_list), node);
+ return nir_before_cf_node(first_node);
+}
+
+static inline nir_cursor
+nir_after_cf_list(struct exec_list *cf_list)
+{
+ nir_cf_node *last_node = exec_node_data(nir_cf_node,
+ exec_list_get_tail(cf_list), node);
+ return nir_after_cf_node(last_node);
+}
+
+/**
+ * Insert a NIR instruction at the given cursor.
+ *
+ * Note: This does not update the cursor.
+ */
+void nir_instr_insert(nir_cursor cursor, nir_instr *instr);
+
+static inline void
+nir_instr_insert_before(nir_instr *instr, nir_instr *before)
+{
+ nir_instr_insert(nir_before_instr(instr), before);
+}
+
+static inline void
+nir_instr_insert_after(nir_instr *instr, nir_instr *after)
+{
+ nir_instr_insert(nir_after_instr(instr), after);
+}
+
+static inline void
+nir_instr_insert_before_block(nir_block *block, nir_instr *before)
+{
+ nir_instr_insert(nir_before_block(block), before);
+}
+
+static inline void
+nir_instr_insert_after_block(nir_block *block, nir_instr *after)
+{
+ nir_instr_insert(nir_after_block(block), after);
+}
+
+static inline void
+nir_instr_insert_before_cf(nir_cf_node *node, nir_instr *before)
+{
+ nir_instr_insert(nir_before_cf_node(node), before);
+}
+
+static inline void
+nir_instr_insert_after_cf(nir_cf_node *node, nir_instr *after)
+{
+ nir_instr_insert(nir_after_cf_node(node), after);
+}
+
+static inline void
+nir_instr_insert_before_cf_list(struct exec_list *list, nir_instr *before)
+{
+ nir_instr_insert(nir_before_cf_list(list), before);
+}
+
+static inline void
+nir_instr_insert_after_cf_list(struct exec_list *list, nir_instr *after)
+{
+ nir_instr_insert(nir_after_cf_list(list), after);
+}
void nir_instr_remove(nir_instr *instr);
+/** @} */
+
typedef bool (*nir_foreach_ssa_def_cb)(nir_ssa_def *def, void *state);
typedef bool (*nir_foreach_dest_cb)(nir_dest *dest, void *state);
typedef bool (*nir_foreach_src_cb)(nir_src *src, void *state);
nir_const_value *nir_src_as_const_value(nir_src src);
bool nir_srcs_equal(nir_src src1, nir_src src2);
void nir_instr_rewrite_src(nir_instr *instr, nir_src *src, nir_src new_src);
+void nir_instr_move_src(nir_instr *dest_instr, nir_src *dest, nir_src *src);
+void nir_if_rewrite_condition(nir_if *if_stmt, nir_src new_src);
void nir_ssa_dest_init(nir_instr *instr, nir_dest *dest,
unsigned num_components, const char *name);
#ifdef DEBUG
void nir_validate_shader(nir_shader *shader);
#else
-static inline void nir_validate_shader(nir_shader *shader) { }
+static inline void nir_validate_shader(nir_shader *shader) { (void) shader; }
#endif /* DEBUG */
void nir_calc_dominance_impl(nir_function_impl *impl);
void nir_lower_locals_to_regs(nir_shader *shader);
-void nir_assign_var_locations_scalar(struct exec_list *var_list,
- unsigned *size);
-void nir_assign_var_locations_scalar_direct_first(nir_shader *shader,
- struct exec_list *var_list,
- unsigned *direct_size,
- unsigned *size);
+void nir_lower_outputs_to_temporaries(nir_shader *shader);
-void nir_lower_io(nir_shader *shader);
+void nir_assign_var_locations(struct exec_list *var_list,
+ unsigned *size,
+ int (*type_size)(const struct glsl_type *));
+void nir_lower_io(nir_shader *shader,
+ int (*type_size)(const struct glsl_type *));
void nir_lower_vars_to_ssa(nir_shader *shader);
void nir_remove_dead_variables(nir_shader *shader);
void nir_lower_vec_to_movs(nir_shader *shader);
void nir_lower_alu_to_scalar(nir_shader *shader);
+void nir_lower_load_const_to_scalar(nir_shader *shader);
void nir_lower_phis_to_scalar(nir_shader *shader);
void nir_lower_samplers(nir_shader *shader,
- struct gl_shader_program *shader_program,
- gl_shader_stage stage);
+ const struct gl_shader_program *shader_program);
+void nir_lower_samplers_for_vk(nir_shader *shader);
void nir_lower_system_values(nir_shader *shader);
void nir_lower_tex_projector(nir_shader *shader);
void nir_convert_to_ssa_impl(nir_function_impl *impl);
void nir_convert_to_ssa(nir_shader *shader);
-void nir_convert_from_ssa(nir_shader *shader);
+
+/* If phi_webs_only is true, only convert SSA values involved in phi nodes to
+ * registers. If false, convert all values (even those not involved in a phi
+ * node) to registers.
+ */
+void nir_convert_from_ssa(nir_shader *shader, bool phi_webs_only);
bool nir_opt_algebraic(nir_shader *shader);
bool nir_opt_algebraic_late(nir_shader *shader);
bool nir_opt_remove_phis(nir_shader *shader);
+bool nir_opt_undef(nir_shader *shader);
+
void nir_sweep(nir_shader *shader);
#ifdef __cplusplus