Variables

NIR is designed to include backend-independent ways to represent things if possible, while allowing backends the ability to lower some things if convenient. One of the main mechanisms for backend independence is through variables, which are based on GLSL variables (the implementation is mostly taken from GLSL IR). Variables are logical instead of physical, meaning that all accesses to them are unaware of any layout issues (even though in some cases, such as UBO’s, the API already defines the layout), and they may not contain any pointers; NIR doesn’t even have the concept of a pointer.

Dereferences

All accesses to variables occur through dereferences, which let you select which part of the variable you want to modify or access. A dereference is a singly-linked list which starts with a pointer to the variable itself and selects structure members or array elements according to the type of the variable. The type of the result of doing the dereference is also stored as part of the dereference, to make working with them easier.

One way that the dereference system is more powerful than GLSL’s is that it supports so-called “wildcard” array dereferences, which are used for array copies (the copy_var intrinsic). For example, this allows us to support something like:

struct s {
    vec4 a, b;
};

struct s foo[10], bar[10];
//...
foo[*].a = bar[*].a

where we can copy part of each element of the array. This is useful because it helps make converting part of the variable into SSA easier. For example, if it turns out that foo[*].a (i.e. all the elements foo[0].a, foo[1].a, foo[2].a, etc.) is always accessed directly while foo[*].b is sometimes accessed indirectly, we can convert foo[*].a to SSA values while only keeping around foo[*].b. Therefore, we lower array copies like

foo = bar;

to multiple wildcard copies like

foo[*].a = bar[*].a;
foo[*].b = bar[*].b;

and some of them may be eliminated by the out-of-SSA pass.

Variables vs. Registers, Inputs/Outputs, etc.

Variables are the core NIR way of handling most things that aren’t SSA values, and frontends should prefer emitting code that uses variables as they’re guaranteed to work with the core NIR optimization passes. However, variables aren’t always the easiest thing for backends to work with. Backends work directly with addresses and locations, and turning variable dereferences into those involves some work and creates code that then needs to be cleaned up. For this reason, there are various mechanisms in NIR that can replace most of the uses of variables and allow the driver’s lowering pass (or a common lowering pass used by the driver) to convert variable references to references to a flat address space. Some of those include:

  • Registers (really, virtual registers) can be used almost everywhere SSA values can be used. This means that they can used either as a replacement for normal local or global variables (i.e. per-instance variables that can only be loaded or stored), or as a way to make NIR shaders almost entirely free of SSA.
  • For inputs, outputs, and uniforms, there are load/store intrinsics that take a direct (constant) and indirect index that are added together.
  • For textures, similarly there are places to add direct and indirect indices for the sampler that are complementary to the variables.

There are some cases, such as alternate interpolation and image load/store, where the backend still currently has to deal directly with variables, but those are mostly due to technical restrictions and may change in the future.

Table Of Contents

Previous topic

Instructions

Next topic

Metadata

This Page