#pragma once
#include "util/hash_table.h"
-#include "main/set.h"
#include "../list.h"
#include "GL/gl.h" /* GLenum */
+#include "util/list.h"
#include "util/ralloc.h"
-#include "main/mtypes.h"
-#include "main/bitset.h"
+#include "util/set.h"
+#include "util/bitset.h"
#include "nir_types.h"
+#include "glsl/shader_enums.h"
#include <stdio.h>
+#include "nir_opcodes.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+struct gl_program;
+struct gl_shader_program;
+
#define NIR_FALSE 0u
#define NIR_TRUE (~0u)
struct nir_function_overload;
struct nir_function;
struct nir_shader;
+struct nir_instr;
/**
nir_var_global,
nir_var_local,
nir_var_uniform,
+ nir_var_shader_storage,
nir_var_system_value
} nir_variable_mode;
* Value of the constant.
*
* The field used to back the values supplied by the constant is determined
- * by the type associated with the \c ir_instruction. Constants may be
+ * by the type associated with the \c nir_variable. Constants may be
* scalars, vectors, or matrices.
*/
union nir_constant_data value;
/**
* Interpolation mode for shader inputs / outputs
*
- * \sa ir_variable_interpolation
+ * \sa glsl_interp_qualifier
*/
unsigned interpolation:2;
/**
* Was an initial binding explicitly set in the shader?
*
- * If so, constant_value contains an integer ir_constant representing the
- * initial binding point.
+ * If so, constant_initializer contains an integer nir_constant
+ * representing the initial binding point.
*/
unsigned explicit_binding:1;
nir_state_slot *state_slots; /**< State descriptors. */
/*@}*/
- /**
- * Value assigned in the initializer of a variable declared "const"
- */
- nir_constant *constant_value;
-
/**
* Constant expression assigned in the initializer of the variable
- *
- * \warning
- * This field and \c ::constant_value are distinct. Even if the two fields
- * refer to constants with the same value, they must point to separate
- * objects.
*/
nir_constant *constant_initializer;
bool is_packed;
/** 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 ifs where this register is used as a condition */
- struct set *if_uses;
+ /** set of nir_if's where this register is used as a condition */
+ struct list_head if_uses;
} nir_register;
typedef enum {
nir_instr_type_parallel_copy,
} nir_instr_type;
-typedef struct {
+typedef struct nir_instr {
struct exec_node node;
nir_instr_type type;
struct nir_block *block;
- /* flag for dead code elimination (see nir_opt_dce.c) */
- bool live;
+ /* A temporary for optimization and analysis passes to use for storing
+ * flags. For instance, DCE uses this to store the "dead/live" info.
+ */
+ uint8_t pass_flags;
} nir_instr;
-#define nir_instr_next(instr) \
- exec_node_data(nir_instr, (instr)->node.next, node)
+static inline nir_instr *
+nir_instr_next(nir_instr *instr)
+{
+ struct exec_node *next = exec_node_get_next(&instr->node);
+ if (exec_node_is_tail_sentinel(next))
+ return NULL;
+ else
+ return exec_node_data(nir_instr, next, node);
+}
-#define nir_instr_prev(instr) \
- exec_node_data(nir_instr, (instr)->node.prev, node)
+static inline nir_instr *
+nir_instr_prev(nir_instr *instr)
+{
+ struct exec_node *prev = exec_node_get_prev(&instr->node);
+ if (exec_node_is_head_sentinel(prev))
+ return NULL;
+ else
+ 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 */
nir_instr *parent_instr;
- struct set *uses;
- struct set *if_uses;
+ /** set of nir_instr's where this register is used (read from) */
+ struct list_head uses;
+
+ /** set of nir_if's where this register is used as a condition */
+ 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;
+#define NIR_SRC_INIT (nir_src) { { NULL } }
+
+#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;
-nir_src nir_src_copy(nir_src src, void *mem_ctx);
-nir_dest nir_dest_copy(nir_dest dest, void *mem_ctx);
+#define NIR_DEST_INIT (nir_dest) { { { NULL } } }
+
+#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_INIT;
+
+ src.is_ssa = true;
+ src.ssa = def;
+
+ return src;
+}
+
+static inline nir_src
+nir_src_for_reg(nir_register *reg)
+{
+ nir_src src = NIR_SRC_INIT;
+
+ src.is_ssa = false;
+ src.reg.reg = reg;
+ src.reg.indirect = NULL;
+ src.reg.base_offset = 0;
+
+ return src;
+}
+
+static inline nir_dest
+nir_dest_for_reg(nir_register *reg)
+{
+ nir_dest dest = NIR_DEST_INIT;
+
+ dest.reg.reg = reg;
+
+ return dest;
+}
+
+void nir_src_copy(nir_src *dest, const nir_src *src, void *mem_ctx);
+void nir_dest_copy(nir_dest *dest, const nir_dest *src, void *mem_ctx);
typedef struct {
nir_src src;
*/
/*@{*/
/**
- * For inputs interpreted as a floating point, flips the sign bit. For inputs
- * interpreted as an integer, performs the two's complement negation.
+ * For inputs interpreted as floating point, flips the sign bit. For
+ * inputs interpreted as integers, performs the two's complement negation.
*/
bool negate;
unsigned write_mask : 4; /* ignored if dest.is_ssa is true */
} nir_alu_dest;
-#define OPCODE(name, num_inputs, output_size, output_type, \
- input_sizes, input_types, algebraic_props) \
- nir_op_##name,
-
-#define LAST_OPCODE(name) nir_last_opcode = nir_op_##name,
-
-typedef enum {
-#include "nir_opcodes.h"
- nir_num_opcodes = nir_last_opcode + 1
-} nir_op;
-
-#undef OPCODE
-#undef LAST_OPCODE
+void nir_alu_src_copy(nir_alu_src *dest, const nir_alu_src *src, void *mem_ctx);
+void nir_alu_dest_copy(nir_alu_dest *dest, const nir_alu_dest *src,
+ void *mem_ctx);
typedef enum {
+ nir_type_invalid = 0, /* Not a valid type */
nir_type_float,
nir_type_int,
nir_type_unsigned,
unsigned output_size;
/**
- * The type of vector that the instruction outputs. Note that this
- * determines whether the saturate modifier is allowed.
+ * The type of vector that the instruction outputs. Note that the
+ * staurate modifier is only allowed on outputs with the float type.
*/
nir_alu_type output_type;
unsigned input_sizes[4];
/**
- * The type of vector that each input takes. Note that negate is only
- * allowed on inputs with int or float type, and behaves differently on the
- * two, and absolute value is only allowed on float type inputs.
+ * The type of vector that each input takes. Note that negate and
+ * absolute value are only allowed on inputs with int or float type and
+ * behave differently on the two.
*/
nir_alu_type input_types[4];
return (instr->dest.write_mask >> channel) & 1;
}
+/*
+ * For instructions whose destinations are SSA, get the number of channels
+ * used for a source
+ */
+static inline unsigned
+nir_ssa_alu_instr_src_components(nir_alu_instr *instr, unsigned src)
+{
+ assert(instr->dest.dest.is_ssa);
+
+ if (nir_op_infos[instr->op].input_sizes[src] > 0)
+ return nir_op_infos[instr->op].input_sizes[src];
+
+ return instr->dest.dest.ssa.num_components;
+}
+
typedef enum {
nir_deref_type_var,
nir_deref_type_array,
#undef INTRINSIC
#undef LAST_INTRINSIC
+/** Represents an intrinsic
+ *
+ * An intrinsic is an instruction type for handling things that are
+ * more-or-less regular operations but don't just consume and produce SSA
+ * values like ALU operations do. Intrinsics are not for things that have
+ * special semantic meaning such as phi nodes and parallel copies.
+ * Examples of intrinsics include variable load/store operations, system
+ * value loads, and the like. Even though texturing more-or-less falls
+ * under this category, texturing is its own instruction type because
+ * trying to represent texturing with intrinsics would lead to a
+ * combinatorial explosion of intrinsic opcodes.
+ *
+ * By having a single instruction type for handling a lot of different
+ * cases, optimization passes can look for intrinsics and, for the most
+ * part, completely ignore them. Each intrinsic type also has a few
+ * possible flags that govern whether or not they can be reordered or
+ * eliminated. That way passes like dead code elimination can still work
+ * on intrisics without understanding the meaning of each.
+ *
+ * Each intrinsic has some number of constant indices, some number of
+ * variables, and some number of sources. What these sources, variables,
+ * and indices mean depends on the intrinsic and is documented with the
+ * intrinsic declaration in nir_intrinsics.h. Intrinsics and texture
+ * instructions are the only types of instruction that can operate on
+ * variables.
+ */
typedef struct {
nir_instr instr;
nir_dest dest;
- /** number of components if this is a vectorized intrinsic */
+ /** number of components if this is a vectorized intrinsic
+ *
+ * Similarly to ALU operations, some intrinsics are vectorized.
+ * An intrinsic is vectorized if nir_intrinsic_infos.dest_components == 0.
+ * For vectorized intrinsics, the num_components field specifies the
+ * number of destination components and the number of source components
+ * for all sources with nir_intrinsic_infos.src_components[i] == 0.
+ */
uint8_t num_components;
int const_index[3];
*
* \sa nir_intrinsic_info::flags
*/
-/*@{*/
-/**
- * whether the intrinsic can be safely eliminated if none of its register
- * outputs are being used.
- */
-#define NIR_INTRINSIC_CAN_ELIMINATE (1 << 0)
+typedef enum {
+ /**
+ * whether the intrinsic can be safely eliminated if none of its output
+ * value is not being used.
+ */
+ NIR_INTRINSIC_CAN_ELIMINATE = (1 << 0),
-/**
- * Whether the intrinsic can be reordered with respect to any other intrinsic,
- * i.e. whether the only reodering dependencies of the intrinsic are due to the
- * register reads/writes.
- */
-#define NIR_INTRINSIC_CAN_REORDER (1 << 1)
-/*@}*/
+ /**
+ * Whether the intrinsic can be reordered with respect to any other
+ * intrinsic, i.e. whether the only reordering dependencies of the
+ * intrinsic are due to the register reads/writes.
+ */
+ NIR_INTRINSIC_CAN_REORDER = (1 << 1),
+} nir_intrinsic_semantic_flag;
#define NIR_INTRINSIC_MAX_INPUTS 4
unsigned num_indices;
/** semantic flags for calls to this intrinsic */
- unsigned flags;
+ nir_intrinsic_semantic_flag flags;
} nir_intrinsic_info;
extern const nir_intrinsic_info nir_intrinsic_infos[nir_num_intrinsics];
nir_tex_src_ddx,
nir_tex_src_ddy,
nir_tex_src_sampler_offset, /* < dynamically uniform indirect offset */
- nir_num_texinput_types
-} nir_texinput_type;
+ nir_num_tex_src_types
+} nir_tex_src_type;
+
+typedef struct {
+ nir_src src;
+ nir_tex_src_type src_type;
+} nir_tex_src;
typedef enum {
nir_texop_tex, /**< Regular texture look-up */
nir_texop op;
nir_dest dest;
- nir_src src[4];
- nir_texinput_type src_type[4];
+ nir_tex_src *src;
unsigned num_srcs, coord_components;
bool is_array, is_shadow;
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:
ret = 3;
break;
default:
- assert(0);
- break;
+ unreachable("not reached");
}
if (instr->is_array)
ret++;
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
nir_tex_instr_src_size(nir_tex_instr *instr, unsigned src)
{
- if (instr->src_type[src] == nir_tex_src_coord)
+ if (instr->src[src].src_type == nir_tex_src_coord)
return instr->coord_components;
- if (instr->src_type[src] == nir_tex_src_offset ||
- instr->src_type[src] == nir_tex_src_ddx ||
- instr->src_type[src] == nir_tex_src_ddy) {
+ if (instr->src[src].src_type == nir_tex_src_offset ||
+ instr->src[src].src_type == nir_tex_src_ddx ||
+ instr->src[src].src_type == nir_tex_src_ddy) {
if (instr->is_array)
return instr->coord_components - 1;
else
}
static inline int
-nir_tex_instr_src_index(nir_tex_instr *instr, nir_texinput_type type)
+nir_tex_instr_src_index(nir_tex_instr *instr, nir_tex_src_type type)
{
for (unsigned i = 0; i < instr->num_srcs; i++)
- if (instr->src_type[i] == type)
+ if (instr->src[i].src_type == type)
return (int) i;
return -1;
typedef struct {
struct exec_node node;
+
+ /* The predecessor block corresponding to this source */
struct nir_block *pred;
+
nir_src src;
} nir_phi_src;
+#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;
- struct exec_list srcs;
+ struct exec_list srcs; /** < list of nir_phi_src */
+
nir_dest dest;
} nir_phi_instr;
struct exec_node node;
nir_src src;
nir_dest dest;
-} nir_parallel_copy_copy;
+} nir_parallel_copy_entry;
+
+#define nir_foreach_parallel_copy_entry(pcopy, entry) \
+ foreach_list_typed(nir_parallel_copy_entry, entry, node, &(pcopy)->entries)
typedef struct {
nir_instr instr;
- struct exec_list copies;
+
+ /* A list of nir_parallel_copy_entry's. The sources of all of the
+ * entries are copied to the corresponding destinations "in parallel".
+ * In other words, if we have two entries: a -> b and b -> a, the values
+ * get swapped.
+ */
+ struct exec_list entries;
} nir_parallel_copy_instr;
NIR_DEFINE_CAST(nir_instr_as_alu, nir_instr, nir_alu_instr, instr)
typedef struct nir_block {
nir_cf_node cf_node;
- struct exec_list instr_list;
+ struct exec_list instr_list; /** < list of nir_instr */
+
+ /** generic block index; generated by nir_index_blocks */
unsigned index;
/*
*/
struct nir_block *successors[2];
+ /* Set of nir_block predecessors in the CFG */
struct set *predecessors;
/*
unsigned num_dom_children;
struct nir_block **dom_children;
+ /* Set of nir_block's on the dominance frontier of this block */
struct set *dom_frontier;
+ /*
+ * These two indices have the property that dom_{pre,post}_index for each
+ * child of this block in the dominance tree will always be between
+ * dom_pre_index and dom_post_index for this block, which makes testing if
+ * a given block is dominated by another block an O(1) operation.
+ */
+ unsigned dom_pre_index, dom_post_index;
+
/* live in and out for this block; used for liveness analysis */
BITSET_WORD *live_in;
BITSET_WORD *live_out;
} nir_block;
-#define nir_block_first_instr(block) \
- exec_node_data(nir_instr, exec_list_get_head(&(block)->instr_list), node)
-#define nir_block_last_instr(block) \
- exec_node_data(nir_instr, exec_list_get_tail(&(block)->instr_list), node)
+static inline nir_instr *
+nir_block_first_instr(nir_block *block)
+{
+ struct exec_node *head = exec_list_get_head(&block->instr_list);
+ return exec_node_data(nir_instr, head, node);
+}
+
+static inline nir_instr *
+nir_block_last_instr(nir_block *block)
+{
+ struct exec_node *tail = exec_list_get_tail(&block->instr_list);
+ return exec_node_data(nir_instr, tail, node);
+}
#define nir_foreach_instr(block, instr) \
foreach_list_typed(nir_instr, instr, node, &(block)->instr_list)
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 then_list;
- struct exec_list else_list;
+
+ struct exec_list then_list; /** < list of nir_cf_node */
+ struct exec_list else_list; /** < list of nir_cf_node */
} nir_if;
-#define nir_if_first_then_node(if) \
- exec_node_data(nir_cf_node, exec_list_get_head(&(if)->then_list), node)
-#define nir_if_last_then_node(if) \
- exec_node_data(nir_cf_node, exec_list_get_tail(&(if)->then_list), node)
-#define nir_if_first_else_node(if) \
- exec_node_data(nir_cf_node, exec_list_get_head(&(if)->else_list), node)
-#define nir_if_last_else_node(if) \
- exec_node_data(nir_cf_node, exec_list_get_tail(&(if)->else_list), node)
+static inline nir_cf_node *
+nir_if_first_then_node(nir_if *if_stmt)
+{
+ struct exec_node *head = exec_list_get_head(&if_stmt->then_list);
+ return exec_node_data(nir_cf_node, head, node);
+}
+
+static inline nir_cf_node *
+nir_if_last_then_node(nir_if *if_stmt)
+{
+ struct exec_node *tail = exec_list_get_tail(&if_stmt->then_list);
+ return exec_node_data(nir_cf_node, tail, node);
+}
+
+static inline nir_cf_node *
+nir_if_first_else_node(nir_if *if_stmt)
+{
+ struct exec_node *head = exec_list_get_head(&if_stmt->else_list);
+ return exec_node_data(nir_cf_node, head, node);
+}
+
+static inline nir_cf_node *
+nir_if_last_else_node(nir_if *if_stmt)
+{
+ struct exec_node *tail = exec_list_get_tail(&if_stmt->else_list);
+ return exec_node_data(nir_cf_node, tail, node);
+}
typedef struct {
nir_cf_node cf_node;
- struct exec_list body;
+
+ struct exec_list body; /** < list of nir_cf_node */
} nir_loop;
-#define nir_loop_first_cf_node(loop) \
- exec_node_data(nir_cf_node, exec_list_get_head(&(loop)->body), node)
-#define nir_loop_last_cf_node(loop) \
- exec_node_data(nir_cf_node, exec_list_get_tail(&(loop)->body), node)
+static inline nir_cf_node *
+nir_loop_first_cf_node(nir_loop *loop)
+{
+ return exec_node_data(nir_cf_node, exec_list_get_head(&loop->body), node);
+}
+
+static inline nir_cf_node *
+nir_loop_last_cf_node(nir_loop *loop)
+{
+ return exec_node_data(nir_cf_node, exec_list_get_tail(&loop->body), node);
+}
/**
* Various bits of metadata that can may be created or required by
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;
-#define nir_cf_node_next(_node) \
- exec_node_data(nir_cf_node, exec_node_get_next(&(_node)->node), node)
+static inline nir_block *
+nir_start_block(nir_function_impl *impl)
+{
+ return (nir_block *) exec_list_get_head(&impl->body);
+}
-#define nir_cf_node_prev(_node) \
- exec_node_data(nir_cf_node, exec_node_get_prev(&(_node)->node), node)
+static inline nir_cf_node *
+nir_cf_node_next(nir_cf_node *node)
+{
+ struct exec_node *next = exec_node_get_next(&node->node);
+ if (exec_node_is_tail_sentinel(next))
+ return NULL;
+ else
+ return exec_node_data(nir_cf_node, next, node);
+}
-#define nir_cf_node_is_first(_node) \
- exec_node_is_head_sentinel((_node)->node.prev)
+static inline nir_cf_node *
+nir_cf_node_prev(nir_cf_node *node)
+{
+ struct exec_node *prev = exec_node_get_prev(&node->node);
+ if (exec_node_is_head_sentinel(prev))
+ return NULL;
+ else
+ return exec_node_data(nir_cf_node, prev, node);
+}
-#define nir_cf_node_is_last(_node) \
- exec_node_is_tail_sentinel((_node)->node.next)
+static inline bool
+nir_cf_node_is_first(const nir_cf_node *node)
+{
+ return exec_node_is_head_sentinel(node->node.prev);
+}
+
+static inline bool
+nir_cf_node_is_last(const nir_cf_node *node)
+{
+ return exec_node_is_tail_sentinel(node->node.next);
+}
NIR_DEFINE_CAST(nir_cf_node_as_block, nir_cf_node, nir_block, cf_node)
NIR_DEFINE_CAST(nir_cf_node_as_if, nir_cf_node, nir_if, cf_node)
typedef struct nir_function {
struct exec_node node;
- struct exec_list overload_list;
+ struct exec_list overload_list; /** < list of nir_function_overload */
const char *name;
struct nir_shader *shader;
} nir_function;
exec_node_data(nir_function_overload, \
exec_list_get_head(&(func)->overload_list), node)
+typedef struct nir_shader_compiler_options {
+ bool lower_ffma;
+ 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;
+
+ /**
+ * Does the driver support real 32-bit integers? (Otherwise, integers
+ * are simulated by floats.)
+ */
+ bool native_integers;
+} nir_shader_compiler_options;
+
typedef struct nir_shader {
- /** hash table of name -> uniform */
- struct hash_table *uniforms;
+ /** hash table of name -> uniform nir_variable */
+ struct exec_list uniforms;
- /** hash table of name -> input */
- struct hash_table *inputs;
+ /** hash table of name -> input nir_variable */
+ struct exec_list inputs;
- /** hash table of name -> output */
- struct hash_table *outputs;
+ /** hash table of name -> output nir_variable */
+ struct exec_list outputs;
+
+ /** Set of driver-specific options for the shader.
+ *
+ * The memory for the options is expected to be kept in a single static
+ * copy by the driver.
+ */
+ const struct nir_shader_compiler_options *options;
/** list of global variables in the shader */
struct exec_list globals;
+ /** list of system value variables in the shader */
struct exec_list system_values;
- struct exec_list functions;
+ struct exec_list functions; /** < list of nir_function */
- /** list of global registers in the shader */
+ /** list of global register in the shader */
struct exec_list registers;
- /** structures used in this shader */
- unsigned num_user_structures;
- struct glsl_type **user_structures;
-
/** next available global register index */
unsigned reg_alloc;
* access plus one
*/
unsigned num_inputs, num_uniforms, num_outputs;
+
+ /** the number of uniforms that are only accessed directly */
+ unsigned num_direct_uniforms;
} nir_shader;
-#define nir_foreach_overload(shader, overload) \
+#define nir_foreach_overload(shader, overload) \
foreach_list_typed(nir_function, func, node, &(shader)->functions) \
foreach_list_typed(nir_function_overload, overload, node, \
&(func)->overload_list)
-nir_shader *nir_shader_create(void *mem_ctx);
+nir_shader *nir_shader_create(void *mem_ctx,
+ const nir_shader_compiler_options *options);
/** creates a register, including assigning it an index and adding it to the list */
nir_register *nir_global_reg_create(nir_shader *shader);
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 */
void nir_metadata_preserve(nir_function_impl *impl, nir_metadata preserved);
/** creates an instruction with default swizzle/writemask/etc. with NULL registers */
-nir_alu_instr *nir_alu_instr_create(void *mem_ctx, nir_op op);
+nir_alu_instr *nir_alu_instr_create(nir_shader *shader, nir_op op);
-nir_jump_instr *nir_jump_instr_create(void *mem_ctx, 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(void *mem_ctx,
+nir_load_const_instr *nir_load_const_instr_create(nir_shader *shader,
unsigned num_components);
-nir_intrinsic_instr *nir_intrinsic_instr_create(void *mem_ctx,
+nir_intrinsic_instr *nir_intrinsic_instr_create(nir_shader *shader,
nir_intrinsic_op op);
-nir_call_instr *nir_call_instr_create(void *mem_ctx,
+nir_call_instr *nir_call_instr_create(nir_shader *shader,
nir_function_overload *callee);
-nir_tex_instr *nir_tex_instr_create(void *mem_ctx, unsigned num_srcs);
+nir_tex_instr *nir_tex_instr_create(nir_shader *shader, unsigned num_srcs);
-nir_phi_instr *nir_phi_instr_create(void *mem_ctx);
+nir_phi_instr *nir_phi_instr_create(nir_shader *shader);
-nir_parallel_copy_instr *nir_parallel_copy_instr_create(void *mem_ctx);
+nir_parallel_copy_instr *nir_parallel_copy_instr_create(nir_shader *shader);
-nir_ssa_undef_instr *nir_ssa_undef_instr_create(void *mem_ctx,
+nir_ssa_undef_instr *nir_ssa_undef_instr_create(nir_shader *shader,
unsigned num_components);
nir_deref_var *nir_deref_var_create(void *mem_ctx, nir_variable *var);
nir_deref *nir_copy_deref(void *mem_ctx, nir_deref *deref);
+nir_load_const_instr *
+nir_deref_get_const_initializer_load(nir_shader *shader, nir_deref_var *deref);
+
void nir_instr_insert_before(nir_instr *instr, nir_instr *before);
void nir_instr_insert_after(nir_instr *instr, nir_instr *after);
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);
void nir_ssa_def_init(nir_instr *instr, nir_ssa_def *def,
unsigned num_components, const char *name);
void nir_ssa_def_rewrite_uses(nir_ssa_def *def, nir_src new_src, void *mem_ctx);
void nir_index_blocks(nir_function_impl *impl);
void nir_print_shader(nir_shader *shader, FILE *fp);
+void nir_print_instr(const nir_instr *instr, FILE *fp);
+#ifdef DEBUG
void nir_validate_shader(nir_shader *shader);
+#else
+static inline void nir_validate_shader(nir_shader *shader) { (void) shader; }
+#endif /* DEBUG */
void nir_calc_dominance_impl(nir_function_impl *impl);
void nir_calc_dominance(nir_shader *shader);
+nir_block *nir_dominance_lca(nir_block *b1, nir_block *b2);
+bool nir_block_dominates(nir_block *parent, nir_block *child);
+
void nir_dump_dom_tree_impl(nir_function_impl *impl, FILE *fp);
void nir_dump_dom_tree(nir_shader *shader, FILE *fp);
void nir_split_var_copies(nir_shader *shader);
+void nir_lower_var_copy_instr(nir_intrinsic_instr *copy, void *mem_ctx);
+void nir_lower_var_copies(nir_shader *shader);
+
void nir_lower_global_vars_to_local(nir_shader *shader);
void nir_lower_locals_to_regs(nir_shader *shader);
-void nir_lower_io(nir_shader *shader);
+void nir_assign_var_locations(struct exec_list *var_list,
+ unsigned *size,
+ bool is_scalar);
+void nir_assign_var_locations_direct_first(nir_shader *shader,
+ struct exec_list *var_list,
+ unsigned *direct_size,
+ unsigned *size,
+ bool is_scalar);
+
+void nir_lower_io(nir_shader *shader, bool is_scalar);
-void nir_lower_variables(nir_shader *shader);
+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,
- struct gl_program *prog);
+ const struct gl_shader_program *shader_program,
+ gl_shader_stage stage);
void nir_lower_system_values(nir_shader *shader);
+void nir_lower_tex_projector(nir_shader *shader);
+void nir_lower_idiv(nir_shader *shader);
void nir_lower_atomics(nir_shader *shader);
void nir_lower_to_source_mods(nir_shader *shader);
+void nir_normalize_cubemap_coords(nir_shader *shader);
+
void nir_live_variables_impl(nir_function_impl *impl);
bool nir_ssa_defs_interfere(nir_ssa_def *a, nir_ssa_def *b);
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_constant_folding(nir_shader *shader);
bool nir_opt_global_to_local(nir_shader *shader);
bool nir_opt_dce_impl(nir_function_impl *impl);
bool nir_opt_dce(nir_shader *shader);
+void nir_opt_gcm(nir_shader *shader);
+
bool nir_opt_peephole_select(nir_shader *shader);
bool nir_opt_peephole_ffma(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
} /* extern "C" */
#endif