NIR is an Intermediate Representation (IR) that’s designed for the needs of graphics drivers in Mesa. It sits between a frontend that translates another language or IR such as GLSL IR or TGSI to NIR and the driver’s own backend IR. It includes several optimization passes, as well as some features that are useful for making translating to the driver’s own IR easier, although it is not intended to replace the backend and as such doesn’t support backend-specific tasks such as scheduling, register allocation, etc.
NIR was designed with several goals in mind:
One thing that NIR is not designed to be is a library for users outside of Mesa. It’s not possible to extend NIR at run-time to add additional operations, although it’s flexible enough that it’s usually easy to do at compile time. Furthermore, there is no stable API; it’s expected that producers and consumers will live in-tree so we can update them if we have to make breaking changes.
NIR is written in C, although in a very object-oriented manner. Structures and enums are typedef’ed:
typedef struct nir_foo {
/* stuff */
} nir_foo;
typedef enum {
nir_enum_thing1,
nir_enum_thing2,
nir_enum_thing3,
} nir_enum;
and inheritance is done through embedding structures. Upcasting is done through inline functions defined by the NIR_DEFINE_CAST macro. For example, here’s how an animal structure inherited by cows, cats, and dogs would be defined:
typedef enum {
nir_animal_type_cow,
nir_animal_type_dog,
nir_animal_type_cat,
} nir_animal_type;
typedef struct {
nir_animal_type type;
/* stuff */
} nir_animal;
typedef struct {
nir_animal animal;
} nir_cow;
typedef struct {
nir_animal animal;
} nir_dog;
typedef struct {
nir_animal animal;
} nir_cat;
NIR_DEFINE_CAST(nir_animal_as_cow, nir_animal, nir_cow, animal)
NIR_DEFINE_CAST(nir_animal_as_dog, nir_animal, nir_dog, animal)
NIR_DEFINE_CAST(nir_animal_as_cat, nir_animal, nir_cat, animal)
The core IR consists of various structures defined in nir.h, as well as functions for creating, destroying, and manipulating them. Currently, these structures include:
NIR includes a function called nir_print_shader() for printing the contents of a shader to a given FILE *, which can be useful for debugging. In addition, nir_print_instr() is exposed, which can be useful for examining instructions in the debugger.
There are various bits of redundant information as well as various invariants which must be satisfied in the IR. Often, passes will have bugs which result in those invariants being broken or the information left incorrect, which may only blow up much later when some other pass or analysis relies on that information. To make debugging those sorts of problems much easier, NIR has a validation pass, nir_validate_shader(), which makes sure that the shader is valid. It’s a no-op on release builds, but when debugging it catches many bugs at the source instead of much later.