1 1.1 mrg New IR, or NIR, is an IR for Mesa intended to sit below GLSL IR and Mesa IR. 2 1.1 mrg Its design inherits from the various IRs that Mesa has used in the past, as 3 1.1 mrg well as Direct3D assembly, and it includes a few new ideas as well. It is a 4 1.1 mrg flat (in terms of using instructions instead of expressions), typeless IR, 5 1.1 mrg similar to TGSI and Mesa IR. It also supports SSA (although it doesn't require 6 1.1 mrg it). 7 1.1 mrg 8 1.1 mrg Variables 9 1.1 mrg ========= 10 1.1 mrg 11 1.1 mrg NIR includes support for source-level GLSL variables through a structure mostly 12 1.1 mrg copied from GLSL IR. These will be used for linking and conversion from GLSL IR 13 1.1 mrg (and later, from an AST), but for the most part, they will be lowered to 14 1.1 mrg registers (see below) and loads/stores. 15 1.1 mrg 16 1.1 mrg Registers 17 1.1 mrg ========= 18 1.1 mrg 19 1.1 mrg Registers are light-weight; they consist of a structure that only contains its 20 1.1 mrg size, its index for liveness analysis, and an optional name for debugging. In 21 1.1 mrg addition, registers can be local to a function or global to the entire shader; 22 1.1 mrg the latter will be used in ARB_shader_subroutine for passing parameters and 23 1.1 mrg getting return values from subroutines. Registers can also be an array, in which 24 1.1 mrg case they can be accessed indirectly. Each ALU instruction (add, subtract, etc.) 25 1.1 mrg works directly with registers or SSA values (see below). 26 1.1 mrg 27 1.1 mrg SSA 28 1.1 mrg ======== 29 1.1 mrg 30 1.1 mrg Everywhere a register can be loaded/stored, an SSA value can be used instead. 31 1.1 mrg The only exception is that arrays/indirect addressing are not supported with 32 1.1 mrg SSA; although research has been done on extensions of SSA to arrays before, it's 33 1.1 mrg usually for the purpose of parallelization (which we're not interested in), and 34 1.1 mrg adds some overhead in the form of adding copies or extra arrays (which is much 35 1.1 mrg more expensive than introducing copies between non-array registers). SSA uses 36 1.1 mrg point directly to their corresponding definition, which in turn points to the 37 1.1 mrg instruction it is part of. This creates an implicit use-def chain and avoids the 38 1.1 mrg need for an external structure for each SSA register. 39 1.1 mrg 40 1.1 mrg Functions 41 1.1 mrg ========= 42 1.1 mrg 43 1.1 mrg Support for function calls is mostly similar to GLSL IR. Each shader contains a 44 1.1 mrg list of functions, and each function has a list of overloads. Each overload 45 1.1 mrg contains a list of parameters, and may contain an implementation which specifies 46 1.1 mrg the variables that correspond to the parameters and return value. Inlining a 47 1.1 mrg function, assuming it has a single return point, is as simple as copying its 48 1.1 mrg instructions, registers, and local variables into the target function and then 49 1.1 mrg inserting copies to and from the new parameters as appropriate. After functions 50 1.1 mrg are inlined and any non-subroutine functions are deleted, parameters and return 51 1.1 mrg variables will be converted to global variables and then global registers. We 52 1.1 mrg don't do this lowering earlier (i.e. the fortranizer idea) for a few reasons: 53 1.1 mrg 54 1.1 mrg - If we want to do optimizations before link time, we need to have the function 55 1.1 mrg signature available during link-time. 56 1.1 mrg 57 1.1 mrg - If we do any inlining before link time, then we might wind up with the 58 1.1 mrg inlined function and the non-inlined function using the same global 59 1.1 mrg variables/registers which would preclude optimization. 60 1.1 mrg 61 1.1 mrg Intrinsics 62 1.1 mrg ========= 63 1.1 mrg 64 1.1 mrg Any operation (other than function calls and textures) which touches a variable 65 1.1 mrg or is not referentially transparent is represented by an intrinsic. Intrinsics 66 1.1 mrg are similar to the idea of a "builtin function," i.e. a function declaration 67 1.1 mrg whose implementation is provided by the backend, except they are more powerful 68 1.1 mrg in the following ways: 69 1.1 mrg 70 1.1 mrg - They can also load and store registers when appropriate, which limits the 71 1.1 mrg number of variables needed in later stages of the IR while obviating the need 72 1.1 mrg for a separate load/store variable instruction. 73 1.1 mrg 74 1.1 mrg - Intrinsics can be marked as side-effect free, which permits them to be 75 1.1 mrg treated like any other instruction when it comes to optimizations. This allows 76 1.1 mrg load intrinsics to be represented as intrinsics while still being optimized 77 1.1 mrg away by dead code elimination, common subexpression elimination, etc. 78 1.1 mrg 79 1.1 mrg Intrinsics are used for: 80 1.1 mrg 81 1.1 mrg - Atomic operations 82 1.1 mrg - Memory barriers 83 1.1 mrg - Subroutine calls 84 1.1 mrg - Geometry shader emitVertex and endPrimitive 85 1.1 mrg - Loading and storing variables (before lowering) 86 1.1 mrg - Loading and storing uniforms, shader inputs and outputs, etc (after lowering) 87 1.1 mrg - Copying variables (cases where in GLSL the destination is a structure or 88 1.1 mrg array) 89 1.1 mrg - The kitchen sink 90 1.1 mrg - ... 91 1.1 mrg 92 1.1 mrg Textures 93 1.1 mrg ========= 94 1.1 mrg 95 1.1 mrg Unfortunately, there are far too many texture operations to represent each one 96 1.1 mrg of them with an intrinsic, so there's a special texture instruction similar to 97 1.1 mrg the GLSL IR one. The biggest difference is that, while the texture instruction 98 1.1 mrg has a sampler dereference field used just like in GLSL IR, this gets lowered to 99 1.1 mrg a texture unit index (with a possible indirect offset) while the type 100 1.1 mrg information of the original sampler is kept around for backends. Also, all the 101 1.1 mrg non-constant sources are stored in a single array to make it easier for 102 1.1 mrg optimization passes to iterate over all the sources. 103 1.1 mrg 104 1.1 mrg Control Flow 105 1.1 mrg ========= 106 1.1 mrg 107 1.1 mrg Like in GLSL IR, control flow consists of a tree of "control flow nodes", which 108 1.1 mrg include if statements and loops, and jump instructions (break, continue, and 109 1.1 mrg return). Unlike GLSL IR, though, the leaves of the tree aren't statements but 110 1.1 mrg basic blocks. Each basic block also keeps track of its successors and 111 1.1 mrg predecessors, and function implementations keep track of the beginning basic 112 1.1 mrg block (the first basic block of the function) and the ending basic block (a fake 113 1.1 mrg basic block that every return statement points to). Together, these elements 114 1.1 mrg make up the control flow graph, in this case a redundant piece of information on 115 1.1 mrg top of the control flow tree that will be used by almost all the optimizations. 116 1.1 mrg There are helper functions to add and remove control flow nodes that also update 117 1.1 mrg the control flow graph, and so usually it doesn't need to be touched by passes 118 1.1 mrg that modify control flow nodes. 119