diff options
author | Jason Ekstrand <[email protected]> | 2016-02-05 15:03:04 -0800 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2016-02-05 15:03:44 -0800 |
commit | 741744f691d6ef63e9f9a4c03136f969f2ffb0bf (patch) | |
tree | 7c9192a0648c2d90bb08efbc21ebcb7a6e2b873a /src/glsl/nir | |
parent | 9645b8eb1f1b79e537ad8ddb683507df7bc9da58 (diff) | |
parent | eb63640c1d38a200a7b1540405051d3ff79d0d8a (diff) |
Merge commit mesa-public/master into vulkan
This pulls in the patches that move all of the compiler stuff around
Diffstat (limited to 'src/glsl/nir')
96 files changed, 0 insertions, 37834 deletions
diff --git a/src/glsl/nir/.gitignore b/src/glsl/nir/.gitignore deleted file mode 100644 index 64828eba6d3..00000000000 --- a/src/glsl/nir/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -nir_builder_opcodes.h -nir_opt_algebraic.c -nir_opcodes.c -nir_opcodes.h -nir_constant_expressions.c diff --git a/src/glsl/nir/README b/src/glsl/nir/README deleted file mode 100644 index 2c81db9db61..00000000000 --- a/src/glsl/nir/README +++ /dev/null @@ -1,118 +0,0 @@ -New IR, or NIR, is an IR for Mesa intended to sit below GLSL IR and Mesa IR. -Its design inherits from the various IR's that Mesa has used in the past, as -well as Direct3D assembly, and it includes a few new ideas as well. It is a -flat (in terms of using instructions instead of expressions), typeless IR, -similar to TGSI and Mesa IR. It also supports SSA (although it doesn't require -it). - -Variables -========= - -NIR includes support for source-level GLSL variables through a structure mostly -copied from GLSL IR. These will be used for linking and conversion from GLSL IR -(and later, from an AST), but for the most part, they will be lowered to -registers (see below) and loads/stores. - -Registers -========= - -Registers are light-weight; they consist of a structure that only contains its -size, its index for liveness analysis, and an optional name for debugging. In -addition, registers can be local to a function or global to the entire shader; -the latter will be used in ARB_shader_subroutine for passing parameters and -getting return values from subroutines. Registers can also be an array, in which -case they can be accessed indirectly. Each ALU instruction (add, subtract, etc.) -works directly with registers or SSA values (see below). - -SSA -======== - -Everywhere a register can be loaded/stored, an SSA value can be used instead. -The only exception is that arrays/indirect addressing are not supported with -SSA; although research has been done on extensions of SSA to arrays before, it's -usually for the purpose of parallelization (which we're not interested in), and -adds some overhead in the form of adding copies or extra arrays (which is much -more expensive than introducing copies between non-array registers). SSA uses -point directly to their corresponding definition, which in turn points to the -instruction it is part of. This creates an implicit use-def chain and avoids the -need for an external structure for each SSA register. - -Functions -========= - -Support for function calls is mostly similar to GLSL IR. Each shader contains a -list of functions, and each function has a list of overloads. Each overload -contains a list of parameters, and may contain an implementation which specifies -the variables that correspond to the parameters and return value. Inlining a -function, assuming it has a single return point, is as simple as copying its -instructions, registers, and local variables into the target function and then -inserting copies to and from the new parameters as appropriate. After functions -are inlined and any non-subroutine functions are deleted, parameters and return -variables will be converted to global variables and then global registers. We -don't do this lowering earlier (i.e. the fortranizer idea) for a few reasons: - -- If we want to do optimizations before link time, we need to have the function -signature available during link-time. - -- If we do any inlining before link time, then we might wind up with the -inlined function and the non-inlined function using the same global -variables/registers which would preclude optimization. - -Intrinsics -========= - -Any operation (other than function calls and textures) which touches a variable -or is not referentially transparent is represented by an intrinsic. Intrinsics -are similar to the idea of a "builtin function," i.e. a function declaration -whose implementation is provided by the backend, except they are more powerful -in the following ways: - -- They can also load and store registers when appropriate, which limits the -number of variables needed in later stages of the IR while obviating the need -for a separate load/store variable instruction. - -- Intrinsics can be marked as side-effect free, which permits them to be -treated like any other instruction when it comes to optimizations. This allows -load intrinsics to be represented as intrinsics while still being optimized -away by dead code elimination, common subexpression elimination, etc. - -Intrinsics are used for: - -- Atomic operations -- Memory barriers -- Subroutine calls -- Geometry shader emitVertex and endPrimitive -- Loading and storing variables (before lowering) -- Loading and storing uniforms, shader inputs and outputs, etc (after lowering) -- Copying variables (cases where in GLSL the destination is a structure or -array) -- The kitchen sink -- ... - -Textures -========= - -Unfortunately, there are far too many texture operations to represent each one -of them with an intrinsic, so there's a special texture instruction similar to -the GLSL IR one. The biggest difference is that, while the texture instruction -has a sampler dereference field used just like in GLSL IR, this gets lowered to -a texture unit index (with a possible indirect offset) while the type -information of the original sampler is kept around for backends. Also, all the -non-constant sources are stored in a single array to make it easier for -optimization passes to iterate over all the sources. - -Control Flow -========= - -Like in GLSL IR, control flow consists of a tree of "control flow nodes", which -include if statements and loops, and jump instructions (break, continue, and -return). Unlike GLSL IR, though, the leaves of the tree aren't statements but -basic blocks. Each basic block also keeps track of its successors and -predecessors, and function implementations keep track of the beginning basic -block (the first basic block of the function) and the ending basic block (a fake -basic block that every return statement points to). Together, these elements -make up the control flow graph, in this case a redundant piece of information on -top of the control flow tree that will be used by almost all the optimizations. -There are helper functions to add and remove control flow nodes that also update -the control flow graph, and so usually it doesn't need to be touched by passes -that modify control flow nodes. diff --git a/src/glsl/nir/builtin_type_macros.h b/src/glsl/nir/builtin_type_macros.h deleted file mode 100644 index 7bd2e4e6558..00000000000 --- a/src/glsl/nir/builtin_type_macros.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright © 2013 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * \file builtin_type_macros.h - * - * This contains definitions for all GLSL built-in types, regardless of what - * language version or extension might provide them. - */ - -DECL_TYPE(error, GL_INVALID_ENUM, GLSL_TYPE_ERROR, 0, 0) -DECL_TYPE(void, GL_INVALID_ENUM, GLSL_TYPE_VOID, 0, 0) - -DECL_TYPE(bool, GL_BOOL, GLSL_TYPE_BOOL, 1, 1) -DECL_TYPE(bvec2, GL_BOOL_VEC2, GLSL_TYPE_BOOL, 2, 1) -DECL_TYPE(bvec3, GL_BOOL_VEC3, GLSL_TYPE_BOOL, 3, 1) -DECL_TYPE(bvec4, GL_BOOL_VEC4, GLSL_TYPE_BOOL, 4, 1) - -DECL_TYPE(int, GL_INT, GLSL_TYPE_INT, 1, 1) -DECL_TYPE(ivec2, GL_INT_VEC2, GLSL_TYPE_INT, 2, 1) -DECL_TYPE(ivec3, GL_INT_VEC3, GLSL_TYPE_INT, 3, 1) -DECL_TYPE(ivec4, GL_INT_VEC4, GLSL_TYPE_INT, 4, 1) - -DECL_TYPE(uint, GL_UNSIGNED_INT, GLSL_TYPE_UINT, 1, 1) -DECL_TYPE(uvec2, GL_UNSIGNED_INT_VEC2, GLSL_TYPE_UINT, 2, 1) -DECL_TYPE(uvec3, GL_UNSIGNED_INT_VEC3, GLSL_TYPE_UINT, 3, 1) -DECL_TYPE(uvec4, GL_UNSIGNED_INT_VEC4, GLSL_TYPE_UINT, 4, 1) - -DECL_TYPE(float, GL_FLOAT, GLSL_TYPE_FLOAT, 1, 1) -DECL_TYPE(vec2, GL_FLOAT_VEC2, GLSL_TYPE_FLOAT, 2, 1) -DECL_TYPE(vec3, GL_FLOAT_VEC3, GLSL_TYPE_FLOAT, 3, 1) -DECL_TYPE(vec4, GL_FLOAT_VEC4, GLSL_TYPE_FLOAT, 4, 1) - -DECL_TYPE(mat2, GL_FLOAT_MAT2, GLSL_TYPE_FLOAT, 2, 2) -DECL_TYPE(mat3, GL_FLOAT_MAT3, GLSL_TYPE_FLOAT, 3, 3) -DECL_TYPE(mat4, GL_FLOAT_MAT4, GLSL_TYPE_FLOAT, 4, 4) - -DECL_TYPE(mat2x3, GL_FLOAT_MAT2x3, GLSL_TYPE_FLOAT, 3, 2) -DECL_TYPE(mat2x4, GL_FLOAT_MAT2x4, GLSL_TYPE_FLOAT, 4, 2) -DECL_TYPE(mat3x2, GL_FLOAT_MAT3x2, GLSL_TYPE_FLOAT, 2, 3) -DECL_TYPE(mat3x4, GL_FLOAT_MAT3x4, GLSL_TYPE_FLOAT, 4, 3) -DECL_TYPE(mat4x2, GL_FLOAT_MAT4x2, GLSL_TYPE_FLOAT, 2, 4) -DECL_TYPE(mat4x3, GL_FLOAT_MAT4x3, GLSL_TYPE_FLOAT, 3, 4) - -DECL_TYPE(double, GL_DOUBLE, GLSL_TYPE_DOUBLE, 1, 1) -DECL_TYPE(dvec2, GL_DOUBLE_VEC2, GLSL_TYPE_DOUBLE, 2, 1) -DECL_TYPE(dvec3, GL_DOUBLE_VEC3, GLSL_TYPE_DOUBLE, 3, 1) -DECL_TYPE(dvec4, GL_DOUBLE_VEC4, GLSL_TYPE_DOUBLE, 4, 1) - -DECL_TYPE(dmat2, GL_DOUBLE_MAT2, GLSL_TYPE_DOUBLE, 2, 2) -DECL_TYPE(dmat3, GL_DOUBLE_MAT3, GLSL_TYPE_DOUBLE, 3, 3) -DECL_TYPE(dmat4, GL_DOUBLE_MAT4, GLSL_TYPE_DOUBLE, 4, 4) - -DECL_TYPE(dmat2x3, GL_DOUBLE_MAT2x3, GLSL_TYPE_DOUBLE, 3, 2) -DECL_TYPE(dmat2x4, GL_DOUBLE_MAT2x4, GLSL_TYPE_DOUBLE, 4, 2) -DECL_TYPE(dmat3x2, GL_DOUBLE_MAT3x2, GLSL_TYPE_DOUBLE, 2, 3) -DECL_TYPE(dmat3x4, GL_DOUBLE_MAT3x4, GLSL_TYPE_DOUBLE, 4, 3) -DECL_TYPE(dmat4x2, GL_DOUBLE_MAT4x2, GLSL_TYPE_DOUBLE, 2, 4) -DECL_TYPE(dmat4x3, GL_DOUBLE_MAT4x3, GLSL_TYPE_DOUBLE, 3, 4) - -DECL_TYPE(sampler1D, GL_SAMPLER_1D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2D, GL_SAMPLER_2D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler3D, GL_SAMPLER_3D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(samplerCube, GL_SAMPLER_CUBE, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler1DArray, GL_SAMPLER_1D_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DArray, GL_SAMPLER_2D_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(samplerCubeArray, GL_SAMPLER_CUBE_MAP_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DRect, GL_SAMPLER_2D_RECT, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(samplerBuffer, GL_SAMPLER_BUFFER, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DMS, GL_SAMPLER_2D_MULTISAMPLE, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_MS, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DMSArray, GL_SAMPLER_2D_MULTISAMPLE_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_MS, 0, 1, GLSL_TYPE_FLOAT) - -DECL_TYPE(isampler1D, GL_INT_SAMPLER_1D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isampler2D, GL_INT_SAMPLER_2D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isampler3D, GL_INT_SAMPLER_3D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isamplerCube, GL_INT_SAMPLER_CUBE, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isampler1DArray, GL_INT_SAMPLER_1D_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(isampler2DArray, GL_INT_SAMPLER_2D_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(isamplerCubeArray, GL_INT_SAMPLER_CUBE_MAP_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(isampler2DRect, GL_INT_SAMPLER_2D_RECT, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isamplerBuffer, GL_INT_SAMPLER_BUFFER, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isampler2DMS, GL_INT_SAMPLER_2D_MULTISAMPLE, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_MS, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(isampler2DMSArray, GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_MS, 0, 1, GLSL_TYPE_INT) - -DECL_TYPE(usampler1D, GL_UNSIGNED_INT_SAMPLER_1D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usampler2D, GL_UNSIGNED_INT_SAMPLER_2D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usampler3D, GL_UNSIGNED_INT_SAMPLER_3D, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usamplerCube, GL_UNSIGNED_INT_SAMPLER_CUBE, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usampler1DArray, GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_UINT) -DECL_TYPE(usampler2DArray, GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_UINT) -DECL_TYPE(usamplerCubeArray, GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 0, 1, GLSL_TYPE_UINT) -DECL_TYPE(usampler2DRect, GL_UNSIGNED_INT_SAMPLER_2D_RECT, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usamplerBuffer, GL_UNSIGNED_INT_SAMPLER_BUFFER, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usampler2DMS, GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_MS, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(usampler2DMSArray, GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_MS, 0, 1, GLSL_TYPE_UINT) - -DECL_TYPE(sampler1DShadow, GL_SAMPLER_1D_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 1, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DShadow, GL_SAMPLER_2D_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 1, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(samplerCubeShadow, GL_SAMPLER_CUBE_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 1, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler1DArrayShadow, GL_SAMPLER_1D_ARRAY_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_1D, 1, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DArrayShadow, GL_SAMPLER_2D_ARRAY_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_2D, 1, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(samplerCubeArrayShadow, GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_CUBE, 1, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(sampler2DRectShadow, GL_SAMPLER_2D_RECT_SHADOW, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_RECT, 1, 0, GLSL_TYPE_FLOAT) - -DECL_TYPE(samplerExternalOES, GL_SAMPLER_EXTERNAL_OES, GLSL_TYPE_SAMPLER, GLSL_SAMPLER_DIM_EXTERNAL, 0, 0, GLSL_TYPE_FLOAT) - -DECL_TYPE(image1D, GL_IMAGE_1D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(image2D, GL_IMAGE_2D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(image3D, GL_IMAGE_3D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(image2DRect, GL_IMAGE_2D_RECT, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(imageCube, GL_IMAGE_CUBE, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(imageBuffer, GL_IMAGE_BUFFER, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(image1DArray, GL_IMAGE_1D_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(image2DArray, GL_IMAGE_2D_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(imageCubeArray, GL_IMAGE_CUBE_MAP_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_CUBE, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(image2DMS, GL_IMAGE_2D_MULTISAMPLE, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_MS, 0, 0, GLSL_TYPE_FLOAT) -DECL_TYPE(image2DMSArray, GL_IMAGE_2D_MULTISAMPLE_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_MS, 0, 1, GLSL_TYPE_FLOAT) -DECL_TYPE(iimage1D, GL_INT_IMAGE_1D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimage2D, GL_INT_IMAGE_2D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimage3D, GL_INT_IMAGE_3D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimage2DRect, GL_INT_IMAGE_2D_RECT, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimageCube, GL_INT_IMAGE_CUBE, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimageBuffer, GL_INT_IMAGE_BUFFER, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimage1DArray, GL_INT_IMAGE_1D_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(iimage2DArray, GL_INT_IMAGE_2D_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(iimageCubeArray, GL_INT_IMAGE_CUBE_MAP_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_CUBE, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(iimage2DMS, GL_INT_IMAGE_2D_MULTISAMPLE, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_MS, 0, 0, GLSL_TYPE_INT) -DECL_TYPE(iimage2DMSArray, GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_MS, 0, 1, GLSL_TYPE_INT) -DECL_TYPE(uimage1D, GL_UNSIGNED_INT_IMAGE_1D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_1D, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimage2D, GL_UNSIGNED_INT_IMAGE_2D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_2D, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimage3D, GL_UNSIGNED_INT_IMAGE_3D, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_3D, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimage2DRect, GL_UNSIGNED_INT_IMAGE_2D_RECT, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_RECT, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimageCube, GL_UNSIGNED_INT_IMAGE_CUBE, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_CUBE, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimageBuffer, GL_UNSIGNED_INT_IMAGE_BUFFER, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_BUF, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimage1DArray, GL_UNSIGNED_INT_IMAGE_1D_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_1D, 0, 1, GLSL_TYPE_UINT) -DECL_TYPE(uimage2DArray, GL_UNSIGNED_INT_IMAGE_2D_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_2D, 0, 1, GLSL_TYPE_UINT) -DECL_TYPE(uimageCubeArray, GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_CUBE, 0, 1, GLSL_TYPE_UINT) -DECL_TYPE(uimage2DMS, GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_MS, 0, 0, GLSL_TYPE_UINT) -DECL_TYPE(uimage2DMSArray, GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY, GLSL_TYPE_IMAGE, GLSL_SAMPLER_DIM_MS, 0, 1, GLSL_TYPE_UINT) - -DECL_TYPE(atomic_uint, GL_UNSIGNED_INT_ATOMIC_COUNTER, GLSL_TYPE_ATOMIC_UINT, 1, 1) - -STRUCT_TYPE(gl_DepthRangeParameters) -STRUCT_TYPE(gl_PointParameters) -STRUCT_TYPE(gl_MaterialParameters) -STRUCT_TYPE(gl_LightSourceParameters) -STRUCT_TYPE(gl_LightModelParameters) -STRUCT_TYPE(gl_LightModelProducts) -STRUCT_TYPE(gl_LightProducts) -STRUCT_TYPE(gl_FogParameters) diff --git a/src/glsl/nir/glsl_to_nir.cpp b/src/glsl/nir/glsl_to_nir.cpp deleted file mode 100644 index f29377cc260..00000000000 --- a/src/glsl/nir/glsl_to_nir.cpp +++ /dev/null @@ -1,2035 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "glsl_to_nir.h" -#include "nir_control_flow.h" -#include "nir_builder.h" -#include "ir_visitor.h" -#include "ir_hierarchical_visitor.h" -#include "ir.h" -#include "main/imports.h" - -/* - * pass to lower GLSL IR to NIR - * - * This will lower variable dereferences to loads/stores of corresponding - * variables in NIR - the variables will be converted to registers in a later - * pass. - */ - -namespace { - -class nir_visitor : public ir_visitor -{ -public: - nir_visitor(nir_shader *shader, gl_shader *sh); - ~nir_visitor(); - - virtual void visit(ir_variable *); - virtual void visit(ir_function *); - virtual void visit(ir_function_signature *); - virtual void visit(ir_loop *); - virtual void visit(ir_if *); - virtual void visit(ir_discard *); - virtual void visit(ir_loop_jump *); - virtual void visit(ir_return *); - virtual void visit(ir_call *); - virtual void visit(ir_assignment *); - virtual void visit(ir_emit_vertex *); - virtual void visit(ir_end_primitive *); - virtual void visit(ir_expression *); - virtual void visit(ir_swizzle *); - virtual void visit(ir_texture *); - virtual void visit(ir_constant *); - virtual void visit(ir_dereference_variable *); - virtual void visit(ir_dereference_record *); - virtual void visit(ir_dereference_array *); - virtual void visit(ir_barrier *); - - void create_function(ir_function_signature *ir); - -private: - void add_instr(nir_instr *instr, unsigned num_components); - nir_ssa_def *evaluate_rvalue(ir_rvalue *ir); - - nir_alu_instr *emit(nir_op op, unsigned dest_size, nir_ssa_def **srcs); - nir_alu_instr *emit(nir_op op, unsigned dest_size, nir_ssa_def *src1); - nir_alu_instr *emit(nir_op op, unsigned dest_size, nir_ssa_def *src1, - nir_ssa_def *src2); - nir_alu_instr *emit(nir_op op, unsigned dest_size, nir_ssa_def *src1, - nir_ssa_def *src2, nir_ssa_def *src3); - - bool supports_ints; - - struct gl_shader *sh; - - nir_shader *shader; - nir_function_impl *impl; - nir_builder b; - nir_ssa_def *result; /* result of the expression tree last visited */ - - nir_deref_var *evaluate_deref(nir_instr *mem_ctx, ir_instruction *ir); - - /* the head of the dereference chain we're creating */ - nir_deref_var *deref_head; - /* the tail of the dereference chain we're creating */ - nir_deref *deref_tail; - - nir_variable *var; /* variable created by ir_variable visitor */ - - /* whether the IR we're operating on is per-function or global */ - bool is_global; - - /* map of ir_variable -> nir_variable */ - struct hash_table *var_table; - - /* map of ir_function_signature -> nir_function_overload */ - struct hash_table *overload_table; -}; - -/* - * This visitor runs before the main visitor, calling create_function() for - * each function so that the main visitor can resolve forward references in - * calls. - */ - -class nir_function_visitor : public ir_hierarchical_visitor -{ -public: - nir_function_visitor(nir_visitor *v) : visitor(v) - { - } - virtual ir_visitor_status visit_enter(ir_function *); - -private: - nir_visitor *visitor; -}; - -}; /* end of anonymous namespace */ - -nir_shader * -glsl_to_nir(const struct gl_shader_program *shader_prog, - gl_shader_stage stage, - const nir_shader_compiler_options *options) -{ - struct gl_shader *sh = shader_prog->_LinkedShaders[stage]; - - nir_shader *shader = nir_shader_create(NULL, stage, options); - - nir_visitor v1(shader, sh); - nir_function_visitor v2(&v1); - v2.run(sh->ir); - visit_exec_list(sh->ir, &v1); - - nir_function *main = NULL; - nir_foreach_function(shader, func) { - if (strcmp(func->name, "main") == 0) { - main = func; - break; - } - } - assert(main); - - nir_lower_outputs_to_temporaries(shader, main); - - shader->info.name = ralloc_asprintf(shader, "GLSL%d", shader_prog->Name); - if (shader_prog->Label) - shader->info.label = ralloc_strdup(shader, shader_prog->Label); - shader->info.num_textures = _mesa_fls(sh->Program->SamplersUsed); - shader->info.num_ubos = sh->NumUniformBlocks; - shader->info.num_abos = shader_prog->NumAtomicBuffers; - shader->info.num_ssbos = sh->NumShaderStorageBlocks; - shader->info.num_images = sh->NumImages; - shader->info.inputs_read = sh->Program->InputsRead; - shader->info.outputs_written = sh->Program->OutputsWritten; - shader->info.patch_inputs_read = sh->Program->PatchInputsRead; - shader->info.patch_outputs_written = sh->Program->PatchOutputsWritten; - shader->info.system_values_read = sh->Program->SystemValuesRead; - shader->info.uses_texture_gather = sh->Program->UsesGather; - shader->info.uses_clip_distance_out = - sh->Program->ClipDistanceArraySize != 0; - shader->info.separate_shader = shader_prog->SeparateShader; - shader->info.has_transform_feedback_varyings = - shader_prog->TransformFeedback.NumVarying > 0; - - switch (stage) { - case MESA_SHADER_TESS_CTRL: - shader->info.tcs.vertices_out = shader_prog->TessCtrl.VerticesOut; - break; - - case MESA_SHADER_GEOMETRY: - shader->info.gs.vertices_in = shader_prog->Geom.VerticesIn; - shader->info.gs.output_primitive = sh->Geom.OutputType; - shader->info.gs.vertices_out = sh->Geom.VerticesOut; - shader->info.gs.invocations = sh->Geom.Invocations; - shader->info.gs.uses_end_primitive = shader_prog->Geom.UsesEndPrimitive; - shader->info.gs.uses_streams = shader_prog->Geom.UsesStreams; - break; - - case MESA_SHADER_FRAGMENT: { - struct gl_fragment_program *fp = - (struct gl_fragment_program *)sh->Program; - - shader->info.fs.uses_discard = fp->UsesKill; - shader->info.fs.early_fragment_tests = sh->EarlyFragmentTests; - shader->info.fs.depth_layout = fp->FragDepthLayout; - break; - } - - case MESA_SHADER_COMPUTE: { - struct gl_compute_program *cp = (struct gl_compute_program *)sh->Program; - shader->info.cs.local_size[0] = cp->LocalSize[0]; - shader->info.cs.local_size[1] = cp->LocalSize[1]; - shader->info.cs.local_size[2] = cp->LocalSize[2]; - break; - } - - default: - break; /* No stage-specific info */ - } - - return shader; -} - -nir_visitor::nir_visitor(nir_shader *shader, gl_shader *sh) -{ - this->supports_ints = shader->options->native_integers; - this->shader = shader; - this->sh = sh; - this->is_global = true; - this->var_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - this->overload_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); -} - -nir_visitor::~nir_visitor() -{ - _mesa_hash_table_destroy(this->var_table, NULL); - _mesa_hash_table_destroy(this->overload_table, NULL); -} - -nir_deref_var * -nir_visitor::evaluate_deref(nir_instr *mem_ctx, ir_instruction *ir) -{ - ir->accept(this); - ralloc_steal(mem_ctx, this->deref_head); - return this->deref_head; -} - -static nir_constant * -constant_copy(ir_constant *ir, void *mem_ctx) -{ - if (ir == NULL) - return NULL; - - nir_constant *ret = ralloc(mem_ctx, nir_constant); - - unsigned total_elems = ir->type->components(); - unsigned i; - - ret->num_elements = 0; - switch (ir->type->base_type) { - case GLSL_TYPE_UINT: - for (i = 0; i < total_elems; i++) - ret->value.u[i] = ir->value.u[i]; - break; - - case GLSL_TYPE_INT: - for (i = 0; i < total_elems; i++) - ret->value.i[i] = ir->value.i[i]; - break; - - case GLSL_TYPE_FLOAT: - for (i = 0; i < total_elems; i++) - ret->value.f[i] = ir->value.f[i]; - break; - - case GLSL_TYPE_BOOL: - for (i = 0; i < total_elems; i++) - ret->value.b[i] = ir->value.b[i]; - break; - - case GLSL_TYPE_STRUCT: - ret->elements = ralloc_array(mem_ctx, nir_constant *, - ir->type->length); - ret->num_elements = ir->type->length; - - i = 0; - foreach_in_list(ir_constant, field, &ir->components) { - ret->elements[i] = constant_copy(field, mem_ctx); - i++; - } - break; - - case GLSL_TYPE_ARRAY: - ret->elements = ralloc_array(mem_ctx, nir_constant *, - ir->type->length); - ret->num_elements = ir->type->length; - - for (i = 0; i < ir->type->length; i++) - ret->elements[i] = constant_copy(ir->array_elements[i], mem_ctx); - break; - - default: - unreachable("not reached"); - } - - return ret; -} - -void -nir_visitor::visit(ir_variable *ir) -{ - nir_variable *var = ralloc(shader, nir_variable); - var->type = ir->type; - var->name = ralloc_strdup(var, ir->name); - - var->data.read_only = ir->data.read_only; - var->data.centroid = ir->data.centroid; - var->data.sample = ir->data.sample; - var->data.patch = ir->data.patch; - var->data.invariant = ir->data.invariant; - var->data.location = ir->data.location; - - switch(ir->data.mode) { - case ir_var_auto: - case ir_var_temporary: - if (is_global) - var->data.mode = nir_var_global; - else - var->data.mode = nir_var_local; - break; - - case ir_var_function_in: - case ir_var_function_out: - case ir_var_function_inout: - case ir_var_const_in: - var->data.mode = nir_var_local; - break; - - case ir_var_shader_in: - if (shader->stage == MESA_SHADER_FRAGMENT && - ir->data.location == VARYING_SLOT_FACE) { - /* For whatever reason, GLSL IR makes gl_FrontFacing an input */ - var->data.location = SYSTEM_VALUE_FRONT_FACE; - var->data.mode = nir_var_system_value; - } else if (shader->stage == MESA_SHADER_GEOMETRY && - ir->data.location == VARYING_SLOT_PRIMITIVE_ID) { - /* For whatever reason, GLSL IR makes gl_PrimitiveIDIn an input */ - var->data.location = SYSTEM_VALUE_PRIMITIVE_ID; - var->data.mode = nir_var_system_value; - } else { - var->data.mode = nir_var_shader_in; - } - break; - - case ir_var_shader_out: - var->data.mode = nir_var_shader_out; - break; - - case ir_var_uniform: - var->data.mode = nir_var_uniform; - break; - - case ir_var_shader_storage: - var->data.mode = nir_var_shader_storage; - break; - - case ir_var_system_value: - var->data.mode = nir_var_system_value; - break; - - default: - unreachable("not reached"); - } - - var->data.interpolation = ir->data.interpolation; - var->data.origin_upper_left = ir->data.origin_upper_left; - var->data.pixel_center_integer = ir->data.pixel_center_integer; - var->data.explicit_location = ir->data.explicit_location; - var->data.explicit_index = ir->data.explicit_index; - var->data.explicit_binding = ir->data.explicit_binding; - var->data.has_initializer = ir->data.has_initializer; - var->data.location_frac = ir->data.location_frac; - var->data.from_named_ifc_block_array = ir->data.from_named_ifc_block_array; - var->data.from_named_ifc_block_nonarray = ir->data.from_named_ifc_block_nonarray; - - switch (ir->data.depth_layout) { - case ir_depth_layout_none: - var->data.depth_layout = nir_depth_layout_none; - break; - case ir_depth_layout_any: - var->data.depth_layout = nir_depth_layout_any; - break; - case ir_depth_layout_greater: - var->data.depth_layout = nir_depth_layout_greater; - break; - case ir_depth_layout_less: - var->data.depth_layout = nir_depth_layout_less; - break; - case ir_depth_layout_unchanged: - var->data.depth_layout = nir_depth_layout_unchanged; - break; - default: - unreachable("not reached"); - } - - var->data.index = ir->data.index; - var->data.descriptor_set = 0; - var->data.binding = ir->data.binding; - var->data.offset = ir->data.offset; - var->data.image.read_only = ir->data.image_read_only; - var->data.image.write_only = ir->data.image_write_only; - var->data.image.coherent = ir->data.image_coherent; - var->data.image._volatile = ir->data.image_volatile; - var->data.image.restrict_flag = ir->data.image_restrict; - var->data.image.format = ir->data.image_format; - var->data.max_array_access = ir->data.max_array_access; - - var->num_state_slots = ir->get_num_state_slots(); - if (var->num_state_slots > 0) { - var->state_slots = ralloc_array(var, nir_state_slot, - var->num_state_slots); - - ir_state_slot *state_slots = ir->get_state_slots(); - for (unsigned i = 0; i < var->num_state_slots; i++) { - for (unsigned j = 0; j < 5; j++) - var->state_slots[i].tokens[j] = state_slots[i].tokens[j]; - var->state_slots[i].swizzle = state_slots[i].swizzle; - } - } else { - var->state_slots = NULL; - } - - var->constant_initializer = constant_copy(ir->constant_initializer, var); - - var->interface_type = ir->get_interface_type(); - - if (var->data.mode == nir_var_local) - nir_function_impl_add_variable(impl, var); - else - nir_shader_add_variable(shader, var); - - _mesa_hash_table_insert(var_table, ir, var); - this->var = var; -} - -ir_visitor_status -nir_function_visitor::visit_enter(ir_function *ir) -{ - foreach_in_list(ir_function_signature, sig, &ir->signatures) { - visitor->create_function(sig); - } - return visit_continue_with_parent; -} - -void -nir_visitor::create_function(ir_function_signature *ir) -{ - if (ir->is_intrinsic) - return; - - nir_function *func = nir_function_create(shader, ir->function_name()); - - unsigned num_params = ir->parameters.length(); - func->num_params = num_params; - func->params = ralloc_array(shader, nir_parameter, num_params); - - unsigned i = 0; - foreach_in_list(ir_variable, param, &ir->parameters) { - switch (param->data.mode) { - case ir_var_function_in: - func->params[i].param_type = nir_parameter_in; - break; - - case ir_var_function_out: - func->params[i].param_type = nir_parameter_out; - break; - - case ir_var_function_inout: - func->params[i].param_type = nir_parameter_inout; - break; - - default: - unreachable("not reached"); - } - - func->params[i].type = param->type; - i++; - } - - func->return_type = ir->return_type; - - _mesa_hash_table_insert(this->overload_table, ir, func); -} - -void -nir_visitor::visit(ir_function *ir) -{ - foreach_in_list(ir_function_signature, sig, &ir->signatures) - sig->accept(this); -} - -void -nir_visitor::visit(ir_function_signature *ir) -{ - if (ir->is_intrinsic) - return; - - struct hash_entry *entry = - _mesa_hash_table_search(this->overload_table, ir); - - assert(entry); - nir_function *func = (nir_function *) entry->data; - - if (ir->is_defined) { - nir_function_impl *impl = nir_function_impl_create(func); - this->impl = impl; - - unsigned num_params = func->num_params; - impl->num_params = num_params; - impl->params = ralloc_array(this->shader, nir_variable *, num_params); - unsigned i = 0; - foreach_in_list(ir_variable, param, &ir->parameters) { - param->accept(this); - impl->params[i] = this->var; - i++; - } - - if (func->return_type == glsl_type::void_type) { - impl->return_var = NULL; - } else { - impl->return_var = ralloc(this->shader, nir_variable); - impl->return_var->name = ralloc_strdup(impl->return_var, - "return_var"); - impl->return_var->type = func->return_type; - } - - this->is_global = false; - - nir_builder_init(&b, impl); - b.cursor = nir_after_cf_list(&impl->body); - visit_exec_list(&ir->body, this); - - this->is_global = true; - } else { - func->impl = NULL; - } -} - -void -nir_visitor::visit(ir_loop *ir) -{ - nir_loop *loop = nir_loop_create(this->shader); - nir_builder_cf_insert(&b, &loop->cf_node); - - b.cursor = nir_after_cf_list(&loop->body); - visit_exec_list(&ir->body_instructions, this); - b.cursor = nir_after_cf_node(&loop->cf_node); -} - -void -nir_visitor::visit(ir_if *ir) -{ - nir_src condition = - nir_src_for_ssa(evaluate_rvalue(ir->condition)); - - nir_if *if_stmt = nir_if_create(this->shader); - if_stmt->condition = condition; - nir_builder_cf_insert(&b, &if_stmt->cf_node); - - b.cursor = nir_after_cf_list(&if_stmt->then_list); - visit_exec_list(&ir->then_instructions, this); - - b.cursor = nir_after_cf_list(&if_stmt->else_list); - visit_exec_list(&ir->else_instructions, this); - - b.cursor = nir_after_cf_node(&if_stmt->cf_node); -} - -void -nir_visitor::visit(ir_discard *ir) -{ - /* - * discards aren't treated as control flow, because before we lower them - * they can appear anywhere in the shader and the stuff after them may still - * be executed (yay, crazy GLSL rules!). However, after lowering, all the - * discards will be immediately followed by a return. - */ - - nir_intrinsic_instr *discard; - if (ir->condition) { - discard = nir_intrinsic_instr_create(this->shader, - nir_intrinsic_discard_if); - discard->src[0] = - nir_src_for_ssa(evaluate_rvalue(ir->condition)); - } else { - discard = nir_intrinsic_instr_create(this->shader, nir_intrinsic_discard); - } - - nir_builder_instr_insert(&b, &discard->instr); -} - -void -nir_visitor::visit(ir_emit_vertex *ir) -{ - nir_intrinsic_instr *instr = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_emit_vertex); - instr->const_index[0] = ir->stream_id(); - nir_builder_instr_insert(&b, &instr->instr); -} - -void -nir_visitor::visit(ir_end_primitive *ir) -{ - nir_intrinsic_instr *instr = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_end_primitive); - instr->const_index[0] = ir->stream_id(); - nir_builder_instr_insert(&b, &instr->instr); -} - -void -nir_visitor::visit(ir_loop_jump *ir) -{ - nir_jump_type type; - switch (ir->mode) { - case ir_loop_jump::jump_break: - type = nir_jump_break; - break; - case ir_loop_jump::jump_continue: - type = nir_jump_continue; - break; - default: - unreachable("not reached"); - } - - nir_jump_instr *instr = nir_jump_instr_create(this->shader, type); - nir_builder_instr_insert(&b, &instr->instr); -} - -void -nir_visitor::visit(ir_return *ir) -{ - if (ir->value != NULL) { - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_copy_var); - - copy->variables[0] = nir_deref_var_create(copy, this->impl->return_var); - copy->variables[1] = evaluate_deref(©->instr, ir->value); - } - - nir_jump_instr *instr = nir_jump_instr_create(this->shader, nir_jump_return); - nir_builder_instr_insert(&b, &instr->instr); -} - -void -nir_visitor::visit(ir_call *ir) -{ - if (ir->callee->is_intrinsic) { - nir_intrinsic_op op; - if (strcmp(ir->callee_name(), "__intrinsic_atomic_read") == 0) { - op = nir_intrinsic_atomic_counter_read_var; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_increment") == 0) { - op = nir_intrinsic_atomic_counter_inc_var; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_predecrement") == 0) { - op = nir_intrinsic_atomic_counter_dec_var; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_load") == 0) { - op = nir_intrinsic_image_load; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_store") == 0) { - op = nir_intrinsic_image_store; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_add") == 0) { - op = nir_intrinsic_image_atomic_add; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_min") == 0) { - op = nir_intrinsic_image_atomic_min; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_max") == 0) { - op = nir_intrinsic_image_atomic_max; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_and") == 0) { - op = nir_intrinsic_image_atomic_and; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_or") == 0) { - op = nir_intrinsic_image_atomic_or; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_xor") == 0) { - op = nir_intrinsic_image_atomic_xor; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_exchange") == 0) { - op = nir_intrinsic_image_atomic_exchange; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_comp_swap") == 0) { - op = nir_intrinsic_image_atomic_comp_swap; - } else if (strcmp(ir->callee_name(), "__intrinsic_memory_barrier") == 0) { - op = nir_intrinsic_memory_barrier; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_size") == 0) { - op = nir_intrinsic_image_size; - } else if (strcmp(ir->callee_name(), "__intrinsic_image_samples") == 0) { - op = nir_intrinsic_image_samples; - } else if (strcmp(ir->callee_name(), "__intrinsic_store_ssbo") == 0) { - op = nir_intrinsic_store_ssbo; - } else if (strcmp(ir->callee_name(), "__intrinsic_load_ssbo") == 0) { - op = nir_intrinsic_load_ssbo; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_add_ssbo") == 0) { - op = nir_intrinsic_ssbo_atomic_add; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_and_ssbo") == 0) { - op = nir_intrinsic_ssbo_atomic_and; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_or_ssbo") == 0) { - op = nir_intrinsic_ssbo_atomic_or; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_xor_ssbo") == 0) { - op = nir_intrinsic_ssbo_atomic_xor; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_min_ssbo") == 0) { - assert(ir->return_deref); - if (ir->return_deref->type == glsl_type::int_type) - op = nir_intrinsic_ssbo_atomic_imin; - else if (ir->return_deref->type == glsl_type::uint_type) - op = nir_intrinsic_ssbo_atomic_umin; - else - unreachable("Invalid type"); - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_max_ssbo") == 0) { - assert(ir->return_deref); - if (ir->return_deref->type == glsl_type::int_type) - op = nir_intrinsic_ssbo_atomic_imax; - else if (ir->return_deref->type == glsl_type::uint_type) - op = nir_intrinsic_ssbo_atomic_umax; - else - unreachable("Invalid type"); - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_exchange_ssbo") == 0) { - op = nir_intrinsic_ssbo_atomic_exchange; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_comp_swap_ssbo") == 0) { - op = nir_intrinsic_ssbo_atomic_comp_swap; - } else if (strcmp(ir->callee_name(), "__intrinsic_shader_clock") == 0) { - op = nir_intrinsic_shader_clock; - } else if (strcmp(ir->callee_name(), "__intrinsic_group_memory_barrier") == 0) { - op = nir_intrinsic_group_memory_barrier; - } else if (strcmp(ir->callee_name(), "__intrinsic_memory_barrier_atomic_counter") == 0) { - op = nir_intrinsic_memory_barrier_atomic_counter; - } else if (strcmp(ir->callee_name(), "__intrinsic_memory_barrier_buffer") == 0) { - op = nir_intrinsic_memory_barrier_buffer; - } else if (strcmp(ir->callee_name(), "__intrinsic_memory_barrier_image") == 0) { - op = nir_intrinsic_memory_barrier_image; - } else if (strcmp(ir->callee_name(), "__intrinsic_memory_barrier_shared") == 0) { - op = nir_intrinsic_memory_barrier_shared; - } else if (strcmp(ir->callee_name(), "__intrinsic_load_shared") == 0) { - op = nir_intrinsic_load_shared; - } else if (strcmp(ir->callee_name(), "__intrinsic_store_shared") == 0) { - op = nir_intrinsic_store_shared; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_add_shared") == 0) { - op = nir_intrinsic_shared_atomic_add; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_and_shared") == 0) { - op = nir_intrinsic_shared_atomic_and; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_or_shared") == 0) { - op = nir_intrinsic_shared_atomic_or; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_xor_shared") == 0) { - op = nir_intrinsic_shared_atomic_xor; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_min_shared") == 0) { - assert(ir->return_deref); - if (ir->return_deref->type == glsl_type::int_type) - op = nir_intrinsic_shared_atomic_imin; - else if (ir->return_deref->type == glsl_type::uint_type) - op = nir_intrinsic_shared_atomic_umin; - else - unreachable("Invalid type"); - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_max_shared") == 0) { - assert(ir->return_deref); - if (ir->return_deref->type == glsl_type::int_type) - op = nir_intrinsic_shared_atomic_imax; - else if (ir->return_deref->type == glsl_type::uint_type) - op = nir_intrinsic_shared_atomic_umax; - else - unreachable("Invalid type"); - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_exchange_shared") == 0) { - op = nir_intrinsic_shared_atomic_exchange; - } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_comp_swap_shared") == 0) { - op = nir_intrinsic_shared_atomic_comp_swap; - } else { - unreachable("not reached"); - } - - nir_intrinsic_instr *instr = nir_intrinsic_instr_create(shader, op); - nir_dest *dest = &instr->dest; - - switch (op) { - case nir_intrinsic_atomic_counter_read_var: - case nir_intrinsic_atomic_counter_inc_var: - case nir_intrinsic_atomic_counter_dec_var: { - ir_dereference *param = - (ir_dereference *) ir->actual_parameters.get_head(); - instr->variables[0] = evaluate_deref(&instr->instr, param); - nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL); - nir_builder_instr_insert(&b, &instr->instr); - break; - } - case nir_intrinsic_image_load: - case nir_intrinsic_image_store: - case nir_intrinsic_image_atomic_add: - case nir_intrinsic_image_atomic_min: - case nir_intrinsic_image_atomic_max: - case nir_intrinsic_image_atomic_and: - case nir_intrinsic_image_atomic_or: - case nir_intrinsic_image_atomic_xor: - case nir_intrinsic_image_atomic_exchange: - case nir_intrinsic_image_atomic_comp_swap: - case nir_intrinsic_image_samples: - case nir_intrinsic_image_size: { - nir_ssa_undef_instr *instr_undef = - nir_ssa_undef_instr_create(shader, 1); - nir_builder_instr_insert(&b, &instr_undef->instr); - - /* Set the image variable dereference. */ - exec_node *param = ir->actual_parameters.get_head(); - ir_dereference *image = (ir_dereference *)param; - const glsl_type *type = - image->variable_referenced()->type->without_array(); - - instr->variables[0] = evaluate_deref(&instr->instr, image); - param = param->get_next(); - - /* Set the intrinsic destination. */ - if (ir->return_deref) { - const nir_intrinsic_info *info = - &nir_intrinsic_infos[instr->intrinsic]; - nir_ssa_dest_init(&instr->instr, &instr->dest, - info->dest_components, NULL); - } - - if (op == nir_intrinsic_image_size || - op == nir_intrinsic_image_samples) { - nir_builder_instr_insert(&b, &instr->instr); - break; - } - - /* Set the address argument, extending the coordinate vector to four - * components. - */ - nir_ssa_def *src_addr = - evaluate_rvalue((ir_dereference *)param); - nir_ssa_def *srcs[4]; - - for (int i = 0; i < 4; i++) { - if (i < type->coordinate_components()) - srcs[i] = nir_channel(&b, src_addr, i); - else - srcs[i] = &instr_undef->def; - } - - instr->src[0] = nir_src_for_ssa(nir_vec(&b, srcs, 4)); - param = param->get_next(); - - /* Set the sample argument, which is undefined for single-sample - * images. - */ - if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_MS) { - instr->src[1] = - nir_src_for_ssa(evaluate_rvalue((ir_dereference *)param)); - param = param->get_next(); - } else { - instr->src[1] = nir_src_for_ssa(&instr_undef->def); - } - - /* Set the intrinsic parameters. */ - if (!param->is_tail_sentinel()) { - instr->src[2] = - nir_src_for_ssa(evaluate_rvalue((ir_dereference *)param)); - param = param->get_next(); - } - - if (!param->is_tail_sentinel()) { - instr->src[3] = - nir_src_for_ssa(evaluate_rvalue((ir_dereference *)param)); - param = param->get_next(); - } - nir_builder_instr_insert(&b, &instr->instr); - break; - } - case nir_intrinsic_memory_barrier: - case nir_intrinsic_group_memory_barrier: - case nir_intrinsic_memory_barrier_atomic_counter: - case nir_intrinsic_memory_barrier_buffer: - case nir_intrinsic_memory_barrier_image: - case nir_intrinsic_memory_barrier_shared: - nir_builder_instr_insert(&b, &instr->instr); - break; - case nir_intrinsic_shader_clock: - nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL); - nir_builder_instr_insert(&b, &instr->instr); - break; - case nir_intrinsic_store_ssbo: { - exec_node *param = ir->actual_parameters.get_head(); - ir_rvalue *block = ((ir_instruction *)param)->as_rvalue(); - - param = param->get_next(); - ir_rvalue *offset = ((ir_instruction *)param)->as_rvalue(); - - param = param->get_next(); - ir_rvalue *val = ((ir_instruction *)param)->as_rvalue(); - - param = param->get_next(); - ir_constant *write_mask = ((ir_instruction *)param)->as_constant(); - assert(write_mask); - - instr->src[0] = nir_src_for_ssa(evaluate_rvalue(val)); - instr->src[1] = nir_src_for_ssa(evaluate_rvalue(block)); - instr->src[2] = nir_src_for_ssa(evaluate_rvalue(offset)); - instr->const_index[0] = write_mask->value.u[0]; - instr->num_components = val->type->vector_elements; - - nir_builder_instr_insert(&b, &instr->instr); - break; - } - case nir_intrinsic_load_ssbo: { - exec_node *param = ir->actual_parameters.get_head(); - ir_rvalue *block = ((ir_instruction *)param)->as_rvalue(); - - param = param->get_next(); - ir_rvalue *offset = ((ir_instruction *)param)->as_rvalue(); - - instr->src[0] = nir_src_for_ssa(evaluate_rvalue(block)); - instr->src[1] = nir_src_for_ssa(evaluate_rvalue(offset)); - - const glsl_type *type = ir->return_deref->var->type; - instr->num_components = type->vector_elements; - - /* Setup destination register */ - nir_ssa_dest_init(&instr->instr, &instr->dest, - type->vector_elements, NULL); - - /* Insert the created nir instruction now since in the case of boolean - * result we will need to emit another instruction after it - */ - nir_builder_instr_insert(&b, &instr->instr); - - /* - * In SSBO/UBO's, a true boolean value is any non-zero value, but we - * consider a true boolean to be ~0. Fix this up with a != 0 - * comparison. - */ - if (type->base_type == GLSL_TYPE_BOOL) { - nir_alu_instr *load_ssbo_compare = - nir_alu_instr_create(shader, nir_op_ine); - load_ssbo_compare->src[0].src.is_ssa = true; - load_ssbo_compare->src[0].src.ssa = &instr->dest.ssa; - load_ssbo_compare->src[1].src = - nir_src_for_ssa(nir_imm_int(&b, 0)); - for (unsigned i = 0; i < type->vector_elements; i++) - load_ssbo_compare->src[1].swizzle[i] = 0; - nir_ssa_dest_init(&load_ssbo_compare->instr, - &load_ssbo_compare->dest.dest, - type->vector_elements, NULL); - load_ssbo_compare->dest.write_mask = (1 << type->vector_elements) - 1; - nir_builder_instr_insert(&b, &load_ssbo_compare->instr); - dest = &load_ssbo_compare->dest.dest; - } - break; - } - case nir_intrinsic_ssbo_atomic_add: - case nir_intrinsic_ssbo_atomic_imin: - case nir_intrinsic_ssbo_atomic_umin: - case nir_intrinsic_ssbo_atomic_imax: - case nir_intrinsic_ssbo_atomic_umax: - case nir_intrinsic_ssbo_atomic_and: - case nir_intrinsic_ssbo_atomic_or: - case nir_intrinsic_ssbo_atomic_xor: - case nir_intrinsic_ssbo_atomic_exchange: - case nir_intrinsic_ssbo_atomic_comp_swap: { - int param_count = ir->actual_parameters.length(); - assert(param_count == 3 || param_count == 4); - - /* Block index */ - exec_node *param = ir->actual_parameters.get_head(); - ir_instruction *inst = (ir_instruction *) param; - instr->src[0] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - - /* Offset */ - param = param->get_next(); - inst = (ir_instruction *) param; - instr->src[1] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - - /* data1 parameter (this is always present) */ - param = param->get_next(); - inst = (ir_instruction *) param; - instr->src[2] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - - /* data2 parameter (only with atomic_comp_swap) */ - if (param_count == 4) { - assert(op == nir_intrinsic_ssbo_atomic_comp_swap); - param = param->get_next(); - inst = (ir_instruction *) param; - instr->src[3] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - } - - /* Atomic result */ - assert(ir->return_deref); - nir_ssa_dest_init(&instr->instr, &instr->dest, - ir->return_deref->type->vector_elements, NULL); - nir_builder_instr_insert(&b, &instr->instr); - break; - } - case nir_intrinsic_load_shared: { - exec_node *param = ir->actual_parameters.get_head(); - ir_rvalue *offset = ((ir_instruction *)param)->as_rvalue(); - - instr->const_index[0] = 0; - instr->src[0] = nir_src_for_ssa(evaluate_rvalue(offset)); - - const glsl_type *type = ir->return_deref->var->type; - instr->num_components = type->vector_elements; - - /* Setup destination register */ - nir_ssa_dest_init(&instr->instr, &instr->dest, - type->vector_elements, NULL); - - nir_builder_instr_insert(&b, &instr->instr); - break; - } - case nir_intrinsic_store_shared: { - exec_node *param = ir->actual_parameters.get_head(); - ir_rvalue *offset = ((ir_instruction *)param)->as_rvalue(); - - param = param->get_next(); - ir_rvalue *val = ((ir_instruction *)param)->as_rvalue(); - - param = param->get_next(); - ir_constant *write_mask = ((ir_instruction *)param)->as_constant(); - assert(write_mask); - - instr->const_index[0] = 0; - instr->src[1] = nir_src_for_ssa(evaluate_rvalue(offset)); - - instr->const_index[1] = write_mask->value.u[0]; - - instr->src[0] = nir_src_for_ssa(evaluate_rvalue(val)); - instr->num_components = val->type->vector_elements; - - nir_builder_instr_insert(&b, &instr->instr); - break; - } - case nir_intrinsic_shared_atomic_add: - case nir_intrinsic_shared_atomic_imin: - case nir_intrinsic_shared_atomic_umin: - case nir_intrinsic_shared_atomic_imax: - case nir_intrinsic_shared_atomic_umax: - case nir_intrinsic_shared_atomic_and: - case nir_intrinsic_shared_atomic_or: - case nir_intrinsic_shared_atomic_xor: - case nir_intrinsic_shared_atomic_exchange: - case nir_intrinsic_shared_atomic_comp_swap: { - int param_count = ir->actual_parameters.length(); - assert(param_count == 2 || param_count == 3); - - /* Offset */ - exec_node *param = ir->actual_parameters.get_head(); - ir_instruction *inst = (ir_instruction *) param; - instr->src[0] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - - /* data1 parameter (this is always present) */ - param = param->get_next(); - inst = (ir_instruction *) param; - instr->src[1] = nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - - /* data2 parameter (only with atomic_comp_swap) */ - if (param_count == 3) { - assert(op == nir_intrinsic_shared_atomic_comp_swap); - param = param->get_next(); - inst = (ir_instruction *) param; - instr->src[2] = - nir_src_for_ssa(evaluate_rvalue(inst->as_rvalue())); - } - - /* Atomic result */ - assert(ir->return_deref); - nir_ssa_dest_init(&instr->instr, &instr->dest, - ir->return_deref->type->vector_elements, NULL); - nir_builder_instr_insert(&b, &instr->instr); - break; - } - default: - unreachable("not reached"); - } - - if (ir->return_deref) { - nir_intrinsic_instr *store_instr = - nir_intrinsic_instr_create(shader, nir_intrinsic_store_var); - store_instr->num_components = ir->return_deref->type->vector_elements; - store_instr->const_index[0] = (1 << store_instr->num_components) - 1; - - store_instr->variables[0] = - evaluate_deref(&store_instr->instr, ir->return_deref); - store_instr->src[0] = nir_src_for_ssa(&dest->ssa); - - nir_builder_instr_insert(&b, &store_instr->instr); - } - - return; - } - - struct hash_entry *entry = - _mesa_hash_table_search(this->overload_table, ir->callee); - assert(entry); - nir_function *callee = (nir_function *) entry->data; - - nir_call_instr *instr = nir_call_instr_create(this->shader, callee); - - unsigned i = 0; - foreach_in_list(ir_dereference, param, &ir->actual_parameters) { - instr->params[i] = evaluate_deref(&instr->instr, param); - i++; - } - - instr->return_deref = evaluate_deref(&instr->instr, ir->return_deref); - nir_builder_instr_insert(&b, &instr->instr); -} - -void -nir_visitor::visit(ir_assignment *ir) -{ - unsigned num_components = ir->lhs->type->vector_elements; - - if ((ir->rhs->as_dereference() || ir->rhs->as_constant()) && - (ir->write_mask == (1 << num_components) - 1 || ir->write_mask == 0)) { - /* We're doing a plain-as-can-be copy, so emit a copy_var */ - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_copy_var); - - copy->variables[0] = evaluate_deref(©->instr, ir->lhs); - copy->variables[1] = evaluate_deref(©->instr, ir->rhs); - - if (ir->condition) { - nir_if *if_stmt = nir_if_create(this->shader); - if_stmt->condition = nir_src_for_ssa(evaluate_rvalue(ir->condition)); - nir_builder_cf_insert(&b, &if_stmt->cf_node); - nir_instr_insert_after_cf_list(&if_stmt->then_list, ©->instr); - b.cursor = nir_after_cf_node(&if_stmt->cf_node); - } else { - nir_builder_instr_insert(&b, ©->instr); - } - return; - } - - assert(ir->rhs->type->is_scalar() || ir->rhs->type->is_vector()); - - ir->lhs->accept(this); - nir_deref_var *lhs_deref = this->deref_head; - nir_ssa_def *src = evaluate_rvalue(ir->rhs); - - if (ir->write_mask != (1 << num_components) - 1 && ir->write_mask != 0) { - /* GLSL IR will give us the input to the write-masked assignment in a - * single packed vector. So, for example, if the writemask is xzw, then - * we have to swizzle x -> x, y -> z, and z -> w and get the y component - * from the load. - */ - unsigned swiz[4]; - unsigned component = 0; - for (unsigned i = 0; i < 4; i++) { - swiz[i] = ir->write_mask & (1 << i) ? component++ : 0; - } - src = nir_swizzle(&b, src, swiz, num_components, !supports_ints); - } - - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_store_var); - store->num_components = ir->lhs->type->vector_elements; - store->const_index[0] = ir->write_mask; - nir_deref *store_deref = nir_copy_deref(store, &lhs_deref->deref); - store->variables[0] = nir_deref_as_var(store_deref); - store->src[0] = nir_src_for_ssa(src); - - if (ir->condition) { - nir_if *if_stmt = nir_if_create(this->shader); - if_stmt->condition = nir_src_for_ssa(evaluate_rvalue(ir->condition)); - nir_builder_cf_insert(&b, &if_stmt->cf_node); - nir_instr_insert_after_cf_list(&if_stmt->then_list, &store->instr); - b.cursor = nir_after_cf_node(&if_stmt->cf_node); - } else { - nir_builder_instr_insert(&b, &store->instr); - } -} - -/* - * Given an instruction, returns a pointer to its destination or NULL if there - * is no destination. - * - * Note that this only handles instructions we generate at this level. - */ -static nir_dest * -get_instr_dest(nir_instr *instr) -{ - nir_alu_instr *alu_instr; - nir_intrinsic_instr *intrinsic_instr; - nir_tex_instr *tex_instr; - - switch (instr->type) { - case nir_instr_type_alu: - alu_instr = nir_instr_as_alu(instr); - return &alu_instr->dest.dest; - - case nir_instr_type_intrinsic: - intrinsic_instr = nir_instr_as_intrinsic(instr); - if (nir_intrinsic_infos[intrinsic_instr->intrinsic].has_dest) - return &intrinsic_instr->dest; - else - return NULL; - - case nir_instr_type_tex: - tex_instr = nir_instr_as_tex(instr); - return &tex_instr->dest; - - default: - unreachable("not reached"); - } - - return NULL; -} - -void -nir_visitor::add_instr(nir_instr *instr, unsigned num_components) -{ - nir_dest *dest = get_instr_dest(instr); - - if (dest) - nir_ssa_dest_init(instr, dest, num_components, NULL); - - nir_builder_instr_insert(&b, instr); - - if (dest) { - assert(dest->is_ssa); - this->result = &dest->ssa; - } -} - -nir_ssa_def * -nir_visitor::evaluate_rvalue(ir_rvalue* ir) -{ - ir->accept(this); - if (ir->as_dereference() || ir->as_constant()) { - /* - * A dereference is being used on the right hand side, which means we - * must emit a variable load. - */ - - nir_intrinsic_instr *load_instr = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_load_var); - load_instr->num_components = ir->type->vector_elements; - load_instr->variables[0] = this->deref_head; - ralloc_steal(load_instr, load_instr->variables[0]); - add_instr(&load_instr->instr, ir->type->vector_elements); - } - - return this->result; -} - -void -nir_visitor::visit(ir_expression *ir) -{ - /* Some special cases */ - switch (ir->operation) { - case ir_binop_ubo_load: { - nir_intrinsic_instr *load = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_load_ubo); - load->num_components = ir->type->vector_elements; - load->src[0] = nir_src_for_ssa(evaluate_rvalue(ir->operands[0])); - load->src[1] = nir_src_for_ssa(evaluate_rvalue(ir->operands[1])); - add_instr(&load->instr, ir->type->vector_elements); - - /* - * In UBO's, a true boolean value is any non-zero value, but we consider - * a true boolean to be ~0. Fix this up with a != 0 comparison. - */ - - if (ir->type->base_type == GLSL_TYPE_BOOL) - this->result = nir_ine(&b, &load->dest.ssa, nir_imm_int(&b, 0)); - - return; - } - - case ir_unop_interpolate_at_centroid: - case ir_binop_interpolate_at_offset: - case ir_binop_interpolate_at_sample: { - ir_dereference *deref = ir->operands[0]->as_dereference(); - ir_swizzle *swizzle = NULL; - if (!deref) { - /* the api does not allow a swizzle here, but the varying packing code - * may have pushed one into here. - */ - swizzle = ir->operands[0]->as_swizzle(); - assert(swizzle); - deref = swizzle->val->as_dereference(); - assert(deref); - } - - deref->accept(this); - - nir_intrinsic_op op; - if (this->deref_head->var->data.mode == nir_var_shader_in) { - switch (ir->operation) { - case ir_unop_interpolate_at_centroid: - op = nir_intrinsic_interp_var_at_centroid; - break; - case ir_binop_interpolate_at_offset: - op = nir_intrinsic_interp_var_at_offset; - break; - case ir_binop_interpolate_at_sample: - op = nir_intrinsic_interp_var_at_sample; - break; - default: - unreachable("Invalid interpolation intrinsic"); - } - } else { - /* This case can happen if the vertex shader does not write the - * given varying. In this case, the linker will lower it to a - * global variable. Since interpolating a variable makes no - * sense, we'll just turn it into a load which will probably - * eventually end up as an SSA definition. - */ - assert(this->deref_head->var->data.mode == nir_var_global); - op = nir_intrinsic_load_var; - } - - nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(shader, op); - intrin->num_components = deref->type->vector_elements; - intrin->variables[0] = this->deref_head; - ralloc_steal(intrin, intrin->variables[0]); - - if (intrin->intrinsic == nir_intrinsic_interp_var_at_offset || - intrin->intrinsic == nir_intrinsic_interp_var_at_sample) - intrin->src[0] = nir_src_for_ssa(evaluate_rvalue(ir->operands[1])); - - add_instr(&intrin->instr, deref->type->vector_elements); - - if (swizzle) { - unsigned swiz[4] = { - swizzle->mask.x, swizzle->mask.y, swizzle->mask.z, swizzle->mask.w - }; - - result = nir_swizzle(&b, result, swiz, - swizzle->type->vector_elements, false); - } - - return; - } - - default: - break; - } - - nir_ssa_def *srcs[4]; - for (unsigned i = 0; i < ir->get_num_operands(); i++) - srcs[i] = evaluate_rvalue(ir->operands[i]); - - glsl_base_type types[4]; - for (unsigned i = 0; i < ir->get_num_operands(); i++) - if (supports_ints) - types[i] = ir->operands[i]->type->base_type; - else - types[i] = GLSL_TYPE_FLOAT; - - glsl_base_type out_type; - if (supports_ints) - out_type = ir->type->base_type; - else - out_type = GLSL_TYPE_FLOAT; - - switch (ir->operation) { - case ir_unop_bit_not: result = nir_inot(&b, srcs[0]); break; - case ir_unop_logic_not: - result = supports_ints ? nir_inot(&b, srcs[0]) : nir_fnot(&b, srcs[0]); - break; - case ir_unop_neg: - result = (types[0] == GLSL_TYPE_FLOAT) ? nir_fneg(&b, srcs[0]) - : nir_ineg(&b, srcs[0]); - break; - case ir_unop_abs: - result = (types[0] == GLSL_TYPE_FLOAT) ? nir_fabs(&b, srcs[0]) - : nir_iabs(&b, srcs[0]); - break; - case ir_unop_saturate: - assert(types[0] == GLSL_TYPE_FLOAT); - result = nir_fsat(&b, srcs[0]); - break; - case ir_unop_sign: - result = (types[0] == GLSL_TYPE_FLOAT) ? nir_fsign(&b, srcs[0]) - : nir_isign(&b, srcs[0]); - break; - case ir_unop_rcp: result = nir_frcp(&b, srcs[0]); break; - case ir_unop_rsq: result = nir_frsq(&b, srcs[0]); break; - case ir_unop_sqrt: result = nir_fsqrt(&b, srcs[0]); break; - case ir_unop_exp: unreachable("ir_unop_exp should have been lowered"); - case ir_unop_log: unreachable("ir_unop_log should have been lowered"); - case ir_unop_exp2: result = nir_fexp2(&b, srcs[0]); break; - case ir_unop_log2: result = nir_flog2(&b, srcs[0]); break; - case ir_unop_i2f: - result = supports_ints ? nir_i2f(&b, srcs[0]) : nir_fmov(&b, srcs[0]); - break; - case ir_unop_u2f: - result = supports_ints ? nir_u2f(&b, srcs[0]) : nir_fmov(&b, srcs[0]); - break; - case ir_unop_b2f: - result = supports_ints ? nir_b2f(&b, srcs[0]) : nir_fmov(&b, srcs[0]); - break; - case ir_unop_f2i: result = nir_f2i(&b, srcs[0]); break; - case ir_unop_f2u: result = nir_f2u(&b, srcs[0]); break; - case ir_unop_f2b: result = nir_f2b(&b, srcs[0]); break; - case ir_unop_i2b: result = nir_i2b(&b, srcs[0]); break; - case ir_unop_b2i: result = nir_b2i(&b, srcs[0]); break; - case ir_unop_i2u: - case ir_unop_u2i: - case ir_unop_bitcast_i2f: - case ir_unop_bitcast_f2i: - case ir_unop_bitcast_u2f: - case ir_unop_bitcast_f2u: - case ir_unop_subroutine_to_int: - /* no-op */ - result = nir_imov(&b, srcs[0]); - break; - case ir_unop_trunc: result = nir_ftrunc(&b, srcs[0]); break; - case ir_unop_ceil: result = nir_fceil(&b, srcs[0]); break; - case ir_unop_floor: result = nir_ffloor(&b, srcs[0]); break; - case ir_unop_fract: result = nir_ffract(&b, srcs[0]); break; - case ir_unop_round_even: result = nir_fround_even(&b, srcs[0]); break; - case ir_unop_sin: result = nir_fsin(&b, srcs[0]); break; - case ir_unop_cos: result = nir_fcos(&b, srcs[0]); break; - case ir_unop_dFdx: result = nir_fddx(&b, srcs[0]); break; - case ir_unop_dFdy: result = nir_fddy(&b, srcs[0]); break; - case ir_unop_dFdx_fine: result = nir_fddx_fine(&b, srcs[0]); break; - case ir_unop_dFdy_fine: result = nir_fddy_fine(&b, srcs[0]); break; - case ir_unop_dFdx_coarse: result = nir_fddx_coarse(&b, srcs[0]); break; - case ir_unop_dFdy_coarse: result = nir_fddy_coarse(&b, srcs[0]); break; - case ir_unop_pack_snorm_2x16: - result = nir_pack_snorm_2x16(&b, srcs[0]); - break; - case ir_unop_pack_snorm_4x8: - result = nir_pack_snorm_4x8(&b, srcs[0]); - break; - case ir_unop_pack_unorm_2x16: - result = nir_pack_unorm_2x16(&b, srcs[0]); - break; - case ir_unop_pack_unorm_4x8: - result = nir_pack_unorm_4x8(&b, srcs[0]); - break; - case ir_unop_pack_half_2x16: - result = nir_pack_half_2x16(&b, srcs[0]); - break; - case ir_unop_unpack_snorm_2x16: - result = nir_unpack_snorm_2x16(&b, srcs[0]); - break; - case ir_unop_unpack_snorm_4x8: - result = nir_unpack_snorm_4x8(&b, srcs[0]); - break; - case ir_unop_unpack_unorm_2x16: - result = nir_unpack_unorm_2x16(&b, srcs[0]); - break; - case ir_unop_unpack_unorm_4x8: - result = nir_unpack_unorm_4x8(&b, srcs[0]); - break; - case ir_unop_unpack_half_2x16: - result = nir_unpack_half_2x16(&b, srcs[0]); - break; - case ir_unop_bitfield_reverse: - result = nir_bitfield_reverse(&b, srcs[0]); - break; - case ir_unop_bit_count: - result = nir_bit_count(&b, srcs[0]); - break; - case ir_unop_find_msb: - switch (types[0]) { - case GLSL_TYPE_UINT: - result = nir_ufind_msb(&b, srcs[0]); - break; - case GLSL_TYPE_INT: - result = nir_ifind_msb(&b, srcs[0]); - break; - default: - unreachable("Invalid type for findMSB()"); - } - break; - case ir_unop_find_lsb: - result = nir_find_lsb(&b, srcs[0]); - break; - - case ir_unop_noise: - switch (ir->type->vector_elements) { - case 1: - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_fnoise1_1(&b, srcs[0]); break; - case 2: result = nir_fnoise1_2(&b, srcs[0]); break; - case 3: result = nir_fnoise1_3(&b, srcs[0]); break; - case 4: result = nir_fnoise1_4(&b, srcs[0]); break; - default: unreachable("not reached"); - } - break; - case 2: - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_fnoise2_1(&b, srcs[0]); break; - case 2: result = nir_fnoise2_2(&b, srcs[0]); break; - case 3: result = nir_fnoise2_3(&b, srcs[0]); break; - case 4: result = nir_fnoise2_4(&b, srcs[0]); break; - default: unreachable("not reached"); - } - break; - case 3: - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_fnoise3_1(&b, srcs[0]); break; - case 2: result = nir_fnoise3_2(&b, srcs[0]); break; - case 3: result = nir_fnoise3_3(&b, srcs[0]); break; - case 4: result = nir_fnoise3_4(&b, srcs[0]); break; - default: unreachable("not reached"); - } - break; - case 4: - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_fnoise4_1(&b, srcs[0]); break; - case 2: result = nir_fnoise4_2(&b, srcs[0]); break; - case 3: result = nir_fnoise4_3(&b, srcs[0]); break; - case 4: result = nir_fnoise4_4(&b, srcs[0]); break; - default: unreachable("not reached"); - } - break; - default: - unreachable("not reached"); - } - break; - case ir_unop_get_buffer_size: { - nir_intrinsic_instr *load = nir_intrinsic_instr_create( - this->shader, - nir_intrinsic_get_buffer_size); - load->num_components = ir->type->vector_elements; - load->src[0] = nir_src_for_ssa(evaluate_rvalue(ir->operands[0])); - add_instr(&load->instr, ir->type->vector_elements); - return; - } - - case ir_binop_add: - result = (out_type == GLSL_TYPE_FLOAT) ? nir_fadd(&b, srcs[0], srcs[1]) - : nir_iadd(&b, srcs[0], srcs[1]); - break; - case ir_binop_sub: - result = (out_type == GLSL_TYPE_FLOAT) ? nir_fsub(&b, srcs[0], srcs[1]) - : nir_isub(&b, srcs[0], srcs[1]); - break; - case ir_binop_mul: - result = (out_type == GLSL_TYPE_FLOAT) ? nir_fmul(&b, srcs[0], srcs[1]) - : nir_imul(&b, srcs[0], srcs[1]); - break; - case ir_binop_div: - if (out_type == GLSL_TYPE_FLOAT) - result = nir_fdiv(&b, srcs[0], srcs[1]); - else if (out_type == GLSL_TYPE_INT) - result = nir_idiv(&b, srcs[0], srcs[1]); - else - result = nir_udiv(&b, srcs[0], srcs[1]); - break; - case ir_binop_mod: - result = (out_type == GLSL_TYPE_FLOAT) ? nir_fmod(&b, srcs[0], srcs[1]) - : nir_umod(&b, srcs[0], srcs[1]); - break; - case ir_binop_min: - if (out_type == GLSL_TYPE_FLOAT) - result = nir_fmin(&b, srcs[0], srcs[1]); - else if (out_type == GLSL_TYPE_INT) - result = nir_imin(&b, srcs[0], srcs[1]); - else - result = nir_umin(&b, srcs[0], srcs[1]); - break; - case ir_binop_max: - if (out_type == GLSL_TYPE_FLOAT) - result = nir_fmax(&b, srcs[0], srcs[1]); - else if (out_type == GLSL_TYPE_INT) - result = nir_imax(&b, srcs[0], srcs[1]); - else - result = nir_umax(&b, srcs[0], srcs[1]); - break; - case ir_binop_pow: result = nir_fpow(&b, srcs[0], srcs[1]); break; - case ir_binop_bit_and: result = nir_iand(&b, srcs[0], srcs[1]); break; - case ir_binop_bit_or: result = nir_ior(&b, srcs[0], srcs[1]); break; - case ir_binop_bit_xor: result = nir_ixor(&b, srcs[0], srcs[1]); break; - case ir_binop_logic_and: - result = supports_ints ? nir_iand(&b, srcs[0], srcs[1]) - : nir_fand(&b, srcs[0], srcs[1]); - break; - case ir_binop_logic_or: - result = supports_ints ? nir_ior(&b, srcs[0], srcs[1]) - : nir_for(&b, srcs[0], srcs[1]); - break; - case ir_binop_logic_xor: - result = supports_ints ? nir_ixor(&b, srcs[0], srcs[1]) - : nir_fxor(&b, srcs[0], srcs[1]); - break; - case ir_binop_lshift: result = nir_ishl(&b, srcs[0], srcs[1]); break; - case ir_binop_rshift: - result = (out_type == GLSL_TYPE_INT) ? nir_ishr(&b, srcs[0], srcs[1]) - : nir_ushr(&b, srcs[0], srcs[1]); - break; - case ir_binop_imul_high: - result = (out_type == GLSL_TYPE_INT) ? nir_imul_high(&b, srcs[0], srcs[1]) - : nir_umul_high(&b, srcs[0], srcs[1]); - break; - case ir_binop_carry: result = nir_uadd_carry(&b, srcs[0], srcs[1]); break; - case ir_binop_borrow: result = nir_usub_borrow(&b, srcs[0], srcs[1]); break; - case ir_binop_less: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) - result = nir_flt(&b, srcs[0], srcs[1]); - else if (types[0] == GLSL_TYPE_INT) - result = nir_ilt(&b, srcs[0], srcs[1]); - else - result = nir_ult(&b, srcs[0], srcs[1]); - } else { - result = nir_slt(&b, srcs[0], srcs[1]); - } - break; - case ir_binop_greater: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) - result = nir_flt(&b, srcs[1], srcs[0]); - else if (types[0] == GLSL_TYPE_INT) - result = nir_ilt(&b, srcs[1], srcs[0]); - else - result = nir_ult(&b, srcs[1], srcs[0]); - } else { - result = nir_slt(&b, srcs[1], srcs[0]); - } - break; - case ir_binop_lequal: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) - result = nir_fge(&b, srcs[1], srcs[0]); - else if (types[0] == GLSL_TYPE_INT) - result = nir_ige(&b, srcs[1], srcs[0]); - else - result = nir_uge(&b, srcs[1], srcs[0]); - } else { - result = nir_slt(&b, srcs[1], srcs[0]); - } - break; - case ir_binop_gequal: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) - result = nir_fge(&b, srcs[0], srcs[1]); - else if (types[0] == GLSL_TYPE_INT) - result = nir_ige(&b, srcs[0], srcs[1]); - else - result = nir_uge(&b, srcs[0], srcs[1]); - } else { - result = nir_slt(&b, srcs[0], srcs[1]); - } - break; - case ir_binop_equal: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) - result = nir_feq(&b, srcs[0], srcs[1]); - else - result = nir_ieq(&b, srcs[0], srcs[1]); - } else { - result = nir_seq(&b, srcs[0], srcs[1]); - } - break; - case ir_binop_nequal: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) - result = nir_fne(&b, srcs[0], srcs[1]); - else - result = nir_ine(&b, srcs[0], srcs[1]); - } else { - result = nir_sne(&b, srcs[0], srcs[1]); - } - break; - case ir_binop_all_equal: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) { - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_feq(&b, srcs[0], srcs[1]); break; - case 2: result = nir_ball_fequal2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_ball_fequal3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_ball_fequal4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - } else { - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_ieq(&b, srcs[0], srcs[1]); break; - case 2: result = nir_ball_iequal2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_ball_iequal3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_ball_iequal4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - } - } else { - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_seq(&b, srcs[0], srcs[1]); break; - case 2: result = nir_fall_equal2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_fall_equal3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_fall_equal4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - } - break; - case ir_binop_any_nequal: - if (supports_ints) { - if (types[0] == GLSL_TYPE_FLOAT) { - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_fne(&b, srcs[0], srcs[1]); break; - case 2: result = nir_bany_fnequal2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_bany_fnequal3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_bany_fnequal4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - } else { - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_ine(&b, srcs[0], srcs[1]); break; - case 2: result = nir_bany_inequal2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_bany_inequal3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_bany_inequal4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - } - } else { - switch (ir->operands[0]->type->vector_elements) { - case 1: result = nir_sne(&b, srcs[0], srcs[1]); break; - case 2: result = nir_fany_nequal2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_fany_nequal3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_fany_nequal4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - } - break; - case ir_binop_dot: - switch (ir->operands[0]->type->vector_elements) { - case 2: result = nir_fdot2(&b, srcs[0], srcs[1]); break; - case 3: result = nir_fdot3(&b, srcs[0], srcs[1]); break; - case 4: result = nir_fdot4(&b, srcs[0], srcs[1]); break; - default: - unreachable("not reached"); - } - break; - - case ir_binop_ldexp: result = nir_ldexp(&b, srcs[0], srcs[1]); break; - case ir_triop_fma: - result = nir_ffma(&b, srcs[0], srcs[1], srcs[2]); - break; - case ir_triop_lrp: - result = nir_flrp(&b, srcs[0], srcs[1], srcs[2]); - break; - case ir_triop_csel: - if (supports_ints) - result = nir_bcsel(&b, srcs[0], srcs[1], srcs[2]); - else - result = nir_fcsel(&b, srcs[0], srcs[1], srcs[2]); - break; - case ir_triop_bitfield_extract: - result = (out_type == GLSL_TYPE_INT) ? - nir_ibitfield_extract(&b, srcs[0], srcs[1], srcs[2]) : - nir_ubitfield_extract(&b, srcs[0], srcs[1], srcs[2]); - break; - case ir_quadop_bitfield_insert: - result = nir_bitfield_insert(&b, srcs[0], srcs[1], srcs[2], srcs[3]); - break; - case ir_quadop_vector: - result = nir_vec(&b, srcs, ir->type->vector_elements); - break; - - default: - unreachable("not reached"); - } -} - -void -nir_visitor::visit(ir_swizzle *ir) -{ - unsigned swizzle[4] = { ir->mask.x, ir->mask.y, ir->mask.z, ir->mask.w }; - result = nir_swizzle(&b, evaluate_rvalue(ir->val), swizzle, - ir->type->vector_elements, !supports_ints); -} - -void -nir_visitor::visit(ir_texture *ir) -{ - unsigned num_srcs; - nir_texop op; - switch (ir->op) { - case ir_tex: - op = nir_texop_tex; - num_srcs = 1; /* coordinate */ - break; - - case ir_txb: - case ir_txl: - op = (ir->op == ir_txb) ? nir_texop_txb : nir_texop_txl; - num_srcs = 2; /* coordinate, bias/lod */ - break; - - case ir_txd: - op = nir_texop_txd; /* coordinate, dPdx, dPdy */ - num_srcs = 3; - break; - - case ir_txf: - op = nir_texop_txf; - if (ir->lod_info.lod != NULL) - num_srcs = 2; /* coordinate, lod */ - else - num_srcs = 1; /* coordinate */ - break; - - case ir_txf_ms: - op = nir_texop_txf_ms; - num_srcs = 2; /* coordinate, sample_index */ - break; - - case ir_txs: - op = nir_texop_txs; - if (ir->lod_info.lod != NULL) - num_srcs = 1; /* lod */ - else - num_srcs = 0; - break; - - case ir_lod: - op = nir_texop_lod; - num_srcs = 1; /* coordinate */ - break; - - case ir_tg4: - op = nir_texop_tg4; - num_srcs = 1; /* coordinate */ - break; - - case ir_query_levels: - op = nir_texop_query_levels; - num_srcs = 0; - break; - - case ir_texture_samples: - op = nir_texop_texture_samples; - num_srcs = 0; - break; - - case ir_samples_identical: - op = nir_texop_samples_identical; - num_srcs = 1; /* coordinate */ - break; - - default: - unreachable("not reached"); - } - - if (ir->projector != NULL) - num_srcs++; - if (ir->shadow_comparitor != NULL) - num_srcs++; - if (ir->offset != NULL && ir->offset->as_constant() == NULL) - num_srcs++; - - nir_tex_instr *instr = nir_tex_instr_create(this->shader, num_srcs); - - instr->op = op; - instr->sampler_dim = - (glsl_sampler_dim) ir->sampler->type->sampler_dimensionality; - instr->is_array = ir->sampler->type->sampler_array; - instr->is_shadow = ir->sampler->type->sampler_shadow; - if (instr->is_shadow) - instr->is_new_style_shadow = (ir->type->vector_elements == 1); - switch (ir->type->base_type) { - case GLSL_TYPE_FLOAT: - instr->dest_type = nir_type_float; - break; - case GLSL_TYPE_INT: - instr->dest_type = nir_type_int; - break; - case GLSL_TYPE_BOOL: - case GLSL_TYPE_UINT: - instr->dest_type = nir_type_uint; - break; - default: - unreachable("not reached"); - } - - instr->sampler = evaluate_deref(&instr->instr, ir->sampler); - - unsigned src_number = 0; - - if (ir->coordinate != NULL) { - instr->coord_components = ir->coordinate->type->vector_elements; - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->coordinate)); - instr->src[src_number].src_type = nir_tex_src_coord; - src_number++; - } - - if (ir->projector != NULL) { - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->projector)); - instr->src[src_number].src_type = nir_tex_src_projector; - src_number++; - } - - if (ir->shadow_comparitor != NULL) { - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->shadow_comparitor)); - instr->src[src_number].src_type = nir_tex_src_comparitor; - src_number++; - } - - if (ir->offset != NULL) { - /* we don't support multiple offsets yet */ - assert(ir->offset->type->is_vector() || ir->offset->type->is_scalar()); - - ir_constant *const_offset = ir->offset->as_constant(); - if (const_offset != NULL) { - for (unsigned i = 0; i < const_offset->type->vector_elements; i++) - instr->const_offset[i] = const_offset->value.i[i]; - } else { - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->offset)); - instr->src[src_number].src_type = nir_tex_src_offset; - src_number++; - } - } - - switch (ir->op) { - case ir_txb: - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->lod_info.bias)); - instr->src[src_number].src_type = nir_tex_src_bias; - src_number++; - break; - - case ir_txl: - case ir_txf: - case ir_txs: - if (ir->lod_info.lod != NULL) { - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->lod_info.lod)); - instr->src[src_number].src_type = nir_tex_src_lod; - src_number++; - } - break; - - case ir_txd: - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->lod_info.grad.dPdx)); - instr->src[src_number].src_type = nir_tex_src_ddx; - src_number++; - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->lod_info.grad.dPdy)); - instr->src[src_number].src_type = nir_tex_src_ddy; - src_number++; - break; - - case ir_txf_ms: - instr->src[src_number].src = - nir_src_for_ssa(evaluate_rvalue(ir->lod_info.sample_index)); - instr->src[src_number].src_type = nir_tex_src_ms_index; - src_number++; - break; - - case ir_tg4: - instr->component = ir->lod_info.component->as_constant()->value.u[0]; - break; - - default: - break; - } - - assert(src_number == num_srcs); - - add_instr(&instr->instr, nir_tex_instr_dest_size(instr)); -} - -void -nir_visitor::visit(ir_constant *ir) -{ - /* - * We don't know if this variable is an an array or struct that gets - * dereferenced, so do the safe thing an make it a variable with a - * constant initializer and return a dereference. - */ - - nir_variable *var = - nir_local_variable_create(this->impl, ir->type, "const_temp"); - var->data.read_only = true; - var->constant_initializer = constant_copy(ir, var); - - this->deref_head = nir_deref_var_create(this->shader, var); - this->deref_tail = &this->deref_head->deref; -} - -void -nir_visitor::visit(ir_dereference_variable *ir) -{ - struct hash_entry *entry = - _mesa_hash_table_search(this->var_table, ir->var); - assert(entry); - nir_variable *var = (nir_variable *) entry->data; - - nir_deref_var *deref = nir_deref_var_create(this->shader, var); - this->deref_head = deref; - this->deref_tail = &deref->deref; -} - -void -nir_visitor::visit(ir_dereference_record *ir) -{ - ir->record->accept(this); - - int field_index = this->deref_tail->type->field_index(ir->field); - assert(field_index >= 0); - - nir_deref_struct *deref = nir_deref_struct_create(this->deref_tail, field_index); - deref->deref.type = ir->type; - this->deref_tail->child = &deref->deref; - this->deref_tail = &deref->deref; -} - -void -nir_visitor::visit(ir_dereference_array *ir) -{ - nir_deref_array *deref = nir_deref_array_create(this->shader); - deref->deref.type = ir->type; - - ir_constant *const_index = ir->array_index->as_constant(); - if (const_index != NULL) { - deref->deref_array_type = nir_deref_array_type_direct; - deref->base_offset = const_index->value.u[0]; - } else { - deref->deref_array_type = nir_deref_array_type_indirect; - deref->indirect = - nir_src_for_ssa(evaluate_rvalue(ir->array_index)); - } - - ir->array->accept(this); - - this->deref_tail->child = &deref->deref; - ralloc_steal(this->deref_tail, deref); - this->deref_tail = &deref->deref; -} - -void -nir_visitor::visit(ir_barrier *ir) -{ - nir_intrinsic_instr *instr = - nir_intrinsic_instr_create(this->shader, nir_intrinsic_barrier); - nir_builder_instr_insert(&b, &instr->instr); -} diff --git a/src/glsl/nir/glsl_to_nir.h b/src/glsl/nir/glsl_to_nir.h deleted file mode 100644 index 29badcda08d..00000000000 --- a/src/glsl/nir/glsl_to_nir.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include "../glsl_parser_extras.h" - -#ifdef __cplusplus -extern "C" { -#endif - -nir_shader *glsl_to_nir(const struct gl_shader_program *shader_prog, - gl_shader_stage stage, - const nir_shader_compiler_options *options); - -#ifdef __cplusplus -} -#endif diff --git a/src/glsl/nir/glsl_types.cpp b/src/glsl/nir/glsl_types.cpp deleted file mode 100644 index 71095fa92e4..00000000000 --- a/src/glsl/nir/glsl_types.cpp +++ /dev/null @@ -1,1950 +0,0 @@ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include <stdio.h> -#include "main/macros.h" -#include "glsl_parser_extras.h" -#include "glsl_types.h" -#include "util/hash_table.h" - - -mtx_t glsl_type::mutex = _MTX_INITIALIZER_NP; -hash_table *glsl_type::array_types = NULL; -hash_table *glsl_type::record_types = NULL; -hash_table *glsl_type::interface_types = NULL; -hash_table *glsl_type::function_types = NULL; -hash_table *glsl_type::subroutine_types = NULL; -void *glsl_type::mem_ctx = NULL; - -void -glsl_type::init_ralloc_type_ctx(void) -{ - if (glsl_type::mem_ctx == NULL) { - glsl_type::mem_ctx = ralloc_autofree_context(); - assert(glsl_type::mem_ctx != NULL); - } -} - -glsl_type::glsl_type(GLenum gl_type, - glsl_base_type base_type, unsigned vector_elements, - unsigned matrix_columns, const char *name) : - gl_type(gl_type), - base_type(base_type), - sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), - sampler_type(0), interface_packing(0), - vector_elements(vector_elements), matrix_columns(matrix_columns), - length(0) -{ - mtx_lock(&glsl_type::mutex); - - init_ralloc_type_ctx(); - assert(name != NULL); - this->name = ralloc_strdup(this->mem_ctx, name); - - mtx_unlock(&glsl_type::mutex); - - /* Neither dimension is zero or both dimensions are zero. - */ - assert((vector_elements == 0) == (matrix_columns == 0)); - memset(& fields, 0, sizeof(fields)); -} - -glsl_type::glsl_type(GLenum gl_type, glsl_base_type base_type, - enum glsl_sampler_dim dim, bool shadow, bool array, - unsigned type, const char *name) : - gl_type(gl_type), - base_type(base_type), - sampler_dimensionality(dim), sampler_shadow(shadow), - sampler_array(array), sampler_type(type), interface_packing(0), - length(0) -{ - mtx_lock(&glsl_type::mutex); - - init_ralloc_type_ctx(); - assert(name != NULL); - this->name = ralloc_strdup(this->mem_ctx, name); - - mtx_unlock(&glsl_type::mutex); - - memset(& fields, 0, sizeof(fields)); - - if (base_type == GLSL_TYPE_SAMPLER) { - /* Samplers take no storage whatsoever. */ - matrix_columns = vector_elements = 0; - } else { - matrix_columns = vector_elements = 1; - } -} - -glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, - const char *name) : - gl_type(0), - base_type(GLSL_TYPE_STRUCT), - sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), - sampler_type(0), interface_packing(0), - vector_elements(0), matrix_columns(0), - length(num_fields) -{ - unsigned int i; - - mtx_lock(&glsl_type::mutex); - - init_ralloc_type_ctx(); - assert(name != NULL); - this->name = ralloc_strdup(this->mem_ctx, name); - this->fields.structure = ralloc_array(this->mem_ctx, - glsl_struct_field, length); - - for (i = 0; i < length; i++) { - this->fields.structure[i].type = fields[i].type; - this->fields.structure[i].name = ralloc_strdup(this->fields.structure, - fields[i].name); - this->fields.structure[i].location = fields[i].location; - this->fields.structure[i].interpolation = fields[i].interpolation; - this->fields.structure[i].centroid = fields[i].centroid; - this->fields.structure[i].sample = fields[i].sample; - this->fields.structure[i].matrix_layout = fields[i].matrix_layout; - this->fields.structure[i].patch = fields[i].patch; - this->fields.structure[i].image_read_only = fields[i].image_read_only; - this->fields.structure[i].image_write_only = fields[i].image_write_only; - this->fields.structure[i].image_coherent = fields[i].image_coherent; - this->fields.structure[i].image_volatile = fields[i].image_volatile; - this->fields.structure[i].image_restrict = fields[i].image_restrict; - this->fields.structure[i].precision = fields[i].precision; - } - - mtx_unlock(&glsl_type::mutex); -} - -glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, - enum glsl_interface_packing packing, const char *name) : - gl_type(0), - base_type(GLSL_TYPE_INTERFACE), - sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), - sampler_type(0), interface_packing((unsigned) packing), - vector_elements(0), matrix_columns(0), - length(num_fields) -{ - unsigned int i; - - mtx_lock(&glsl_type::mutex); - - init_ralloc_type_ctx(); - assert(name != NULL); - this->name = ralloc_strdup(this->mem_ctx, name); - this->fields.structure = ralloc_array(this->mem_ctx, - glsl_struct_field, length); - for (i = 0; i < length; i++) { - this->fields.structure[i].type = fields[i].type; - this->fields.structure[i].name = ralloc_strdup(this->fields.structure, - fields[i].name); - this->fields.structure[i].location = fields[i].location; - this->fields.structure[i].interpolation = fields[i].interpolation; - this->fields.structure[i].centroid = fields[i].centroid; - this->fields.structure[i].sample = fields[i].sample; - this->fields.structure[i].matrix_layout = fields[i].matrix_layout; - this->fields.structure[i].patch = fields[i].patch; - this->fields.structure[i].precision = fields[i].precision; - } - - mtx_unlock(&glsl_type::mutex); -} - -glsl_type::glsl_type(const glsl_type *return_type, - const glsl_function_param *params, unsigned num_params) : - gl_type(0), - base_type(GLSL_TYPE_FUNCTION), - sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), - sampler_type(0), interface_packing(0), - vector_elements(0), matrix_columns(0), - length(num_params) -{ - unsigned int i; - - mtx_lock(&glsl_type::mutex); - - init_ralloc_type_ctx(); - - this->fields.parameters = rzalloc_array(this->mem_ctx, - glsl_function_param, num_params + 1); - - /* We store the return type as the first parameter */ - this->fields.parameters[0].type = return_type; - this->fields.parameters[0].in = false; - this->fields.parameters[0].out = true; - - /* We store the i'th parameter in slot i+1 */ - for (i = 0; i < length; i++) { - this->fields.parameters[i + 1].type = params[i].type; - this->fields.parameters[i + 1].in = params[i].in; - this->fields.parameters[i + 1].out = params[i].out; - } - - mtx_unlock(&glsl_type::mutex); -} - -glsl_type::glsl_type(const char *subroutine_name) : - gl_type(0), - base_type(GLSL_TYPE_SUBROUTINE), - sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), - sampler_type(0), interface_packing(0), - vector_elements(1), matrix_columns(1), - length(0) -{ - mtx_lock(&glsl_type::mutex); - - init_ralloc_type_ctx(); - assert(subroutine_name != NULL); - this->name = ralloc_strdup(this->mem_ctx, subroutine_name); - mtx_unlock(&glsl_type::mutex); -} - -bool -glsl_type::contains_sampler() const -{ - if (this->is_array()) { - return this->fields.array->contains_sampler(); - } else if (this->is_record()) { - for (unsigned int i = 0; i < this->length; i++) { - if (this->fields.structure[i].type->contains_sampler()) - return true; - } - return false; - } else { - return this->is_sampler(); - } -} - - -bool -glsl_type::contains_integer() const -{ - if (this->is_array()) { - return this->fields.array->contains_integer(); - } else if (this->is_record()) { - for (unsigned int i = 0; i < this->length; i++) { - if (this->fields.structure[i].type->contains_integer()) - return true; - } - return false; - } else { - return this->is_integer(); - } -} - -bool -glsl_type::contains_double() const -{ - if (this->is_array()) { - return this->fields.array->contains_double(); - } else if (this->is_record()) { - for (unsigned int i = 0; i < this->length; i++) { - if (this->fields.structure[i].type->contains_double()) - return true; - } - return false; - } else { - return this->is_double(); - } -} - -bool -glsl_type::contains_opaque() const { - switch (base_type) { - case GLSL_TYPE_SAMPLER: - case GLSL_TYPE_IMAGE: - case GLSL_TYPE_ATOMIC_UINT: - return true; - case GLSL_TYPE_ARRAY: - return fields.array->contains_opaque(); - case GLSL_TYPE_STRUCT: - for (unsigned int i = 0; i < length; i++) { - if (fields.structure[i].type->contains_opaque()) - return true; - } - return false; - default: - return false; - } -} - -bool -glsl_type::contains_subroutine() const -{ - if (this->is_array()) { - return this->fields.array->contains_subroutine(); - } else if (this->is_record()) { - for (unsigned int i = 0; i < this->length; i++) { - if (this->fields.structure[i].type->contains_subroutine()) - return true; - } - return false; - } else { - return this->is_subroutine(); - } -} - -gl_texture_index -glsl_type::sampler_index() const -{ - const glsl_type *const t = (this->is_array()) ? this->fields.array : this; - - assert(t->is_sampler()); - - switch (t->sampler_dimensionality) { - case GLSL_SAMPLER_DIM_1D: - return (t->sampler_array) ? TEXTURE_1D_ARRAY_INDEX : TEXTURE_1D_INDEX; - case GLSL_SAMPLER_DIM_2D: - return (t->sampler_array) ? TEXTURE_2D_ARRAY_INDEX : TEXTURE_2D_INDEX; - case GLSL_SAMPLER_DIM_3D: - return TEXTURE_3D_INDEX; - case GLSL_SAMPLER_DIM_CUBE: - return (t->sampler_array) ? TEXTURE_CUBE_ARRAY_INDEX : TEXTURE_CUBE_INDEX; - case GLSL_SAMPLER_DIM_RECT: - return TEXTURE_RECT_INDEX; - case GLSL_SAMPLER_DIM_BUF: - return TEXTURE_BUFFER_INDEX; - case GLSL_SAMPLER_DIM_EXTERNAL: - return TEXTURE_EXTERNAL_INDEX; - case GLSL_SAMPLER_DIM_MS: - return (t->sampler_array) ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX : TEXTURE_2D_MULTISAMPLE_INDEX; - default: - assert(!"Should not get here."); - return TEXTURE_BUFFER_INDEX; - } -} - -bool -glsl_type::contains_image() const -{ - if (this->is_array()) { - return this->fields.array->contains_image(); - } else if (this->is_record()) { - for (unsigned int i = 0; i < this->length; i++) { - if (this->fields.structure[i].type->contains_image()) - return true; - } - return false; - } else { - return this->is_image(); - } -} - -const glsl_type *glsl_type::get_base_type() const -{ - switch (base_type) { - case GLSL_TYPE_UINT: - return uint_type; - case GLSL_TYPE_INT: - return int_type; - case GLSL_TYPE_FLOAT: - return float_type; - case GLSL_TYPE_DOUBLE: - return double_type; - case GLSL_TYPE_BOOL: - return bool_type; - default: - return error_type; - } -} - - -const glsl_type *glsl_type::get_scalar_type() const -{ - const glsl_type *type = this; - - /* Handle arrays */ - while (type->base_type == GLSL_TYPE_ARRAY) - type = type->fields.array; - - /* Handle vectors and matrices */ - switch (type->base_type) { - case GLSL_TYPE_UINT: - return uint_type; - case GLSL_TYPE_INT: - return int_type; - case GLSL_TYPE_FLOAT: - return float_type; - case GLSL_TYPE_DOUBLE: - return double_type; - case GLSL_TYPE_BOOL: - return bool_type; - default: - /* Handle everything else */ - return type; - } -} - - -void -_mesa_glsl_release_types(void) -{ - /* Should only be called during atexit (either when unloading shared - * object, or if process terminates), so no mutex-locking should be - * necessary. - */ - if (glsl_type::array_types != NULL) { - _mesa_hash_table_destroy(glsl_type::array_types, NULL); - glsl_type::array_types = NULL; - } - - if (glsl_type::record_types != NULL) { - _mesa_hash_table_destroy(glsl_type::record_types, NULL); - glsl_type::record_types = NULL; - } - - if (glsl_type::interface_types != NULL) { - _mesa_hash_table_destroy(glsl_type::interface_types, NULL); - glsl_type::interface_types = NULL; - } -} - - -glsl_type::glsl_type(const glsl_type *array, unsigned length) : - base_type(GLSL_TYPE_ARRAY), - sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), - sampler_type(0), interface_packing(0), - vector_elements(0), matrix_columns(0), - length(length), name(NULL) -{ - this->fields.array = array; - /* Inherit the gl type of the base. The GL type is used for - * uniform/statevar handling in Mesa and the arrayness of the type - * is represented by the size rather than the type. - */ - this->gl_type = array->gl_type; - - /* Allow a maximum of 10 characters for the array size. This is enough - * for 32-bits of ~0. The extra 3 are for the '[', ']', and terminating - * NUL. - */ - const unsigned name_length = strlen(array->name) + 10 + 3; - - mtx_lock(&glsl_type::mutex); - char *const n = (char *) ralloc_size(this->mem_ctx, name_length); - mtx_unlock(&glsl_type::mutex); - - if (length == 0) - snprintf(n, name_length, "%s[]", array->name); - else { - /* insert outermost dimensions in the correct spot - * otherwise the dimension order will be backwards - */ - const char *pos = strchr(array->name, '['); - if (pos) { - int idx = pos - array->name; - snprintf(n, idx+1, "%s", array->name); - snprintf(n + idx, name_length - idx, "[%u]%s", - length, array->name + idx); - } else { - snprintf(n, name_length, "%s[%u]", array->name, length); - } - } - - this->name = n; -} - - -const glsl_type * -glsl_type::vec(unsigned components) -{ - if (components == 0 || components > 4) - return error_type; - - static const glsl_type *const ts[] = { - float_type, vec2_type, vec3_type, vec4_type - }; - return ts[components - 1]; -} - -const glsl_type * -glsl_type::dvec(unsigned components) -{ - if (components == 0 || components > 4) - return error_type; - - static const glsl_type *const ts[] = { - double_type, dvec2_type, dvec3_type, dvec4_type - }; - return ts[components - 1]; -} - -const glsl_type * -glsl_type::ivec(unsigned components) -{ - if (components == 0 || components > 4) - return error_type; - - static const glsl_type *const ts[] = { - int_type, ivec2_type, ivec3_type, ivec4_type - }; - return ts[components - 1]; -} - - -const glsl_type * -glsl_type::uvec(unsigned components) -{ - if (components == 0 || components > 4) - return error_type; - - static const glsl_type *const ts[] = { - uint_type, uvec2_type, uvec3_type, uvec4_type - }; - return ts[components - 1]; -} - - -const glsl_type * -glsl_type::bvec(unsigned components) -{ - if (components == 0 || components > 4) - return error_type; - - static const glsl_type *const ts[] = { - bool_type, bvec2_type, bvec3_type, bvec4_type - }; - return ts[components - 1]; -} - - -const glsl_type * -glsl_type::get_instance(unsigned base_type, unsigned rows, unsigned columns) -{ - if (base_type == GLSL_TYPE_VOID) - return void_type; - - if ((rows < 1) || (rows > 4) || (columns < 1) || (columns > 4)) - return error_type; - - /* Treat GLSL vectors as Nx1 matrices. - */ - if (columns == 1) { - switch (base_type) { - case GLSL_TYPE_UINT: - return uvec(rows); - case GLSL_TYPE_INT: - return ivec(rows); - case GLSL_TYPE_FLOAT: - return vec(rows); - case GLSL_TYPE_DOUBLE: - return dvec(rows); - case GLSL_TYPE_BOOL: - return bvec(rows); - default: - return error_type; - } - } else { - if ((base_type != GLSL_TYPE_FLOAT && base_type != GLSL_TYPE_DOUBLE) || (rows == 1)) - return error_type; - - /* GLSL matrix types are named mat{COLUMNS}x{ROWS}. Only the following - * combinations are valid: - * - * 1 2 3 4 - * 1 - * 2 x x x - * 3 x x x - * 4 x x x - */ -#define IDX(c,r) (((c-1)*3) + (r-1)) - - if (base_type == GLSL_TYPE_DOUBLE) { - switch (IDX(columns, rows)) { - case IDX(2,2): return dmat2_type; - case IDX(2,3): return dmat2x3_type; - case IDX(2,4): return dmat2x4_type; - case IDX(3,2): return dmat3x2_type; - case IDX(3,3): return dmat3_type; - case IDX(3,4): return dmat3x4_type; - case IDX(4,2): return dmat4x2_type; - case IDX(4,3): return dmat4x3_type; - case IDX(4,4): return dmat4_type; - default: return error_type; - } - } else { - switch (IDX(columns, rows)) { - case IDX(2,2): return mat2_type; - case IDX(2,3): return mat2x3_type; - case IDX(2,4): return mat2x4_type; - case IDX(3,2): return mat3x2_type; - case IDX(3,3): return mat3_type; - case IDX(3,4): return mat3x4_type; - case IDX(4,2): return mat4x2_type; - case IDX(4,3): return mat4x3_type; - case IDX(4,4): return mat4_type; - default: return error_type; - } - } - } - - assert(!"Should not get here."); - return error_type; -} - -const glsl_type * -glsl_type::get_sampler_instance(enum glsl_sampler_dim dim, - bool shadow, - bool array, - glsl_base_type type) -{ - switch (type) { - case GLSL_TYPE_FLOAT: - switch (dim) { - case GLSL_SAMPLER_DIM_1D: - if (shadow) - return (array ? sampler1DArrayShadow_type : sampler1DShadow_type); - else - return (array ? sampler1DArray_type : sampler1D_type); - case GLSL_SAMPLER_DIM_2D: - if (shadow) - return (array ? sampler2DArrayShadow_type : sampler2DShadow_type); - else - return (array ? sampler2DArray_type : sampler2D_type); - case GLSL_SAMPLER_DIM_3D: - if (shadow || array) - return error_type; - else - return sampler3D_type; - case GLSL_SAMPLER_DIM_CUBE: - if (shadow) - return (array ? samplerCubeArrayShadow_type : samplerCubeShadow_type); - else - return (array ? samplerCubeArray_type : samplerCube_type); - case GLSL_SAMPLER_DIM_RECT: - if (array) - return error_type; - if (shadow) - return sampler2DRectShadow_type; - else - return sampler2DRect_type; - case GLSL_SAMPLER_DIM_BUF: - if (shadow || array) - return error_type; - else - return samplerBuffer_type; - case GLSL_SAMPLER_DIM_MS: - if (shadow) - return error_type; - return (array ? sampler2DMSArray_type : sampler2DMS_type); - case GLSL_SAMPLER_DIM_EXTERNAL: - if (shadow || array) - return error_type; - else - return samplerExternalOES_type; - } - case GLSL_TYPE_INT: - if (shadow) - return error_type; - switch (dim) { - case GLSL_SAMPLER_DIM_1D: - return (array ? isampler1DArray_type : isampler1D_type); - case GLSL_SAMPLER_DIM_2D: - return (array ? isampler2DArray_type : isampler2D_type); - case GLSL_SAMPLER_DIM_3D: - if (array) - return error_type; - return isampler3D_type; - case GLSL_SAMPLER_DIM_CUBE: - return (array ? isamplerCubeArray_type : isamplerCube_type); - case GLSL_SAMPLER_DIM_RECT: - if (array) - return error_type; - return isampler2DRect_type; - case GLSL_SAMPLER_DIM_BUF: - if (array) - return error_type; - return isamplerBuffer_type; - case GLSL_SAMPLER_DIM_MS: - return (array ? isampler2DMSArray_type : isampler2DMS_type); - case GLSL_SAMPLER_DIM_EXTERNAL: - return error_type; - } - case GLSL_TYPE_UINT: - if (shadow) - return error_type; - switch (dim) { - case GLSL_SAMPLER_DIM_1D: - return (array ? usampler1DArray_type : usampler1D_type); - case GLSL_SAMPLER_DIM_2D: - return (array ? usampler2DArray_type : usampler2D_type); - case GLSL_SAMPLER_DIM_3D: - if (array) - return error_type; - return usampler3D_type; - case GLSL_SAMPLER_DIM_CUBE: - return (array ? usamplerCubeArray_type : usamplerCube_type); - case GLSL_SAMPLER_DIM_RECT: - if (array) - return error_type; - return usampler2DRect_type; - case GLSL_SAMPLER_DIM_BUF: - if (array) - return error_type; - return usamplerBuffer_type; - case GLSL_SAMPLER_DIM_MS: - return (array ? usampler2DMSArray_type : usampler2DMS_type); - case GLSL_SAMPLER_DIM_EXTERNAL: - return error_type; - } - default: - return error_type; - } - - unreachable("switch statement above should be complete"); -} - -const glsl_type * -glsl_type::get_image_instance(enum glsl_sampler_dim dim, - bool array, glsl_base_type type) -{ - switch (type) { - case GLSL_TYPE_FLOAT: - switch (dim) { - case GLSL_SAMPLER_DIM_1D: - return (array ? image1DArray_type : image1D_type); - case GLSL_SAMPLER_DIM_2D: - return (array ? image2DArray_type : image2D_type); - case GLSL_SAMPLER_DIM_3D: - return image3D_type; - case GLSL_SAMPLER_DIM_CUBE: - return (array ? imageCubeArray_type : imageCube_type); - case GLSL_SAMPLER_DIM_RECT: - if (array) - return error_type; - else - return image2DRect_type; - case GLSL_SAMPLER_DIM_BUF: - if (array) - return error_type; - else - return imageBuffer_type; - case GLSL_SAMPLER_DIM_MS: - return (array ? image2DMSArray_type : image2DMS_type); - case GLSL_SAMPLER_DIM_EXTERNAL: - return error_type; - } - case GLSL_TYPE_INT: - switch (dim) { - case GLSL_SAMPLER_DIM_1D: - return (array ? iimage1DArray_type : iimage1D_type); - case GLSL_SAMPLER_DIM_2D: - return (array ? iimage2DArray_type : iimage2D_type); - case GLSL_SAMPLER_DIM_3D: - if (array) - return error_type; - return iimage3D_type; - case GLSL_SAMPLER_DIM_CUBE: - return (array ? iimageCubeArray_type : iimageCube_type); - case GLSL_SAMPLER_DIM_RECT: - if (array) - return error_type; - return iimage2DRect_type; - case GLSL_SAMPLER_DIM_BUF: - if (array) - return error_type; - return iimageBuffer_type; - case GLSL_SAMPLER_DIM_MS: - return (array ? iimage2DMSArray_type : iimage2DMS_type); - case GLSL_SAMPLER_DIM_EXTERNAL: - return error_type; - } - case GLSL_TYPE_UINT: - switch (dim) { - case GLSL_SAMPLER_DIM_1D: - return (array ? uimage1DArray_type : uimage1D_type); - case GLSL_SAMPLER_DIM_2D: - return (array ? uimage2DArray_type : uimage2D_type); - case GLSL_SAMPLER_DIM_3D: - if (array) - return error_type; - return uimage3D_type; - case GLSL_SAMPLER_DIM_CUBE: - return (array ? uimageCubeArray_type : uimageCube_type); - case GLSL_SAMPLER_DIM_RECT: - if (array) - return error_type; - return uimage2DRect_type; - case GLSL_SAMPLER_DIM_BUF: - if (array) - return error_type; - return uimageBuffer_type; - case GLSL_SAMPLER_DIM_MS: - return (array ? uimage2DMSArray_type : uimage2DMS_type); - case GLSL_SAMPLER_DIM_EXTERNAL: - return error_type; - } - default: - return error_type; - } - - unreachable("switch statement above should be complete"); -} - -const glsl_type * -glsl_type::get_array_instance(const glsl_type *base, unsigned array_size) -{ - /* Generate a name using the base type pointer in the key. This is - * done because the name of the base type may not be unique across - * shaders. For example, two shaders may have different record types - * named 'foo'. - */ - char key[128]; - snprintf(key, sizeof(key), "%p[%u]", (void *) base, array_size); - - mtx_lock(&glsl_type::mutex); - - if (array_types == NULL) { - array_types = _mesa_hash_table_create(NULL, _mesa_key_hash_string, - _mesa_key_string_equal); - } - - const struct hash_entry *entry = _mesa_hash_table_search(array_types, key); - if (entry == NULL) { - mtx_unlock(&glsl_type::mutex); - const glsl_type *t = new glsl_type(base, array_size); - mtx_lock(&glsl_type::mutex); - - entry = _mesa_hash_table_insert(array_types, - ralloc_strdup(mem_ctx, key), - (void *) t); - } - - assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_ARRAY); - assert(((glsl_type *) entry->data)->length == array_size); - assert(((glsl_type *) entry->data)->fields.array == base); - - mtx_unlock(&glsl_type::mutex); - - return (glsl_type *) entry->data; -} - - -bool -glsl_type::record_compare(const glsl_type *b) const -{ - if (this->length != b->length) - return false; - - if (this->interface_packing != b->interface_packing) - return false; - - /* From the GLSL 4.20 specification (Sec 4.2): - * - * "Structures must have the same name, sequence of type names, and - * type definitions, and field names to be considered the same type." - * - * GLSL ES behaves the same (Ver 1.00 Sec 4.2.4, Ver 3.00 Sec 4.2.5). - * - * Note that we cannot force type name check when comparing unnamed - * structure types, these have a unique name assigned during parsing. - */ - if (!this->is_anonymous() && !b->is_anonymous()) - if (strcmp(this->name, b->name) != 0) - return false; - - for (unsigned i = 0; i < this->length; i++) { - if (this->fields.structure[i].type != b->fields.structure[i].type) - return false; - if (strcmp(this->fields.structure[i].name, - b->fields.structure[i].name) != 0) - return false; - if (this->fields.structure[i].matrix_layout - != b->fields.structure[i].matrix_layout) - return false; - if (this->fields.structure[i].location - != b->fields.structure[i].location) - return false; - if (this->fields.structure[i].interpolation - != b->fields.structure[i].interpolation) - return false; - if (this->fields.structure[i].centroid - != b->fields.structure[i].centroid) - return false; - if (this->fields.structure[i].sample - != b->fields.structure[i].sample) - return false; - if (this->fields.structure[i].patch - != b->fields.structure[i].patch) - return false; - if (this->fields.structure[i].image_read_only - != b->fields.structure[i].image_read_only) - return false; - if (this->fields.structure[i].image_write_only - != b->fields.structure[i].image_write_only) - return false; - if (this->fields.structure[i].image_coherent - != b->fields.structure[i].image_coherent) - return false; - if (this->fields.structure[i].image_volatile - != b->fields.structure[i].image_volatile) - return false; - if (this->fields.structure[i].image_restrict - != b->fields.structure[i].image_restrict) - return false; - if (this->fields.structure[i].precision - != b->fields.structure[i].precision) - return false; - } - - return true; -} - - -bool -glsl_type::record_key_compare(const void *a, const void *b) -{ - const glsl_type *const key1 = (glsl_type *) a; - const glsl_type *const key2 = (glsl_type *) b; - - return strcmp(key1->name, key2->name) == 0 && key1->record_compare(key2); -} - - -/** - * Generate an integer hash value for a glsl_type structure type. - */ -unsigned -glsl_type::record_key_hash(const void *a) -{ - const glsl_type *const key = (glsl_type *) a; - uintptr_t hash = key->length; - unsigned retval; - - for (unsigned i = 0; i < key->length; i++) { - /* casting pointer to uintptr_t */ - hash = (hash * 13 ) + (uintptr_t) key->fields.structure[i].type; - } - - if (sizeof(hash) == 8) - retval = (hash & 0xffffffff) ^ ((uint64_t) hash >> 32); - else - retval = hash; - - return retval; -} - - -const glsl_type * -glsl_type::get_record_instance(const glsl_struct_field *fields, - unsigned num_fields, - const char *name) -{ - const glsl_type key(fields, num_fields, name); - - mtx_lock(&glsl_type::mutex); - - if (record_types == NULL) { - record_types = _mesa_hash_table_create(NULL, record_key_hash, - record_key_compare); - } - - const struct hash_entry *entry = _mesa_hash_table_search(record_types, - &key); - if (entry == NULL) { - mtx_unlock(&glsl_type::mutex); - const glsl_type *t = new glsl_type(fields, num_fields, name); - mtx_lock(&glsl_type::mutex); - - entry = _mesa_hash_table_insert(record_types, t, (void *) t); - } - - assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_STRUCT); - assert(((glsl_type *) entry->data)->length == num_fields); - assert(strcmp(((glsl_type *) entry->data)->name, name) == 0); - - mtx_unlock(&glsl_type::mutex); - - return (glsl_type *) entry->data; -} - - -const glsl_type * -glsl_type::get_interface_instance(const glsl_struct_field *fields, - unsigned num_fields, - enum glsl_interface_packing packing, - const char *block_name) -{ - const glsl_type key(fields, num_fields, packing, block_name); - - mtx_lock(&glsl_type::mutex); - - if (interface_types == NULL) { - interface_types = _mesa_hash_table_create(NULL, record_key_hash, - record_key_compare); - } - - const struct hash_entry *entry = _mesa_hash_table_search(interface_types, - &key); - if (entry == NULL) { - mtx_unlock(&glsl_type::mutex); - const glsl_type *t = new glsl_type(fields, num_fields, - packing, block_name); - mtx_lock(&glsl_type::mutex); - - entry = _mesa_hash_table_insert(interface_types, t, (void *) t); - } - - assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_INTERFACE); - assert(((glsl_type *) entry->data)->length == num_fields); - assert(strcmp(((glsl_type *) entry->data)->name, block_name) == 0); - - mtx_unlock(&glsl_type::mutex); - - return (glsl_type *) entry->data; -} - -const glsl_type * -glsl_type::get_subroutine_instance(const char *subroutine_name) -{ - const glsl_type key(subroutine_name); - - mtx_lock(&glsl_type::mutex); - - if (subroutine_types == NULL) { - subroutine_types = _mesa_hash_table_create(NULL, record_key_hash, - record_key_compare); - } - - const struct hash_entry *entry = _mesa_hash_table_search(subroutine_types, - &key); - if (entry == NULL) { - mtx_unlock(&glsl_type::mutex); - const glsl_type *t = new glsl_type(subroutine_name); - mtx_lock(&glsl_type::mutex); - - entry = _mesa_hash_table_insert(subroutine_types, t, (void *) t); - } - - assert(((glsl_type *) entry->data)->base_type == GLSL_TYPE_SUBROUTINE); - assert(strcmp(((glsl_type *) entry->data)->name, subroutine_name) == 0); - - mtx_unlock(&glsl_type::mutex); - - return (glsl_type *) entry->data; -} - - -static bool -function_key_compare(const void *a, const void *b) -{ - const glsl_type *const key1 = (glsl_type *) a; - const glsl_type *const key2 = (glsl_type *) b; - - if (key1->length != key2->length) - return 1; - - return memcmp(key1->fields.parameters, key2->fields.parameters, - (key1->length + 1) * sizeof(*key1->fields.parameters)) == 0; -} - - -static uint32_t -function_key_hash(const void *a) -{ - const glsl_type *const key = (glsl_type *) a; - char hash_key[128]; - unsigned size = 0; - - size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length); - - for (unsigned i = 0; i < key->length; i++) { - if (size >= sizeof(hash_key)) - break; - - size += snprintf(& hash_key[size], sizeof(hash_key) - size, - "%p", (void *) key->fields.structure[i].type); - } - - return _mesa_hash_string(hash_key); -} - -const glsl_type * -glsl_type::get_function_instance(const glsl_type *return_type, - const glsl_function_param *params, - unsigned num_params) -{ - const glsl_type key(return_type, params, num_params); - - mtx_lock(&glsl_type::mutex); - - if (function_types == NULL) { - function_types = _mesa_hash_table_create(NULL, function_key_hash, - function_key_compare); - } - - struct hash_entry *entry = _mesa_hash_table_search(function_types, &key); - if (entry == NULL) { - mtx_unlock(&glsl_type::mutex); - const glsl_type *t = new glsl_type(return_type, params, num_params); - mtx_lock(&glsl_type::mutex); - - entry = _mesa_hash_table_insert(function_types, t, (void *) t); - } - - const glsl_type *t = (const glsl_type *)entry->data; - - assert(t->base_type == GLSL_TYPE_FUNCTION); - assert(t->length == num_params); - - mtx_unlock(&glsl_type::mutex); - - return t; -} - - -const glsl_type * -glsl_type::get_mul_type(const glsl_type *type_a, const glsl_type *type_b) -{ - if (type_a == type_b) { - return type_a; - } else if (type_a->is_matrix() && type_b->is_matrix()) { - /* Matrix multiply. The columns of A must match the rows of B. Given - * the other previously tested constraints, this means the vector type - * of a row from A must be the same as the vector type of a column from - * B. - */ - if (type_a->row_type() == type_b->column_type()) { - /* The resulting matrix has the number of columns of matrix B and - * the number of rows of matrix A. We get the row count of A by - * looking at the size of a vector that makes up a column. The - * transpose (size of a row) is done for B. - */ - const glsl_type *const type = - get_instance(type_a->base_type, - type_a->column_type()->vector_elements, - type_b->row_type()->vector_elements); - assert(type != error_type); - - return type; - } - } else if (type_a->is_matrix()) { - /* A is a matrix and B is a column vector. Columns of A must match - * rows of B. Given the other previously tested constraints, this - * means the vector type of a row from A must be the same as the - * vector the type of B. - */ - if (type_a->row_type() == type_b) { - /* The resulting vector has a number of elements equal to - * the number of rows of matrix A. */ - const glsl_type *const type = - get_instance(type_a->base_type, - type_a->column_type()->vector_elements, - 1); - assert(type != error_type); - - return type; - } - } else { - assert(type_b->is_matrix()); - - /* A is a row vector and B is a matrix. Columns of A must match rows - * of B. Given the other previously tested constraints, this means - * the type of A must be the same as the vector type of a column from - * B. - */ - if (type_a == type_b->column_type()) { - /* The resulting vector has a number of elements equal to - * the number of columns of matrix B. */ - const glsl_type *const type = - get_instance(type_a->base_type, - type_b->row_type()->vector_elements, - 1); - assert(type != error_type); - - return type; - } - } - - return error_type; -} - - -const glsl_type * -glsl_type::field_type(const char *name) const -{ - if (this->base_type != GLSL_TYPE_STRUCT - && this->base_type != GLSL_TYPE_INTERFACE) - return error_type; - - for (unsigned i = 0; i < this->length; i++) { - if (strcmp(name, this->fields.structure[i].name) == 0) - return this->fields.structure[i].type; - } - - return error_type; -} - - -int -glsl_type::field_index(const char *name) const -{ - if (this->base_type != GLSL_TYPE_STRUCT - && this->base_type != GLSL_TYPE_INTERFACE) - return -1; - - for (unsigned i = 0; i < this->length; i++) { - if (strcmp(name, this->fields.structure[i].name) == 0) - return i; - } - - return -1; -} - - -unsigned -glsl_type::component_slots() const -{ - switch (this->base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - return this->components(); - - case GLSL_TYPE_DOUBLE: - return 2 * this->components(); - - case GLSL_TYPE_STRUCT: - case GLSL_TYPE_INTERFACE: { - unsigned size = 0; - - for (unsigned i = 0; i < this->length; i++) - size += this->fields.structure[i].type->component_slots(); - - return size; - } - - case GLSL_TYPE_ARRAY: - return this->length * this->fields.array->component_slots(); - - case GLSL_TYPE_IMAGE: - return 1; - case GLSL_TYPE_SUBROUTINE: - return 1; - - case GLSL_TYPE_FUNCTION: - case GLSL_TYPE_SAMPLER: - case GLSL_TYPE_ATOMIC_UINT: - case GLSL_TYPE_VOID: - case GLSL_TYPE_ERROR: - break; - } - - return 0; -} - -unsigned -glsl_type::record_location_offset(unsigned length) const -{ - unsigned offset = 0; - const glsl_type *t = this->without_array(); - if (t->is_record()) { - assert(length <= t->length); - - for (unsigned i = 0; i < length; i++) { - const glsl_type *st = t->fields.structure[i].type; - const glsl_type *wa = st->without_array(); - if (wa->is_record()) { - unsigned r_offset = wa->record_location_offset(wa->length); - offset += st->is_array() ? - st->arrays_of_arrays_size() * r_offset : r_offset; - } else if (st->is_array() && st->fields.array->is_array()) { - unsigned outer_array_size = st->length; - const glsl_type *base_type = st->fields.array; - - /* For arrays of arrays the outer arrays take up a uniform - * slot for each element. The innermost array elements share a - * single slot so we ignore the innermost array when calculating - * the offset. - */ - while (base_type->fields.array->is_array()) { - outer_array_size = outer_array_size * base_type->length; - base_type = base_type->fields.array; - } - offset += outer_array_size; - } else { - /* We dont worry about arrays here because unless the array - * contains a structure or another array it only takes up a single - * uniform slot. - */ - offset += 1; - } - } - } - return offset; -} - -unsigned -glsl_type::uniform_locations() const -{ - unsigned size = 0; - - switch (this->base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_SAMPLER: - case GLSL_TYPE_IMAGE: - case GLSL_TYPE_SUBROUTINE: - return 1; - - case GLSL_TYPE_STRUCT: - case GLSL_TYPE_INTERFACE: - for (unsigned i = 0; i < this->length; i++) - size += this->fields.structure[i].type->uniform_locations(); - return size; - case GLSL_TYPE_ARRAY: - return this->length * this->fields.array->uniform_locations(); - default: - return 0; - } -} - -bool -glsl_type::can_implicitly_convert_to(const glsl_type *desired, - _mesa_glsl_parse_state *state) const -{ - if (this == desired) - return true; - - /* There is no conversion among matrix types. */ - if (this->matrix_columns > 1 || desired->matrix_columns > 1) - return false; - - /* Vector size must match. */ - if (this->vector_elements != desired->vector_elements) - return false; - - /* int and uint can be converted to float. */ - if (desired->is_float() && this->is_integer()) - return true; - - /* With GLSL 4.0 / ARB_gpu_shader5, int can be converted to uint. - * Note that state may be NULL here, when resolving function calls in the - * linker. By this time, all the state-dependent checks have already - * happened though, so allow anything that's allowed in any shader version. */ - if ((!state || state->is_version(400, 0) || state->ARB_gpu_shader5_enable) && - desired->base_type == GLSL_TYPE_UINT && this->base_type == GLSL_TYPE_INT) - return true; - - /* No implicit conversions from double. */ - if ((!state || state->has_double()) && this->is_double()) - return false; - - /* Conversions from different types to double. */ - if ((!state || state->has_double()) && desired->is_double()) { - if (this->is_float()) - return true; - if (this->is_integer()) - return true; - } - - return false; -} - -unsigned -glsl_type::std140_base_alignment(bool row_major) const -{ - unsigned N = is_double() ? 8 : 4; - - /* (1) If the member is a scalar consuming <N> basic machine units, the - * base alignment is <N>. - * - * (2) If the member is a two- or four-component vector with components - * consuming <N> basic machine units, the base alignment is 2<N> or - * 4<N>, respectively. - * - * (3) If the member is a three-component vector with components consuming - * <N> basic machine units, the base alignment is 4<N>. - */ - if (this->is_scalar() || this->is_vector()) { - switch (this->vector_elements) { - case 1: - return N; - case 2: - return 2 * N; - case 3: - case 4: - return 4 * N; - } - } - - /* (4) If the member is an array of scalars or vectors, the base alignment - * and array stride are set to match the base alignment of a single - * array element, according to rules (1), (2), and (3), and rounded up - * to the base alignment of a vec4. The array may have padding at the - * end; the base offset of the member following the array is rounded up - * to the next multiple of the base alignment. - * - * (6) If the member is an array of <S> column-major matrices with <C> - * columns and <R> rows, the matrix is stored identically to a row of - * <S>*<C> column vectors with <R> components each, according to rule - * (4). - * - * (8) If the member is an array of <S> row-major matrices with <C> columns - * and <R> rows, the matrix is stored identically to a row of <S>*<R> - * row vectors with <C> components each, according to rule (4). - * - * (10) If the member is an array of <S> structures, the <S> elements of - * the array are laid out in order, according to rule (9). - */ - if (this->is_array()) { - if (this->fields.array->is_scalar() || - this->fields.array->is_vector() || - this->fields.array->is_matrix()) { - return MAX2(this->fields.array->std140_base_alignment(row_major), 16); - } else { - assert(this->fields.array->is_record() || - this->fields.array->is_array()); - return this->fields.array->std140_base_alignment(row_major); - } - } - - /* (5) If the member is a column-major matrix with <C> columns and - * <R> rows, the matrix is stored identically to an array of - * <C> column vectors with <R> components each, according to - * rule (4). - * - * (7) If the member is a row-major matrix with <C> columns and <R> - * rows, the matrix is stored identically to an array of <R> - * row vectors with <C> components each, according to rule (4). - */ - if (this->is_matrix()) { - const struct glsl_type *vec_type, *array_type; - int c = this->matrix_columns; - int r = this->vector_elements; - - if (row_major) { - vec_type = get_instance(base_type, c, 1); - array_type = glsl_type::get_array_instance(vec_type, r); - } else { - vec_type = get_instance(base_type, r, 1); - array_type = glsl_type::get_array_instance(vec_type, c); - } - - return array_type->std140_base_alignment(false); - } - - /* (9) If the member is a structure, the base alignment of the - * structure is <N>, where <N> is the largest base alignment - * value of any of its members, and rounded up to the base - * alignment of a vec4. The individual members of this - * sub-structure are then assigned offsets by applying this set - * of rules recursively, where the base offset of the first - * member of the sub-structure is equal to the aligned offset - * of the structure. The structure may have padding at the end; - * the base offset of the member following the sub-structure is - * rounded up to the next multiple of the base alignment of the - * structure. - */ - if (this->is_record()) { - unsigned base_alignment = 16; - for (unsigned i = 0; i < this->length; i++) { - bool field_row_major = row_major; - const enum glsl_matrix_layout matrix_layout = - glsl_matrix_layout(this->fields.structure[i].matrix_layout); - if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { - field_row_major = true; - } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { - field_row_major = false; - } - - const struct glsl_type *field_type = this->fields.structure[i].type; - base_alignment = MAX2(base_alignment, - field_type->std140_base_alignment(field_row_major)); - } - return base_alignment; - } - - assert(!"not reached"); - return -1; -} - -unsigned -glsl_type::std140_size(bool row_major) const -{ - unsigned N = is_double() ? 8 : 4; - - /* (1) If the member is a scalar consuming <N> basic machine units, the - * base alignment is <N>. - * - * (2) If the member is a two- or four-component vector with components - * consuming <N> basic machine units, the base alignment is 2<N> or - * 4<N>, respectively. - * - * (3) If the member is a three-component vector with components consuming - * <N> basic machine units, the base alignment is 4<N>. - */ - if (this->is_scalar() || this->is_vector()) { - return this->vector_elements * N; - } - - /* (5) If the member is a column-major matrix with <C> columns and - * <R> rows, the matrix is stored identically to an array of - * <C> column vectors with <R> components each, according to - * rule (4). - * - * (6) If the member is an array of <S> column-major matrices with <C> - * columns and <R> rows, the matrix is stored identically to a row of - * <S>*<C> column vectors with <R> components each, according to rule - * (4). - * - * (7) If the member is a row-major matrix with <C> columns and <R> - * rows, the matrix is stored identically to an array of <R> - * row vectors with <C> components each, according to rule (4). - * - * (8) If the member is an array of <S> row-major matrices with <C> columns - * and <R> rows, the matrix is stored identically to a row of <S>*<R> - * row vectors with <C> components each, according to rule (4). - */ - if (this->without_array()->is_matrix()) { - const struct glsl_type *element_type; - const struct glsl_type *vec_type; - unsigned int array_len; - - if (this->is_array()) { - element_type = this->without_array(); - array_len = this->arrays_of_arrays_size(); - } else { - element_type = this; - array_len = 1; - } - - if (row_major) { - vec_type = get_instance(element_type->base_type, - element_type->matrix_columns, 1); - - array_len *= element_type->vector_elements; - } else { - vec_type = get_instance(element_type->base_type, - element_type->vector_elements, 1); - array_len *= element_type->matrix_columns; - } - const glsl_type *array_type = glsl_type::get_array_instance(vec_type, - array_len); - - return array_type->std140_size(false); - } - - /* (4) If the member is an array of scalars or vectors, the base alignment - * and array stride are set to match the base alignment of a single - * array element, according to rules (1), (2), and (3), and rounded up - * to the base alignment of a vec4. The array may have padding at the - * end; the base offset of the member following the array is rounded up - * to the next multiple of the base alignment. - * - * (10) If the member is an array of <S> structures, the <S> elements of - * the array are laid out in order, according to rule (9). - */ - if (this->is_array()) { - if (this->without_array()->is_record()) { - return this->arrays_of_arrays_size() * - this->without_array()->std140_size(row_major); - } else { - unsigned element_base_align = - this->without_array()->std140_base_alignment(row_major); - return this->arrays_of_arrays_size() * MAX2(element_base_align, 16); - } - } - - /* (9) If the member is a structure, the base alignment of the - * structure is <N>, where <N> is the largest base alignment - * value of any of its members, and rounded up to the base - * alignment of a vec4. The individual members of this - * sub-structure are then assigned offsets by applying this set - * of rules recursively, where the base offset of the first - * member of the sub-structure is equal to the aligned offset - * of the structure. The structure may have padding at the end; - * the base offset of the member following the sub-structure is - * rounded up to the next multiple of the base alignment of the - * structure. - */ - if (this->is_record() || this->is_interface()) { - unsigned size = 0; - unsigned max_align = 0; - - for (unsigned i = 0; i < this->length; i++) { - bool field_row_major = row_major; - const enum glsl_matrix_layout matrix_layout = - glsl_matrix_layout(this->fields.structure[i].matrix_layout); - if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { - field_row_major = true; - } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { - field_row_major = false; - } - - const struct glsl_type *field_type = this->fields.structure[i].type; - unsigned align = field_type->std140_base_alignment(field_row_major); - - /* Ignore unsized arrays when calculating size */ - if (field_type->is_unsized_array()) - continue; - - size = glsl_align(size, align); - size += field_type->std140_size(field_row_major); - - max_align = MAX2(align, max_align); - - if (field_type->is_record() && (i + 1 < this->length)) - size = glsl_align(size, 16); - } - size = glsl_align(size, MAX2(max_align, 16)); - return size; - } - - assert(!"not reached"); - return -1; -} - -unsigned -glsl_type::std430_base_alignment(bool row_major) const -{ - - unsigned N = is_double() ? 8 : 4; - - /* (1) If the member is a scalar consuming <N> basic machine units, the - * base alignment is <N>. - * - * (2) If the member is a two- or four-component vector with components - * consuming <N> basic machine units, the base alignment is 2<N> or - * 4<N>, respectively. - * - * (3) If the member is a three-component vector with components consuming - * <N> basic machine units, the base alignment is 4<N>. - */ - if (this->is_scalar() || this->is_vector()) { - switch (this->vector_elements) { - case 1: - return N; - case 2: - return 2 * N; - case 3: - case 4: - return 4 * N; - } - } - - /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout": - * - * "When using the std430 storage layout, shader storage blocks will be - * laid out in buffer storage identically to uniform and shader storage - * blocks using the std140 layout, except that the base alignment and - * stride of arrays of scalars and vectors in rule 4 and of structures - * in rule 9 are not rounded up a multiple of the base alignment of a vec4. - */ - - /* (1) If the member is a scalar consuming <N> basic machine units, the - * base alignment is <N>. - * - * (2) If the member is a two- or four-component vector with components - * consuming <N> basic machine units, the base alignment is 2<N> or - * 4<N>, respectively. - * - * (3) If the member is a three-component vector with components consuming - * <N> basic machine units, the base alignment is 4<N>. - */ - if (this->is_array()) - return this->fields.array->std430_base_alignment(row_major); - - /* (5) If the member is a column-major matrix with <C> columns and - * <R> rows, the matrix is stored identically to an array of - * <C> column vectors with <R> components each, according to - * rule (4). - * - * (7) If the member is a row-major matrix with <C> columns and <R> - * rows, the matrix is stored identically to an array of <R> - * row vectors with <C> components each, according to rule (4). - */ - if (this->is_matrix()) { - const struct glsl_type *vec_type, *array_type; - int c = this->matrix_columns; - int r = this->vector_elements; - - if (row_major) { - vec_type = get_instance(base_type, c, 1); - array_type = glsl_type::get_array_instance(vec_type, r); - } else { - vec_type = get_instance(base_type, r, 1); - array_type = glsl_type::get_array_instance(vec_type, c); - } - - return array_type->std430_base_alignment(false); - } - - /* (9) If the member is a structure, the base alignment of the - * structure is <N>, where <N> is the largest base alignment - * value of any of its members, and rounded up to the base - * alignment of a vec4. The individual members of this - * sub-structure are then assigned offsets by applying this set - * of rules recursively, where the base offset of the first - * member of the sub-structure is equal to the aligned offset - * of the structure. The structure may have padding at the end; - * the base offset of the member following the sub-structure is - * rounded up to the next multiple of the base alignment of the - * structure. - */ - if (this->is_record()) { - unsigned base_alignment = 0; - for (unsigned i = 0; i < this->length; i++) { - bool field_row_major = row_major; - const enum glsl_matrix_layout matrix_layout = - glsl_matrix_layout(this->fields.structure[i].matrix_layout); - if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { - field_row_major = true; - } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { - field_row_major = false; - } - - const struct glsl_type *field_type = this->fields.structure[i].type; - base_alignment = MAX2(base_alignment, - field_type->std430_base_alignment(field_row_major)); - } - assert(base_alignment > 0); - return base_alignment; - } - assert(!"not reached"); - return -1; -} - -unsigned -glsl_type::std430_array_stride(bool row_major) const -{ - unsigned N = is_double() ? 8 : 4; - - /* Notice that the array stride of a vec3 is not 3 * N but 4 * N. - * See OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout" - * - * (3) If the member is a three-component vector with components consuming - * <N> basic machine units, the base alignment is 4<N>. - */ - if (this->is_vector() && this->vector_elements == 3) - return 4 * N; - - /* By default use std430_size(row_major) */ - return this->std430_size(row_major); -} - -unsigned -glsl_type::std430_size(bool row_major) const -{ - unsigned N = is_double() ? 8 : 4; - - /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout": - * - * "When using the std430 storage layout, shader storage blocks will be - * laid out in buffer storage identically to uniform and shader storage - * blocks using the std140 layout, except that the base alignment and - * stride of arrays of scalars and vectors in rule 4 and of structures - * in rule 9 are not rounded up a multiple of the base alignment of a vec4. - */ - if (this->is_scalar() || this->is_vector()) - return this->vector_elements * N; - - if (this->without_array()->is_matrix()) { - const struct glsl_type *element_type; - const struct glsl_type *vec_type; - unsigned int array_len; - - if (this->is_array()) { - element_type = this->without_array(); - array_len = this->arrays_of_arrays_size(); - } else { - element_type = this; - array_len = 1; - } - - if (row_major) { - vec_type = get_instance(element_type->base_type, - element_type->matrix_columns, 1); - - array_len *= element_type->vector_elements; - } else { - vec_type = get_instance(element_type->base_type, - element_type->vector_elements, 1); - array_len *= element_type->matrix_columns; - } - const glsl_type *array_type = glsl_type::get_array_instance(vec_type, - array_len); - - return array_type->std430_size(false); - } - - if (this->is_array()) { - if (this->without_array()->is_record()) - return this->arrays_of_arrays_size() * - this->without_array()->std430_size(row_major); - else - return this->arrays_of_arrays_size() * - this->without_array()->std430_base_alignment(row_major); - } - - if (this->is_record() || this->is_interface()) { - unsigned size = 0; - unsigned max_align = 0; - - for (unsigned i = 0; i < this->length; i++) { - bool field_row_major = row_major; - const enum glsl_matrix_layout matrix_layout = - glsl_matrix_layout(this->fields.structure[i].matrix_layout); - if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) { - field_row_major = true; - } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) { - field_row_major = false; - } - - const struct glsl_type *field_type = this->fields.structure[i].type; - unsigned align = field_type->std430_base_alignment(field_row_major); - size = glsl_align(size, align); - size += field_type->std430_size(field_row_major); - - max_align = MAX2(align, max_align); - } - size = glsl_align(size, max_align); - return size; - } - - assert(!"not reached"); - return -1; -} - -unsigned -glsl_type::count_attribute_slots(bool vertex_input_slots) const -{ - /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec: - * - * "A scalar input counts the same amount against this limit as a vec4, - * so applications may want to consider packing groups of four - * unrelated float inputs together into a vector to better utilize the - * capabilities of the underlying hardware. A matrix input will use up - * multiple locations. The number of locations used will equal the - * number of columns in the matrix." - * - * The spec does not explicitly say how arrays are counted. However, it - * should be safe to assume the total number of slots consumed by an array - * is the number of entries in the array multiplied by the number of slots - * consumed by a single element of the array. - * - * The spec says nothing about how structs are counted, because vertex - * attributes are not allowed to be (or contain) structs. However, Mesa - * allows varying structs, the number of varying slots taken up by a - * varying struct is simply equal to the sum of the number of slots taken - * up by each element. - * - * Doubles are counted different depending on whether they are vertex - * inputs or everything else. Vertex inputs from ARB_vertex_attrib_64bit - * take one location no matter what size they are, otherwise dvec3/4 - * take two locations. - */ - switch (this->base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - return this->matrix_columns; - case GLSL_TYPE_DOUBLE: - if (this->vector_elements > 2 && !vertex_input_slots) - return this->matrix_columns * 2; - else - return this->matrix_columns; - case GLSL_TYPE_STRUCT: - case GLSL_TYPE_INTERFACE: { - unsigned size = 0; - - for (unsigned i = 0; i < this->length; i++) - size += this->fields.structure[i].type->count_attribute_slots(vertex_input_slots); - - return size; - } - - case GLSL_TYPE_ARRAY: - return this->length * this->fields.array->count_attribute_slots(vertex_input_slots); - - case GLSL_TYPE_FUNCTION: - case GLSL_TYPE_SAMPLER: - case GLSL_TYPE_IMAGE: - case GLSL_TYPE_ATOMIC_UINT: - case GLSL_TYPE_VOID: - case GLSL_TYPE_SUBROUTINE: - case GLSL_TYPE_ERROR: - break; - } - - assert(!"Unexpected type in count_attribute_slots()"); - - return 0; -} - -int -glsl_type::coordinate_components() const -{ - int size; - - switch (sampler_dimensionality) { - case GLSL_SAMPLER_DIM_1D: - case GLSL_SAMPLER_DIM_BUF: - size = 1; - break; - case GLSL_SAMPLER_DIM_2D: - case GLSL_SAMPLER_DIM_RECT: - case GLSL_SAMPLER_DIM_MS: - case GLSL_SAMPLER_DIM_EXTERNAL: - size = 2; - break; - case GLSL_SAMPLER_DIM_3D: - case GLSL_SAMPLER_DIM_CUBE: - size = 3; - break; - default: - assert(!"Should not get here."); - size = 1; - break; - } - - /* Array textures need an additional component for the array index, except - * for cubemap array images that behave like a 2D array of interleaved - * cubemap faces. - */ - if (sampler_array && - !(base_type == GLSL_TYPE_IMAGE && - sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE)) - size += 1; - - return size; -} - -/** - * Declarations of type flyweights (glsl_type::_foo_type) and - * convenience pointers (glsl_type::foo_type). - * @{ - */ -#define DECL_TYPE(NAME, ...) \ - const glsl_type glsl_type::_##NAME##_type = glsl_type(__VA_ARGS__, #NAME); \ - const glsl_type *const glsl_type::NAME##_type = &glsl_type::_##NAME##_type; - -#define STRUCT_TYPE(NAME) - -#include "builtin_type_macros.h" -/** @} */ diff --git a/src/glsl/nir/glsl_types.h b/src/glsl/nir/glsl_types.h deleted file mode 100644 index ff8dcc7a5f6..00000000000 --- a/src/glsl/nir/glsl_types.h +++ /dev/null @@ -1,913 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright © 2009 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#pragma once -#ifndef GLSL_TYPES_H -#define GLSL_TYPES_H - -#include <string.h> -#include <assert.h> - -#ifdef __cplusplus -extern "C" { -#endif - -struct _mesa_glsl_parse_state; -struct glsl_symbol_table; - -extern void -_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state); - -extern void -_mesa_glsl_release_types(void); - -#ifdef __cplusplus -} -#endif - -enum glsl_base_type { - GLSL_TYPE_UINT = 0, - GLSL_TYPE_INT, - GLSL_TYPE_FLOAT, - GLSL_TYPE_DOUBLE, - GLSL_TYPE_BOOL, - GLSL_TYPE_SAMPLER, - GLSL_TYPE_IMAGE, - GLSL_TYPE_ATOMIC_UINT, - GLSL_TYPE_STRUCT, - GLSL_TYPE_FUNCTION, - GLSL_TYPE_INTERFACE, - GLSL_TYPE_ARRAY, - GLSL_TYPE_VOID, - GLSL_TYPE_SUBROUTINE, - GLSL_TYPE_ERROR -}; - -enum glsl_sampler_dim { - GLSL_SAMPLER_DIM_1D = 0, - GLSL_SAMPLER_DIM_2D, - GLSL_SAMPLER_DIM_3D, - GLSL_SAMPLER_DIM_CUBE, - GLSL_SAMPLER_DIM_RECT, - GLSL_SAMPLER_DIM_BUF, - GLSL_SAMPLER_DIM_EXTERNAL, - GLSL_SAMPLER_DIM_MS -}; - -enum glsl_interface_packing { - GLSL_INTERFACE_PACKING_STD140, - GLSL_INTERFACE_PACKING_SHARED, - GLSL_INTERFACE_PACKING_PACKED, - GLSL_INTERFACE_PACKING_STD430 -}; - -enum glsl_matrix_layout { - /** - * The layout of the matrix is inherited from the object containing the - * matrix (the top level structure or the uniform block). - */ - GLSL_MATRIX_LAYOUT_INHERITED, - - /** - * Explicit column-major layout - * - * If a uniform block doesn't have an explicit layout set, it will default - * to this layout. - */ - GLSL_MATRIX_LAYOUT_COLUMN_MAJOR, - - /** - * Row-major layout - */ - GLSL_MATRIX_LAYOUT_ROW_MAJOR -}; - -enum { - GLSL_PRECISION_NONE = 0, - GLSL_PRECISION_HIGH, - GLSL_PRECISION_MEDIUM, - GLSL_PRECISION_LOW -}; - -#ifdef __cplusplus -#include "GL/gl.h" -#include "util/ralloc.h" -#include "main/mtypes.h" /* for gl_texture_index, C++'s enum rules are broken */ - -struct glsl_type { - GLenum gl_type; - glsl_base_type base_type; - - unsigned sampler_dimensionality:3; /**< \see glsl_sampler_dim */ - unsigned sampler_shadow:1; - unsigned sampler_array:1; - unsigned sampler_type:2; /**< Type of data returned using this - * sampler or image. Only \c - * GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT, - * and \c GLSL_TYPE_UINT are valid. - */ - unsigned interface_packing:2; - - /* Callers of this ralloc-based new need not call delete. It's - * easier to just ralloc_free 'mem_ctx' (or any of its ancestors). */ - static void* operator new(size_t size) - { - mtx_lock(&glsl_type::mutex); - - /* mem_ctx should have been created by the static members */ - assert(glsl_type::mem_ctx != NULL); - - void *type; - - type = ralloc_size(glsl_type::mem_ctx, size); - assert(type != NULL); - - mtx_unlock(&glsl_type::mutex); - - return type; - } - - /* If the user *does* call delete, that's OK, we will just - * ralloc_free in that case. */ - static void operator delete(void *type) - { - mtx_lock(&glsl_type::mutex); - ralloc_free(type); - mtx_unlock(&glsl_type::mutex); - } - - /** - * \name Vector and matrix element counts - * - * For scalars, each of these values will be 1. For non-numeric types - * these will be 0. - */ - /*@{*/ - uint8_t vector_elements; /**< 1, 2, 3, or 4 vector elements. */ - uint8_t matrix_columns; /**< 1, 2, 3, or 4 matrix columns. */ - /*@}*/ - - /** - * For \c GLSL_TYPE_ARRAY, this is the length of the array. For - * \c GLSL_TYPE_STRUCT or \c GLSL_TYPE_INTERFACE, it is the number of - * elements in the structure and the number of values pointed to by - * \c fields.structure (below). - */ - unsigned length; - - /** - * Name of the data type - * - * Will never be \c NULL. - */ - const char *name; - - /** - * Subtype of composite data types. - */ - union { - const struct glsl_type *array; /**< Type of array elements. */ - struct glsl_function_param *parameters; /**< Parameters to function. */ - struct glsl_struct_field *structure; /**< List of struct fields. */ - } fields; - - /** - * \name Pointers to various public type singletons - */ - /*@{*/ -#undef DECL_TYPE -#define DECL_TYPE(NAME, ...) \ - static const glsl_type *const NAME##_type; -#undef STRUCT_TYPE -#define STRUCT_TYPE(NAME) \ - static const glsl_type *const struct_##NAME##_type; -#include "builtin_type_macros.h" - /*@}*/ - - /** - * Convenience accessors for vector types (shorter than get_instance()). - * @{ - */ - static const glsl_type *vec(unsigned components); - static const glsl_type *dvec(unsigned components); - static const glsl_type *ivec(unsigned components); - static const glsl_type *uvec(unsigned components); - static const glsl_type *bvec(unsigned components); - /**@}*/ - - /** - * For numeric and boolean derived types returns the basic scalar type - * - * If the type is a numeric or boolean scalar, vector, or matrix type, - * this function gets the scalar type of the individual components. For - * all other types, including arrays of numeric or boolean types, the - * error type is returned. - */ - const glsl_type *get_base_type() const; - - /** - * Get the basic scalar type which this type aggregates. - * - * If the type is a numeric or boolean scalar, vector, or matrix, or an - * array of any of those, this function gets the scalar type of the - * individual components. For structs and arrays of structs, this function - * returns the struct type. For samplers and arrays of samplers, this - * function returns the sampler type. - */ - const glsl_type *get_scalar_type() const; - - /** - * Get the instance of a built-in scalar, vector, or matrix type - */ - static const glsl_type *get_instance(unsigned base_type, unsigned rows, - unsigned columns); - - /** - * Get the instance of a sampler type - */ - static const glsl_type *get_sampler_instance(enum glsl_sampler_dim dim, - bool shadow, - bool array, - glsl_base_type type); - - static const glsl_type *get_image_instance(enum glsl_sampler_dim dim, - bool array, glsl_base_type type); - - /** - * Get the instance of an array type - */ - static const glsl_type *get_array_instance(const glsl_type *base, - unsigned elements); - - /** - * Get the instance of a record type - */ - static const glsl_type *get_record_instance(const glsl_struct_field *fields, - unsigned num_fields, - const char *name); - - /** - * Get the instance of an interface block type - */ - static const glsl_type *get_interface_instance(const glsl_struct_field *fields, - unsigned num_fields, - enum glsl_interface_packing packing, - const char *block_name); - - /** - * Get the instance of an subroutine type - */ - static const glsl_type *get_subroutine_instance(const char *subroutine_name); - - /** - * Get the instance of a function type - */ - static const glsl_type *get_function_instance(const struct glsl_type *return_type, - const glsl_function_param *parameters, - unsigned num_params); - - /** - * Get the type resulting from a multiplication of \p type_a * \p type_b - */ - static const glsl_type *get_mul_type(const glsl_type *type_a, - const glsl_type *type_b); - - /** - * Query the total number of scalars that make up a scalar, vector or matrix - */ - unsigned components() const - { - return vector_elements * matrix_columns; - } - - /** - * Calculate the number of components slots required to hold this type - * - * This is used to determine how many uniform or varying locations a type - * might occupy. - */ - unsigned component_slots() const; - - /** - * Calculate offset between the base location of the struct in - * uniform storage and a struct member. - * For the initial call, length is the index of the member to find the - * offset for. - */ - unsigned record_location_offset(unsigned length) const; - - /** - * Calculate the number of unique values from glGetUniformLocation for the - * elements of the type. - * - * This is used to allocate slots in the UniformRemapTable, the amount of - * locations may not match with actual used storage space by the driver. - */ - unsigned uniform_locations() const; - - /** - * Calculate the number of attribute slots required to hold this type - * - * This implements the language rules of GLSL 1.50 for counting the number - * of slots used by a vertex attribute. It also determines the number of - * varying slots the type will use up in the absence of varying packing - * (and thus, it can be used to measure the number of varying slots used by - * the varyings that are generated by lower_packed_varyings). - * - * For vertex shader attributes - doubles only take one slot. - * For inter-shader varyings - dvec3/dvec4 take two slots. - */ - unsigned count_attribute_slots(bool vertex_input_slots) const; - - /** - * Alignment in bytes of the start of this type in a std140 uniform - * block. - */ - unsigned std140_base_alignment(bool row_major) const; - - /** Size in bytes of this type in a std140 uniform block. - * - * Note that this is not GL_UNIFORM_SIZE (which is the number of - * elements in the array) - */ - unsigned std140_size(bool row_major) const; - - /** - * Alignment in bytes of the start of this type in a std430 shader - * storage block. - */ - unsigned std430_base_alignment(bool row_major) const; - - /** - * Calculate array stride in bytes of this type in a std430 shader storage - * block. - */ - unsigned std430_array_stride(bool row_major) const; - - /** - * Size in bytes of this type in a std430 shader storage block. - * - * Note that this is not GL_BUFFER_SIZE - */ - unsigned std430_size(bool row_major) const; - - /** - * \brief Can this type be implicitly converted to another? - * - * \return True if the types are identical or if this type can be converted - * to \c desired according to Section 4.1.10 of the GLSL spec. - * - * \verbatim - * From page 25 (31 of the pdf) of the GLSL 1.50 spec, Section 4.1.10 - * Implicit Conversions: - * - * In some situations, an expression and its type will be implicitly - * converted to a different type. The following table shows all allowed - * implicit conversions: - * - * Type of expression | Can be implicitly converted to - * -------------------------------------------------- - * int float - * uint - * - * ivec2 vec2 - * uvec2 - * - * ivec3 vec3 - * uvec3 - * - * ivec4 vec4 - * uvec4 - * - * There are no implicit array or structure conversions. For example, - * an array of int cannot be implicitly converted to an array of float. - * There are no implicit conversions between signed and unsigned - * integers. - * \endverbatim - */ - bool can_implicitly_convert_to(const glsl_type *desired, - _mesa_glsl_parse_state *state) const; - - /** - * Query whether or not a type is a scalar (non-vector and non-matrix). - */ - bool is_scalar() const - { - return (vector_elements == 1) - && (base_type >= GLSL_TYPE_UINT) - && (base_type <= GLSL_TYPE_BOOL); - } - - /** - * Query whether or not a type is a vector - */ - bool is_vector() const - { - return (vector_elements > 1) - && (matrix_columns == 1) - && (base_type >= GLSL_TYPE_UINT) - && (base_type <= GLSL_TYPE_BOOL); - } - - /** - * Query whether or not a type is a matrix - */ - bool is_matrix() const - { - /* GLSL only has float matrices. */ - return (matrix_columns > 1) && (base_type == GLSL_TYPE_FLOAT || base_type == GLSL_TYPE_DOUBLE); - } - - /** - * Query whether or not a type is a non-array numeric type - */ - bool is_numeric() const - { - return (base_type >= GLSL_TYPE_UINT) && (base_type <= GLSL_TYPE_DOUBLE); - } - - /** - * Query whether or not a type is an integral type - */ - bool is_integer() const - { - return (base_type == GLSL_TYPE_UINT) || (base_type == GLSL_TYPE_INT); - } - - /** - * Query whether or not type is an integral type, or for struct and array - * types, contains an integral type. - */ - bool contains_integer() const; - - /** - * Query whether or not type is a double type, or for struct and array - * types, contains a double type. - */ - bool contains_double() const; - - /** - * Query whether or not a type is a float type - */ - bool is_float() const - { - return base_type == GLSL_TYPE_FLOAT; - } - - /** - * Query whether or not a type is a double type - */ - bool is_double() const - { - return base_type == GLSL_TYPE_DOUBLE; - } - - /** - * Query whether a double takes two slots. - */ - bool is_dual_slot_double() const - { - return base_type == GLSL_TYPE_DOUBLE && vector_elements > 2; - } - - /** - * Query whether or not a type is a non-array boolean type - */ - bool is_boolean() const - { - return base_type == GLSL_TYPE_BOOL; - } - - /** - * Query whether or not a type is a sampler - */ - bool is_sampler() const - { - return base_type == GLSL_TYPE_SAMPLER; - } - - /** - * Query whether or not type is a sampler, or for struct and array - * types, contains a sampler. - */ - bool contains_sampler() const; - - /** - * Get the Mesa texture target index for a sampler type. - */ - gl_texture_index sampler_index() const; - - /** - * Query whether or not type is an image, or for struct and array - * types, contains an image. - */ - bool contains_image() const; - - /** - * Query whether or not a type is an image - */ - bool is_image() const - { - return base_type == GLSL_TYPE_IMAGE; - } - - /** - * Query whether or not a type is an array - */ - bool is_array() const - { - return base_type == GLSL_TYPE_ARRAY; - } - - bool is_array_of_arrays() const - { - return is_array() && fields.array->is_array(); - } - - /** - * Query whether or not a type is a record - */ - bool is_record() const - { - return base_type == GLSL_TYPE_STRUCT; - } - - /** - * Query whether or not a type is an interface - */ - bool is_interface() const - { - return base_type == GLSL_TYPE_INTERFACE; - } - - /** - * Query whether or not a type is the void type singleton. - */ - bool is_void() const - { - return base_type == GLSL_TYPE_VOID; - } - - /** - * Query whether or not a type is the error type singleton. - */ - bool is_error() const - { - return base_type == GLSL_TYPE_ERROR; - } - - /** - * Query if a type is unnamed/anonymous (named by the parser) - */ - - bool is_subroutine() const - { - return base_type == GLSL_TYPE_SUBROUTINE; - } - bool contains_subroutine() const; - - bool is_anonymous() const - { - return !strncmp(name, "#anon", 5); - } - - /** - * Get the type stripped of any arrays - * - * \return - * Pointer to the type of elements of the first non-array type for array - * types, or pointer to itself for non-array types. - */ - const glsl_type *without_array() const - { - const glsl_type *t = this; - - while (t->is_array()) - t = t->fields.array; - - return t; - } - - /** - * Return the total number of elements in an array including the elements - * in arrays of arrays. - */ - unsigned arrays_of_arrays_size() const - { - if (!is_array()) - return 0; - - unsigned size = length; - const glsl_type *base_type = fields.array; - - while (base_type->is_array()) { - size = size * base_type->length; - base_type = base_type->fields.array; - } - return size; - } - - /** - * Return the amount of atomic counter storage required for a type. - */ - unsigned atomic_size() const - { - if (base_type == GLSL_TYPE_ATOMIC_UINT) - return ATOMIC_COUNTER_SIZE; - else if (is_array()) - return length * fields.array->atomic_size(); - else - return 0; - } - - /** - * Return whether a type contains any atomic counters. - */ - bool contains_atomic() const - { - return atomic_size() > 0; - } - - /** - * Return whether a type contains any opaque types. - */ - bool contains_opaque() const; - - /** - * Query the full type of a matrix row - * - * \return - * If the type is not a matrix, \c glsl_type::error_type is returned. - * Otherwise a type matching the rows of the matrix is returned. - */ - const glsl_type *row_type() const - { - return is_matrix() - ? get_instance(base_type, matrix_columns, 1) - : error_type; - } - - /** - * Query the full type of a matrix column - * - * \return - * If the type is not a matrix, \c glsl_type::error_type is returned. - * Otherwise a type matching the columns of the matrix is returned. - */ - const glsl_type *column_type() const - { - return is_matrix() - ? get_instance(base_type, vector_elements, 1) - : error_type; - } - - /** - * Get the type of a structure field - * - * \return - * Pointer to the type of the named field. If the type is not a structure - * or the named field does not exist, \c glsl_type::error_type is returned. - */ - const glsl_type *field_type(const char *name) const; - - /** - * Get the location of a field within a record type - */ - int field_index(const char *name) const; - - /** - * Query the number of elements in an array type - * - * \return - * The number of elements in the array for array types or -1 for non-array - * types. If the number of elements in the array has not yet been declared, - * zero is returned. - */ - int array_size() const - { - return is_array() ? length : -1; - } - - /** - * Query whether the array size for all dimensions has been declared. - */ - bool is_unsized_array() const - { - return is_array() && length == 0; - } - - /** - * Return the number of coordinate components needed for this - * sampler or image type. - * - * This is based purely on the sampler's dimensionality. For example, this - * returns 1 for sampler1D, and 3 for sampler2DArray. - * - * Note that this is often different than actual coordinate type used in - * a texturing built-in function, since those pack additional values (such - * as the shadow comparitor or projector) into the coordinate type. - */ - int coordinate_components() const; - - /** - * Compare a record type against another record type. - * - * This is useful for matching record types declared across shader stages. - */ - bool record_compare(const glsl_type *b) const; - -private: - - static mtx_t mutex; - - /** - * ralloc context for all glsl_type allocations - * - * Set on the first call to \c glsl_type::new. - */ - static void *mem_ctx; - - void init_ralloc_type_ctx(void); - - /** Constructor for vector and matrix types */ - glsl_type(GLenum gl_type, - glsl_base_type base_type, unsigned vector_elements, - unsigned matrix_columns, const char *name); - - /** Constructor for sampler or image types */ - glsl_type(GLenum gl_type, glsl_base_type base_type, - enum glsl_sampler_dim dim, bool shadow, bool array, - unsigned type, const char *name); - - /** Constructor for record types */ - glsl_type(const glsl_struct_field *fields, unsigned num_fields, - const char *name); - - /** Constructor for interface types */ - glsl_type(const glsl_struct_field *fields, unsigned num_fields, - enum glsl_interface_packing packing, const char *name); - - /** Constructor for interface types */ - glsl_type(const glsl_type *return_type, - const glsl_function_param *params, unsigned num_params); - - /** Constructor for array types */ - glsl_type(const glsl_type *array, unsigned length); - - /** Constructor for subroutine types */ - glsl_type(const char *name); - - /** Hash table containing the known array types. */ - static struct hash_table *array_types; - - /** Hash table containing the known record types. */ - static struct hash_table *record_types; - - /** Hash table containing the known interface types. */ - static struct hash_table *interface_types; - - /** Hash table containing the known subroutine types. */ - static struct hash_table *subroutine_types; - - /** Hash table containing the known function types. */ - static struct hash_table *function_types; - - static bool record_key_compare(const void *a, const void *b); - static unsigned record_key_hash(const void *key); - - /** - * \name Built-in type flyweights - */ - /*@{*/ -#undef DECL_TYPE -#define DECL_TYPE(NAME, ...) static const glsl_type _##NAME##_type; -#undef STRUCT_TYPE -#define STRUCT_TYPE(NAME) static const glsl_type _struct_##NAME##_type; -#include "builtin_type_macros.h" - /*@}*/ - - /** - * \name Friend functions. - * - * These functions are friends because they must have C linkage and the - * need to call various private methods or access various private static - * data. - */ - /*@{*/ - friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *); - friend void _mesa_glsl_release_types(void); - /*@}*/ -}; - -#undef DECL_TYPE -#undef STRUCT_TYPE -#endif /* __cplusplus */ - -struct glsl_struct_field { - const struct glsl_type *type; - const char *name; - - /** - * For interface blocks, gl_varying_slot corresponding to the input/output - * if this is a built-in input/output (i.e. a member of the built-in - * gl_PerVertex interface block); -1 otherwise. - * - * Ignored for structs. - */ - int location; - - /** - * For interface blocks, the interpolation mode (as in - * ir_variable::interpolation). 0 otherwise. - */ - unsigned interpolation:2; - - /** - * For interface blocks, 1 if this variable uses centroid interpolation (as - * in ir_variable::centroid). 0 otherwise. - */ - unsigned centroid:1; - - /** - * For interface blocks, 1 if this variable uses sample interpolation (as - * in ir_variable::sample). 0 otherwise. - */ - unsigned sample:1; - - /** - * Layout of the matrix. Uses glsl_matrix_layout values. - */ - unsigned matrix_layout:2; - - /** - * For interface blocks, 1 if this variable is a per-patch input or output - * (as in ir_variable::patch). 0 otherwise. - */ - unsigned patch:1; - - /** - * Precision qualifier - */ - unsigned precision:2; - - /** - * Image qualifiers, applicable to buffer variables defined in shader - * storage buffer objects (SSBOs) - */ - unsigned image_read_only:1; - unsigned image_write_only:1; - unsigned image_coherent:1; - unsigned image_volatile:1; - unsigned image_restrict:1; - -#ifdef __cplusplus - glsl_struct_field(const struct glsl_type *_type, const char *_name) - : type(_type), name(_name), location(-1), interpolation(0), centroid(0), - sample(0), matrix_layout(GLSL_MATRIX_LAYOUT_INHERITED), patch(0), - precision(GLSL_PRECISION_NONE) - { - /* empty */ - } - - glsl_struct_field() - { - /* empty */ - } -#endif -}; - -struct glsl_function_param { - const struct glsl_type *type; - - bool in; - bool out; -}; - -static inline unsigned int -glsl_align(unsigned int a, unsigned int align) -{ - return (a + align - 1) / align * align; -} - -#endif /* GLSL_TYPES_H */ diff --git a/src/glsl/nir/nir.c b/src/glsl/nir/nir.c deleted file mode 100644 index 42a53f6f3db..00000000000 --- a/src/glsl/nir/nir.c +++ /dev/null @@ -1,1753 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include "nir_control_flow_private.h" -#include <assert.h> - -nir_shader * -nir_shader_create(void *mem_ctx, - gl_shader_stage stage, - const nir_shader_compiler_options *options) -{ - nir_shader *shader = ralloc(mem_ctx, nir_shader); - - exec_list_make_empty(&shader->uniforms); - exec_list_make_empty(&shader->inputs); - exec_list_make_empty(&shader->outputs); - exec_list_make_empty(&shader->shared); - - shader->options = options; - memset(&shader->info, 0, sizeof(shader->info)); - - exec_list_make_empty(&shader->functions); - exec_list_make_empty(&shader->registers); - exec_list_make_empty(&shader->globals); - exec_list_make_empty(&shader->system_values); - shader->reg_alloc = 0; - - shader->num_inputs = 0; - shader->num_outputs = 0; - shader->num_uniforms = 0; - shader->num_shared = 0; - - shader->stage = stage; - - return shader; -} - -static nir_register * -reg_create(void *mem_ctx, struct exec_list *list) -{ - nir_register *reg = ralloc(mem_ctx, nir_register); - - list_inithead(®->uses); - list_inithead(®->defs); - list_inithead(®->if_uses); - - reg->num_components = 0; - reg->num_array_elems = 0; - reg->is_packed = false; - reg->name = NULL; - - exec_list_push_tail(list, ®->node); - - return reg; -} - -nir_register * -nir_global_reg_create(nir_shader *shader) -{ - nir_register *reg = reg_create(shader, &shader->registers); - reg->index = shader->reg_alloc++; - reg->is_global = true; - - return reg; -} - -nir_register * -nir_local_reg_create(nir_function_impl *impl) -{ - nir_register *reg = reg_create(ralloc_parent(impl), &impl->registers); - reg->index = impl->reg_alloc++; - reg->is_global = false; - - return reg; -} - -void -nir_reg_remove(nir_register *reg) -{ - exec_node_remove(®->node); -} - -void -nir_shader_add_variable(nir_shader *shader, nir_variable *var) -{ - switch (var->data.mode) { - case nir_var_all: - assert(!"invalid mode"); - break; - - case nir_var_local: - assert(!"nir_shader_add_variable cannot be used for local variables"); - break; - - case nir_var_global: - exec_list_push_tail(&shader->globals, &var->node); - break; - - case nir_var_shader_in: - exec_list_push_tail(&shader->inputs, &var->node); - break; - - case nir_var_shader_out: - exec_list_push_tail(&shader->outputs, &var->node); - break; - - case nir_var_uniform: - case nir_var_shader_storage: - exec_list_push_tail(&shader->uniforms, &var->node); - break; - - case nir_var_shared: - assert(shader->stage == MESA_SHADER_COMPUTE); - exec_list_push_tail(&shader->shared, &var->node); - break; - - case nir_var_system_value: - exec_list_push_tail(&shader->system_values, &var->node); - break; - } -} - -nir_variable * -nir_variable_create(nir_shader *shader, nir_variable_mode mode, - const struct glsl_type *type, const char *name) -{ - nir_variable *var = rzalloc(shader, nir_variable); - var->name = ralloc_strdup(var, name); - var->type = type; - var->data.mode = mode; - - if ((mode == nir_var_shader_in && shader->stage != MESA_SHADER_VERTEX) || - (mode == nir_var_shader_out && shader->stage != MESA_SHADER_FRAGMENT)) - var->data.interpolation = INTERP_QUALIFIER_SMOOTH; - - if (mode == nir_var_shader_in || mode == nir_var_uniform) - var->data.read_only = true; - - nir_shader_add_variable(shader, var); - - return var; -} - -nir_variable * -nir_local_variable_create(nir_function_impl *impl, - const struct glsl_type *type, const char *name) -{ - nir_variable *var = rzalloc(impl->function->shader, nir_variable); - var->name = ralloc_strdup(var, name); - var->type = type; - var->data.mode = nir_var_local; - - nir_function_impl_add_variable(impl, var); - - return var; -} - -nir_function * -nir_function_create(nir_shader *shader, const char *name) -{ - nir_function *func = ralloc(shader, nir_function); - - exec_list_push_tail(&shader->functions, &func->node); - - func->name = ralloc_strdup(func, name); - func->shader = shader; - func->num_params = 0; - func->params = NULL; - func->return_type = glsl_void_type(); - func->impl = NULL; - - return func; -} - -void nir_src_copy(nir_src *dest, const nir_src *src, void *mem_ctx) -{ - dest->is_ssa = src->is_ssa; - if (src->is_ssa) { - dest->ssa = src->ssa; - } else { - dest->reg.base_offset = src->reg.base_offset; - dest->reg.reg = src->reg.reg; - if (src->reg.indirect) { - dest->reg.indirect = ralloc(mem_ctx, nir_src); - nir_src_copy(dest->reg.indirect, src->reg.indirect, mem_ctx); - } else { - dest->reg.indirect = NULL; - } - } -} - -void nir_dest_copy(nir_dest *dest, const nir_dest *src, nir_instr *instr) -{ - /* Copying an SSA definition makes no sense whatsoever. */ - assert(!src->is_ssa); - - dest->is_ssa = false; - - dest->reg.base_offset = src->reg.base_offset; - dest->reg.reg = src->reg.reg; - if (src->reg.indirect) { - dest->reg.indirect = ralloc(instr, nir_src); - nir_src_copy(dest->reg.indirect, src->reg.indirect, instr); - } else { - dest->reg.indirect = NULL; - } -} - -void -nir_alu_src_copy(nir_alu_src *dest, const nir_alu_src *src, - nir_alu_instr *instr) -{ - nir_src_copy(&dest->src, &src->src, &instr->instr); - dest->abs = src->abs; - dest->negate = src->negate; - for (unsigned i = 0; i < 4; i++) - dest->swizzle[i] = src->swizzle[i]; -} - -void -nir_alu_dest_copy(nir_alu_dest *dest, const nir_alu_dest *src, - nir_alu_instr *instr) -{ - nir_dest_copy(&dest->dest, &src->dest, &instr->instr); - dest->write_mask = src->write_mask; - dest->saturate = src->saturate; -} - - -static void -cf_init(nir_cf_node *node, nir_cf_node_type type) -{ - exec_node_init(&node->node); - node->parent = NULL; - node->type = type; -} - -nir_function_impl * -nir_function_impl_create_bare(nir_shader *shader) -{ - nir_function_impl *impl = ralloc(shader, nir_function_impl); - - impl->function = NULL; - - cf_init(&impl->cf_node, nir_cf_node_function); - - exec_list_make_empty(&impl->body); - exec_list_make_empty(&impl->registers); - exec_list_make_empty(&impl->locals); - impl->num_params = 0; - impl->params = NULL; - impl->return_var = NULL; - impl->reg_alloc = 0; - impl->ssa_alloc = 0; - impl->valid_metadata = nir_metadata_none; - - /* create start & end blocks */ - nir_block *start_block = nir_block_create(shader); - nir_block *end_block = nir_block_create(shader); - start_block->cf_node.parent = &impl->cf_node; - end_block->cf_node.parent = &impl->cf_node; - impl->end_block = end_block; - - exec_list_push_tail(&impl->body, &start_block->cf_node.node); - - start_block->successors[0] = end_block; - _mesa_set_add(end_block->predecessors, start_block); - return impl; -} - -nir_function_impl * -nir_function_impl_create(nir_function *function) -{ - assert(function->impl == NULL); - - nir_function_impl *impl = nir_function_impl_create_bare(function->shader); - - function->impl = impl; - impl->function = function; - - impl->num_params = function->num_params; - impl->params = ralloc_array(function->shader, - nir_variable *, impl->num_params); - - return impl; -} - -nir_block * -nir_block_create(nir_shader *shader) -{ - nir_block *block = ralloc(shader, nir_block); - - cf_init(&block->cf_node, nir_cf_node_block); - - block->successors[0] = block->successors[1] = NULL; - block->predecessors = _mesa_set_create(block, _mesa_hash_pointer, - _mesa_key_pointer_equal); - block->imm_dom = NULL; - /* XXX maybe it would be worth it to defer allocation? This - * way it doesn't get allocated for shader ref's that never run - * nir_calc_dominance? For example, state-tracker creates an - * initial IR, clones that, runs appropriate lowering pass, passes - * to driver which does common lowering/opt, and then stores ref - * which is later used to do state specific lowering and futher - * opt. Do any of the references not need dominance metadata? - */ - block->dom_frontier = _mesa_set_create(block, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - exec_list_make_empty(&block->instr_list); - - return block; -} - -static inline void -src_init(nir_src *src) -{ - src->is_ssa = false; - src->reg.reg = NULL; - src->reg.indirect = NULL; - src->reg.base_offset = 0; -} - -nir_if * -nir_if_create(nir_shader *shader) -{ - nir_if *if_stmt = ralloc(shader, nir_if); - - cf_init(&if_stmt->cf_node, nir_cf_node_if); - src_init(&if_stmt->condition); - - nir_block *then = nir_block_create(shader); - exec_list_make_empty(&if_stmt->then_list); - exec_list_push_tail(&if_stmt->then_list, &then->cf_node.node); - then->cf_node.parent = &if_stmt->cf_node; - - nir_block *else_stmt = nir_block_create(shader); - exec_list_make_empty(&if_stmt->else_list); - exec_list_push_tail(&if_stmt->else_list, &else_stmt->cf_node.node); - else_stmt->cf_node.parent = &if_stmt->cf_node; - - return if_stmt; -} - -nir_loop * -nir_loop_create(nir_shader *shader) -{ - nir_loop *loop = ralloc(shader, nir_loop); - - cf_init(&loop->cf_node, nir_cf_node_loop); - - nir_block *body = nir_block_create(shader); - exec_list_make_empty(&loop->body); - exec_list_push_tail(&loop->body, &body->cf_node.node); - body->cf_node.parent = &loop->cf_node; - - body->successors[0] = body; - _mesa_set_add(body->predecessors, body); - - return loop; -} - -static void -instr_init(nir_instr *instr, nir_instr_type type) -{ - instr->type = type; - instr->block = NULL; - exec_node_init(&instr->node); -} - -static void -dest_init(nir_dest *dest) -{ - dest->is_ssa = false; - dest->reg.reg = NULL; - dest->reg.indirect = NULL; - dest->reg.base_offset = 0; -} - -static void -alu_dest_init(nir_alu_dest *dest) -{ - dest_init(&dest->dest); - dest->saturate = false; - dest->write_mask = 0xf; -} - -static void -alu_src_init(nir_alu_src *src) -{ - src_init(&src->src); - src->abs = src->negate = false; - src->swizzle[0] = 0; - src->swizzle[1] = 1; - src->swizzle[2] = 2; - src->swizzle[3] = 3; -} - -nir_alu_instr * -nir_alu_instr_create(nir_shader *shader, nir_op op) -{ - unsigned num_srcs = nir_op_infos[op].num_inputs; - nir_alu_instr *instr = - ralloc_size(shader, - sizeof(nir_alu_instr) + num_srcs * sizeof(nir_alu_src)); - - instr_init(&instr->instr, nir_instr_type_alu); - instr->op = op; - alu_dest_init(&instr->dest); - for (unsigned i = 0; i < num_srcs; i++) - alu_src_init(&instr->src[i]); - - return instr; -} - -nir_jump_instr * -nir_jump_instr_create(nir_shader *shader, nir_jump_type type) -{ - nir_jump_instr *instr = ralloc(shader, nir_jump_instr); - instr_init(&instr->instr, nir_instr_type_jump); - instr->type = type; - return instr; -} - -nir_load_const_instr * -nir_load_const_instr_create(nir_shader *shader, unsigned num_components) -{ - nir_load_const_instr *instr = ralloc(shader, nir_load_const_instr); - instr_init(&instr->instr, nir_instr_type_load_const); - - nir_ssa_def_init(&instr->instr, &instr->def, num_components, NULL); - - return instr; -} - -nir_intrinsic_instr * -nir_intrinsic_instr_create(nir_shader *shader, nir_intrinsic_op op) -{ - unsigned num_srcs = nir_intrinsic_infos[op].num_srcs; - nir_intrinsic_instr *instr = - ralloc_size(shader, - sizeof(nir_intrinsic_instr) + num_srcs * sizeof(nir_src)); - - instr_init(&instr->instr, nir_instr_type_intrinsic); - instr->intrinsic = op; - - if (nir_intrinsic_infos[op].has_dest) - dest_init(&instr->dest); - - for (unsigned i = 0; i < num_srcs; i++) - src_init(&instr->src[i]); - - return instr; -} - -nir_call_instr * -nir_call_instr_create(nir_shader *shader, nir_function *callee) -{ - nir_call_instr *instr = ralloc(shader, nir_call_instr); - instr_init(&instr->instr, nir_instr_type_call); - - instr->callee = callee; - instr->num_params = callee->num_params; - instr->params = ralloc_array(instr, nir_deref_var *, instr->num_params); - instr->return_deref = NULL; - - return instr; -} - -nir_tex_instr * -nir_tex_instr_create(nir_shader *shader, unsigned num_srcs) -{ - nir_tex_instr *instr = rzalloc(shader, nir_tex_instr); - instr_init(&instr->instr, nir_instr_type_tex); - - dest_init(&instr->dest); - - instr->num_srcs = num_srcs; - instr->src = ralloc_array(instr, nir_tex_src, num_srcs); - for (unsigned i = 0; i < num_srcs; i++) - src_init(&instr->src[i].src); - - instr->texture_index = 0; - instr->texture_array_size = 0; - instr->texture = NULL; - instr->sampler_index = 0; - instr->sampler = NULL; - - return instr; -} - -nir_phi_instr * -nir_phi_instr_create(nir_shader *shader) -{ - nir_phi_instr *instr = ralloc(shader, nir_phi_instr); - instr_init(&instr->instr, nir_instr_type_phi); - - dest_init(&instr->dest); - exec_list_make_empty(&instr->srcs); - return instr; -} - -nir_parallel_copy_instr * -nir_parallel_copy_instr_create(nir_shader *shader) -{ - nir_parallel_copy_instr *instr = ralloc(shader, nir_parallel_copy_instr); - instr_init(&instr->instr, nir_instr_type_parallel_copy); - - exec_list_make_empty(&instr->entries); - - return instr; -} - -nir_ssa_undef_instr * -nir_ssa_undef_instr_create(nir_shader *shader, unsigned num_components) -{ - nir_ssa_undef_instr *instr = ralloc(shader, nir_ssa_undef_instr); - instr_init(&instr->instr, nir_instr_type_ssa_undef); - - nir_ssa_def_init(&instr->instr, &instr->def, num_components, NULL); - - return instr; -} - -nir_deref_var * -nir_deref_var_create(void *mem_ctx, nir_variable *var) -{ - nir_deref_var *deref = ralloc(mem_ctx, nir_deref_var); - deref->deref.deref_type = nir_deref_type_var; - deref->deref.child = NULL; - deref->deref.type = var->type; - deref->var = var; - return deref; -} - -nir_deref_array * -nir_deref_array_create(void *mem_ctx) -{ - nir_deref_array *deref = ralloc(mem_ctx, nir_deref_array); - deref->deref.deref_type = nir_deref_type_array; - deref->deref.child = NULL; - deref->deref_array_type = nir_deref_array_type_direct; - src_init(&deref->indirect); - deref->base_offset = 0; - return deref; -} - -nir_deref_struct * -nir_deref_struct_create(void *mem_ctx, unsigned field_index) -{ - nir_deref_struct *deref = ralloc(mem_ctx, nir_deref_struct); - deref->deref.deref_type = nir_deref_type_struct; - deref->deref.child = NULL; - deref->index = field_index; - return deref; -} - -static nir_deref_var * -copy_deref_var(void *mem_ctx, nir_deref_var *deref) -{ - nir_deref_var *ret = nir_deref_var_create(mem_ctx, deref->var); - ret->deref.type = deref->deref.type; - if (deref->deref.child) - ret->deref.child = nir_copy_deref(ret, deref->deref.child); - return ret; -} - -static nir_deref_array * -copy_deref_array(void *mem_ctx, nir_deref_array *deref) -{ - nir_deref_array *ret = nir_deref_array_create(mem_ctx); - ret->base_offset = deref->base_offset; - ret->deref_array_type = deref->deref_array_type; - if (deref->deref_array_type == nir_deref_array_type_indirect) { - nir_src_copy(&ret->indirect, &deref->indirect, mem_ctx); - } - ret->deref.type = deref->deref.type; - if (deref->deref.child) - ret->deref.child = nir_copy_deref(ret, deref->deref.child); - return ret; -} - -static nir_deref_struct * -copy_deref_struct(void *mem_ctx, nir_deref_struct *deref) -{ - nir_deref_struct *ret = nir_deref_struct_create(mem_ctx, deref->index); - ret->deref.type = deref->deref.type; - if (deref->deref.child) - ret->deref.child = nir_copy_deref(ret, deref->deref.child); - return ret; -} - -nir_deref * -nir_copy_deref(void *mem_ctx, nir_deref *deref) -{ - switch (deref->deref_type) { - case nir_deref_type_var: - return ©_deref_var(mem_ctx, nir_deref_as_var(deref))->deref; - case nir_deref_type_array: - return ©_deref_array(mem_ctx, nir_deref_as_array(deref))->deref; - case nir_deref_type_struct: - return ©_deref_struct(mem_ctx, nir_deref_as_struct(deref))->deref; - default: - unreachable("Invalid dereference type"); - } - - return NULL; -} - -/* Returns a load_const instruction that represents the constant - * initializer for the given deref chain. The caller is responsible for - * ensuring that there actually is a constant initializer. - */ -nir_load_const_instr * -nir_deref_get_const_initializer_load(nir_shader *shader, nir_deref_var *deref) -{ - nir_constant *constant = deref->var->constant_initializer; - assert(constant); - - const nir_deref *tail = &deref->deref; - unsigned matrix_offset = 0; - while (tail->child) { - switch (tail->child->deref_type) { - case nir_deref_type_array: { - nir_deref_array *arr = nir_deref_as_array(tail->child); - assert(arr->deref_array_type == nir_deref_array_type_direct); - if (glsl_type_is_matrix(tail->type)) { - assert(arr->deref.child == NULL); - matrix_offset = arr->base_offset; - } else { - constant = constant->elements[arr->base_offset]; - } - break; - } - - case nir_deref_type_struct: { - constant = constant->elements[nir_deref_as_struct(tail->child)->index]; - break; - } - - default: - unreachable("Invalid deref child type"); - } - - tail = tail->child; - } - - nir_load_const_instr *load = - nir_load_const_instr_create(shader, glsl_get_vector_elements(tail->type)); - - matrix_offset *= load->def.num_components; - for (unsigned i = 0; i < load->def.num_components; i++) { - switch (glsl_get_base_type(tail->type)) { - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_INT: - case GLSL_TYPE_UINT: - load->value.u[i] = constant->value.u[matrix_offset + i]; - break; - case GLSL_TYPE_BOOL: - load->value.u[i] = constant->value.b[matrix_offset + i] ? - NIR_TRUE : NIR_FALSE; - break; - default: - unreachable("Invalid immediate type"); - } - } - - return load; -} - -nir_function_impl * -nir_cf_node_get_function(nir_cf_node *node) -{ - while (node->type != nir_cf_node_function) { - node = node->parent; - } - - return nir_cf_node_as_function(node); -} - -/* Reduces a cursor by trying to convert everything to after and trying to - * go up to block granularity when possible. - */ -static nir_cursor -reduce_cursor(nir_cursor cursor) -{ - switch (cursor.option) { - case nir_cursor_before_block: - if (exec_list_is_empty(&cursor.block->instr_list)) { - /* Empty block. After is as good as before. */ - cursor.option = nir_cursor_after_block; - } else { - /* Try to switch to after the previous block if there is one. - * (This isn't likely, but it can happen.) - */ - nir_cf_node *prev_node = nir_cf_node_prev(&cursor.block->cf_node); - if (prev_node && prev_node->type == nir_cf_node_block) { - cursor.block = nir_cf_node_as_block(prev_node); - cursor.option = nir_cursor_after_block; - } - } - return cursor; - - case nir_cursor_after_block: - return cursor; - - case nir_cursor_before_instr: { - nir_instr *prev_instr = nir_instr_prev(cursor.instr); - if (prev_instr) { - /* Before this instruction is after the previous */ - cursor.instr = prev_instr; - cursor.option = nir_cursor_after_instr; - } else { - /* No previous instruction. Switch to before block */ - cursor.block = cursor.instr->block; - cursor.option = nir_cursor_before_block; - } - return reduce_cursor(cursor); - } - - case nir_cursor_after_instr: - if (nir_instr_next(cursor.instr) == NULL) { - /* This is the last instruction, switch to after block */ - cursor.option = nir_cursor_after_block; - cursor.block = cursor.instr->block; - } - return cursor; - - default: - unreachable("Inavlid cursor option"); - } -} - -bool -nir_cursors_equal(nir_cursor a, nir_cursor b) -{ - /* Reduced cursors should be unique */ - a = reduce_cursor(a); - b = reduce_cursor(b); - - return a.block == b.block && a.option == b.option; -} - -static bool -add_use_cb(nir_src *src, void *state) -{ - nir_instr *instr = state; - - src->parent_instr = instr; - list_addtail(&src->use_link, - src->is_ssa ? &src->ssa->uses : &src->reg.reg->uses); - - return true; -} - -static bool -add_ssa_def_cb(nir_ssa_def *def, void *state) -{ - nir_instr *instr = state; - - if (instr->block && def->index == UINT_MAX) { - nir_function_impl *impl = - nir_cf_node_get_function(&instr->block->cf_node); - - def->index = impl->ssa_alloc++; - } - - return true; -} - -static bool -add_reg_def_cb(nir_dest *dest, void *state) -{ - nir_instr *instr = state; - - if (!dest->is_ssa) { - dest->reg.parent_instr = instr; - list_addtail(&dest->reg.def_link, &dest->reg.reg->defs); - } - - return true; -} - -static void -add_defs_uses(nir_instr *instr) -{ - nir_foreach_src(instr, add_use_cb, instr); - nir_foreach_dest(instr, add_reg_def_cb, instr); - nir_foreach_ssa_def(instr, add_ssa_def_cb, instr); -} - -void -nir_instr_insert(nir_cursor cursor, nir_instr *instr) -{ - switch (cursor.option) { - case nir_cursor_before_block: - /* Only allow inserting jumps into empty blocks. */ - if (instr->type == nir_instr_type_jump) - assert(exec_list_is_empty(&cursor.block->instr_list)); - - instr->block = cursor.block; - add_defs_uses(instr); - exec_list_push_head(&cursor.block->instr_list, &instr->node); - break; - case nir_cursor_after_block: { - /* Inserting instructions after a jump is illegal. */ - nir_instr *last = nir_block_last_instr(cursor.block); - assert(last == NULL || last->type != nir_instr_type_jump); - (void) last; - - instr->block = cursor.block; - add_defs_uses(instr); - exec_list_push_tail(&cursor.block->instr_list, &instr->node); - break; - } - case nir_cursor_before_instr: - assert(instr->type != nir_instr_type_jump); - instr->block = cursor.instr->block; - add_defs_uses(instr); - exec_node_insert_node_before(&cursor.instr->node, &instr->node); - break; - case nir_cursor_after_instr: - /* Inserting instructions after a jump is illegal. */ - assert(cursor.instr->type != nir_instr_type_jump); - - /* Only allow inserting jumps at the end of the block. */ - if (instr->type == nir_instr_type_jump) - assert(cursor.instr == nir_block_last_instr(cursor.instr->block)); - - instr->block = cursor.instr->block; - add_defs_uses(instr); - exec_node_insert_after(&cursor.instr->node, &instr->node); - break; - } - - if (instr->type == nir_instr_type_jump) - nir_handle_add_jump(instr->block); -} - -static bool -src_is_valid(const nir_src *src) -{ - return src->is_ssa ? (src->ssa != NULL) : (src->reg.reg != NULL); -} - -static bool -remove_use_cb(nir_src *src, void *state) -{ - if (src_is_valid(src)) - list_del(&src->use_link); - - return true; -} - -static bool -remove_def_cb(nir_dest *dest, void *state) -{ - if (!dest->is_ssa) - list_del(&dest->reg.def_link); - - return true; -} - -static void -remove_defs_uses(nir_instr *instr) -{ - nir_foreach_dest(instr, remove_def_cb, instr); - nir_foreach_src(instr, remove_use_cb, instr); -} - -void nir_instr_remove(nir_instr *instr) -{ - remove_defs_uses(instr); - exec_node_remove(&instr->node); - - if (instr->type == nir_instr_type_jump) { - nir_jump_instr *jump_instr = nir_instr_as_jump(instr); - nir_handle_remove_jump(instr->block, jump_instr->type); - } -} - -/*@}*/ - -void -nir_index_local_regs(nir_function_impl *impl) -{ - unsigned index = 0; - foreach_list_typed(nir_register, reg, node, &impl->registers) { - reg->index = index++; - } - impl->reg_alloc = index; -} - -void -nir_index_global_regs(nir_shader *shader) -{ - unsigned index = 0; - foreach_list_typed(nir_register, reg, node, &shader->registers) { - reg->index = index++; - } - shader->reg_alloc = index; -} - -static bool -visit_alu_dest(nir_alu_instr *instr, nir_foreach_dest_cb cb, void *state) -{ - return cb(&instr->dest.dest, state); -} - -static bool -visit_intrinsic_dest(nir_intrinsic_instr *instr, nir_foreach_dest_cb cb, - void *state) -{ - if (nir_intrinsic_infos[instr->intrinsic].has_dest) - return cb(&instr->dest, state); - - return true; -} - -static bool -visit_texture_dest(nir_tex_instr *instr, nir_foreach_dest_cb cb, - void *state) -{ - return cb(&instr->dest, state); -} - -static bool -visit_phi_dest(nir_phi_instr *instr, nir_foreach_dest_cb cb, void *state) -{ - return cb(&instr->dest, state); -} - -static bool -visit_parallel_copy_dest(nir_parallel_copy_instr *instr, - nir_foreach_dest_cb cb, void *state) -{ - nir_foreach_parallel_copy_entry(instr, entry) { - if (!cb(&entry->dest, state)) - return false; - } - - return true; -} - -bool -nir_foreach_dest(nir_instr *instr, nir_foreach_dest_cb cb, void *state) -{ - switch (instr->type) { - case nir_instr_type_alu: - return visit_alu_dest(nir_instr_as_alu(instr), cb, state); - case nir_instr_type_intrinsic: - return visit_intrinsic_dest(nir_instr_as_intrinsic(instr), cb, state); - case nir_instr_type_tex: - return visit_texture_dest(nir_instr_as_tex(instr), cb, state); - case nir_instr_type_phi: - return visit_phi_dest(nir_instr_as_phi(instr), cb, state); - case nir_instr_type_parallel_copy: - return visit_parallel_copy_dest(nir_instr_as_parallel_copy(instr), - cb, state); - - case nir_instr_type_load_const: - case nir_instr_type_ssa_undef: - case nir_instr_type_call: - case nir_instr_type_jump: - break; - - default: - unreachable("Invalid instruction type"); - break; - } - - return true; -} - -struct foreach_ssa_def_state { - nir_foreach_ssa_def_cb cb; - void *client_state; -}; - -static inline bool -nir_ssa_def_visitor(nir_dest *dest, void *void_state) -{ - struct foreach_ssa_def_state *state = void_state; - - if (dest->is_ssa) - return state->cb(&dest->ssa, state->client_state); - else - return true; -} - -bool -nir_foreach_ssa_def(nir_instr *instr, nir_foreach_ssa_def_cb cb, void *state) -{ - switch (instr->type) { - case nir_instr_type_alu: - case nir_instr_type_tex: - case nir_instr_type_intrinsic: - case nir_instr_type_phi: - case nir_instr_type_parallel_copy: { - struct foreach_ssa_def_state foreach_state = {cb, state}; - return nir_foreach_dest(instr, nir_ssa_def_visitor, &foreach_state); - } - - case nir_instr_type_load_const: - return cb(&nir_instr_as_load_const(instr)->def, state); - case nir_instr_type_ssa_undef: - return cb(&nir_instr_as_ssa_undef(instr)->def, state); - case nir_instr_type_call: - case nir_instr_type_jump: - return true; - default: - unreachable("Invalid instruction type"); - } -} - -static bool -visit_src(nir_src *src, nir_foreach_src_cb cb, void *state) -{ - if (!cb(src, state)) - return false; - if (!src->is_ssa && src->reg.indirect) - return cb(src->reg.indirect, state); - return true; -} - -static bool -visit_deref_array_src(nir_deref_array *deref, nir_foreach_src_cb cb, - void *state) -{ - if (deref->deref_array_type == nir_deref_array_type_indirect) - return visit_src(&deref->indirect, cb, state); - return true; -} - -static bool -visit_deref_src(nir_deref_var *deref, nir_foreach_src_cb cb, void *state) -{ - nir_deref *cur = &deref->deref; - while (cur != NULL) { - if (cur->deref_type == nir_deref_type_array) - if (!visit_deref_array_src(nir_deref_as_array(cur), cb, state)) - return false; - - cur = cur->child; - } - - return true; -} - -static bool -visit_alu_src(nir_alu_instr *instr, nir_foreach_src_cb cb, void *state) -{ - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) - if (!visit_src(&instr->src[i].src, cb, state)) - return false; - - return true; -} - -static bool -visit_tex_src(nir_tex_instr *instr, nir_foreach_src_cb cb, void *state) -{ - for (unsigned i = 0; i < instr->num_srcs; i++) - if (!visit_src(&instr->src[i].src, cb, state)) - return false; - - if (instr->texture != NULL) - if (!visit_deref_src(instr->texture, cb, state)) - return false; - - if (instr->sampler != NULL) - if (!visit_deref_src(instr->sampler, cb, state)) - return false; - - return true; -} - -static bool -visit_intrinsic_src(nir_intrinsic_instr *instr, nir_foreach_src_cb cb, - void *state) -{ - unsigned num_srcs = nir_intrinsic_infos[instr->intrinsic].num_srcs; - for (unsigned i = 0; i < num_srcs; i++) - if (!visit_src(&instr->src[i], cb, state)) - return false; - - unsigned num_vars = - nir_intrinsic_infos[instr->intrinsic].num_variables; - for (unsigned i = 0; i < num_vars; i++) - if (!visit_deref_src(instr->variables[i], cb, state)) - return false; - - return true; -} - -static bool -visit_call_src(nir_call_instr *instr, nir_foreach_src_cb cb, void *state) -{ - return true; -} - -static bool -visit_load_const_src(nir_load_const_instr *instr, nir_foreach_src_cb cb, - void *state) -{ - return true; -} - -static bool -visit_phi_src(nir_phi_instr *instr, nir_foreach_src_cb cb, void *state) -{ - nir_foreach_phi_src(instr, src) { - if (!visit_src(&src->src, cb, state)) - return false; - } - - return true; -} - -static bool -visit_parallel_copy_src(nir_parallel_copy_instr *instr, - nir_foreach_src_cb cb, void *state) -{ - nir_foreach_parallel_copy_entry(instr, entry) { - if (!visit_src(&entry->src, cb, state)) - return false; - } - - return true; -} - -typedef struct { - void *state; - nir_foreach_src_cb cb; -} visit_dest_indirect_state; - -static bool -visit_dest_indirect(nir_dest *dest, void *_state) -{ - visit_dest_indirect_state *state = (visit_dest_indirect_state *) _state; - - if (!dest->is_ssa && dest->reg.indirect) - return state->cb(dest->reg.indirect, state->state); - - return true; -} - -bool -nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state) -{ - switch (instr->type) { - case nir_instr_type_alu: - if (!visit_alu_src(nir_instr_as_alu(instr), cb, state)) - return false; - break; - case nir_instr_type_intrinsic: - if (!visit_intrinsic_src(nir_instr_as_intrinsic(instr), cb, state)) - return false; - break; - case nir_instr_type_tex: - if (!visit_tex_src(nir_instr_as_tex(instr), cb, state)) - return false; - break; - case nir_instr_type_call: - if (!visit_call_src(nir_instr_as_call(instr), cb, state)) - return false; - break; - case nir_instr_type_load_const: - if (!visit_load_const_src(nir_instr_as_load_const(instr), cb, state)) - return false; - break; - case nir_instr_type_phi: - if (!visit_phi_src(nir_instr_as_phi(instr), cb, state)) - return false; - break; - case nir_instr_type_parallel_copy: - if (!visit_parallel_copy_src(nir_instr_as_parallel_copy(instr), - cb, state)) - return false; - break; - case nir_instr_type_jump: - case nir_instr_type_ssa_undef: - return true; - - default: - unreachable("Invalid instruction type"); - break; - } - - visit_dest_indirect_state dest_state; - dest_state.state = state; - dest_state.cb = cb; - return nir_foreach_dest(instr, visit_dest_indirect, &dest_state); -} - -nir_const_value * -nir_src_as_const_value(nir_src src) -{ - if (!src.is_ssa) - return NULL; - - if (src.ssa->parent_instr->type != nir_instr_type_load_const) - return NULL; - - nir_load_const_instr *load = nir_instr_as_load_const(src.ssa->parent_instr); - - return &load->value; -} - -/** - * Returns true if the source is known to be dynamically uniform. Otherwise it - * returns false which means it may or may not be dynamically uniform but it - * can't be determined. - */ -bool -nir_src_is_dynamically_uniform(nir_src src) -{ - if (!src.is_ssa) - return false; - - /* Constants are trivially dynamically uniform */ - if (src.ssa->parent_instr->type == nir_instr_type_load_const) - return true; - - /* As are uniform variables */ - if (src.ssa->parent_instr->type == nir_instr_type_intrinsic) { - nir_intrinsic_instr *intr = nir_instr_as_intrinsic(src.ssa->parent_instr); - - if (intr->intrinsic == nir_intrinsic_load_uniform) - return true; - } - - /* XXX: this could have many more tests, such as when a sampler function is - * called with dynamically uniform arguments. - */ - return false; -} - -static void -src_remove_all_uses(nir_src *src) -{ - for (; src; src = src->is_ssa ? NULL : src->reg.indirect) { - if (!src_is_valid(src)) - continue; - - list_del(&src->use_link); - } -} - -static void -src_add_all_uses(nir_src *src, nir_instr *parent_instr, nir_if *parent_if) -{ - for (; src; src = src->is_ssa ? NULL : src->reg.indirect) { - if (!src_is_valid(src)) - continue; - - if (parent_instr) { - src->parent_instr = parent_instr; - if (src->is_ssa) - list_addtail(&src->use_link, &src->ssa->uses); - else - list_addtail(&src->use_link, &src->reg.reg->uses); - } else { - assert(parent_if); - src->parent_if = parent_if; - if (src->is_ssa) - list_addtail(&src->use_link, &src->ssa->if_uses); - else - list_addtail(&src->use_link, &src->reg.reg->if_uses); - } - } -} - -void -nir_instr_rewrite_src(nir_instr *instr, nir_src *src, nir_src new_src) -{ - assert(!src_is_valid(src) || src->parent_instr == instr); - - src_remove_all_uses(src); - *src = new_src; - src_add_all_uses(src, instr, NULL); -} - -void -nir_instr_move_src(nir_instr *dest_instr, nir_src *dest, nir_src *src) -{ - assert(!src_is_valid(dest) || dest->parent_instr == dest_instr); - - src_remove_all_uses(dest); - src_remove_all_uses(src); - *dest = *src; - *src = NIR_SRC_INIT; - src_add_all_uses(dest, dest_instr, NULL); -} - -void -nir_if_rewrite_condition(nir_if *if_stmt, nir_src new_src) -{ - nir_src *src = &if_stmt->condition; - assert(!src_is_valid(src) || src->parent_if == if_stmt); - - src_remove_all_uses(src); - *src = new_src; - src_add_all_uses(src, NULL, if_stmt); -} - -void -nir_instr_rewrite_dest(nir_instr *instr, nir_dest *dest, nir_dest new_dest) -{ - if (dest->is_ssa) { - /* We can only overwrite an SSA destination if it has no uses. */ - assert(list_empty(&dest->ssa.uses) && list_empty(&dest->ssa.if_uses)); - } else { - list_del(&dest->reg.def_link); - if (dest->reg.indirect) - src_remove_all_uses(dest->reg.indirect); - } - - /* We can't re-write with an SSA def */ - assert(!new_dest.is_ssa); - - nir_dest_copy(dest, &new_dest, instr); - - dest->reg.parent_instr = instr; - list_addtail(&dest->reg.def_link, &new_dest.reg.reg->defs); - - if (dest->reg.indirect) - src_add_all_uses(dest->reg.indirect, instr, NULL); -} - -void -nir_ssa_def_init(nir_instr *instr, nir_ssa_def *def, - unsigned num_components, const char *name) -{ - def->name = name; - def->parent_instr = instr; - list_inithead(&def->uses); - list_inithead(&def->if_uses); - def->num_components = num_components; - - if (instr->block) { - nir_function_impl *impl = - nir_cf_node_get_function(&instr->block->cf_node); - - def->index = impl->ssa_alloc++; - } else { - def->index = UINT_MAX; - } -} - -void -nir_ssa_dest_init(nir_instr *instr, nir_dest *dest, - unsigned num_components, const char *name) -{ - dest->is_ssa = true; - nir_ssa_def_init(instr, &dest->ssa, num_components, name); -} - -void -nir_ssa_def_rewrite_uses(nir_ssa_def *def, nir_src new_src) -{ - assert(!new_src.is_ssa || def != new_src.ssa); - - nir_foreach_use_safe(def, use_src) - nir_instr_rewrite_src(use_src->parent_instr, use_src, new_src); - - nir_foreach_if_use_safe(def, use_src) - nir_if_rewrite_condition(use_src->parent_if, new_src); -} - -static bool -is_instr_between(nir_instr *start, nir_instr *end, nir_instr *between) -{ - assert(start->block == end->block); - - if (between->block != start->block) - return false; - - /* Search backwards looking for "between" */ - while (start != end) { - if (between == end) - return true; - - end = nir_instr_prev(end); - assert(end); - } - - return false; -} - -/* Replaces all uses of the given SSA def with the given source but only if - * the use comes after the after_me instruction. This can be useful if you - * are emitting code to fix up the result of some instruction: you can freely - * use the result in that code and then call rewrite_uses_after and pass the - * last fixup instruction as after_me and it will replace all of the uses you - * want without touching the fixup code. - * - * This function assumes that after_me is in the same block as - * def->parent_instr and that after_me comes after def->parent_instr. - */ -void -nir_ssa_def_rewrite_uses_after(nir_ssa_def *def, nir_src new_src, - nir_instr *after_me) -{ - assert(!new_src.is_ssa || def != new_src.ssa); - - nir_foreach_use_safe(def, use_src) { - assert(use_src->parent_instr != def->parent_instr); - /* Since def already dominates all of its uses, the only way a use can - * not be dominated by after_me is if it is between def and after_me in - * the instruction list. - */ - if (!is_instr_between(def->parent_instr, after_me, use_src->parent_instr)) - nir_instr_rewrite_src(use_src->parent_instr, use_src, new_src); - } - - nir_foreach_if_use_safe(def, use_src) - nir_if_rewrite_condition(use_src->parent_if, new_src); -} - -static bool foreach_cf_node(nir_cf_node *node, nir_foreach_block_cb cb, - bool reverse, void *state); - -static inline bool -foreach_if(nir_if *if_stmt, nir_foreach_block_cb cb, bool reverse, void *state) -{ - if (reverse) { - foreach_list_typed_reverse_safe(nir_cf_node, node, node, - &if_stmt->else_list) { - if (!foreach_cf_node(node, cb, reverse, state)) - return false; - } - - foreach_list_typed_reverse_safe(nir_cf_node, node, node, - &if_stmt->then_list) { - if (!foreach_cf_node(node, cb, reverse, state)) - return false; - } - } else { - foreach_list_typed_safe(nir_cf_node, node, node, &if_stmt->then_list) { - if (!foreach_cf_node(node, cb, reverse, state)) - return false; - } - - foreach_list_typed_safe(nir_cf_node, node, node, &if_stmt->else_list) { - if (!foreach_cf_node(node, cb, reverse, state)) - return false; - } - } - - return true; -} - -static inline bool -foreach_loop(nir_loop *loop, nir_foreach_block_cb cb, bool reverse, void *state) -{ - if (reverse) { - foreach_list_typed_reverse_safe(nir_cf_node, node, node, &loop->body) { - if (!foreach_cf_node(node, cb, reverse, state)) - return false; - } - } else { - foreach_list_typed_safe(nir_cf_node, node, node, &loop->body) { - if (!foreach_cf_node(node, cb, reverse, state)) - return false; - } - } - - return true; -} - -static bool -foreach_cf_node(nir_cf_node *node, nir_foreach_block_cb cb, - bool reverse, void *state) -{ - switch (node->type) { - case nir_cf_node_block: - return cb(nir_cf_node_as_block(node), state); - case nir_cf_node_if: - return foreach_if(nir_cf_node_as_if(node), cb, reverse, state); - case nir_cf_node_loop: - return foreach_loop(nir_cf_node_as_loop(node), cb, reverse, state); - break; - - default: - unreachable("Invalid CFG node type"); - break; - } - - return false; -} - -bool -nir_foreach_block_in_cf_node(nir_cf_node *node, nir_foreach_block_cb cb, - void *state) -{ - return foreach_cf_node(node, cb, false, state); -} - -bool -nir_foreach_block(nir_function_impl *impl, nir_foreach_block_cb cb, void *state) -{ - foreach_list_typed_safe(nir_cf_node, node, node, &impl->body) { - if (!foreach_cf_node(node, cb, false, state)) - return false; - } - - return cb(impl->end_block, state); -} - -bool -nir_foreach_block_reverse(nir_function_impl *impl, nir_foreach_block_cb cb, - void *state) -{ - if (!cb(impl->end_block, state)) - return false; - - foreach_list_typed_reverse_safe(nir_cf_node, node, node, &impl->body) { - if (!foreach_cf_node(node, cb, true, state)) - return false; - } - - return true; -} - -nir_if * -nir_block_get_following_if(nir_block *block) -{ - if (exec_node_is_tail_sentinel(&block->cf_node.node)) - return NULL; - - if (nir_cf_node_is_last(&block->cf_node)) - return NULL; - - nir_cf_node *next_node = nir_cf_node_next(&block->cf_node); - - if (next_node->type != nir_cf_node_if) - return NULL; - - return nir_cf_node_as_if(next_node); -} - -nir_loop * -nir_block_get_following_loop(nir_block *block) -{ - if (exec_node_is_tail_sentinel(&block->cf_node.node)) - return NULL; - - if (nir_cf_node_is_last(&block->cf_node)) - return NULL; - - nir_cf_node *next_node = nir_cf_node_next(&block->cf_node); - - if (next_node->type != nir_cf_node_loop) - return NULL; - - return nir_cf_node_as_loop(next_node); -} -static bool -index_block(nir_block *block, void *state) -{ - unsigned *index = state; - block->index = (*index)++; - return true; -} - -void -nir_index_blocks(nir_function_impl *impl) -{ - unsigned index = 0; - - if (impl->valid_metadata & nir_metadata_block_index) - return; - - nir_foreach_block(impl, index_block, &index); - - impl->num_blocks = index; -} - -static bool -index_ssa_def_cb(nir_ssa_def *def, void *state) -{ - unsigned *index = (unsigned *) state; - def->index = (*index)++; - - return true; -} - -static bool -index_ssa_block(nir_block *block, void *state) -{ - nir_foreach_instr(block, instr) - nir_foreach_ssa_def(instr, index_ssa_def_cb, state); - - return true; -} - -/** - * The indices are applied top-to-bottom which has the very nice property - * that, if A dominates B, then A->index <= B->index. - */ -void -nir_index_ssa_defs(nir_function_impl *impl) -{ - unsigned index = 0; - nir_foreach_block(impl, index_ssa_block, &index); - impl->ssa_alloc = index; -} - -static bool -index_instrs_block(nir_block *block, void *state) -{ - unsigned *index = state; - nir_foreach_instr(block, instr) - instr->index = (*index)++; - - return true; -} - -/** - * The indices are applied top-to-bottom which has the very nice property - * that, if A dominates B, then A->index <= B->index. - */ -unsigned -nir_index_instrs(nir_function_impl *impl) -{ - unsigned index = 0; - nir_foreach_block(impl, index_instrs_block, &index); - return index; -} - -nir_intrinsic_op -nir_intrinsic_from_system_value(gl_system_value val) -{ - switch (val) { - case SYSTEM_VALUE_VERTEX_ID: - return nir_intrinsic_load_vertex_id; - case SYSTEM_VALUE_INSTANCE_ID: - return nir_intrinsic_load_instance_id; - case SYSTEM_VALUE_DRAW_ID: - return nir_intrinsic_load_draw_id; - case SYSTEM_VALUE_BASE_INSTANCE: - return nir_intrinsic_load_base_instance; - case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE: - return nir_intrinsic_load_vertex_id_zero_base; - case SYSTEM_VALUE_BASE_VERTEX: - return nir_intrinsic_load_base_vertex; - case SYSTEM_VALUE_INVOCATION_ID: - return nir_intrinsic_load_invocation_id; - case SYSTEM_VALUE_FRONT_FACE: - return nir_intrinsic_load_front_face; - case SYSTEM_VALUE_SAMPLE_ID: - return nir_intrinsic_load_sample_id; - case SYSTEM_VALUE_SAMPLE_POS: - return nir_intrinsic_load_sample_pos; - case SYSTEM_VALUE_SAMPLE_MASK_IN: - return nir_intrinsic_load_sample_mask_in; - case SYSTEM_VALUE_LOCAL_INVOCATION_ID: - return nir_intrinsic_load_local_invocation_id; - case SYSTEM_VALUE_WORK_GROUP_ID: - return nir_intrinsic_load_work_group_id; - case SYSTEM_VALUE_NUM_WORK_GROUPS: - return nir_intrinsic_load_num_work_groups; - case SYSTEM_VALUE_PRIMITIVE_ID: - return nir_intrinsic_load_primitive_id; - case SYSTEM_VALUE_TESS_COORD: - return nir_intrinsic_load_tess_coord; - case SYSTEM_VALUE_TESS_LEVEL_OUTER: - return nir_intrinsic_load_tess_level_outer; - case SYSTEM_VALUE_TESS_LEVEL_INNER: - return nir_intrinsic_load_tess_level_inner; - case SYSTEM_VALUE_VERTICES_IN: - return nir_intrinsic_load_patch_vertices_in; - case SYSTEM_VALUE_HELPER_INVOCATION: - return nir_intrinsic_load_helper_invocation; - default: - unreachable("system value does not directly correspond to intrinsic"); - } -} - -gl_system_value -nir_system_value_from_intrinsic(nir_intrinsic_op intrin) -{ - switch (intrin) { - case nir_intrinsic_load_vertex_id: - return SYSTEM_VALUE_VERTEX_ID; - case nir_intrinsic_load_instance_id: - return SYSTEM_VALUE_INSTANCE_ID; - case nir_intrinsic_load_draw_id: - return SYSTEM_VALUE_DRAW_ID; - case nir_intrinsic_load_base_instance: - return SYSTEM_VALUE_BASE_INSTANCE; - case nir_intrinsic_load_vertex_id_zero_base: - return SYSTEM_VALUE_VERTEX_ID_ZERO_BASE; - case nir_intrinsic_load_base_vertex: - return SYSTEM_VALUE_BASE_VERTEX; - case nir_intrinsic_load_invocation_id: - return SYSTEM_VALUE_INVOCATION_ID; - case nir_intrinsic_load_front_face: - return SYSTEM_VALUE_FRONT_FACE; - case nir_intrinsic_load_sample_id: - return SYSTEM_VALUE_SAMPLE_ID; - case nir_intrinsic_load_sample_pos: - return SYSTEM_VALUE_SAMPLE_POS; - case nir_intrinsic_load_sample_mask_in: - return SYSTEM_VALUE_SAMPLE_MASK_IN; - case nir_intrinsic_load_local_invocation_id: - return SYSTEM_VALUE_LOCAL_INVOCATION_ID; - case nir_intrinsic_load_num_work_groups: - return SYSTEM_VALUE_NUM_WORK_GROUPS; - case nir_intrinsic_load_work_group_id: - return SYSTEM_VALUE_WORK_GROUP_ID; - case nir_intrinsic_load_primitive_id: - return SYSTEM_VALUE_PRIMITIVE_ID; - case nir_intrinsic_load_tess_coord: - return SYSTEM_VALUE_TESS_COORD; - case nir_intrinsic_load_tess_level_outer: - return SYSTEM_VALUE_TESS_LEVEL_OUTER; - case nir_intrinsic_load_tess_level_inner: - return SYSTEM_VALUE_TESS_LEVEL_INNER; - case nir_intrinsic_load_patch_vertices_in: - return SYSTEM_VALUE_VERTICES_IN; - case nir_intrinsic_load_helper_invocation: - return SYSTEM_VALUE_HELPER_INVOCATION; - default: - unreachable("intrinsic doesn't produce a system value"); - } -} diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h deleted file mode 100644 index ec6595b091d..00000000000 --- a/src/glsl/nir/nir.h +++ /dev/null @@ -1,2239 +0,0 @@ -/* - * Copyright © 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#pragma once - -#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" -#include "nir_types.h" -#include "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) - -/** Defines a cast function - * - * This macro defines a cast function from in_type to out_type where - * out_type is some structure type that contains a field of type out_type. - * - * Note that you have to be a bit careful as the generated cast function - * destroys constness. - */ -#define NIR_DEFINE_CAST(name, in_type, out_type, field) \ -static inline out_type * \ -name(const in_type *parent) \ -{ \ - return exec_node_data(out_type, parent, field); \ -} - -struct nir_function; -struct nir_shader; -struct nir_instr; - - -/** - * Description of built-in state associated with a uniform - * - * \sa nir_variable::state_slots - */ -typedef struct { - int tokens[5]; - int swizzle; -} nir_state_slot; - -typedef enum { - nir_var_all = -1, - nir_var_shader_in, - nir_var_shader_out, - nir_var_global, - nir_var_local, - nir_var_uniform, - nir_var_shader_storage, - nir_var_shared, - nir_var_system_value -} nir_variable_mode; - -/** - * Data stored in an nir_constant - */ -union nir_constant_data { - unsigned u[16]; - int i[16]; - float f[16]; - bool b[16]; -}; - -typedef struct nir_constant { - /** - * Value of the constant. - * - * The field used to back the values supplied by the constant is determined - * by the type associated with the \c nir_variable. Constants may be - * scalars, vectors, or matrices. - */ - union nir_constant_data value; - - /* we could get this from the var->type but makes clone *much* easier to - * not have to care about the type. - */ - unsigned num_elements; - - /* Array elements / Structure Fields */ - struct nir_constant **elements; -} nir_constant; - -/** - * \brief Layout qualifiers for gl_FragDepth. - * - * The AMD/ARB_conservative_depth extensions allow gl_FragDepth to be redeclared - * with a layout qualifier. - */ -typedef enum { - nir_depth_layout_none, /**< No depth layout is specified. */ - nir_depth_layout_any, - nir_depth_layout_greater, - nir_depth_layout_less, - nir_depth_layout_unchanged -} nir_depth_layout; - -/** - * Either a uniform, global variable, shader input, or shader output. Based on - * ir_variable - it should be easy to translate between the two. - */ - -typedef struct nir_variable { - struct exec_node node; - - /** - * Declared type of the variable - */ - const struct glsl_type *type; - - /** - * Declared name of the variable - */ - char *name; - - struct nir_variable_data { - - /** - * Is the variable read-only? - * - * This is set for variables declared as \c const, shader inputs, - * and uniforms. - */ - unsigned read_only:1; - unsigned centroid:1; - unsigned sample:1; - unsigned patch:1; - unsigned invariant:1; - - /** - * Storage class of the variable. - * - * \sa nir_variable_mode - */ - nir_variable_mode mode:4; - - /** - * Interpolation mode for shader inputs / outputs - * - * \sa glsl_interp_qualifier - */ - unsigned interpolation:2; - - /** - * \name ARB_fragment_coord_conventions - * @{ - */ - unsigned origin_upper_left:1; - unsigned pixel_center_integer:1; - /*@}*/ - - /** - * Was the location explicitly set in the shader? - * - * If the location is explicitly set in the shader, it \b cannot be changed - * by the linker or by the API (e.g., calls to \c glBindAttribLocation have - * no effect). - */ - unsigned explicit_location:1; - unsigned explicit_index:1; - - /** - * Was an initial binding explicitly set in the shader? - * - * If so, constant_initializer contains an integer nir_constant - * representing the initial binding point. - */ - unsigned explicit_binding:1; - - /** - * Does this variable have an initializer? - * - * This is used by the linker to cross-validiate initializers of global - * variables. - */ - unsigned has_initializer:1; - - /** - * If non-zero, then this variable may be packed along with other variables - * into a single varying slot, so this offset should be applied when - * accessing components. For example, an offset of 1 means that the x - * component of this variable is actually stored in component y of the - * location specified by \c location. - */ - unsigned location_frac:2; - - /** - * Non-zero if this variable was created by lowering a named interface - * block which was not an array. - * - * Note that this variable and \c from_named_ifc_block_array will never - * both be non-zero. - */ - unsigned from_named_ifc_block_nonarray:1; - - /** - * Non-zero if this variable was created by lowering a named interface - * block which was an array. - * - * Note that this variable and \c from_named_ifc_block_nonarray will never - * both be non-zero. - */ - unsigned from_named_ifc_block_array:1; - - /** - * \brief Layout qualifier for gl_FragDepth. - * - * This is not equal to \c ir_depth_layout_none if and only if this - * variable is \c gl_FragDepth and a layout qualifier is specified. - */ - nir_depth_layout depth_layout; - - /** - * Storage location of the base of this variable - * - * The precise meaning of this field depends on the nature of the variable. - * - * - Vertex shader input: one of the values from \c gl_vert_attrib. - * - Vertex shader output: one of the values from \c gl_varying_slot. - * - Geometry shader input: one of the values from \c gl_varying_slot. - * - Geometry shader output: one of the values from \c gl_varying_slot. - * - Fragment shader input: one of the values from \c gl_varying_slot. - * - Fragment shader output: one of the values from \c gl_frag_result. - * - Uniforms: Per-stage uniform slot number for default uniform block. - * - Uniforms: Index within the uniform block definition for UBO members. - * - Non-UBO Uniforms: uniform slot number. - * - Other: This field is not currently used. - * - * If the variable is a uniform, shader input, or shader output, and the - * slot has not been assigned, the value will be -1. - */ - int location; - - /** - * The actual location of the variable in the IR. Only valid for inputs - * and outputs. - */ - unsigned int driver_location; - - /** - * output index for dual source blending. - */ - int index; - - /** - * Descriptor set binding for sampler or UBO. - */ - int descriptor_set; - - /** - * Initial binding point for a sampler or UBO. - * - * For array types, this represents the binding point for the first element. - */ - int binding; - - /** - * Location an atomic counter is stored at. - */ - unsigned offset; - - /** - * ARB_shader_image_load_store qualifiers. - */ - struct { - bool read_only; /**< "readonly" qualifier. */ - bool write_only; /**< "writeonly" qualifier. */ - bool coherent; - bool _volatile; - bool restrict_flag; - - /** Image internal format if specified explicitly, otherwise GL_NONE. */ - GLenum format; - } image; - - /** - * Highest element accessed with a constant expression array index - * - * Not used for non-array variables. - */ - unsigned max_array_access; - - } data; - - /** - * Built-in state that backs this uniform - * - * Once set at variable creation, \c state_slots must remain invariant. - * This is because, ideally, this array would be shared by all clones of - * this variable in the IR tree. In other words, we'd really like for it - * to be a fly-weight. - * - * If the variable is not a uniform, \c num_state_slots will be zero and - * \c state_slots will be \c NULL. - */ - /*@{*/ - unsigned num_state_slots; /**< Number of state slots used */ - nir_state_slot *state_slots; /**< State descriptors. */ - /*@}*/ - - /** - * Constant expression assigned in the initializer of the variable - */ - nir_constant *constant_initializer; - - /** - * For variables that are in an interface block or are an instance of an - * interface block, this is the \c GLSL_TYPE_INTERFACE type for that block. - * - * \sa ir_variable::location - */ - const struct glsl_type *interface_type; -} nir_variable; - -#define nir_foreach_variable(var, var_list) \ - foreach_list_typed(nir_variable, var, node, var_list) - -/** - * Returns the bits in the inputs_read, outputs_written, or - * system_values_read bitfield corresponding to this variable. - */ -static inline uint64_t -nir_variable_get_io_mask(nir_variable *var, gl_shader_stage stage) -{ - assert(var->data.mode == nir_var_shader_in || - var->data.mode == nir_var_shader_out || - var->data.mode == nir_var_system_value); - assert(var->data.location >= 0); - - const struct glsl_type *var_type = var->type; - if (stage == MESA_SHADER_GEOMETRY && var->data.mode == nir_var_shader_in) { - /* Most geometry shader inputs are per-vertex arrays */ - if (var->data.location >= VARYING_SLOT_VAR0) - assert(glsl_type_is_array(var_type)); - - if (glsl_type_is_array(var_type)) - var_type = glsl_get_array_element(var_type); - } - - bool is_vertex_input = (var->data.mode == nir_var_shader_in && - stage == MESA_SHADER_VERTEX); - unsigned slots = glsl_count_attribute_slots(var_type, is_vertex_input); - return ((1ull << slots) - 1) << var->data.location; -} - -typedef struct nir_register { - struct exec_node node; - - unsigned num_components; /** < number of vector components */ - unsigned num_array_elems; /** < size of array (0 for no array) */ - - /** generic register index. */ - unsigned index; - - /** only for debug purposes, can be NULL */ - const char *name; - - /** whether this register is local (per-function) or global (per-shader) */ - bool is_global; - - /** - * If this flag is set to true, then accessing channels >= num_components - * is well-defined, and simply spills over to the next array element. This - * is useful for backends that can do per-component accessing, in - * particular scalar backends. By setting this flag and making - * num_components equal to 1, structures can be packed tightly into - * registers and then registers can be accessed per-component to get to - * each structure member, even if it crosses vec4 boundaries. - */ - bool is_packed; - - /** set of nir_src's where this register is used (read from) */ - struct list_head uses; - - /** set of nir_dest's where this register is defined (written to) */ - struct list_head defs; - - /** 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_alu, - nir_instr_type_call, - nir_instr_type_tex, - nir_instr_type_intrinsic, - nir_instr_type_load_const, - nir_instr_type_jump, - nir_instr_type_ssa_undef, - nir_instr_type_phi, - nir_instr_type_parallel_copy, -} nir_instr_type; - -typedef struct nir_instr { - struct exec_node node; - nir_instr_type type; - struct nir_block *block; - - /** generic instruction index. */ - unsigned index; - - /* 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; - -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); -} - -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 nir_ssa_def { - /** for debugging only, can be NULL */ - const char* name; - - /** generic SSA definition index. */ - unsigned index; - - /** Index into the live_in and live_out bitfields */ - unsigned live_index; - - nir_instr *parent_instr; - - /** 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; - -struct nir_src; - -typedef struct { - nir_register *reg; - struct nir_src *indirect; /** < NULL for no indirect offset */ - unsigned base_offset; - - /* TODO use-def chain goes here */ -} 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; - nir_ssa_def ssa; - }; - - 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_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 *instr_or_if); -void nir_dest_copy(nir_dest *dest, const nir_dest *src, nir_instr *instr); - -typedef struct { - nir_src src; - - /** - * \name input modifiers - */ - /*@{*/ - /** - * For inputs interpreted as floating point, flips the sign bit. For - * inputs interpreted as integers, performs the two's complement negation. - */ - bool negate; - - /** - * Clears the sign bit for floating point values, and computes the integer - * absolute value for integers. Note that the negate modifier acts after - * the absolute value modifier, therefore if both are set then all inputs - * will become negative. - */ - bool abs; - /*@}*/ - - /** - * For each input component, says which component of the register it is - * chosen from. Note that which elements of the swizzle are used and which - * are ignored are based on the write mask for most opcodes - for example, - * a statement like "foo.xzw = bar.zyx" would have a writemask of 1101b and - * a swizzle of {2, x, 1, 0} where x means "don't care." - */ - uint8_t swizzle[4]; -} nir_alu_src; - -typedef struct { - nir_dest dest; - - /** - * \name saturate output modifier - * - * Only valid for opcodes that output floating-point numbers. Clamps the - * output to between 0.0 and 1.0 inclusive. - */ - - bool saturate; - - unsigned write_mask : 4; /* ignored if dest.is_ssa is true */ -} nir_alu_dest; - -typedef enum { - nir_type_invalid = 0, /* Not a valid type */ - nir_type_float, - nir_type_int, - nir_type_uint, - nir_type_bool -} nir_alu_type; - -typedef enum { - NIR_OP_IS_COMMUTATIVE = (1 << 0), - NIR_OP_IS_ASSOCIATIVE = (1 << 1), -} nir_op_algebraic_property; - -typedef struct { - const char *name; - - unsigned num_inputs; - - /** - * The number of components in the output - * - * If non-zero, this is the size of the output and input sizes are - * explicitly given; swizzle and writemask are still in effect, but if - * the output component is masked out, then the input component may - * still be in use. - * - * If zero, the opcode acts in the standard, per-component manner; the - * operation is performed on each component (except the ones that are - * masked out) with the input being taken from the input swizzle for - * that component. - * - * The size of some of the inputs may be given (i.e. non-zero) even - * though output_size is zero; in that case, the inputs with a zero - * size act per-component, while the inputs with non-zero size don't. - */ - unsigned output_size; - - /** - * 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; - - /** - * The number of components in each input - */ - unsigned input_sizes[4]; - - /** - * 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]; - - nir_op_algebraic_property algebraic_properties; -} nir_op_info; - -extern const nir_op_info nir_op_infos[nir_num_opcodes]; - -typedef struct nir_alu_instr { - nir_instr instr; - nir_op op; - nir_alu_dest dest; - nir_alu_src src[]; -} nir_alu_instr; - -void nir_alu_src_copy(nir_alu_src *dest, const nir_alu_src *src, - nir_alu_instr *instr); -void nir_alu_dest_copy(nir_alu_dest *dest, const nir_alu_dest *src, - nir_alu_instr *instr); - -/* is this source channel used? */ -static inline bool -nir_alu_instr_channel_used(nir_alu_instr *instr, unsigned src, unsigned channel) -{ - if (nir_op_infos[instr->op].input_sizes[src] > 0) - return channel < nir_op_infos[instr->op].input_sizes[src]; - - 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(const 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, - nir_deref_type_struct -} nir_deref_type; - -typedef struct nir_deref { - nir_deref_type deref_type; - struct nir_deref *child; - const struct glsl_type *type; -} nir_deref; - -typedef struct { - nir_deref deref; - - nir_variable *var; -} nir_deref_var; - -/* This enum describes how the array is referenced. If the deref is - * direct then the base_offset is used. If the deref is indirect then then - * offset is given by base_offset + indirect. If the deref is a wildcard - * then the deref refers to all of the elements of the array at the same - * time. Wildcard dereferences are only ever allowed in copy_var - * intrinsics and the source and destination derefs must have matching - * wildcards. - */ -typedef enum { - nir_deref_array_type_direct, - nir_deref_array_type_indirect, - nir_deref_array_type_wildcard, -} nir_deref_array_type; - -typedef struct { - nir_deref deref; - - nir_deref_array_type deref_array_type; - unsigned base_offset; - nir_src indirect; -} nir_deref_array; - -typedef struct { - nir_deref deref; - - unsigned index; -} nir_deref_struct; - -NIR_DEFINE_CAST(nir_deref_as_var, nir_deref, nir_deref_var, deref) -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 last deref in the chain. */ -static inline nir_deref * -nir_deref_tail(nir_deref *deref) -{ - while (deref->child) - deref = deref->child; - return deref; -} - -typedef struct { - nir_instr instr; - - unsigned num_params; - nir_deref_var **params; - nir_deref_var *return_deref; - - struct nir_function *callee; -} nir_call_instr; - -#define INTRINSIC(name, num_srcs, src_components, has_dest, dest_components, \ - num_variables, num_indices, flags) \ - nir_intrinsic_##name, - -#define LAST_INTRINSIC(name) nir_last_intrinsic = nir_intrinsic_##name, - -typedef enum { -#include "nir_intrinsics.h" - nir_num_intrinsics = nir_last_intrinsic + 1 -} nir_intrinsic_op; - -#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_intrinsic_op intrinsic; - - nir_dest dest; - - /** 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]; - - nir_deref_var *variables[2]; - - nir_src src[]; -} nir_intrinsic_instr; - -/** - * \name NIR intrinsics semantic flags - * - * information about what the compiler can do with the intrinsics. - * - * \sa nir_intrinsic_info::flags - */ -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 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 - -typedef struct { - const char *name; - - unsigned num_srcs; /** < number of register/SSA inputs */ - - /** number of components of each input register - * - * If this value is 0, the number of components is given by the - * num_components field of nir_intrinsic_instr. - */ - unsigned src_components[NIR_INTRINSIC_MAX_INPUTS]; - - bool has_dest; - - /** number of components of the output register - * - * If this value is 0, the number of components is given by the - * num_components field of nir_intrinsic_instr. - */ - unsigned dest_components; - - /** the number of inputs/outputs that are variables */ - unsigned num_variables; - - /** the number of constant indices used by the intrinsic */ - unsigned num_indices; - - /** semantic flags for calls to this intrinsic */ - nir_intrinsic_semantic_flag flags; -} nir_intrinsic_info; - -extern const nir_intrinsic_info nir_intrinsic_infos[nir_num_intrinsics]; - -/** - * \group texture information - * - * This gives semantic information about textures which is useful to the - * frontend, the backend, and lowering passes, but not the optimizer. - */ - -typedef enum { - nir_tex_src_coord, - nir_tex_src_projector, - nir_tex_src_comparitor, /* shadow comparitor */ - nir_tex_src_offset, - nir_tex_src_bias, - nir_tex_src_lod, - nir_tex_src_ms_index, /* MSAA sample index */ - nir_tex_src_ddx, - nir_tex_src_ddy, - nir_tex_src_texture_offset, /* < dynamically uniform indirect offset */ - nir_tex_src_sampler_offset, /* < dynamically uniform indirect offset */ - 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_txb, /**< Texture look-up with LOD bias */ - nir_texop_txl, /**< Texture look-up with explicit LOD */ - nir_texop_txd, /**< Texture look-up with partial derivatvies */ - nir_texop_txf, /**< Texel fetch with explicit LOD */ - nir_texop_txf_ms, /**< Multisample texture fetch */ - nir_texop_txs, /**< Texture size */ - nir_texop_lod, /**< Texture lod query */ - nir_texop_tg4, /**< Texture gather */ - nir_texop_query_levels, /**< Texture levels query */ - nir_texop_texture_samples, /**< Texture samples query */ - nir_texop_samples_identical, /**< Query whether all samples are definitely - * identical. - */ -} nir_texop; - -typedef struct { - nir_instr instr; - - enum glsl_sampler_dim sampler_dim; - nir_alu_type dest_type; - - nir_texop op; - nir_dest dest; - nir_tex_src *src; - unsigned num_srcs, coord_components; - bool is_array, is_shadow; - - /** - * If is_shadow is true, whether this is the old-style shadow that outputs 4 - * components or the new-style shadow that outputs 1 component. - */ - bool is_new_style_shadow; - - /* constant offset - must be 0 if the offset source is used */ - int const_offset[4]; - - /* gather component selector */ - unsigned component : 2; - - /** The texture index - * - * If this texture instruction has a nir_tex_src_texture_offset source, - * then the texture index is given by texture_index + texture_offset. - */ - unsigned texture_index; - - /** The size of the texture array or 0 if it's not an array */ - unsigned texture_array_size; - - /** The texture deref - * - * If both this and `sampler` are both NULL, use texture_index instead. - * If `texture` is NULL, but `sampler` is non-NULL, then the texture is - * implied from the sampler. - */ - nir_deref_var *texture; - - /** The sampler index - * - * If this texture instruction has a nir_tex_src_sampler_offset source, - * then the sampler index is given by sampler_index + sampler_offset. - */ - unsigned sampler_index; - - /** The sampler deref - * - * If this is null, use sampler_index instead. - */ - nir_deref_var *sampler; -} nir_tex_instr; - -static inline unsigned -nir_tex_instr_dest_size(nir_tex_instr *instr) -{ - switch (instr->op) { - case nir_texop_txs: { - unsigned ret; - switch (instr->sampler_dim) { - case GLSL_SAMPLER_DIM_1D: - case GLSL_SAMPLER_DIM_BUF: - ret = 1; - break; - case GLSL_SAMPLER_DIM_2D: - case GLSL_SAMPLER_DIM_CUBE: - case GLSL_SAMPLER_DIM_MS: - case GLSL_SAMPLER_DIM_RECT: - case GLSL_SAMPLER_DIM_EXTERNAL: - ret = 2; - break; - case GLSL_SAMPLER_DIM_3D: - ret = 3; - break; - default: - unreachable("not reached"); - } - if (instr->is_array) - ret++; - return ret; - } - - case nir_texop_lod: - return 2; - - case nir_texop_texture_samples: - case nir_texop_query_levels: - case nir_texop_samples_identical: - return 1; - - default: - if (instr->is_shadow && instr->is_new_style_shadow) - return 1; - - return 4; - } -} - -/* Returns true if this texture operation queries something about the texture - * rather than actually sampling it. - */ -static inline bool -nir_tex_instr_is_query(nir_tex_instr *instr) -{ - switch (instr->op) { - case nir_texop_txs: - case nir_texop_lod: - case nir_texop_texture_samples: - case nir_texop_query_levels: - return true; - case nir_texop_tex: - case nir_texop_txb: - case nir_texop_txl: - case nir_texop_txd: - case nir_texop_txf: - case nir_texop_txf_ms: - case nir_texop_tg4: - return false; - default: - unreachable("Invalid texture opcode"); - } -} - -static inline unsigned -nir_tex_instr_src_size(nir_tex_instr *instr, unsigned src) -{ - if (instr->src[src].src_type == nir_tex_src_coord) - return instr->coord_components; - - - 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 - return instr->coord_components; - } - - return 1; -} - -static inline int -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[i].src_type == type) - return (int) i; - - return -1; -} - -typedef struct { - union { - float f[4]; - int32_t i[4]; - uint32_t u[4]; - }; -} nir_const_value; - -typedef struct { - nir_instr instr; - - nir_const_value value; - - nir_ssa_def def; -} nir_load_const_instr; - -typedef enum { - nir_jump_return, - nir_jump_break, - nir_jump_continue, -} nir_jump_type; - -typedef struct { - nir_instr instr; - nir_jump_type type; -} nir_jump_instr; - -/* creates a new SSA variable in an undefined state */ - -typedef struct { - nir_instr instr; - nir_ssa_def def; -} nir_ssa_undef_instr; - -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; /** < list of nir_phi_src */ - - nir_dest dest; -} nir_phi_instr; - -typedef struct { - struct exec_node node; - nir_src src; - nir_dest dest; -} 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; - - /* 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) -NIR_DEFINE_CAST(nir_instr_as_call, nir_instr, nir_call_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_jump, nir_instr, nir_jump_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_tex, nir_instr, nir_tex_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_intrinsic, nir_instr, nir_intrinsic_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_load_const, nir_instr, nir_load_const_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_ssa_undef, nir_instr, nir_ssa_undef_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_phi, nir_instr, nir_phi_instr, instr) -NIR_DEFINE_CAST(nir_instr_as_parallel_copy, nir_instr, - nir_parallel_copy_instr, instr) - -/* - * Control flow - * - * Control flow consists of a tree of control flow nodes, which include - * if-statements and loops. The leaves of the tree are basic blocks, lists of - * instructions that always run start-to-finish. Each basic block also keeps - * track of its successors (blocks which may run immediately after the current - * block) and predecessors (blocks which could have run immediately before the - * current block). Each function also has a start block and an end block which - * all return statements point to (which is always empty). Together, all the - * blocks with their predecessors and successors make up the control flow - * graph (CFG) of the function. There are helpers that modify the tree of - * control flow nodes while modifying the CFG appropriately; these should be - * used instead of modifying the tree directly. - */ - -typedef enum { - nir_cf_node_block, - nir_cf_node_if, - nir_cf_node_loop, - nir_cf_node_function -} nir_cf_node_type; - -typedef struct nir_cf_node { - struct exec_node node; - nir_cf_node_type type; - struct nir_cf_node *parent; -} nir_cf_node; - -typedef struct nir_block { - nir_cf_node cf_node; - - struct exec_list instr_list; /** < list of nir_instr */ - - /** generic block index; generated by nir_index_blocks */ - unsigned index; - - /* - * Each block can only have up to 2 successors, so we put them in a simple - * array - no need for anything more complicated. - */ - struct nir_block *successors[2]; - - /* Set of nir_block predecessors in the CFG */ - struct set *predecessors; - - /* - * this node's immediate dominator in the dominance tree - set to NULL for - * the start block. - */ - struct nir_block *imm_dom; - - /* This node's children in the dominance tree */ - 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; - -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) -#define nir_foreach_instr_reverse(block, 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_reverse_safe(block, instr) \ - foreach_list_typed_reverse_safe(nir_instr, instr, node, &(block)->instr_list) - -typedef struct nir_if { - nir_cf_node cf_node; - nir_src condition; - - struct exec_list then_list; /** < list of nir_cf_node */ - struct exec_list else_list; /** < list of nir_cf_node */ -} nir_if; - -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; /** < list of nir_cf_node */ -} nir_loop; - -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 - * optimization and analysis passes - */ -typedef enum { - nir_metadata_none = 0x0, - nir_metadata_block_index = 0x1, - nir_metadata_dominance = 0x2, - nir_metadata_live_ssa_defs = 0x4, - nir_metadata_not_properly_reset = 0x8, -} nir_metadata; - -typedef struct { - nir_cf_node cf_node; - - /** pointer to the function of which this is an implementation */ - struct nir_function *function; - - struct exec_list body; /** < list of nir_cf_node */ - - nir_block *end_block; - - /** list for all local variables in the function */ - struct exec_list locals; - - /** array of variables used as parameters */ - unsigned num_params; - nir_variable **params; - - /** variable used to hold the result of the function */ - nir_variable *return_var; - - /** list of local registers in the function */ - struct exec_list registers; - - /** next available local register index */ - unsigned reg_alloc; - - /** next available SSA value index */ - unsigned ssa_alloc; - - /* total number of basic blocks, only valid when block_index_dirty = false */ - unsigned num_blocks; - - 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) -{ - 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); -} - -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); -} - -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) -NIR_DEFINE_CAST(nir_cf_node_as_loop, nir_cf_node, nir_loop, cf_node) -NIR_DEFINE_CAST(nir_cf_node_as_function, nir_cf_node, nir_function_impl, cf_node) - -typedef enum { - nir_parameter_in, - nir_parameter_out, - nir_parameter_inout, -} nir_parameter_type; - -typedef struct { - nir_parameter_type param_type; - const struct glsl_type *type; -} nir_parameter; - -typedef struct nir_function { - struct exec_node node; - - const char *name; - struct nir_shader *shader; - - unsigned num_params; - nir_parameter *params; - const struct glsl_type *return_type; - - /** The implementation of this function. - * - * If the function is only declared and not implemented, this is NULL. - */ - nir_function_impl *impl; -} nir_function; - -typedef struct nir_shader_compiler_options { - bool lower_fdiv; - bool lower_ffma; - bool lower_flrp; - bool lower_fpow; - bool lower_fsat; - bool lower_fsqrt; - bool lower_fmod; - bool lower_bitfield_extract; - bool lower_bitfield_insert; - bool lower_uadd_carry; - bool lower_usub_borrow; - /** 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 native fdot instruction replicate its result for four - * components? If so, then opt_algebraic_late will turn all fdotN - * instructions into fdot_replicatedN instructions. - */ - bool fdot_replicates; - - /** lowers ffract to fsub+ffloor: */ - bool lower_ffract; - - bool lower_pack_half_2x16; - bool lower_pack_unorm_2x16; - bool lower_pack_snorm_2x16; - bool lower_pack_unorm_4x8; - bool lower_pack_snorm_4x8; - bool lower_unpack_half_2x16; - bool lower_unpack_unorm_2x16; - bool lower_unpack_snorm_2x16; - bool lower_unpack_unorm_4x8; - bool lower_unpack_snorm_4x8; - - bool lower_extract_byte; - bool lower_extract_word; - - /** - * Does the driver support real 32-bit integers? (Otherwise, integers - * are simulated by floats.) - */ - bool native_integers; - - /* Indicates that the driver only has zero-based vertex id */ - bool vertex_id_zero_based; -} nir_shader_compiler_options; - -typedef struct nir_shader_info { - const char *name; - - /* Descriptive name provided by the client; may be NULL */ - const char *label; - - /* Number of textures used by this shader */ - unsigned num_textures; - /* Number of uniform buffers used by this shader */ - unsigned num_ubos; - /* Number of atomic buffers used by this shader */ - unsigned num_abos; - /* Number of shader storage buffers used by this shader */ - unsigned num_ssbos; - /* Number of images used by this shader */ - unsigned num_images; - - /* Which inputs are actually read */ - uint64_t inputs_read; - /* Which outputs are actually written */ - uint64_t outputs_written; - /* Which system values are actually read */ - uint64_t system_values_read; - - /* Which patch inputs are actually read */ - uint32_t patch_inputs_read; - /* Which patch outputs are actually written */ - uint32_t patch_outputs_written; - - /* Whether or not this shader ever uses textureGather() */ - bool uses_texture_gather; - - /* Whether or not this shader uses the gl_ClipDistance output */ - bool uses_clip_distance_out; - - /* Whether or not separate shader objects were used */ - bool separate_shader; - - /** Was this shader linked with any transform feedback varyings? */ - bool has_transform_feedback_varyings; - - union { - struct { - /** The number of vertices recieves per input primitive */ - unsigned vertices_in; - - /** The output primitive type (GL enum value) */ - unsigned output_primitive; - - /** The maximum number of vertices the geometry shader might write. */ - unsigned vertices_out; - - /** 1 .. MAX_GEOMETRY_SHADER_INVOCATIONS */ - unsigned invocations; - - /** Whether or not this shader uses EndPrimitive */ - bool uses_end_primitive; - - /** Whether or not this shader uses non-zero streams */ - bool uses_streams; - } gs; - - struct { - bool uses_discard; - - /** - * Whether early fragment tests are enabled as defined by - * ARB_shader_image_load_store. - */ - bool early_fragment_tests; - - /** gl_FragDepth layout for ARB_conservative_depth. */ - enum gl_frag_depth_layout depth_layout; - } fs; - - struct { - unsigned local_size[3]; - } cs; - - struct { - /** The number of vertices in the TCS output patch. */ - unsigned vertices_out; - } tcs; - }; -} nir_shader_info; - -typedef struct nir_shader { - /** list of uniforms (nir_variable) */ - struct exec_list uniforms; - - /** list of inputs (nir_variable) */ - struct exec_list inputs; - - /** list of outputs (nir_variable) */ - struct exec_list outputs; - - /** list of shared compute variables (nir_variable) */ - struct exec_list shared; - - /** 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; - - /** Various bits of compile-time information about a given shader */ - struct nir_shader_info info; - - /** list of global variables in the shader (nir_variable) */ - struct exec_list globals; - - /** list of system value variables in the shader (nir_variable) */ - struct exec_list system_values; - - struct exec_list functions; /** < list of nir_function */ - - /** list of global register in the shader */ - struct exec_list registers; - - /** next available global register index */ - unsigned reg_alloc; - - /** - * the highest index a load_input_*, load_uniform_*, etc. intrinsic can - * access plus one - */ - unsigned num_inputs, num_uniforms, num_outputs, num_shared; - - /** The shader stage, such as MESA_SHADER_VERTEX. */ - gl_shader_stage stage; -} nir_shader; - -#define nir_foreach_function(shader, func) \ - foreach_list_typed(nir_function, func, node, &(shader)->functions) - -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_register *nir_global_reg_create(nir_shader *shader); - -nir_register *nir_local_reg_create(nir_function_impl *impl); - -void nir_reg_remove(nir_register *reg); - -/** Adds a variable to the appropreate list in nir_shader */ -void nir_shader_add_variable(nir_shader *shader, nir_variable *var); - -static inline void -nir_function_impl_add_variable(nir_function_impl *impl, nir_variable *var) -{ - assert(var->data.mode == nir_var_local); - exec_list_push_tail(&impl->locals, &var->node); -} - -/** creates a variable, sets a few defaults, and adds it to the list */ -nir_variable *nir_variable_create(nir_shader *shader, - nir_variable_mode mode, - const struct glsl_type *type, - const char *name); -/** creates a local variable and adds it to the list */ -nir_variable *nir_local_variable_create(nir_function_impl *impl, - const struct glsl_type *type, - const char *name); - -/** creates a function and adds it to the shader's list of functions */ -nir_function *nir_function_create(nir_shader *shader, const char *name); - -nir_function_impl *nir_function_impl_create(nir_function *func); -/** creates a function_impl that isn't tied to any particular function */ -nir_function_impl *nir_function_impl_create_bare(nir_shader *shader); - -nir_block *nir_block_create(nir_shader *shader); -nir_if *nir_if_create(nir_shader *shader); -nir_loop *nir_loop_create(nir_shader *shader); - -nir_function_impl *nir_cf_node_get_function(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(nir_shader *shader, nir_op op); - -nir_jump_instr *nir_jump_instr_create(nir_shader *shader, nir_jump_type type); - -nir_load_const_instr *nir_load_const_instr_create(nir_shader *shader, - unsigned num_components); - -nir_intrinsic_instr *nir_intrinsic_instr_create(nir_shader *shader, - nir_intrinsic_op op); - -nir_call_instr *nir_call_instr_create(nir_shader *shader, - nir_function *callee); - -nir_tex_instr *nir_tex_instr_create(nir_shader *shader, unsigned num_srcs); - -nir_phi_instr *nir_phi_instr_create(nir_shader *shader); - -nir_parallel_copy_instr *nir_parallel_copy_instr_create(nir_shader *shader); - -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_array *nir_deref_array_create(void *mem_ctx); -nir_deref_struct *nir_deref_struct_create(void *mem_ctx, unsigned field_index); - -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); - -/** - * 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; - -typedef struct { - nir_cursor_option option; - union { - nir_block *block; - nir_instr *instr; - }; -} nir_cursor; - -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; - } -} - -bool nir_cursors_equal(nir_cursor a, nir_cursor b); - -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_after_cf_node_and_phis(nir_cf_node *node) -{ - if (node->type == nir_cf_node_block) - return nir_after_block(nir_cf_node_as_block(node)); - - nir_block *block = nir_cf_node_as_block(nir_cf_node_next(node)); - assert(block->cf_node.type == nir_cf_node_block); - - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_phi) - return nir_before_instr(instr); - } - return nir_after_block(block); -} - -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); -bool nir_foreach_ssa_def(nir_instr *instr, nir_foreach_ssa_def_cb cb, - void *state); -bool nir_foreach_dest(nir_instr *instr, nir_foreach_dest_cb cb, void *state); -bool nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state); - -nir_const_value *nir_src_as_const_value(nir_src src); -bool nir_src_is_dynamically_uniform(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_instr_rewrite_dest(nir_instr *instr, nir_dest *dest, - nir_dest new_dest); - -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 nir_ssa_def_rewrite_uses_after(nir_ssa_def *def, nir_src new_src, - nir_instr *after_me); - -/* visits basic blocks in source-code order */ -typedef bool (*nir_foreach_block_cb)(nir_block *block, void *state); -bool nir_foreach_block(nir_function_impl *impl, nir_foreach_block_cb cb, - void *state); -bool nir_foreach_block_reverse(nir_function_impl *impl, nir_foreach_block_cb cb, - void *state); -bool nir_foreach_block_in_cf_node(nir_cf_node *node, nir_foreach_block_cb cb, - void *state); - -/* If the following CF node is an if, this function returns that if. - * Otherwise, it returns NULL. - */ -nir_if *nir_block_get_following_if(nir_block *block); - -nir_loop *nir_block_get_following_loop(nir_block *block); - -void nir_index_local_regs(nir_function_impl *impl); -void nir_index_global_regs(nir_shader *shader); -void nir_index_ssa_defs(nir_function_impl *impl); -unsigned nir_index_instrs(nir_function_impl *impl); - -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); - -nir_shader *nir_shader_clone(void *mem_ctx, const nir_shader *s); -nir_function_impl *nir_function_impl_clone(const nir_function_impl *impl); -nir_constant *nir_constant_clone(const nir_constant *c, nir_variable *var); - -#ifdef DEBUG -void nir_validate_shader(nir_shader *shader); -void nir_metadata_set_validation_flag(nir_shader *shader); -void nir_metadata_check_validation_flag(nir_shader *shader); - -#include "util/debug.h" -static inline bool -should_clone_nir(void) -{ - static int should_clone = -1; - if (should_clone < 0) - should_clone = env_var_as_boolean("NIR_TEST_CLONE", false); - - return should_clone; -} -#else -static inline void nir_validate_shader(nir_shader *shader) { (void) shader; } -static inline void nir_metadata_set_validation_flag(nir_shader *shader) { (void) shader; } -static inline void nir_metadata_check_validation_flag(nir_shader *shader) { (void) shader; } -static inline bool should_clone_nir(void) { return false; } -#endif /* DEBUG */ - -#define _PASS(nir, do_pass) do { \ - do_pass \ - nir_validate_shader(nir); \ - if (should_clone_nir()) { \ - nir_shader *clone = nir_shader_clone(ralloc_parent(nir), nir); \ - ralloc_free(nir); \ - nir = clone; \ - } \ -} while (0) - -#define NIR_PASS(progress, nir, pass, ...) _PASS(nir, \ - nir_metadata_set_validation_flag(nir); \ - if (pass(nir, ##__VA_ARGS__)) { \ - progress = true; \ - nir_metadata_check_validation_flag(nir); \ - } \ -) - -#define NIR_PASS_V(nir, pass, ...) _PASS(nir, \ - pass(nir, ##__VA_ARGS__); \ -) - -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_dump_dom_frontier_impl(nir_function_impl *impl, FILE *fp); -void nir_dump_dom_frontier(nir_shader *shader, FILE *fp); - -void nir_dump_cfg_impl(nir_function_impl *impl, FILE *fp); -void nir_dump_cfg(nir_shader *shader, FILE *fp); - -int nir_gs_count_vertices(const nir_shader *shader); - -bool nir_split_var_copies(nir_shader *shader); - -bool nir_lower_returns_impl(nir_function_impl *impl); -bool nir_lower_returns(nir_shader *shader); - -bool nir_inline_functions(nir_shader *shader); - -void nir_lower_var_copy_instr(nir_intrinsic_instr *copy, void *mem_ctx); -void nir_lower_var_copies(nir_shader *shader); - -bool nir_lower_global_vars_to_local(nir_shader *shader); - -bool nir_lower_indirect_derefs(nir_shader *shader, uint32_t mode_mask); - -bool nir_lower_locals_to_regs(nir_shader *shader); - -void nir_lower_outputs_to_temporaries(nir_shader *shader, - nir_function *entrypoint); - -void nir_shader_gather_info(nir_shader *shader, nir_function_impl *entrypoint); - -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, - nir_variable_mode mode, - int (*type_size)(const struct glsl_type *)); -nir_src *nir_get_io_offset_src(nir_intrinsic_instr *instr); -nir_src *nir_get_io_vertex_index_src(nir_intrinsic_instr *instr); - -void nir_lower_vars_to_ssa(nir_shader *shader); - -bool nir_remove_dead_variables(nir_shader *shader, nir_variable_mode mode); - -void nir_move_vec_src_uses_to_dest(nir_shader *shader); -bool 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, - const struct gl_shader_program *shader_program); - -bool nir_lower_system_values(nir_shader *shader); - -typedef struct nir_lower_tex_options { - /** - * bitmask of (1 << GLSL_SAMPLER_DIM_x) to control for which - * sampler types a texture projector is lowered. - */ - unsigned lower_txp; - - /** - * If true, lower rect textures to 2D, using txs to fetch the - * texture dimensions and dividing the texture coords by the - * texture dims to normalize. - */ - bool lower_rect; - - /** - * To emulate certain texture wrap modes, this can be used - * to saturate the specified tex coord to [0.0, 1.0]. The - * bits are according to sampler #, ie. if, for example: - * - * (conf->saturate_s & (1 << n)) - * - * is true, then the s coord for sampler n is saturated. - * - * Note that clamping must happen *after* projector lowering - * so any projected texture sample instruction with a clamped - * coordinate gets automatically lowered, regardless of the - * 'lower_txp' setting. - */ - unsigned saturate_s; - unsigned saturate_t; - unsigned saturate_r; - - /* Bitmask of samplers that need swizzling. - * - * If (swizzle_result & (1 << sampler_index)), then the swizzle in - * swizzles[sampler_index] is applied to the result of the texturing - * operation. - */ - unsigned swizzle_result; - - /* A swizzle for each sampler. Values 0-3 represent x, y, z, or w swizzles - * while 4 and 5 represent 0 and 1 respectively. - */ - uint8_t swizzles[32][4]; -} nir_lower_tex_options; - -bool nir_lower_tex(nir_shader *shader, - const nir_lower_tex_options *options); - -void nir_lower_idiv(nir_shader *shader); - -void nir_lower_clip_vs(nir_shader *shader, unsigned ucp_enables); -void nir_lower_clip_fs(nir_shader *shader, unsigned ucp_enables); - -void nir_lower_two_sided_color(nir_shader *shader); - -void nir_lower_atomics(nir_shader *shader, - const struct gl_shader_program *shader_program); -void nir_lower_to_source_mods(nir_shader *shader); - -bool nir_lower_gs_intrinsics(nir_shader *shader); - -bool nir_normalize_cubemap_coords(nir_shader *shader); - -void nir_live_ssa_defs_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); - -bool nir_repair_ssa_impl(nir_function_impl *impl); -bool nir_repair_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_copy_prop(nir_shader *shader); - -bool nir_opt_cse(nir_shader *shader); - -bool nir_opt_dce(nir_shader *shader); - -bool nir_opt_dead_cf(nir_shader *shader); - -void nir_opt_gcm(nir_shader *shader); - -bool nir_opt_peephole_select(nir_shader *shader); - -bool nir_opt_remove_phis(nir_shader *shader); - -bool nir_opt_undef(nir_shader *shader); - -void nir_sweep(nir_shader *shader); - -nir_intrinsic_op nir_intrinsic_from_system_value(gl_system_value val); -gl_system_value nir_system_value_from_intrinsic(nir_intrinsic_op intrin); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/src/glsl/nir/nir_algebraic.py b/src/glsl/nir/nir_algebraic.py deleted file mode 100644 index 14c0e822ad8..00000000000 --- a/src/glsl/nir/nir_algebraic.py +++ /dev/null @@ -1,305 +0,0 @@ -#! /usr/bin/env python -# -# Copyright (C) 2014 Intel Corporation -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# -# Authors: -# Jason Ekstrand ([email protected]) - -import itertools -import struct -import sys -import mako.template -import re - -# Represents a set of variables, each with a unique id -class VarSet(object): - def __init__(self): - self.names = {} - self.ids = itertools.count() - self.immutable = False; - - def __getitem__(self, name): - if name not in self.names: - assert not self.immutable, "Unknown replacement variable: " + name - self.names[name] = self.ids.next() - - return self.names[name] - - def lock(self): - self.immutable = True - -class Value(object): - @staticmethod - def create(val, name_base, varset): - if isinstance(val, tuple): - return Expression(val, name_base, varset) - elif isinstance(val, Expression): - return val - elif isinstance(val, (str, unicode)): - return Variable(val, name_base, varset) - elif isinstance(val, (bool, int, long, float)): - return Constant(val, name_base) - - __template = mako.template.Template(""" -static const ${val.c_type} ${val.name} = { - { ${val.type_enum} }, -% if isinstance(val, Constant): - { ${hex(val)} /* ${val.value} */ }, -% elif isinstance(val, Variable): - ${val.index}, /* ${val.var_name} */ - ${'true' if val.is_constant else 'false'}, - nir_type_${ val.required_type or 'invalid' }, -% elif isinstance(val, Expression): - nir_op_${val.opcode}, - { ${', '.join(src.c_ptr for src in val.sources)} }, -% endif -};""") - - def __init__(self, name, type_str): - self.name = name - self.type_str = type_str - - @property - def type_enum(self): - return "nir_search_value_" + self.type_str - - @property - def c_type(self): - return "nir_search_" + self.type_str - - @property - def c_ptr(self): - return "&{0}.value".format(self.name) - - def render(self): - return self.__template.render(val=self, - Constant=Constant, - Variable=Variable, - Expression=Expression) - -class Constant(Value): - def __init__(self, val, name): - Value.__init__(self, name, "constant") - self.value = val - - def __hex__(self): - # Even if it's an integer, we still need to unpack as an unsigned - # int. This is because, without C99, we can only assign to the first - # element of a union in an initializer. - if isinstance(self.value, (bool)): - return 'NIR_TRUE' if self.value else 'NIR_FALSE' - if isinstance(self.value, (int, long)): - return hex(struct.unpack('I', struct.pack('i' if self.value < 0 else 'I', self.value))[0]) - elif isinstance(self.value, float): - return hex(struct.unpack('I', struct.pack('f', self.value))[0]) - else: - assert False - -_var_name_re = re.compile(r"(?P<const>#)?(?P<name>\w+)(?:@(?P<type>\w+))?") - -class Variable(Value): - def __init__(self, val, name, varset): - Value.__init__(self, name, "variable") - - m = _var_name_re.match(val) - assert m and m.group('name') is not None - - self.var_name = m.group('name') - self.is_constant = m.group('const') is not None - self.required_type = m.group('type') - - if self.required_type is not None: - assert self.required_type in ('float', 'bool', 'int', 'unsigned') - - self.index = varset[self.var_name] - -class Expression(Value): - def __init__(self, expr, name_base, varset): - Value.__init__(self, name_base, "expression") - assert isinstance(expr, tuple) - - self.opcode = expr[0] - self.sources = [ Value.create(src, "{0}_{1}".format(name_base, i), varset) - for (i, src) in enumerate(expr[1:]) ] - - def render(self): - srcs = "\n".join(src.render() for src in self.sources) - return srcs + super(Expression, self).render() - -_optimization_ids = itertools.count() - -condition_list = ['true'] - -class SearchAndReplace(object): - def __init__(self, transform): - self.id = _optimization_ids.next() - - search = transform[0] - replace = transform[1] - if len(transform) > 2: - self.condition = transform[2] - else: - self.condition = 'true' - - if self.condition not in condition_list: - condition_list.append(self.condition) - self.condition_index = condition_list.index(self.condition) - - varset = VarSet() - if isinstance(search, Expression): - self.search = search - else: - self.search = Expression(search, "search{0}".format(self.id), varset) - - varset.lock() - - if isinstance(replace, Value): - self.replace = replace - else: - self.replace = Value.create(replace, "replace{0}".format(self.id), varset) - -_algebraic_pass_template = mako.template.Template(""" -#include "nir.h" -#include "nir_search.h" - -#ifndef NIR_OPT_ALGEBRAIC_STRUCT_DEFS -#define NIR_OPT_ALGEBRAIC_STRUCT_DEFS - -struct transform { - const nir_search_expression *search; - const nir_search_value *replace; - unsigned condition_offset; -}; - -struct opt_state { - void *mem_ctx; - bool progress; - const bool *condition_flags; -}; - -#endif - -% for (opcode, xform_list) in xform_dict.iteritems(): -% for xform in xform_list: - ${xform.search.render()} - ${xform.replace.render()} -% endfor - -static const struct transform ${pass_name}_${opcode}_xforms[] = { -% for xform in xform_list: - { &${xform.search.name}, ${xform.replace.c_ptr}, ${xform.condition_index} }, -% endfor -}; -% endfor - -static bool -${pass_name}_block(nir_block *block, void *void_state) -{ - struct opt_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_alu) - continue; - - nir_alu_instr *alu = nir_instr_as_alu(instr); - if (!alu->dest.dest.is_ssa) - continue; - - switch (alu->op) { - % for opcode in xform_dict.keys(): - case nir_op_${opcode}: - for (unsigned i = 0; i < ARRAY_SIZE(${pass_name}_${opcode}_xforms); i++) { - const struct transform *xform = &${pass_name}_${opcode}_xforms[i]; - if (state->condition_flags[xform->condition_offset] && - nir_replace_instr(alu, xform->search, xform->replace, - state->mem_ctx)) { - state->progress = true; - break; - } - } - break; - % endfor - default: - break; - } - } - - return true; -} - -static bool -${pass_name}_impl(nir_function_impl *impl, const bool *condition_flags) -{ - struct opt_state state; - - state.mem_ctx = ralloc_parent(impl); - state.progress = false; - state.condition_flags = condition_flags; - - nir_foreach_block(impl, ${pass_name}_block, &state); - - if (state.progress) - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - return state.progress; -} - - -bool -${pass_name}(nir_shader *shader) -{ - bool progress = false; - bool condition_flags[${len(condition_list)}]; - const nir_shader_compiler_options *options = shader->options; - - % for index, condition in enumerate(condition_list): - condition_flags[${index}] = ${condition}; - % endfor - - nir_foreach_function(shader, function) { - if (function->impl) - progress |= ${pass_name}_impl(function->impl, condition_flags); - } - - return progress; -} -""") - -class AlgebraicPass(object): - def __init__(self, pass_name, transforms): - self.xform_dict = {} - self.pass_name = pass_name - - for xform in transforms: - if not isinstance(xform, SearchAndReplace): - xform = SearchAndReplace(xform) - - if xform.search.opcode not in self.xform_dict: - self.xform_dict[xform.search.opcode] = [] - - self.xform_dict[xform.search.opcode].append(xform) - - def render(self): - return _algebraic_pass_template.render(pass_name=self.pass_name, - xform_dict=self.xform_dict, - condition_list=condition_list) diff --git a/src/glsl/nir/nir_array.h b/src/glsl/nir/nir_array.h deleted file mode 100644 index 1db4e8cea36..00000000000 --- a/src/glsl/nir/nir_array.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - void *mem_ctx; - size_t size; - size_t alloc; - void *data; -} nir_array; - -static inline void -nir_array_init(nir_array *arr, void *mem_ctx) -{ - arr->mem_ctx = mem_ctx; - arr->size = 0; - arr->alloc = 0; - arr->data = NULL; -} - -static inline void -nir_array_fini(nir_array *arr) -{ - if (arr->mem_ctx) - ralloc_free(arr->data); - else - free(arr->data); -} - -#define NIR_ARRAY_INITIAL_SIZE 64 - -/* Increments the size of the array by the given ammount and returns a - * pointer to the beginning of the newly added space. - */ -static inline void * -nir_array_grow(nir_array *arr, size_t additional) -{ - size_t new_size = arr->size + additional; - if (new_size > arr->alloc) { - if (arr->alloc == 0) - arr->alloc = NIR_ARRAY_INITIAL_SIZE; - - while (new_size > arr->alloc) - arr->alloc *= 2; - - if (arr->mem_ctx) - arr->data = reralloc_size(arr->mem_ctx, arr->data, arr->alloc); - else - arr->data = realloc(arr->data, arr->alloc); - } - - void *ptr = (void *)((char *)arr->data + arr->size); - arr->size = new_size; - - return ptr; -} - -#define nir_array_add(arr, type, elem) \ - *(type *)nir_array_grow(arr, sizeof(type)) = (elem) - -#define nir_array_foreach(arr, type, elem) \ - for (type *elem = (type *)(arr)->data; \ - elem < (type *)((char *)(arr)->data + (arr)->size); elem++) - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/src/glsl/nir/nir_builder.h b/src/glsl/nir/nir_builder.h deleted file mode 100644 index 1c7c78acae8..00000000000 --- a/src/glsl/nir/nir_builder.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright © 2014-2015 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef NIR_BUILDER_H -#define NIR_BUILDER_H - -#include "nir_control_flow.h" - -struct exec_list; - -typedef struct nir_builder { - nir_cursor cursor; - - nir_shader *shader; - nir_function_impl *impl; -} nir_builder; - -static inline void -nir_builder_init(nir_builder *build, nir_function_impl *impl) -{ - memset(build, 0, sizeof(*build)); - build->impl = impl; - build->shader = impl->function->shader; -} - -static inline void -nir_builder_init_simple_shader(nir_builder *build, void *mem_ctx, - gl_shader_stage stage, - const nir_shader_compiler_options *options) -{ - build->shader = nir_shader_create(mem_ctx, stage, options); - nir_function *func = nir_function_create(build->shader, "main"); - build->impl = nir_function_impl_create(func); - build->cursor = nir_after_cf_list(&build->impl->body); -} - -static inline void -nir_builder_instr_insert(nir_builder *build, nir_instr *instr) -{ - nir_instr_insert(build->cursor, instr); - - /* Move the cursor forward. */ - build->cursor = nir_after_instr(instr); -} - -static inline void -nir_builder_cf_insert(nir_builder *build, nir_cf_node *cf) -{ - nir_cf_node_insert(build->cursor, cf); -} - -static inline nir_ssa_def * -nir_ssa_undef(nir_builder *build, unsigned num_components) -{ - nir_ssa_undef_instr *undef = - nir_ssa_undef_instr_create(build->shader, num_components); - if (!undef) - return NULL; - - nir_instr_insert(nir_before_block(nir_start_block(build->impl)), - &undef->instr); - - return &undef->def; -} - -static inline nir_ssa_def * -nir_build_imm(nir_builder *build, unsigned num_components, nir_const_value value) -{ - nir_load_const_instr *load_const = - nir_load_const_instr_create(build->shader, num_components); - if (!load_const) - return NULL; - - load_const->value = value; - - nir_builder_instr_insert(build, &load_const->instr); - - return &load_const->def; -} - -static inline nir_ssa_def * -nir_imm_float(nir_builder *build, float x) -{ - nir_const_value v; - - memset(&v, 0, sizeof(v)); - v.f[0] = x; - - return nir_build_imm(build, 1, v); -} - -static inline nir_ssa_def * -nir_imm_vec4(nir_builder *build, float x, float y, float z, float w) -{ - nir_const_value v; - - memset(&v, 0, sizeof(v)); - v.f[0] = x; - v.f[1] = y; - v.f[2] = z; - v.f[3] = w; - - return nir_build_imm(build, 4, v); -} - -static inline nir_ssa_def * -nir_imm_int(nir_builder *build, int x) -{ - nir_const_value v; - - memset(&v, 0, sizeof(v)); - v.i[0] = x; - - return nir_build_imm(build, 1, v); -} - -static inline nir_ssa_def * -nir_imm_ivec4(nir_builder *build, int x, int y, int z, int w) -{ - nir_const_value v; - - memset(&v, 0, sizeof(v)); - v.i[0] = x; - v.i[1] = y; - v.i[2] = z; - v.i[3] = w; - - return nir_build_imm(build, 4, v); -} - -static inline nir_ssa_def * -nir_build_alu(nir_builder *build, nir_op op, nir_ssa_def *src0, - nir_ssa_def *src1, nir_ssa_def *src2, nir_ssa_def *src3) -{ - const nir_op_info *op_info = &nir_op_infos[op]; - nir_alu_instr *instr = nir_alu_instr_create(build->shader, op); - if (!instr) - return NULL; - - instr->src[0].src = nir_src_for_ssa(src0); - if (src1) - instr->src[1].src = nir_src_for_ssa(src1); - if (src2) - instr->src[2].src = nir_src_for_ssa(src2); - if (src3) - instr->src[3].src = nir_src_for_ssa(src3); - - /* Guess the number of components the destination temporary should have - * based on our input sizes, if it's not fixed for the op. - */ - unsigned num_components = op_info->output_size; - if (num_components == 0) { - for (unsigned i = 0; i < op_info->num_inputs; i++) { - if (op_info->input_sizes[i] == 0) - num_components = MAX2(num_components, - instr->src[i].src.ssa->num_components); - } - } - assert(num_components != 0); - - /* Make sure we don't swizzle from outside of our source vector (like if a - * scalar value was passed into a multiply with a vector). - */ - for (unsigned i = 0; i < op_info->num_inputs; i++) { - for (unsigned j = instr->src[i].src.ssa->num_components; j < 4; j++) { - instr->src[i].swizzle[j] = instr->src[i].src.ssa->num_components - 1; - } - } - - nir_ssa_dest_init(&instr->instr, &instr->dest.dest, num_components, NULL); - instr->dest.write_mask = (1 << num_components) - 1; - - nir_builder_instr_insert(build, &instr->instr); - - return &instr->dest.dest.ssa; -} - -#define ALU1(op) \ -static inline nir_ssa_def * \ -nir_##op(nir_builder *build, nir_ssa_def *src0) \ -{ \ - return nir_build_alu(build, nir_op_##op, src0, NULL, NULL, NULL); \ -} - -#define ALU2(op) \ -static inline nir_ssa_def * \ -nir_##op(nir_builder *build, nir_ssa_def *src0, nir_ssa_def *src1) \ -{ \ - return nir_build_alu(build, nir_op_##op, src0, src1, NULL, NULL); \ -} - -#define ALU3(op) \ -static inline nir_ssa_def * \ -nir_##op(nir_builder *build, nir_ssa_def *src0, \ - nir_ssa_def *src1, nir_ssa_def *src2) \ -{ \ - return nir_build_alu(build, nir_op_##op, src0, src1, src2, NULL); \ -} - -#define ALU4(op) \ -static inline nir_ssa_def * \ -nir_##op(nir_builder *build, nir_ssa_def *src0, \ - nir_ssa_def *src1, nir_ssa_def *src2, nir_ssa_def *src3) \ -{ \ - return nir_build_alu(build, nir_op_##op, src0, src1, src2, src3); \ -} - -#include "nir_builder_opcodes.h" - -static inline nir_ssa_def * -nir_vec(nir_builder *build, nir_ssa_def **comp, unsigned num_components) -{ - switch (num_components) { - case 4: - return nir_vec4(build, comp[0], comp[1], comp[2], comp[3]); - case 3: - return nir_vec3(build, comp[0], comp[1], comp[2]); - case 2: - return nir_vec2(build, comp[0], comp[1]); - case 1: - return comp[0]; - default: - unreachable("bad component count"); - return NULL; - } -} - -/** - * Similar to nir_fmov, but takes a nir_alu_src instead of a nir_ssa_def. - */ -static inline nir_ssa_def * -nir_fmov_alu(nir_builder *build, nir_alu_src src, unsigned num_components) -{ - nir_alu_instr *mov = nir_alu_instr_create(build->shader, nir_op_fmov); - nir_ssa_dest_init(&mov->instr, &mov->dest.dest, num_components, NULL); - mov->dest.write_mask = (1 << num_components) - 1; - mov->src[0] = src; - nir_builder_instr_insert(build, &mov->instr); - - return &mov->dest.dest.ssa; -} - -static inline nir_ssa_def * -nir_imov_alu(nir_builder *build, nir_alu_src src, unsigned num_components) -{ - nir_alu_instr *mov = nir_alu_instr_create(build->shader, nir_op_imov); - nir_ssa_dest_init(&mov->instr, &mov->dest.dest, num_components, NULL); - mov->dest.write_mask = (1 << num_components) - 1; - mov->src[0] = src; - nir_builder_instr_insert(build, &mov->instr); - - return &mov->dest.dest.ssa; -} - -/** - * Construct an fmov or imov that reswizzles the source's components. - */ -static inline nir_ssa_def * -nir_swizzle(nir_builder *build, nir_ssa_def *src, unsigned swiz[4], - unsigned num_components, bool use_fmov) -{ - nir_alu_src alu_src = { NIR_SRC_INIT }; - alu_src.src = nir_src_for_ssa(src); - for (unsigned i = 0; i < num_components; i++) - alu_src.swizzle[i] = swiz[i]; - - return use_fmov ? nir_fmov_alu(build, alu_src, num_components) : - nir_imov_alu(build, alu_src, num_components); -} - -/* Selects the right fdot given the number of components in each source. */ -static inline nir_ssa_def * -nir_fdot(nir_builder *build, nir_ssa_def *src0, nir_ssa_def *src1) -{ - assert(src0->num_components == src1->num_components); - switch (src0->num_components) { - case 1: return nir_fmul(build, src0, src1); - case 2: return nir_fdot2(build, src0, src1); - case 3: return nir_fdot3(build, src0, src1); - case 4: return nir_fdot4(build, src0, src1); - default: - unreachable("bad component size"); - } - - return NULL; -} - -static inline nir_ssa_def * -nir_channel(nir_builder *b, nir_ssa_def *def, unsigned c) -{ - unsigned swizzle[4] = {c, c, c, c}; - return nir_swizzle(b, def, swizzle, 1, false); -} - -/** - * Turns a nir_src into a nir_ssa_def * so it can be passed to - * nir_build_alu()-based builder calls. - * - * See nir_ssa_for_alu_src() for alu instructions. - */ -static inline nir_ssa_def * -nir_ssa_for_src(nir_builder *build, nir_src src, int num_components) -{ - if (src.is_ssa && src.ssa->num_components == num_components) - return src.ssa; - - nir_alu_src alu = { NIR_SRC_INIT }; - alu.src = src; - for (int j = 0; j < 4; j++) - alu.swizzle[j] = j; - - return nir_imov_alu(build, alu, num_components); -} - -/** - * Similar to nir_ssa_for_src(), but for alu src's, respecting the - * nir_alu_src's swizzle. - */ -static inline nir_ssa_def * -nir_ssa_for_alu_src(nir_builder *build, nir_alu_instr *instr, unsigned srcn) -{ - static uint8_t trivial_swizzle[4] = { 0, 1, 2, 3 }; - nir_alu_src *src = &instr->src[srcn]; - unsigned num_components = nir_ssa_alu_instr_src_components(instr, srcn); - - if (src->src.is_ssa && (src->src.ssa->num_components == num_components) && - !src->abs && !src->negate && - (memcmp(src->swizzle, trivial_swizzle, num_components) == 0)) - return src->src.ssa; - - return nir_imov_alu(build, *src, num_components); -} - -static inline nir_ssa_def * -nir_load_var(nir_builder *build, nir_variable *var) -{ - const unsigned num_components = glsl_get_vector_elements(var->type); - - nir_intrinsic_instr *load = - nir_intrinsic_instr_create(build->shader, nir_intrinsic_load_var); - load->num_components = num_components; - load->variables[0] = nir_deref_var_create(load, var); - nir_ssa_dest_init(&load->instr, &load->dest, num_components, NULL); - nir_builder_instr_insert(build, &load->instr); - return &load->dest.ssa; -} - -static inline void -nir_store_var(nir_builder *build, nir_variable *var, nir_ssa_def *value, - unsigned writemask) -{ - const unsigned num_components = glsl_get_vector_elements(var->type); - - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(build->shader, nir_intrinsic_store_var); - store->num_components = num_components; - store->const_index[0] = writemask; - store->variables[0] = nir_deref_var_create(store, var); - store->src[0] = nir_src_for_ssa(value); - nir_builder_instr_insert(build, &store->instr); -} - -static inline void -nir_store_deref_var(nir_builder *build, nir_deref_var *deref, - nir_ssa_def *value, unsigned writemask) -{ - const unsigned num_components = - glsl_get_vector_elements(nir_deref_tail(&deref->deref)->type); - - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(build->shader, nir_intrinsic_store_var); - store->num_components = num_components; - store->const_index[0] = writemask & ((1 << num_components) - 1); - store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &deref->deref)); - store->src[0] = nir_src_for_ssa(value); - nir_builder_instr_insert(build, &store->instr); -} - -static inline void -nir_copy_deref_var(nir_builder *build, nir_deref_var *dest, nir_deref_var *src) -{ - assert(nir_deref_tail(&dest->deref)->type == - nir_deref_tail(&src->deref)->type); - - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(build->shader, nir_intrinsic_copy_var); - copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); - copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref)); - nir_builder_instr_insert(build, ©->instr); -} - -static inline void -nir_copy_var(nir_builder *build, nir_variable *dest, nir_variable *src) -{ - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(build->shader, nir_intrinsic_copy_var); - copy->variables[0] = nir_deref_var_create(copy, dest); - copy->variables[1] = nir_deref_var_create(copy, src); - nir_builder_instr_insert(build, ©->instr); -} - -static inline nir_ssa_def * -nir_load_system_value(nir_builder *build, nir_intrinsic_op op, int index) -{ - nir_intrinsic_instr *load = nir_intrinsic_instr_create(build->shader, op); - load->num_components = nir_intrinsic_infos[op].dest_components; - load->const_index[0] = index; - nir_ssa_dest_init(&load->instr, &load->dest, - nir_intrinsic_infos[op].dest_components, NULL); - nir_builder_instr_insert(build, &load->instr); - return &load->dest.ssa; -} - -static inline void -nir_jump(nir_builder *build, nir_jump_type jump_type) -{ - nir_jump_instr *jump = nir_jump_instr_create(build->shader, jump_type); - nir_builder_instr_insert(build, &jump->instr); -} - -#endif /* NIR_BUILDER_H */ diff --git a/src/glsl/nir/nir_builder_opcodes_h.py b/src/glsl/nir/nir_builder_opcodes_h.py deleted file mode 100644 index e27206ea8fc..00000000000 --- a/src/glsl/nir/nir_builder_opcodes_h.py +++ /dev/null @@ -1,38 +0,0 @@ -#! /usr/bin/env python - -template = """\ -/* Copyright (C) 2015 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef _NIR_BUILDER_OPCODES_ -#define _NIR_BUILDER_OPCODES_ - -% for name, opcode in sorted(opcodes.iteritems()): -ALU${opcode.num_inputs}(${name}); -% endfor - -#endif /* _NIR_BUILDER_OPCODES_ */""" - -from nir_opcodes import opcodes -from mako.template import Template - -print Template(template).render(opcodes=opcodes) diff --git a/src/glsl/nir/nir_clone.c b/src/glsl/nir/nir_clone.c deleted file mode 100644 index bc6df56b753..00000000000 --- a/src/glsl/nir/nir_clone.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * Copyright © 2015 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_control_flow_private.h" - -/* Secret Decoder Ring: - * clone_foo(): - * Allocate and clone a foo. - * __clone_foo(): - * Clone body of foo (ie. parent class, embedded struct, etc) - */ - -typedef struct { - /* True if we are cloning an entire shader. */ - bool global_clone; - - /* maps orig ptr -> cloned ptr: */ - struct hash_table *remap_table; - - /* List of phi sources. */ - struct list_head phi_srcs; - - /* new shader object, used as memctx for just about everything else: */ - nir_shader *ns; -} clone_state; - -static void -init_clone_state(clone_state *state, bool global) -{ - state->global_clone = global; - state->remap_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - list_inithead(&state->phi_srcs); -} - -static void -free_clone_state(clone_state *state) -{ - _mesa_hash_table_destroy(state->remap_table, NULL); -} - -static inline void * -_lookup_ptr(clone_state *state, const void *ptr, bool global) -{ - struct hash_entry *entry; - - if (!ptr) - return NULL; - - if (!state->global_clone && global) - return (void *)ptr; - - entry = _mesa_hash_table_search(state->remap_table, ptr); - assert(entry && "Failed to find pointer!"); - if (!entry) - return NULL; - - return entry->data; -} - -static void -add_remap(clone_state *state, void *nptr, const void *ptr) -{ - _mesa_hash_table_insert(state->remap_table, ptr, nptr); -} - -static void * -remap_local(clone_state *state, const void *ptr) -{ - return _lookup_ptr(state, ptr, false); -} - -static void * -remap_global(clone_state *state, const void *ptr) -{ - return _lookup_ptr(state, ptr, true); -} - -static nir_register * -remap_reg(clone_state *state, const nir_register *reg) -{ - return _lookup_ptr(state, reg, reg->is_global); -} - -static nir_variable * -remap_var(clone_state *state, const nir_variable *var) -{ - return _lookup_ptr(state, var, var->data.mode != nir_var_local); -} - -nir_constant * -nir_constant_clone(const nir_constant *c, nir_variable *nvar) -{ - nir_constant *nc = ralloc(nvar, nir_constant); - - nc->value = c->value; - nc->num_elements = c->num_elements; - nc->elements = ralloc_array(nvar, nir_constant *, c->num_elements); - for (unsigned i = 0; i < c->num_elements; i++) { - nc->elements[i] = nir_constant_clone(c->elements[i], nvar); - } - - return nc; -} - -/* NOTE: for cloning nir_variable's, bypass nir_variable_create to avoid - * having to deal with locals and globals separately: - */ -static nir_variable * -clone_variable(clone_state *state, const nir_variable *var) -{ - nir_variable *nvar = rzalloc(state->ns, nir_variable); - add_remap(state, nvar, var); - - nvar->type = var->type; - nvar->name = ralloc_strdup(nvar, var->name); - nvar->data = var->data; - nvar->num_state_slots = var->num_state_slots; - nvar->state_slots = ralloc_array(nvar, nir_state_slot, var->num_state_slots); - memcpy(nvar->state_slots, var->state_slots, - var->num_state_slots * sizeof(nir_state_slot)); - if (var->constant_initializer) { - nvar->constant_initializer = - nir_constant_clone(var->constant_initializer, nvar); - } - nvar->interface_type = var->interface_type; - - return nvar; -} - -/* clone list of nir_variable: */ -static void -clone_var_list(clone_state *state, struct exec_list *dst, - const struct exec_list *list) -{ - exec_list_make_empty(dst); - foreach_list_typed(nir_variable, var, node, list) { - nir_variable *nvar = clone_variable(state, var); - exec_list_push_tail(dst, &nvar->node); - } -} - -/* NOTE: for cloning nir_register's, bypass nir_global/local_reg_create() - * to avoid having to deal with locals and globals separately: - */ -static nir_register * -clone_register(clone_state *state, const nir_register *reg) -{ - nir_register *nreg = rzalloc(state->ns, nir_register); - add_remap(state, nreg, reg); - - nreg->num_components = reg->num_components; - nreg->num_array_elems = reg->num_array_elems; - nreg->index = reg->index; - nreg->name = ralloc_strdup(nreg, reg->name); - nreg->is_global = reg->is_global; - nreg->is_packed = reg->is_packed; - - /* reconstructing uses/defs/if_uses handled by nir_instr_insert() */ - list_inithead(&nreg->uses); - list_inithead(&nreg->defs); - list_inithead(&nreg->if_uses); - - return nreg; -} - -/* clone list of nir_register: */ -static void -clone_reg_list(clone_state *state, struct exec_list *dst, - const struct exec_list *list) -{ - exec_list_make_empty(dst); - foreach_list_typed(nir_register, reg, node, list) { - nir_register *nreg = clone_register(state, reg); - exec_list_push_tail(dst, &nreg->node); - } -} - -static void -__clone_src(clone_state *state, void *ninstr_or_if, - nir_src *nsrc, const nir_src *src) -{ - nsrc->is_ssa = src->is_ssa; - if (src->is_ssa) { - nsrc->ssa = remap_local(state, src->ssa); - } else { - nsrc->reg.reg = remap_reg(state, src->reg.reg); - if (src->reg.indirect) { - nsrc->reg.indirect = ralloc(ninstr_or_if, nir_src); - __clone_src(state, ninstr_or_if, nsrc->reg.indirect, src->reg.indirect); - } - nsrc->reg.base_offset = src->reg.base_offset; - } -} - -static void -__clone_dst(clone_state *state, nir_instr *ninstr, - nir_dest *ndst, const nir_dest *dst) -{ - ndst->is_ssa = dst->is_ssa; - if (dst->is_ssa) { - nir_ssa_dest_init(ninstr, ndst, dst->ssa.num_components, dst->ssa.name); - add_remap(state, &ndst->ssa, &dst->ssa); - } else { - ndst->reg.reg = remap_reg(state, dst->reg.reg); - if (dst->reg.indirect) { - ndst->reg.indirect = ralloc(ninstr, nir_src); - __clone_src(state, ninstr, ndst->reg.indirect, dst->reg.indirect); - } - ndst->reg.base_offset = dst->reg.base_offset; - } -} - -static nir_deref *clone_deref(clone_state *state, const nir_deref *deref, - nir_instr *ninstr, nir_deref *parent); - -static nir_deref_var * -clone_deref_var(clone_state *state, const nir_deref_var *dvar, - nir_instr *ninstr) -{ - nir_variable *nvar = remap_var(state, dvar->var); - nir_deref_var *ndvar = nir_deref_var_create(ninstr, nvar); - - if (dvar->deref.child) - ndvar->deref.child = clone_deref(state, dvar->deref.child, - ninstr, &ndvar->deref); - - return ndvar; -} - -static nir_deref_array * -clone_deref_array(clone_state *state, const nir_deref_array *darr, - nir_instr *ninstr, nir_deref *parent) -{ - nir_deref_array *ndarr = nir_deref_array_create(parent); - - ndarr->deref.type = darr->deref.type; - if (darr->deref.child) - ndarr->deref.child = clone_deref(state, darr->deref.child, - ninstr, &ndarr->deref); - - ndarr->deref_array_type = darr->deref_array_type; - ndarr->base_offset = darr->base_offset; - if (ndarr->deref_array_type == nir_deref_array_type_indirect) - __clone_src(state, ninstr, &ndarr->indirect, &darr->indirect); - - return ndarr; -} - -static nir_deref_struct * -clone_deref_struct(clone_state *state, const nir_deref_struct *dstr, - nir_instr *ninstr, nir_deref *parent) -{ - nir_deref_struct *ndstr = nir_deref_struct_create(parent, dstr->index); - - ndstr->deref.type = dstr->deref.type; - if (dstr->deref.child) - ndstr->deref.child = clone_deref(state, dstr->deref.child, - ninstr, &ndstr->deref); - - return ndstr; -} - -static nir_deref * -clone_deref(clone_state *state, const nir_deref *dref, - nir_instr *ninstr, nir_deref *parent) -{ - switch (dref->deref_type) { - case nir_deref_type_array: - return &clone_deref_array(state, nir_deref_as_array(dref), - ninstr, parent)->deref; - case nir_deref_type_struct: - return &clone_deref_struct(state, nir_deref_as_struct(dref), - ninstr, parent)->deref; - default: - unreachable("bad deref type"); - return NULL; - } -} - -static nir_alu_instr * -clone_alu(clone_state *state, const nir_alu_instr *alu) -{ - nir_alu_instr *nalu = nir_alu_instr_create(state->ns, alu->op); - - __clone_dst(state, &nalu->instr, &nalu->dest.dest, &alu->dest.dest); - nalu->dest.saturate = alu->dest.saturate; - nalu->dest.write_mask = alu->dest.write_mask; - - for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) { - __clone_src(state, &nalu->instr, &nalu->src[i].src, &alu->src[i].src); - nalu->src[i].negate = alu->src[i].negate; - nalu->src[i].abs = alu->src[i].abs; - memcpy(nalu->src[i].swizzle, alu->src[i].swizzle, - sizeof(nalu->src[i].swizzle)); - } - - return nalu; -} - -static nir_intrinsic_instr * -clone_intrinsic(clone_state *state, const nir_intrinsic_instr *itr) -{ - nir_intrinsic_instr *nitr = - nir_intrinsic_instr_create(state->ns, itr->intrinsic); - - unsigned num_variables = nir_intrinsic_infos[itr->intrinsic].num_variables; - unsigned num_srcs = nir_intrinsic_infos[itr->intrinsic].num_srcs; - - if (nir_intrinsic_infos[itr->intrinsic].has_dest) - __clone_dst(state, &nitr->instr, &nitr->dest, &itr->dest); - - nitr->num_components = itr->num_components; - memcpy(nitr->const_index, itr->const_index, sizeof(nitr->const_index)); - - for (unsigned i = 0; i < num_variables; i++) { - nitr->variables[i] = clone_deref_var(state, itr->variables[i], - &nitr->instr); - } - - for (unsigned i = 0; i < num_srcs; i++) - __clone_src(state, &nitr->instr, &nitr->src[i], &itr->src[i]); - - return nitr; -} - -static nir_load_const_instr * -clone_load_const(clone_state *state, const nir_load_const_instr *lc) -{ - nir_load_const_instr *nlc = - nir_load_const_instr_create(state->ns, lc->def.num_components); - - memcpy(&nlc->value, &lc->value, sizeof(nlc->value)); - - add_remap(state, &nlc->def, &lc->def); - - return nlc; -} - -static nir_ssa_undef_instr * -clone_ssa_undef(clone_state *state, const nir_ssa_undef_instr *sa) -{ - nir_ssa_undef_instr *nsa = - nir_ssa_undef_instr_create(state->ns, sa->def.num_components); - - add_remap(state, &nsa->def, &sa->def); - - return nsa; -} - -static nir_tex_instr * -clone_tex(clone_state *state, const nir_tex_instr *tex) -{ - nir_tex_instr *ntex = nir_tex_instr_create(state->ns, tex->num_srcs); - - ntex->sampler_dim = tex->sampler_dim; - ntex->dest_type = tex->dest_type; - ntex->op = tex->op; - __clone_dst(state, &ntex->instr, &ntex->dest, &tex->dest); - for (unsigned i = 0; i < ntex->num_srcs; i++) { - ntex->src[i].src_type = tex->src[i].src_type; - __clone_src(state, &ntex->instr, &ntex->src[i].src, &tex->src[i].src); - } - ntex->coord_components = tex->coord_components; - ntex->is_array = tex->is_array; - ntex->is_shadow = tex->is_shadow; - ntex->is_new_style_shadow = tex->is_new_style_shadow; - memcpy(ntex->const_offset, tex->const_offset, sizeof(ntex->const_offset)); - ntex->component = tex->component; - ntex->texture_index = tex->texture_index; - ntex->texture_array_size = tex->texture_array_size; - if (tex->texture) - ntex->texture = clone_deref_var(state, tex->texture, &ntex->instr); - ntex->sampler_index = tex->sampler_index; - if (tex->sampler) - ntex->sampler = clone_deref_var(state, tex->sampler, &ntex->instr); - - return ntex; -} - -static nir_phi_instr * -clone_phi(clone_state *state, const nir_phi_instr *phi, nir_block *nblk) -{ - nir_phi_instr *nphi = nir_phi_instr_create(state->ns); - - __clone_dst(state, &nphi->instr, &nphi->dest, &phi->dest); - - /* Cloning a phi node is a bit different from other instructions. The - * sources of phi instructions are the only time where we can use an SSA - * def before it is defined. In order to handle this, we just copy over - * the sources from the old phi instruction directly and then fix them up - * in a second pass once all the instrutions in the function have been - * properly cloned. - * - * In order to ensure that the copied sources (which are the same as the - * old phi instruction's sources for now) don't get inserted into the old - * shader's use-def lists, we have to add the phi instruction *before* we - * set up its sources. - */ - nir_instr_insert_after_block(nblk, &nphi->instr); - - foreach_list_typed(nir_phi_src, src, node, &phi->srcs) { - nir_phi_src *nsrc = ralloc(nphi, nir_phi_src); - - /* Just copy the old source for now. */ - memcpy(nsrc, src, sizeof(*src)); - - /* Since we're not letting nir_insert_instr handle use/def stuff for us, - * we have to set the parent_instr manually. It doesn't really matter - * when we do it, so we might as well do it here. - */ - nsrc->src.parent_instr = &nphi->instr; - - /* Stash it in the list of phi sources. We'll walk this list and fix up - * sources at the very end of clone_function_impl. - */ - list_add(&nsrc->src.use_link, &state->phi_srcs); - - exec_list_push_tail(&nphi->srcs, &nsrc->node); - } - - return nphi; -} - -static nir_jump_instr * -clone_jump(clone_state *state, const nir_jump_instr *jmp) -{ - nir_jump_instr *njmp = nir_jump_instr_create(state->ns, jmp->type); - - return njmp; -} - -static nir_call_instr * -clone_call(clone_state *state, const nir_call_instr *call) -{ - nir_function *ncallee = remap_global(state, call->callee); - nir_call_instr *ncall = nir_call_instr_create(state->ns, ncallee); - - for (unsigned i = 0; i < ncall->num_params; i++) - ncall->params[i] = clone_deref_var(state, call->params[i], &ncall->instr); - - ncall->return_deref = clone_deref_var(state, call->return_deref, - &ncall->instr); - - return ncall; -} - -static nir_instr * -clone_instr(clone_state *state, const nir_instr *instr) -{ - switch (instr->type) { - case nir_instr_type_alu: - return &clone_alu(state, nir_instr_as_alu(instr))->instr; - case nir_instr_type_intrinsic: - return &clone_intrinsic(state, nir_instr_as_intrinsic(instr))->instr; - case nir_instr_type_load_const: - return &clone_load_const(state, nir_instr_as_load_const(instr))->instr; - case nir_instr_type_ssa_undef: - return &clone_ssa_undef(state, nir_instr_as_ssa_undef(instr))->instr; - case nir_instr_type_tex: - return &clone_tex(state, nir_instr_as_tex(instr))->instr; - case nir_instr_type_phi: - unreachable("Cannot clone phis with clone_instr"); - case nir_instr_type_jump: - return &clone_jump(state, nir_instr_as_jump(instr))->instr; - case nir_instr_type_call: - return &clone_call(state, nir_instr_as_call(instr))->instr; - case nir_instr_type_parallel_copy: - unreachable("Cannot clone parallel copies"); - default: - unreachable("bad instr type"); - return NULL; - } -} - -static nir_block * -clone_block(clone_state *state, struct exec_list *cf_list, const nir_block *blk) -{ - /* Don't actually create a new block. Just use the one from the tail of - * the list. NIR guarantees that the tail of the list is a block and that - * no two blocks are side-by-side in the IR; It should be empty. - */ - nir_block *nblk = - exec_node_data(nir_block, exec_list_get_tail(cf_list), cf_node.node); - assert(nblk->cf_node.type == nir_cf_node_block); - assert(exec_list_is_empty(&nblk->instr_list)); - - /* We need this for phi sources */ - add_remap(state, nblk, blk); - - nir_foreach_instr(blk, instr) { - if (instr->type == nir_instr_type_phi) { - /* Phi instructions are a bit of a special case when cloning because - * we don't want inserting the instruction to automatically handle - * use/defs for us. Instead, we need to wait until all the - * blocks/instructions are in so that we can set their sources up. - */ - clone_phi(state, nir_instr_as_phi(instr), nblk); - } else { - nir_instr *ninstr = clone_instr(state, instr); - nir_instr_insert_after_block(nblk, ninstr); - } - } - - return nblk; -} - -static void -clone_cf_list(clone_state *state, struct exec_list *dst, - const struct exec_list *list); - -static nir_if * -clone_if(clone_state *state, struct exec_list *cf_list, const nir_if *i) -{ - nir_if *ni = nir_if_create(state->ns); - - __clone_src(state, ni, &ni->condition, &i->condition); - - nir_cf_node_insert_end(cf_list, &ni->cf_node); - - clone_cf_list(state, &ni->then_list, &i->then_list); - clone_cf_list(state, &ni->else_list, &i->else_list); - - return ni; -} - -static nir_loop * -clone_loop(clone_state *state, struct exec_list *cf_list, const nir_loop *loop) -{ - nir_loop *nloop = nir_loop_create(state->ns); - - nir_cf_node_insert_end(cf_list, &nloop->cf_node); - - clone_cf_list(state, &nloop->body, &loop->body); - - return nloop; -} - -/* clone list of nir_cf_node: */ -static void -clone_cf_list(clone_state *state, struct exec_list *dst, - const struct exec_list *list) -{ - foreach_list_typed(nir_cf_node, cf, node, list) { - switch (cf->type) { - case nir_cf_node_block: - clone_block(state, dst, nir_cf_node_as_block(cf)); - break; - case nir_cf_node_if: - clone_if(state, dst, nir_cf_node_as_if(cf)); - break; - case nir_cf_node_loop: - clone_loop(state, dst, nir_cf_node_as_loop(cf)); - break; - default: - unreachable("bad cf type"); - } - } -} - -static nir_function_impl * -clone_function_impl(clone_state *state, const nir_function_impl *fi) -{ - nir_function_impl *nfi = nir_function_impl_create_bare(state->ns); - - clone_var_list(state, &nfi->locals, &fi->locals); - clone_reg_list(state, &nfi->registers, &fi->registers); - nfi->reg_alloc = fi->reg_alloc; - - nfi->num_params = fi->num_params; - nfi->params = ralloc_array(state->ns, nir_variable *, fi->num_params); - for (unsigned i = 0; i < fi->num_params; i++) { - nfi->params[i] = remap_local(state, fi->params[i]); - } - nfi->return_var = remap_local(state, fi->return_var); - - assert(list_empty(&state->phi_srcs)); - - clone_cf_list(state, &nfi->body, &fi->body); - - /* After we've cloned almost everything, we have to walk the list of phi - * sources and fix them up. Thanks to loops, the block and SSA value for a - * phi source may not be defined when we first encounter it. Instead, we - * add it to the phi_srcs list and we fix it up here. - */ - list_for_each_entry_safe(nir_phi_src, src, &state->phi_srcs, src.use_link) { - src->pred = remap_local(state, src->pred); - assert(src->src.is_ssa); - src->src.ssa = remap_local(state, src->src.ssa); - - /* Remove from this list and place in the uses of the SSA def */ - list_del(&src->src.use_link); - list_addtail(&src->src.use_link, &src->src.ssa->uses); - } - assert(list_empty(&state->phi_srcs)); - - /* All metadata is invalidated in the cloning process */ - nfi->valid_metadata = 0; - - return nfi; -} - -nir_function_impl * -nir_function_impl_clone(const nir_function_impl *fi) -{ - clone_state state; - init_clone_state(&state, false); - - /* We use the same shader */ - state.ns = fi->function->shader; - - nir_function_impl *nfi = clone_function_impl(&state, fi); - - free_clone_state(&state); - - return nfi; -} - -static nir_function * -clone_function(clone_state *state, const nir_function *fxn, nir_shader *ns) -{ - assert(ns == state->ns); - nir_function *nfxn = nir_function_create(ns, fxn->name); - - /* Needed for call instructions */ - add_remap(state, nfxn, fxn); - - nfxn->num_params = fxn->num_params; - nfxn->params = ralloc_array(state->ns, nir_parameter, fxn->num_params); - memcpy(nfxn->params, fxn->params, sizeof(nir_parameter) * fxn->num_params); - - nfxn->return_type = fxn->return_type; - - /* At first glance, it looks like we should clone the function_impl here. - * However, call instructions need to be able to reference at least the - * function and those will get processed as we clone the function_impl's. - * We stop here and do function_impls as a second pass. - */ - - return nfxn; -} - -nir_shader * -nir_shader_clone(void *mem_ctx, const nir_shader *s) -{ - clone_state state; - init_clone_state(&state, true); - - nir_shader *ns = nir_shader_create(mem_ctx, s->stage, s->options); - state.ns = ns; - - clone_var_list(&state, &ns->uniforms, &s->uniforms); - clone_var_list(&state, &ns->inputs, &s->inputs); - clone_var_list(&state, &ns->outputs, &s->outputs); - clone_var_list(&state, &ns->shared, &s->shared); - clone_var_list(&state, &ns->globals, &s->globals); - clone_var_list(&state, &ns->system_values, &s->system_values); - - /* Go through and clone functions */ - foreach_list_typed(nir_function, fxn, node, &s->functions) - clone_function(&state, fxn, ns); - - /* Only after all functions are cloned can we clone the actual function - * implementations. This is because nir_call_instr's need to reference the - * functions of other functions and we don't know what order the functions - * will have in the list. - */ - nir_foreach_function(s, fxn) { - nir_function *nfxn = remap_global(&state, fxn); - nfxn->impl = clone_function_impl(&state, fxn->impl); - nfxn->impl->function = nfxn; - } - - clone_reg_list(&state, &ns->registers, &s->registers); - ns->reg_alloc = s->reg_alloc; - - ns->info = s->info; - ns->info.name = ralloc_strdup(ns, ns->info.name); - if (ns->info.label) - ns->info.label = ralloc_strdup(ns, ns->info.label); - - ns->num_inputs = s->num_inputs; - ns->num_uniforms = s->num_uniforms; - ns->num_outputs = s->num_outputs; - ns->num_shared = s->num_shared; - - free_clone_state(&state); - - return ns; -} diff --git a/src/glsl/nir/nir_constant_expressions.h b/src/glsl/nir/nir_constant_expressions.h deleted file mode 100644 index 97997f2e514..00000000000 --- a/src/glsl/nir/nir_constant_expressions.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright © 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -nir_const_value nir_eval_const_opcode(nir_op op, unsigned num_components, - nir_const_value *src); diff --git a/src/glsl/nir/nir_constant_expressions.py b/src/glsl/nir/nir_constant_expressions.py deleted file mode 100644 index 32784f6398d..00000000000 --- a/src/glsl/nir/nir_constant_expressions.py +++ /dev/null @@ -1,336 +0,0 @@ -#! /usr/bin/python2 -template = """\ -/* - * Copyright (C) 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - */ - -#include <math.h> -#include "main/core.h" -#include "util/rounding.h" /* for _mesa_roundeven */ -#include "util/half_float.h" -#include "nir_constant_expressions.h" - -/** - * Evaluate one component of packSnorm4x8. - */ -static uint8_t -pack_snorm_1x8(float x) -{ - /* From section 8.4 of the GLSL 4.30 spec: - * - * packSnorm4x8 - * ------------ - * The conversion for component c of v to fixed point is done as - * follows: - * - * packSnorm4x8: round(clamp(c, -1, +1) * 127.0) - * - * We must first cast the float to an int, because casting a negative - * float to a uint is undefined. - */ - return (uint8_t) (int) - _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 127.0f); -} - -/** - * Evaluate one component of packSnorm2x16. - */ -static uint16_t -pack_snorm_1x16(float x) -{ - /* From section 8.4 of the GLSL ES 3.00 spec: - * - * packSnorm2x16 - * ------------- - * The conversion for component c of v to fixed point is done as - * follows: - * - * packSnorm2x16: round(clamp(c, -1, +1) * 32767.0) - * - * We must first cast the float to an int, because casting a negative - * float to a uint is undefined. - */ - return (uint16_t) (int) - _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 32767.0f); -} - -/** - * Evaluate one component of unpackSnorm4x8. - */ -static float -unpack_snorm_1x8(uint8_t u) -{ - /* From section 8.4 of the GLSL 4.30 spec: - * - * unpackSnorm4x8 - * -------------- - * The conversion for unpacked fixed-point value f to floating point is - * done as follows: - * - * unpackSnorm4x8: clamp(f / 127.0, -1, +1) - */ - return CLAMP((int8_t) u / 127.0f, -1.0f, +1.0f); -} - -/** - * Evaluate one component of unpackSnorm2x16. - */ -static float -unpack_snorm_1x16(uint16_t u) -{ - /* From section 8.4 of the GLSL ES 3.00 spec: - * - * unpackSnorm2x16 - * --------------- - * The conversion for unpacked fixed-point value f to floating point is - * done as follows: - * - * unpackSnorm2x16: clamp(f / 32767.0, -1, +1) - */ - return CLAMP((int16_t) u / 32767.0f, -1.0f, +1.0f); -} - -/** - * Evaluate one component packUnorm4x8. - */ -static uint8_t -pack_unorm_1x8(float x) -{ - /* From section 8.4 of the GLSL 4.30 spec: - * - * packUnorm4x8 - * ------------ - * The conversion for component c of v to fixed point is done as - * follows: - * - * packUnorm4x8: round(clamp(c, 0, +1) * 255.0) - */ - return (uint8_t) (int) - _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 255.0f); -} - -/** - * Evaluate one component packUnorm2x16. - */ -static uint16_t -pack_unorm_1x16(float x) -{ - /* From section 8.4 of the GLSL ES 3.00 spec: - * - * packUnorm2x16 - * ------------- - * The conversion for component c of v to fixed point is done as - * follows: - * - * packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) - */ - return (uint16_t) (int) - _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 65535.0f); -} - -/** - * Evaluate one component of unpackUnorm4x8. - */ -static float -unpack_unorm_1x8(uint8_t u) -{ - /* From section 8.4 of the GLSL 4.30 spec: - * - * unpackUnorm4x8 - * -------------- - * The conversion for unpacked fixed-point value f to floating point is - * done as follows: - * - * unpackUnorm4x8: f / 255.0 - */ - return (float) u / 255.0f; -} - -/** - * Evaluate one component of unpackUnorm2x16. - */ -static float -unpack_unorm_1x16(uint16_t u) -{ - /* From section 8.4 of the GLSL ES 3.00 spec: - * - * unpackUnorm2x16 - * --------------- - * The conversion for unpacked fixed-point value f to floating point is - * done as follows: - * - * unpackUnorm2x16: f / 65535.0 - */ - return (float) u / 65535.0f; -} - -/** - * Evaluate one component of packHalf2x16. - */ -static uint16_t -pack_half_1x16(float x) -{ - return _mesa_float_to_half(x); -} - -/** - * Evaluate one component of unpackHalf2x16. - */ -static float -unpack_half_1x16(uint16_t u) -{ - return _mesa_half_to_float(u); -} - -/* Some typed vector structures to make things like src0.y work */ -% for type in ["float", "int", "uint", "bool"]: -struct ${type}_vec { - ${type} x; - ${type} y; - ${type} z; - ${type} w; -}; -% endfor - -% for name, op in sorted(opcodes.iteritems()): -static nir_const_value -evaluate_${name}(unsigned num_components, nir_const_value *_src) -{ - nir_const_value _dst_val = { { {0, 0, 0, 0} } }; - - ## For each non-per-component input, create a variable srcN that - ## contains x, y, z, and w elements which are filled in with the - ## appropriately-typed values. - % for j in range(op.num_inputs): - % if op.input_sizes[j] == 0: - <% continue %> - % elif "src" + str(j) not in op.const_expr: - ## Avoid unused variable warnings - <% continue %> - %endif - - struct ${op.input_types[j]}_vec src${j} = { - % for k in range(op.input_sizes[j]): - % if op.input_types[j] == "bool": - _src[${j}].u[${k}] != 0, - % else: - _src[${j}].${op.input_types[j][:1]}[${k}], - % endif - % endfor - }; - % endfor - - % if op.output_size == 0: - ## For per-component instructions, we need to iterate over the - ## components and apply the constant expression one component - ## at a time. - for (unsigned _i = 0; _i < num_components; _i++) { - ## For each per-component input, create a variable srcN that - ## contains the value of the current (_i'th) component. - % for j in range(op.num_inputs): - % if op.input_sizes[j] != 0: - <% continue %> - % elif "src" + str(j) not in op.const_expr: - ## Avoid unused variable warnings - <% continue %> - % elif op.input_types[j] == "bool": - bool src${j} = _src[${j}].u[_i] != 0; - % else: - ${op.input_types[j]} src${j} = _src[${j}].${op.input_types[j][:1]}[_i]; - % endif - % endfor - - ## Create an appropriately-typed variable dst and assign the - ## result of the const_expr to it. If const_expr already contains - ## writes to dst, just include const_expr directly. - % if "dst" in op.const_expr: - ${op.output_type} dst; - ${op.const_expr} - % else: - ${op.output_type} dst = ${op.const_expr}; - % endif - - ## Store the current component of the actual destination to the - ## value of dst. - % if op.output_type == "bool": - ## Sanitize the C value to a proper NIR bool - _dst_val.u[_i] = dst ? NIR_TRUE : NIR_FALSE; - % else: - _dst_val.${op.output_type[:1]}[_i] = dst; - % endif - } - % else: - ## In the non-per-component case, create a struct dst with - ## appropriately-typed elements x, y, z, and w and assign the result - ## of the const_expr to all components of dst, or include the - ## const_expr directly if it writes to dst already. - struct ${op.output_type}_vec dst; - - % if "dst" in op.const_expr: - ${op.const_expr} - % else: - ## Splat the value to all components. This way expressions which - ## write the same value to all components don't need to explicitly - ## write to dest. One such example is fnoise which has a - ## const_expr of 0.0f. - dst.x = dst.y = dst.z = dst.w = ${op.const_expr}; - % endif - - ## For each component in the destination, copy the value of dst to - ## the actual destination. - % for k in range(op.output_size): - % if op.output_type == "bool": - ## Sanitize the C value to a proper NIR bool - _dst_val.u[${k}] = dst.${"xyzw"[k]} ? NIR_TRUE : NIR_FALSE; - % else: - _dst_val.${op.output_type[:1]}[${k}] = dst.${"xyzw"[k]}; - % endif - % endfor - % endif - - return _dst_val; -} -% endfor - -nir_const_value -nir_eval_const_opcode(nir_op op, unsigned num_components, - nir_const_value *src) -{ - switch (op) { -% for name in sorted(opcodes.iterkeys()): - case nir_op_${name}: { - return evaluate_${name}(num_components, src); - break; - } -% endfor - default: - unreachable("shouldn't get here"); - } -}""" - -from nir_opcodes import opcodes -from mako.template import Template - -print Template(template).render(opcodes=opcodes) diff --git a/src/glsl/nir/nir_control_flow.c b/src/glsl/nir/nir_control_flow.c deleted file mode 100644 index 33b06d0cc84..00000000000 --- a/src/glsl/nir/nir_control_flow.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir_control_flow_private.h" - -/** - * \name Control flow modification - * - * These functions modify the control flow tree while keeping the control flow - * graph up-to-date. The invariants respected are: - * 1. Each then statement, else statement, or loop body must have at least one - * control flow node. - * 2. Each if-statement and loop must have one basic block before it and one - * after. - * 3. Two basic blocks cannot be directly next to each other. - * 4. If a basic block has a jump instruction, there must be only one and it - * must be at the end of the block. - * 5. The CFG must always be connected - this means that we must insert a fake - * CFG edge for loops with no break statement. - * - * The purpose of the second one is so that we have places to insert code during - * GCM, as well as eliminating the possibility of critical edges. - */ -/*@{*/ - -static bool -block_ends_in_jump(nir_block *block) -{ - return !exec_list_is_empty(&block->instr_list) && - nir_block_last_instr(block)->type == nir_instr_type_jump; -} - -static inline void -block_add_pred(nir_block *block, nir_block *pred) -{ - _mesa_set_add(block->predecessors, pred); -} - -static inline void -block_remove_pred(nir_block *block, nir_block *pred) -{ - struct set_entry *entry = _mesa_set_search(block->predecessors, pred); - - assert(entry); - - _mesa_set_remove(block->predecessors, entry); -} - -static void -link_blocks(nir_block *pred, nir_block *succ1, nir_block *succ2) -{ - pred->successors[0] = succ1; - if (succ1 != NULL) - block_add_pred(succ1, pred); - - pred->successors[1] = succ2; - if (succ2 != NULL) - block_add_pred(succ2, pred); -} - -static void -unlink_blocks(nir_block *pred, nir_block *succ) -{ - if (pred->successors[0] == succ) { - pred->successors[0] = pred->successors[1]; - pred->successors[1] = NULL; - } else { - assert(pred->successors[1] == succ); - pred->successors[1] = NULL; - } - - block_remove_pred(succ, pred); -} - -static void -unlink_block_successors(nir_block *block) -{ - if (block->successors[1] != NULL) - unlink_blocks(block, block->successors[1]); - if (block->successors[0] != NULL) - unlink_blocks(block, block->successors[0]); -} - -static void -link_non_block_to_block(nir_cf_node *node, nir_block *block) -{ - if (node->type == nir_cf_node_if) { - /* - * We're trying to link an if to a block after it; this just means linking - * the last block of the then and else branches. - */ - - nir_if *if_stmt = nir_cf_node_as_if(node); - - nir_cf_node *last_then = nir_if_last_then_node(if_stmt); - assert(last_then->type == nir_cf_node_block); - nir_block *last_then_block = nir_cf_node_as_block(last_then); - - nir_cf_node *last_else = nir_if_last_else_node(if_stmt); - assert(last_else->type == nir_cf_node_block); - nir_block *last_else_block = nir_cf_node_as_block(last_else); - - if (!block_ends_in_jump(last_then_block)) { - unlink_block_successors(last_then_block); - link_blocks(last_then_block, block, NULL); - } - - if (!block_ends_in_jump(last_else_block)) { - unlink_block_successors(last_else_block); - link_blocks(last_else_block, block, NULL); - } - } else { - assert(node->type == nir_cf_node_loop); - - /* - * We can only get to this codepath if we're inserting a new loop, or - * at least a loop with no break statements; we can't insert break - * statements into a loop when we haven't inserted it into the CFG - * because we wouldn't know which block comes after the loop - * and therefore, which block should be the successor of the block with - * the break). Therefore, we need to insert a fake edge (see invariant - * #5). - */ - - nir_loop *loop = nir_cf_node_as_loop(node); - - nir_cf_node *last = nir_loop_last_cf_node(loop); - assert(last->type == nir_cf_node_block); - nir_block *last_block = nir_cf_node_as_block(last); - - last_block->successors[1] = block; - block_add_pred(block, last_block); - } -} - -static void -link_block_to_non_block(nir_block *block, nir_cf_node *node) -{ - if (node->type == nir_cf_node_if) { - /* - * We're trying to link a block to an if after it; this just means linking - * the block to the first block of the then and else branches. - */ - - nir_if *if_stmt = nir_cf_node_as_if(node); - - nir_cf_node *first_then = nir_if_first_then_node(if_stmt); - assert(first_then->type == nir_cf_node_block); - nir_block *first_then_block = nir_cf_node_as_block(first_then); - - nir_cf_node *first_else = nir_if_first_else_node(if_stmt); - assert(first_else->type == nir_cf_node_block); - nir_block *first_else_block = nir_cf_node_as_block(first_else); - - unlink_block_successors(block); - link_blocks(block, first_then_block, first_else_block); - } else { - /* - * For similar reasons as the corresponding case in - * link_non_block_to_block(), don't worry about if the loop header has - * any predecessors that need to be unlinked. - */ - - assert(node->type == nir_cf_node_loop); - - nir_loop *loop = nir_cf_node_as_loop(node); - - nir_cf_node *loop_header = nir_loop_first_cf_node(loop); - assert(loop_header->type == nir_cf_node_block); - nir_block *loop_header_block = nir_cf_node_as_block(loop_header); - - unlink_block_successors(block); - link_blocks(block, loop_header_block, NULL); - } - -} - -/** - * Replace a block's successor with a different one. - */ -static void -replace_successor(nir_block *block, nir_block *old_succ, nir_block *new_succ) -{ - if (block->successors[0] == old_succ) { - block->successors[0] = new_succ; - } else { - assert(block->successors[1] == old_succ); - block->successors[1] = new_succ; - } - - block_remove_pred(old_succ, block); - block_add_pred(new_succ, block); -} - -/** - * Takes a basic block and inserts a new empty basic block before it, making its - * predecessors point to the new block. This essentially splits the block into - * an empty header and a body so that another non-block CF node can be inserted - * between the two. Note that this does *not* link the two basic blocks, so - * some kind of cleanup *must* be performed after this call. - */ - -static nir_block * -split_block_beginning(nir_block *block) -{ - nir_block *new_block = nir_block_create(ralloc_parent(block)); - new_block->cf_node.parent = block->cf_node.parent; - exec_node_insert_node_before(&block->cf_node.node, &new_block->cf_node.node); - - struct set_entry *entry; - set_foreach(block->predecessors, entry) { - nir_block *pred = (nir_block *) entry->key; - replace_successor(pred, block, new_block); - } - - /* Any phi nodes must stay part of the new block, or else their - * sourcse will be messed up. This will reverse the order of the phi's, but - * order shouldn't matter. - */ - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - exec_node_remove(&instr->node); - instr->block = new_block; - exec_list_push_head(&new_block->instr_list, &instr->node); - } - - return new_block; -} - -static void -rewrite_phi_preds(nir_block *block, nir_block *old_pred, nir_block *new_pred) -{ - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - nir_foreach_phi_src(phi, src) { - if (src->pred == old_pred) { - src->pred = new_pred; - break; - } - } - } -} - -static void -insert_phi_undef(nir_block *block, nir_block *pred) -{ - nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node); - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - nir_ssa_undef_instr *undef = - nir_ssa_undef_instr_create(ralloc_parent(phi), - phi->dest.ssa.num_components); - nir_instr_insert_before_cf_list(&impl->body, &undef->instr); - nir_phi_src *src = ralloc(phi, nir_phi_src); - src->pred = pred; - src->src.parent_instr = &phi->instr; - src->src.is_ssa = true; - src->src.ssa = &undef->def; - - list_addtail(&src->src.use_link, &undef->def.uses); - - exec_list_push_tail(&phi->srcs, &src->node); - } -} - -/** - * Moves the successors of source to the successors of dest, leaving both - * successors of source NULL. - */ - -static void -move_successors(nir_block *source, nir_block *dest) -{ - nir_block *succ1 = source->successors[0]; - nir_block *succ2 = source->successors[1]; - - if (succ1) { - unlink_blocks(source, succ1); - rewrite_phi_preds(succ1, source, dest); - } - - if (succ2) { - unlink_blocks(source, succ2); - rewrite_phi_preds(succ2, source, dest); - } - - unlink_block_successors(dest); - link_blocks(dest, succ1, succ2); -} - -/* Given a basic block with no successors that has been inserted into the - * control flow tree, gives it the successors it would normally have assuming - * it doesn't end in a jump instruction. Also inserts phi sources with undefs - * if necessary. - */ -static void -block_add_normal_succs(nir_block *block) -{ - if (exec_node_is_tail_sentinel(block->cf_node.node.next)) { - nir_cf_node *parent = block->cf_node.parent; - if (parent->type == nir_cf_node_if) { - nir_cf_node *next = nir_cf_node_next(parent); - assert(next->type == nir_cf_node_block); - nir_block *next_block = nir_cf_node_as_block(next); - - link_blocks(block, next_block, NULL); - } else if (parent->type == nir_cf_node_loop) { - nir_loop *loop = nir_cf_node_as_loop(parent); - - nir_cf_node *head = nir_loop_first_cf_node(loop); - assert(head->type == nir_cf_node_block); - nir_block *head_block = nir_cf_node_as_block(head); - - link_blocks(block, head_block, NULL); - insert_phi_undef(head_block, block); - } else { - assert(parent->type == nir_cf_node_function); - nir_function_impl *impl = nir_cf_node_as_function(parent); - link_blocks(block, impl->end_block, NULL); - } - } else { - nir_cf_node *next = nir_cf_node_next(&block->cf_node); - if (next->type == nir_cf_node_if) { - nir_if *next_if = nir_cf_node_as_if(next); - - nir_cf_node *first_then = nir_if_first_then_node(next_if); - assert(first_then->type == nir_cf_node_block); - nir_block *first_then_block = nir_cf_node_as_block(first_then); - - nir_cf_node *first_else = nir_if_first_else_node(next_if); - assert(first_else->type == nir_cf_node_block); - nir_block *first_else_block = nir_cf_node_as_block(first_else); - - link_blocks(block, first_then_block, first_else_block); - } else { - assert(next->type == nir_cf_node_loop); - nir_loop *next_loop = nir_cf_node_as_loop(next); - - nir_cf_node *first = nir_loop_first_cf_node(next_loop); - assert(first->type == nir_cf_node_block); - nir_block *first_block = nir_cf_node_as_block(first); - - link_blocks(block, first_block, NULL); - insert_phi_undef(first_block, block); - } - } -} - -static nir_block * -split_block_end(nir_block *block) -{ - nir_block *new_block = nir_block_create(ralloc_parent(block)); - new_block->cf_node.parent = block->cf_node.parent; - exec_node_insert_after(&block->cf_node.node, &new_block->cf_node.node); - - if (block_ends_in_jump(block)) { - /* Figure out what successor block would've had if it didn't have a jump - * instruction, and make new_block have that successor. - */ - block_add_normal_succs(new_block); - } else { - move_successors(block, new_block); - } - - return new_block; -} - -static nir_block * -split_block_before_instr(nir_instr *instr) -{ - assert(instr->type != nir_instr_type_phi); - nir_block *new_block = split_block_beginning(instr->block); - - nir_foreach_instr_safe(instr->block, cur_instr) { - if (cur_instr == instr) - break; - - exec_node_remove(&cur_instr->node); - cur_instr->block = new_block; - exec_list_push_tail(&new_block->instr_list, &cur_instr->node); - } - - return new_block; -} - -/* Splits a basic block at the point specified by the cursor. The "before" and - * "after" arguments are filled out with the blocks resulting from the split - * if non-NULL. Note that the "beginning" of the block is actually interpreted - * as before the first non-phi instruction, and it's illegal to split a block - * before a phi instruction. - */ - -static void -split_block_cursor(nir_cursor cursor, - nir_block **_before, nir_block **_after) -{ - nir_block *before, *after; - switch (cursor.option) { - case nir_cursor_before_block: - after = cursor.block; - before = split_block_beginning(cursor.block); - break; - - case nir_cursor_after_block: - before = cursor.block; - after = split_block_end(cursor.block); - break; - - case nir_cursor_before_instr: - after = cursor.instr->block; - before = split_block_before_instr(cursor.instr); - break; - - case nir_cursor_after_instr: - /* We lower this to split_block_before_instr() so that we can keep the - * after-a-jump-instr case contained to split_block_end(). - */ - if (nir_instr_is_last(cursor.instr)) { - before = cursor.instr->block; - after = split_block_end(cursor.instr->block); - } else { - after = cursor.instr->block; - before = split_block_before_instr(nir_instr_next(cursor.instr)); - } - break; - - default: - unreachable("not reached"); - } - - if (_before) - *_before = before; - if (_after) - *_after = after; -} - -/** - * Inserts a non-basic block between two basic blocks and links them together. - */ - -static void -insert_non_block(nir_block *before, nir_cf_node *node, nir_block *after) -{ - node->parent = before->cf_node.parent; - exec_node_insert_after(&before->cf_node.node, &node->node); - link_block_to_non_block(before, node); - link_non_block_to_block(node, after); -} - -/* walk up the control flow tree to find the innermost enclosed loop */ -static nir_loop * -nearest_loop(nir_cf_node *node) -{ - while (node->type != nir_cf_node_loop) { - node = node->parent; - } - - return nir_cf_node_as_loop(node); -} - -/* - * update the CFG after a jump instruction has been added to the end of a block - */ - -void -nir_handle_add_jump(nir_block *block) -{ - nir_instr *instr = nir_block_last_instr(block); - nir_jump_instr *jump_instr = nir_instr_as_jump(instr); - - unlink_block_successors(block); - - nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node); - nir_metadata_preserve(impl, nir_metadata_none); - - if (jump_instr->type == nir_jump_break || - jump_instr->type == nir_jump_continue) { - nir_loop *loop = nearest_loop(&block->cf_node); - - if (jump_instr->type == nir_jump_continue) { - nir_cf_node *first_node = nir_loop_first_cf_node(loop); - assert(first_node->type == nir_cf_node_block); - nir_block *first_block = nir_cf_node_as_block(first_node); - link_blocks(block, first_block, NULL); - } else { - nir_cf_node *after = nir_cf_node_next(&loop->cf_node); - assert(after->type == nir_cf_node_block); - nir_block *after_block = nir_cf_node_as_block(after); - link_blocks(block, after_block, NULL); - - /* If we inserted a fake link, remove it */ - nir_cf_node *last = nir_loop_last_cf_node(loop); - assert(last->type == nir_cf_node_block); - nir_block *last_block = nir_cf_node_as_block(last); - if (last_block->successors[1] != NULL) - unlink_blocks(last_block, after_block); - } - } else { - assert(jump_instr->type == nir_jump_return); - link_blocks(block, impl->end_block, NULL); - } -} - -static void -remove_phi_src(nir_block *block, nir_block *pred) -{ - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - nir_foreach_phi_src_safe(phi, src) { - if (src->pred == pred) { - list_del(&src->src.use_link); - exec_node_remove(&src->node); - } - } - } -} - -/* Removes the successor of a block with a jump, and inserts a fake edge for - * infinite loops. Note that the jump to be eliminated may be free-floating. - */ - -static void -unlink_jump(nir_block *block, nir_jump_type type, bool add_normal_successors) -{ - nir_block *next = block->successors[0]; - - if (block->successors[0]) - remove_phi_src(block->successors[0], block); - if (block->successors[1]) - remove_phi_src(block->successors[1], block); - - unlink_block_successors(block); - if (add_normal_successors) - block_add_normal_succs(block); - - /* If we've just removed a break, and the block we were jumping to (after - * the loop) now has zero predecessors, we've created a new infinite loop. - * - * NIR doesn't allow blocks (other than the start block) to have zero - * predecessors. In particular, dominance assumes all blocks are reachable. - * So, we insert a "fake link" by making successors[1] point after the loop. - * - * Note that we have to do this after unlinking/recreating the block's - * successors. If we removed a "break" at the end of the loop, then - * block == last_block, so block->successors[0] would already be "next", - * and adding a fake link would create two identical successors. Doing - * this afterward works, as we'll have changed block->successors[0] to - * be the top of the loop. - */ - if (type == nir_jump_break && next->predecessors->entries == 0) { - nir_loop *loop = - nir_cf_node_as_loop(nir_cf_node_prev(&next->cf_node)); - - /* insert fake link */ - nir_cf_node *last = nir_loop_last_cf_node(loop); - assert(last->type == nir_cf_node_block); - nir_block *last_block = nir_cf_node_as_block(last); - - last_block->successors[1] = next; - block_add_pred(next, last_block); - } -} - -void -nir_handle_remove_jump(nir_block *block, nir_jump_type type) -{ - unlink_jump(block, type, true); - - nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node); - nir_metadata_preserve(impl, nir_metadata_none); -} - -static void -update_if_uses(nir_cf_node *node) -{ - if (node->type != nir_cf_node_if) - return; - - nir_if *if_stmt = nir_cf_node_as_if(node); - - if_stmt->condition.parent_if = if_stmt; - if (if_stmt->condition.is_ssa) { - list_addtail(&if_stmt->condition.use_link, - &if_stmt->condition.ssa->if_uses); - } else { - list_addtail(&if_stmt->condition.use_link, - &if_stmt->condition.reg.reg->if_uses); - } -} - -/** - * Stitch two basic blocks together into one. The aggregate must have the same - * predecessors as the first and the same successors as the second. - */ - -static void -stitch_blocks(nir_block *before, nir_block *after) -{ - /* - * We move after into before, so we have to deal with up to 2 successors vs. - * possibly a large number of predecessors. - * - * TODO: special case when before is empty and after isn't? - */ - - if (block_ends_in_jump(before)) { - assert(exec_list_is_empty(&after->instr_list)); - if (after->successors[0]) - remove_phi_src(after->successors[0], after); - if (after->successors[1]) - remove_phi_src(after->successors[1], after); - unlink_block_successors(after); - exec_node_remove(&after->cf_node.node); - } else { - move_successors(after, before); - - foreach_list_typed(nir_instr, instr, node, &after->instr_list) { - instr->block = before; - } - - exec_list_append(&before->instr_list, &after->instr_list); - exec_node_remove(&after->cf_node.node); - } -} - -void -nir_cf_node_insert(nir_cursor cursor, nir_cf_node *node) -{ - nir_block *before, *after; - - split_block_cursor(cursor, &before, &after); - - if (node->type == nir_cf_node_block) { - nir_block *block = nir_cf_node_as_block(node); - exec_node_insert_after(&before->cf_node.node, &block->cf_node.node); - block->cf_node.parent = before->cf_node.parent; - /* stitch_blocks() assumes that any block that ends with a jump has - * already been setup with the correct successors, so we need to set - * up jumps here as the block is being inserted. - */ - if (block_ends_in_jump(block)) - nir_handle_add_jump(block); - - stitch_blocks(block, after); - stitch_blocks(before, block); - } else { - update_if_uses(node); - insert_non_block(before, node, after); - } -} - -static bool -replace_ssa_def_uses(nir_ssa_def *def, void *void_impl) -{ - nir_function_impl *impl = void_impl; - void *mem_ctx = ralloc_parent(impl); - - nir_ssa_undef_instr *undef = - nir_ssa_undef_instr_create(mem_ctx, def->num_components); - nir_instr_insert_before_cf_list(&impl->body, &undef->instr); - nir_ssa_def_rewrite_uses(def, nir_src_for_ssa(&undef->def)); - return true; -} - -static void -cleanup_cf_node(nir_cf_node *node, nir_function_impl *impl) -{ - switch (node->type) { - case nir_cf_node_block: { - nir_block *block = nir_cf_node_as_block(node); - /* We need to walk the instructions and clean up defs/uses */ - nir_foreach_instr_safe(block, instr) { - if (instr->type == nir_instr_type_jump) { - nir_jump_type jump_type = nir_instr_as_jump(instr)->type; - unlink_jump(block, jump_type, false); - } else { - nir_foreach_ssa_def(instr, replace_ssa_def_uses, impl); - nir_instr_remove(instr); - } - } - break; - } - - case nir_cf_node_if: { - nir_if *if_stmt = nir_cf_node_as_if(node); - foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list) - cleanup_cf_node(child, impl); - foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list) - cleanup_cf_node(child, impl); - - list_del(&if_stmt->condition.use_link); - break; - } - - case nir_cf_node_loop: { - nir_loop *loop = nir_cf_node_as_loop(node); - foreach_list_typed(nir_cf_node, child, node, &loop->body) - cleanup_cf_node(child, impl); - break; - } - case nir_cf_node_function: { - nir_function_impl *impl = nir_cf_node_as_function(node); - foreach_list_typed(nir_cf_node, child, node, &impl->body) - cleanup_cf_node(child, impl); - break; - } - default: - unreachable("Invalid CF node type"); - } -} - -void -nir_cf_extract(nir_cf_list *extracted, nir_cursor begin, nir_cursor end) -{ - nir_block *block_begin, *block_end, *block_before, *block_after; - - if (nir_cursors_equal(begin, end)) { - exec_list_make_empty(&extracted->list); - extracted->impl = NULL; /* we shouldn't need this */ - return; - } - - /* In the case where begin points to an instruction in some basic block and - * end points to the end of the same basic block, we rely on the fact that - * splitting on an instruction moves earlier instructions into a new basic - * block. If the later instructions were moved instead, then the end cursor - * would be pointing to the same place that begin used to point to, which - * is obviously not what we want. - */ - split_block_cursor(begin, &block_before, &block_begin); - split_block_cursor(end, &block_end, &block_after); - - extracted->impl = nir_cf_node_get_function(&block_begin->cf_node); - exec_list_make_empty(&extracted->list); - - /* Dominance and other block-related information is toast. */ - nir_metadata_preserve(extracted->impl, nir_metadata_none); - - nir_cf_node *cf_node = &block_begin->cf_node; - nir_cf_node *cf_node_end = &block_end->cf_node; - while (true) { - nir_cf_node *next = nir_cf_node_next(cf_node); - - exec_node_remove(&cf_node->node); - cf_node->parent = NULL; - exec_list_push_tail(&extracted->list, &cf_node->node); - - if (cf_node == cf_node_end) - break; - - cf_node = next; - } - - stitch_blocks(block_before, block_after); -} - -void -nir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor) -{ - nir_block *before, *after; - - if (exec_list_is_empty(&cf_list->list)) - return; - - split_block_cursor(cursor, &before, &after); - - foreach_list_typed_safe(nir_cf_node, node, node, &cf_list->list) { - exec_node_remove(&node->node); - node->parent = before->cf_node.parent; - exec_node_insert_node_before(&after->cf_node.node, &node->node); - } - - stitch_blocks(before, - nir_cf_node_as_block(nir_cf_node_next(&before->cf_node))); - stitch_blocks(nir_cf_node_as_block(nir_cf_node_prev(&after->cf_node)), - after); -} - -void -nir_cf_delete(nir_cf_list *cf_list) -{ - foreach_list_typed(nir_cf_node, node, node, &cf_list->list) { - cleanup_cf_node(node, cf_list->impl); - } -} diff --git a/src/glsl/nir/nir_control_flow.h b/src/glsl/nir/nir_control_flow.h deleted file mode 100644 index b71382fc597..00000000000 --- a/src/glsl/nir/nir_control_flow.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -/** NIR Control Flow Modification - * - * This file contains various API's that make modifying control flow in NIR, - * while maintaining the invariants checked by the validator, much easier. - * There are two parts to this: - * - * 1. Inserting control flow (if's and loops) in various places, for creating - * IR either from scratch or as part of some lowering pass. - * 2. Taking existing pieces of the IR and either moving them around or - * deleting them. - */ - -/** Control flow insertion. */ - -/** puts a control flow node where the cursor is */ -void nir_cf_node_insert(nir_cursor cursor, nir_cf_node *node); - -/** puts a control flow node immediately after another control flow node */ -static inline void -nir_cf_node_insert_after(nir_cf_node *node, nir_cf_node *after) -{ - nir_cf_node_insert(nir_after_cf_node(node), after); -} - -/** puts a control flow node immediately before another control flow node */ -static inline void -nir_cf_node_insert_before(nir_cf_node *node, nir_cf_node *before) -{ - nir_cf_node_insert(nir_before_cf_node(node), before); -} - -/** puts a control flow node at the beginning of a list from an if, loop, or function */ -static inline void -nir_cf_node_insert_begin(struct exec_list *list, nir_cf_node *node) -{ - nir_cf_node_insert(nir_before_cf_list(list), node); -} - -/** puts a control flow node at the end of a list from an if, loop, or function */ -static inline void -nir_cf_node_insert_end(struct exec_list *list, nir_cf_node *node) -{ - nir_cf_node_insert(nir_after_cf_list(list), node); -} - - -/** Control flow motion. - * - * These functions let you take a part of a control flow list (basically - * equivalent to a series of statement in GLSL) and "extract" it from the IR, - * so that it's a free-floating piece of IR that can be either re-inserted - * somewhere else or deleted entirely. A few notes on using it: - * - * 1. Phi nodes are considered attached to the piece of control flow that - * their sources come from. There are three places where phi nodes can - * occur, which are the three places where a block can have multiple - * predecessors: - * - * 1) After an if statement, if neither branch ends in a jump. - * 2) After a loop, if there are multiple break's. - * 3) At the beginning of a loop. - * - * For #1, the phi node is considered to be part of the if, and for #2 and - * #3 the phi node is considered to be part of the loop. This allows us to - * keep phi's intact, but it means that phi nodes cannot be separated from - * the control flow they come from. For example, extracting an if without - * extracting all the phi nodes after it is not allowed, and neither is - * extracting only some of the phi nodes at the beginning of a block. It - * also means that extracting from the beginning of a basic block actually - * means extracting from the first non-phi instruction, since there's no - * situation where extracting phi nodes without extracting what comes - * before them makes any sense. - * - * 2. Phi node sources are guaranteed to remain valid, meaning that they still - * correspond one-to-one with the predecessors of the basic block they're - * part of. In addition, the original sources will be preserved unless they - * correspond to a break or continue that was deleted. However, no attempt - * is made to ensure that SSA form is maintained. In particular, it is - * *not* guaranteed that definitions of SSA values will dominate all their - * uses after all is said and done. Either the caller must ensure that this - * is the case, or it must insert extra phi nodes to restore SSA. - * - * 3. It is invalid to move a piece of IR with a break/continue outside of the - * loop it references. Doing this will result in invalid - * successors/predecessors and phi node sources. - * - * 4. It is invalid to move a piece of IR from one function implementation to - * another. - * - * 5. Extracting a control flow list will leave lots of dangling references to - * and from other pieces of the IR. It also leaves things in a not 100% - * consistent state. This means that some things (e.g. inserting - * instructions) might not work reliably on the extracted control flow. It - * also means that extracting control flow without re-inserting it or - * deleting it is a Bad Thing (tm). - */ - -typedef struct { - struct exec_list list; - nir_function_impl *impl; /* for cleaning up if the list is deleted */ -} nir_cf_list; - -void nir_cf_extract(nir_cf_list *extracted, nir_cursor begin, nir_cursor end); - -void nir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor); - -void nir_cf_delete(nir_cf_list *cf_list); - -static inline void -nir_cf_list_extract(nir_cf_list *extracted, struct exec_list *cf_list) -{ - nir_cf_extract(extracted, nir_before_cf_list(cf_list), - nir_after_cf_list(cf_list)); -} - -/** removes a control flow node, doing any cleanup necessary */ -static inline void -nir_cf_node_remove(nir_cf_node *node) -{ - nir_cf_list list; - nir_cf_extract(&list, nir_before_cf_node(node), nir_after_cf_node(node)); - nir_cf_delete(&list); -} - -#ifdef __cplusplus -} -#endif diff --git a/src/glsl/nir/nir_control_flow_private.h b/src/glsl/nir/nir_control_flow_private.h deleted file mode 100644 index f32b57a8cef..00000000000 --- a/src/glsl/nir/nir_control_flow_private.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir_control_flow.h" - -#pragma once - -/* Internal control-flow modification functions used when inserting/removing - * instructions. - */ - -void nir_handle_add_jump(nir_block *block); -void nir_handle_remove_jump(nir_block *block, nir_jump_type type); diff --git a/src/glsl/nir/nir_dominance.c b/src/glsl/nir/nir_dominance.c deleted file mode 100644 index d95f3968074..00000000000 --- a/src/glsl/nir/nir_dominance.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -/* - * Implements the algorithms for computing the dominance tree and the - * dominance frontier from "A Simple, Fast Dominance Algorithm" by Cooper, - * Harvey, and Kennedy. - */ - -typedef struct { - nir_function_impl *impl; - bool progress; -} dom_state; - -static bool -init_block_cb(nir_block *block, void *_state) -{ - dom_state *state = (dom_state *) _state; - if (block == nir_start_block(state->impl)) - block->imm_dom = block; - else - block->imm_dom = NULL; - block->num_dom_children = 0; - - struct set_entry *entry; - set_foreach(block->dom_frontier, entry) { - _mesa_set_remove(block->dom_frontier, entry); - } - - return true; -} - -static nir_block * -intersect(nir_block *b1, nir_block *b2) -{ - while (b1 != b2) { - /* - * Note, the comparisons here are the opposite of what the paper says - * because we index blocks from beginning -> end (i.e. reverse - * post-order) instead of post-order like they assume. - */ - while (b1->index > b2->index) - b1 = b1->imm_dom; - while (b2->index > b1->index) - b2 = b2->imm_dom; - } - - return b1; -} - -static bool -calc_dominance_cb(nir_block *block, void *_state) -{ - dom_state *state = (dom_state *) _state; - if (block == nir_start_block(state->impl)) - return true; - - nir_block *new_idom = NULL; - struct set_entry *entry; - set_foreach(block->predecessors, entry) { - nir_block *pred = (nir_block *) entry->key; - - if (pred->imm_dom) { - if (new_idom) - new_idom = intersect(pred, new_idom); - else - new_idom = pred; - } - } - - if (block->imm_dom != new_idom) { - block->imm_dom = new_idom; - state->progress = true; - } - - return true; -} - -static bool -calc_dom_frontier_cb(nir_block *block, void *state) -{ - (void) state; - - if (block->predecessors->entries > 1) { - struct set_entry *entry; - set_foreach(block->predecessors, entry) { - nir_block *runner = (nir_block *) entry->key; - - /* Skip unreachable predecessors */ - if (runner->imm_dom == NULL) - continue; - - while (runner != block->imm_dom) { - _mesa_set_add(runner->dom_frontier, block); - runner = runner->imm_dom; - } - } - } - - return true; -} - -/* - * Compute each node's children in the dominance tree from the immediate - * dominator information. We do this in three stages: - * - * 1. Calculate the number of children each node has - * 2. Allocate arrays, setting the number of children to 0 again - * 3. For each node, add itself to its parent's list of children, using - * num_dom_children as an index - at the end of this step, num_dom_children - * for each node will be the same as it was at the end of step #1. - */ - -static bool -block_count_children(nir_block *block, void *state) -{ - (void) state; - - if (block->imm_dom) - block->imm_dom->num_dom_children++; - - return true; -} - -static bool -block_alloc_children(nir_block *block, void *state) -{ - void *mem_ctx = state; - - block->dom_children = ralloc_array(mem_ctx, nir_block *, - block->num_dom_children); - block->num_dom_children = 0; - - return true; -} - -static bool -block_add_child(nir_block *block, void *state) -{ - (void) state; - - if (block->imm_dom) - block->imm_dom->dom_children[block->imm_dom->num_dom_children++] = block; - - return true; -} - -static void -calc_dom_children(nir_function_impl* impl) -{ - void *mem_ctx = ralloc_parent(impl); - - nir_foreach_block(impl, block_count_children, NULL); - nir_foreach_block(impl, block_alloc_children, mem_ctx); - nir_foreach_block(impl, block_add_child, NULL); -} - -static void -calc_dfs_indicies(nir_block *block, unsigned *index) -{ - block->dom_pre_index = (*index)++; - - for (unsigned i = 0; i < block->num_dom_children; i++) - calc_dfs_indicies(block->dom_children[i], index); - - block->dom_post_index = (*index)++; -} - -void -nir_calc_dominance_impl(nir_function_impl *impl) -{ - if (impl->valid_metadata & nir_metadata_dominance) - return; - - nir_metadata_require(impl, nir_metadata_block_index); - - dom_state state; - state.impl = impl; - state.progress = true; - - nir_foreach_block(impl, init_block_cb, &state); - - while (state.progress) { - state.progress = false; - nir_foreach_block(impl, calc_dominance_cb, &state); - } - - nir_foreach_block(impl, calc_dom_frontier_cb, &state); - - nir_block *start_block = nir_start_block(impl); - start_block->imm_dom = NULL; - - calc_dom_children(impl); - - unsigned dfs_index = 0; - calc_dfs_indicies(start_block, &dfs_index); -} - -void -nir_calc_dominance(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_calc_dominance_impl(function->impl); - } -} - -/** - * Computes the least common anscestor of two blocks. If one of the blocks - * is null, the other block is returned. - */ -nir_block * -nir_dominance_lca(nir_block *b1, nir_block *b2) -{ - if (b1 == NULL) - return b2; - - if (b2 == NULL) - return b1; - - assert(nir_cf_node_get_function(&b1->cf_node) == - nir_cf_node_get_function(&b2->cf_node)); - - assert(nir_cf_node_get_function(&b1->cf_node)->valid_metadata & - nir_metadata_dominance); - - return intersect(b1, b2); -} - -/** - * Returns true if parent dominates child - */ -bool -nir_block_dominates(nir_block *parent, nir_block *child) -{ - assert(nir_cf_node_get_function(&parent->cf_node) == - nir_cf_node_get_function(&child->cf_node)); - - assert(nir_cf_node_get_function(&parent->cf_node)->valid_metadata & - nir_metadata_dominance); - - return child->dom_pre_index >= parent->dom_pre_index && - child->dom_post_index <= parent->dom_post_index; -} - -static bool -dump_block_dom(nir_block *block, void *state) -{ - FILE *fp = state; - if (block->imm_dom) - fprintf(fp, "\t%u -> %u\n", block->imm_dom->index, block->index); - return true; -} - -void -nir_dump_dom_tree_impl(nir_function_impl *impl, FILE *fp) -{ - fprintf(fp, "digraph doms_%s {\n", impl->function->name); - nir_foreach_block(impl, dump_block_dom, fp); - fprintf(fp, "}\n\n"); -} - -void -nir_dump_dom_tree(nir_shader *shader, FILE *fp) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_dump_dom_tree_impl(function->impl, fp); - } -} - -static bool -dump_block_dom_frontier(nir_block *block, void *state) -{ - FILE *fp = state; - - fprintf(fp, "DF(%u) = {", block->index); - struct set_entry *entry; - set_foreach(block->dom_frontier, entry) { - nir_block *df = (nir_block *) entry->key; - fprintf(fp, "%u, ", df->index); - } - fprintf(fp, "}\n"); - return true; -} - -void -nir_dump_dom_frontier_impl(nir_function_impl *impl, FILE *fp) -{ - nir_foreach_block(impl, dump_block_dom_frontier, fp); -} - -void -nir_dump_dom_frontier(nir_shader *shader, FILE *fp) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_dump_dom_frontier_impl(function->impl, fp); - } -} - -static bool -dump_block_succs(nir_block *block, void *state) -{ - FILE *fp = state; - if (block->successors[0]) - fprintf(fp, "\t%u -> %u\n", block->index, block->successors[0]->index); - if (block->successors[1]) - fprintf(fp, "\t%u -> %u\n", block->index, block->successors[1]->index); - return true; -} - -void -nir_dump_cfg_impl(nir_function_impl *impl, FILE *fp) -{ - fprintf(fp, "digraph cfg_%s {\n", impl->function->name); - nir_foreach_block(impl, dump_block_succs, fp); - fprintf(fp, "}\n\n"); -} - -void -nir_dump_cfg(nir_shader *shader, FILE *fp) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_dump_cfg_impl(function->impl, fp); - } -} diff --git a/src/glsl/nir/nir_from_ssa.c b/src/glsl/nir/nir_from_ssa.c deleted file mode 100644 index 8bc9f24e406..00000000000 --- a/src/glsl/nir/nir_from_ssa.c +++ /dev/null @@ -1,805 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" -#include "nir_vla.h" - -/* - * This file implements an out-of-SSA pass as described in "Revisiting - * Out-of-SSA Translation for Correctness, Code Quality, and Efficiency" by - * Boissinot et. al. - */ - -struct from_ssa_state { - void *mem_ctx; - void *dead_ctx; - bool phi_webs_only; - struct hash_table *merge_node_table; - nir_instr *instr; - nir_function_impl *impl; -}; - -/* Returns true if a dominates b */ -static bool -ssa_def_dominates(nir_ssa_def *a, nir_ssa_def *b) -{ - if (a->live_index == 0) { - /* SSA undefs always dominate */ - return true; - } else if (b->live_index < a->live_index) { - return false; - } else if (a->parent_instr->block == b->parent_instr->block) { - return a->live_index <= b->live_index; - } else { - return nir_block_dominates(a->parent_instr->block, - b->parent_instr->block); - } -} - - -/* The following data structure, which I have named merge_set is a way of - * representing a set registers of non-interfering registers. This is - * based on the concept of a "dominence forest" presented in "Fast Copy - * Coalescing and Live-Range Identification" by Budimlic et. al. but the - * implementation concept is taken from "Revisiting Out-of-SSA Translation - * for Correctness, Code Quality, and Efficiency" by Boissinot et. al.. - * - * Each SSA definition is associated with a merge_node and the association - * is represented by a combination of a hash table and the "def" parameter - * in the merge_node structure. The merge_set stores a linked list of - * merge_node's in dominence order of the ssa definitions. (Since the - * liveness analysis pass indexes the SSA values in dominence order for us, - * this is an easy thing to keep up.) It is assumed that no pair of the - * nodes in a given set interfere. Merging two sets or checking for - * interference can be done in a single linear-time merge-sort walk of the - * two lists of nodes. - */ -struct merge_set; - -typedef struct { - struct exec_node node; - struct merge_set *set; - nir_ssa_def *def; -} merge_node; - -typedef struct merge_set { - struct exec_list nodes; - unsigned size; - nir_register *reg; -} merge_set; - -#if 0 -static void -merge_set_dump(merge_set *set, FILE *fp) -{ - nir_ssa_def *dom[set->size]; - int dom_idx = -1; - - foreach_list_typed(merge_node, node, node, &set->nodes) { - while (dom_idx >= 0 && !ssa_def_dominates(dom[dom_idx], node->def)) - dom_idx--; - - for (int i = 0; i <= dom_idx; i++) - fprintf(fp, " "); - - if (node->def->name) - fprintf(fp, "ssa_%d /* %s */\n", node->def->index, node->def->name); - else - fprintf(fp, "ssa_%d\n", node->def->index); - - dom[++dom_idx] = node->def; - } -} -#endif - -static merge_node * -get_merge_node(nir_ssa_def *def, struct from_ssa_state *state) -{ - struct hash_entry *entry = - _mesa_hash_table_search(state->merge_node_table, def); - if (entry) - return entry->data; - - merge_set *set = ralloc(state->dead_ctx, merge_set); - exec_list_make_empty(&set->nodes); - set->size = 1; - set->reg = NULL; - - merge_node *node = ralloc(state->dead_ctx, merge_node); - node->set = set; - node->def = def; - exec_list_push_head(&set->nodes, &node->node); - - _mesa_hash_table_insert(state->merge_node_table, def, node); - - return node; -} - -static bool -merge_nodes_interfere(merge_node *a, merge_node *b) -{ - return nir_ssa_defs_interfere(a->def, b->def); -} - -/* Merges b into a */ -static merge_set * -merge_merge_sets(merge_set *a, merge_set *b) -{ - struct exec_node *an = exec_list_get_head(&a->nodes); - struct exec_node *bn = exec_list_get_head(&b->nodes); - while (!exec_node_is_tail_sentinel(bn)) { - merge_node *a_node = exec_node_data(merge_node, an, node); - merge_node *b_node = exec_node_data(merge_node, bn, node); - - if (exec_node_is_tail_sentinel(an) || - a_node->def->live_index > b_node->def->live_index) { - struct exec_node *next = bn->next; - exec_node_remove(bn); - exec_node_insert_node_before(an, bn); - exec_node_data(merge_node, bn, node)->set = a; - bn = next; - } else { - an = an->next; - } - } - - a->size += b->size; - b->size = 0; - - return a; -} - -/* Checks for any interference between two merge sets - * - * This is an implementation of Algorithm 2 in "Revisiting Out-of-SSA - * Translation for Correctness, Code Quality, and Efficiency" by - * Boissinot et. al. - */ -static bool -merge_sets_interfere(merge_set *a, merge_set *b) -{ - NIR_VLA(merge_node *, dom, a->size + b->size); - int dom_idx = -1; - - struct exec_node *an = exec_list_get_head(&a->nodes); - struct exec_node *bn = exec_list_get_head(&b->nodes); - while (!exec_node_is_tail_sentinel(an) || - !exec_node_is_tail_sentinel(bn)) { - - merge_node *current; - if (exec_node_is_tail_sentinel(an)) { - current = exec_node_data(merge_node, bn, node); - bn = bn->next; - } else if (exec_node_is_tail_sentinel(bn)) { - current = exec_node_data(merge_node, an, node); - an = an->next; - } else { - merge_node *a_node = exec_node_data(merge_node, an, node); - merge_node *b_node = exec_node_data(merge_node, bn, node); - - if (a_node->def->live_index <= b_node->def->live_index) { - current = a_node; - an = an->next; - } else { - current = b_node; - bn = bn->next; - } - } - - while (dom_idx >= 0 && - !ssa_def_dominates(dom[dom_idx]->def, current->def)) - dom_idx--; - - if (dom_idx >= 0 && merge_nodes_interfere(current, dom[dom_idx])) - return true; - - dom[++dom_idx] = current; - } - - return false; -} - -static bool -add_parallel_copy_to_end_of_block(nir_block *block, void *void_state) -{ - struct from_ssa_state *state = void_state; - - bool need_end_copy = false; - if (block->successors[0]) { - nir_instr *instr = nir_block_first_instr(block->successors[0]); - if (instr && instr->type == nir_instr_type_phi) - need_end_copy = true; - } - - if (block->successors[1]) { - nir_instr *instr = nir_block_first_instr(block->successors[1]); - if (instr && instr->type == nir_instr_type_phi) - need_end_copy = true; - } - - if (need_end_copy) { - /* If one of our successors has at least one phi node, we need to - * create a parallel copy at the end of the block but before the jump - * (if there is one). - */ - nir_parallel_copy_instr *pcopy = - nir_parallel_copy_instr_create(state->dead_ctx); - - nir_instr_insert(nir_after_block_before_jump(block), &pcopy->instr); - } - - return true; -} - -static nir_parallel_copy_instr * -get_parallel_copy_at_end_of_block(nir_block *block) -{ - nir_instr *last_instr = nir_block_last_instr(block); - if (last_instr == NULL) - return NULL; - - /* The last instruction may be a jump in which case the parallel copy is - * right before it. - */ - if (last_instr->type == nir_instr_type_jump) - last_instr = nir_instr_prev(last_instr); - - if (last_instr && last_instr->type == nir_instr_type_parallel_copy) - return nir_instr_as_parallel_copy(last_instr); - else - return NULL; -} - -/** Isolate phi nodes with parallel copies - * - * In order to solve the dependency problems with the sources and - * destinations of phi nodes, we first isolate them by adding parallel - * copies to the beginnings and ends of basic blocks. For every block with - * phi nodes, we add a parallel copy immediately following the last phi - * node that copies the destinations of all of the phi nodes to new SSA - * values. We also add a parallel copy to the end of every block that has - * a successor with phi nodes that, for each phi node in each successor, - * copies the corresponding sorce of the phi node and adjust the phi to - * used the destination of the parallel copy. - * - * In SSA form, each value has exactly one definition. What this does is - * ensure that each value used in a phi also has exactly one use. The - * destinations of phis are only used by the parallel copy immediately - * following the phi nodes and. Thanks to the parallel copy at the end of - * the predecessor block, the sources of phi nodes are are the only use of - * that value. This allows us to immediately assign all the sources and - * destinations of any given phi node to the same register without worrying - * about interference at all. We do coalescing to get rid of the parallel - * copies where possible. - * - * Before this pass can be run, we have to iterate over the blocks with - * add_parallel_copy_to_end_of_block to ensure that the parallel copies at - * the ends of blocks exist. We can create the ones at the beginnings as - * we go, but the ones at the ends of blocks need to be created ahead of - * time because of potential back-edges in the CFG. - */ -static bool -isolate_phi_nodes_block(nir_block *block, void *void_state) -{ - struct from_ssa_state *state = void_state; - - nir_instr *last_phi_instr = NULL; - nir_foreach_instr(block, instr) { - /* Phi nodes only ever come at the start of a block */ - if (instr->type != nir_instr_type_phi) - break; - - last_phi_instr = instr; - } - - /* If we don't have any phi's, then there's nothing for us to do. */ - if (last_phi_instr == NULL) - return true; - - /* If we have phi nodes, we need to create a parallel copy at the - * start of this block but after the phi nodes. - */ - nir_parallel_copy_instr *block_pcopy = - nir_parallel_copy_instr_create(state->dead_ctx); - nir_instr_insert_after(last_phi_instr, &block_pcopy->instr); - - nir_foreach_instr(block, instr) { - /* Phi nodes only ever come at the start of a block */ - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - assert(phi->dest.is_ssa); - nir_foreach_phi_src(phi, src) { - nir_parallel_copy_instr *pcopy = - get_parallel_copy_at_end_of_block(src->pred); - assert(pcopy); - - nir_parallel_copy_entry *entry = rzalloc(state->dead_ctx, - nir_parallel_copy_entry); - nir_ssa_dest_init(&pcopy->instr, &entry->dest, - phi->dest.ssa.num_components, src->src.ssa->name); - exec_list_push_tail(&pcopy->entries, &entry->node); - - assert(src->src.is_ssa); - nir_instr_rewrite_src(&pcopy->instr, &entry->src, src->src); - - nir_instr_rewrite_src(&phi->instr, &src->src, - nir_src_for_ssa(&entry->dest.ssa)); - } - - nir_parallel_copy_entry *entry = rzalloc(state->dead_ctx, - nir_parallel_copy_entry); - nir_ssa_dest_init(&block_pcopy->instr, &entry->dest, - phi->dest.ssa.num_components, phi->dest.ssa.name); - exec_list_push_tail(&block_pcopy->entries, &entry->node); - - nir_ssa_def_rewrite_uses(&phi->dest.ssa, - nir_src_for_ssa(&entry->dest.ssa)); - - nir_instr_rewrite_src(&block_pcopy->instr, &entry->src, - nir_src_for_ssa(&phi->dest.ssa)); - } - - return true; -} - -static bool -coalesce_phi_nodes_block(nir_block *block, void *void_state) -{ - struct from_ssa_state *state = void_state; - - nir_foreach_instr(block, instr) { - /* Phi nodes only ever come at the start of a block */ - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - - assert(phi->dest.is_ssa); - merge_node *dest_node = get_merge_node(&phi->dest.ssa, state); - - nir_foreach_phi_src(phi, src) { - assert(src->src.is_ssa); - merge_node *src_node = get_merge_node(src->src.ssa, state); - if (src_node->set != dest_node->set) - merge_merge_sets(dest_node->set, src_node->set); - } - } - - return true; -} - -static void -aggressive_coalesce_parallel_copy(nir_parallel_copy_instr *pcopy, - struct from_ssa_state *state) -{ - nir_foreach_parallel_copy_entry(pcopy, entry) { - if (!entry->src.is_ssa) - continue; - - /* Since load_const instructions are SSA only, we can't replace their - * destinations with registers and, therefore, can't coalesce them. - */ - if (entry->src.ssa->parent_instr->type == nir_instr_type_load_const) - continue; - - /* Don't try and coalesce these */ - if (entry->dest.ssa.num_components != entry->src.ssa->num_components) - continue; - - merge_node *src_node = get_merge_node(entry->src.ssa, state); - merge_node *dest_node = get_merge_node(&entry->dest.ssa, state); - - if (src_node->set == dest_node->set) - continue; - - if (!merge_sets_interfere(src_node->set, dest_node->set)) - merge_merge_sets(src_node->set, dest_node->set); - } -} - -static bool -aggressive_coalesce_block(nir_block *block, void *void_state) -{ - struct from_ssa_state *state = void_state; - - nir_parallel_copy_instr *start_pcopy = NULL; - nir_foreach_instr(block, instr) { - /* Phi nodes only ever come at the start of a block */ - if (instr->type != nir_instr_type_phi) { - if (instr->type != nir_instr_type_parallel_copy) - break; /* The parallel copy must be right after the phis */ - - start_pcopy = nir_instr_as_parallel_copy(instr); - - aggressive_coalesce_parallel_copy(start_pcopy, state); - - break; - } - } - - nir_parallel_copy_instr *end_pcopy = - get_parallel_copy_at_end_of_block(block); - - if (end_pcopy && end_pcopy != start_pcopy) - aggressive_coalesce_parallel_copy(end_pcopy, state); - - return true; -} - -static bool -rewrite_ssa_def(nir_ssa_def *def, void *void_state) -{ - struct from_ssa_state *state = void_state; - nir_register *reg; - - struct hash_entry *entry = - _mesa_hash_table_search(state->merge_node_table, def); - if (entry) { - /* In this case, we're part of a phi web. Use the web's register. */ - merge_node *node = (merge_node *)entry->data; - - /* If it doesn't have a register yet, create one. Note that all of - * the things in the merge set should be the same so it doesn't - * matter which node's definition we use. - */ - if (node->set->reg == NULL) { - node->set->reg = nir_local_reg_create(state->impl); - node->set->reg->name = def->name; - node->set->reg->num_components = def->num_components; - node->set->reg->num_array_elems = 0; - } - - reg = node->set->reg; - } else { - if (state->phi_webs_only) - return true; - - /* We leave load_const SSA values alone. They act as immediates to - * the backend. If it got coalesced into a phi, that's ok. - */ - if (def->parent_instr->type == nir_instr_type_load_const) - return true; - - reg = nir_local_reg_create(state->impl); - reg->name = def->name; - reg->num_components = def->num_components; - reg->num_array_elems = 0; - } - - nir_ssa_def_rewrite_uses(def, nir_src_for_reg(reg)); - assert(list_empty(&def->uses) && list_empty(&def->if_uses)); - - if (def->parent_instr->type == nir_instr_type_ssa_undef) { - /* If it's an ssa_undef instruction, remove it since we know we just got - * rid of all its uses. - */ - nir_instr *parent_instr = def->parent_instr; - nir_instr_remove(parent_instr); - ralloc_steal(state->dead_ctx, parent_instr); - return true; - } - - assert(def->parent_instr->type != nir_instr_type_load_const); - - /* At this point we know a priori that this SSA def is part of a - * nir_dest. We can use exec_node_data to get the dest pointer. - */ - nir_dest *dest = exec_node_data(nir_dest, def, ssa); - - nir_instr_rewrite_dest(state->instr, dest, nir_dest_for_reg(reg)); - - return true; -} - -/* Resolves ssa definitions to registers. While we're at it, we also - * remove phi nodes. - */ -static bool -resolve_registers_block(nir_block *block, void *void_state) -{ - struct from_ssa_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - state->instr = instr; - nir_foreach_ssa_def(instr, rewrite_ssa_def, state); - - if (instr->type == nir_instr_type_phi) { - nir_instr_remove(instr); - ralloc_steal(state->dead_ctx, instr); - } - } - state->instr = NULL; - - return true; -} - -static void -emit_copy(nir_parallel_copy_instr *pcopy, nir_src src, nir_src dest_src, - void *mem_ctx) -{ - assert(!dest_src.is_ssa && - dest_src.reg.indirect == NULL && - dest_src.reg.base_offset == 0); - - if (src.is_ssa) - assert(src.ssa->num_components >= dest_src.reg.reg->num_components); - else - assert(src.reg.reg->num_components >= dest_src.reg.reg->num_components); - - nir_alu_instr *mov = nir_alu_instr_create(mem_ctx, nir_op_imov); - nir_src_copy(&mov->src[0].src, &src, mov); - mov->dest.dest = nir_dest_for_reg(dest_src.reg.reg); - mov->dest.write_mask = (1 << dest_src.reg.reg->num_components) - 1; - - nir_instr_insert_before(&pcopy->instr, &mov->instr); -} - -/* Resolves a single parallel copy operation into a sequence of mov's - * - * This is based on Algorithm 1 from "Revisiting Out-of-SSA Translation for - * Correctness, Code Quality, and Efficiency" by Boissinot et. al.. - * However, I never got the algorithm to work as written, so this version - * is slightly modified. - * - * The algorithm works by playing this little shell game with the values. - * We start by recording where every source value is and which source value - * each destination value should receive. We then grab any copy whose - * destination is "empty", i.e. not used as a source, and do the following: - * - Find where its source value currently lives - * - Emit the move instruction - * - Set the location of the source value to the destination - * - Mark the location containing the source value - * - Mark the destination as no longer needing to be copied - * - * When we run out of "empty" destinations, we have a cycle and so we - * create a temporary register, copy to that register, and mark the value - * we copied as living in that temporary. Now, the cycle is broken, so we - * can continue with the above steps. - */ -static void -resolve_parallel_copy(nir_parallel_copy_instr *pcopy, - struct from_ssa_state *state) -{ - unsigned num_copies = 0; - nir_foreach_parallel_copy_entry(pcopy, entry) { - /* Sources may be SSA */ - if (!entry->src.is_ssa && entry->src.reg.reg == entry->dest.reg.reg) - continue; - - num_copies++; - } - - if (num_copies == 0) { - /* Hooray, we don't need any copies! */ - nir_instr_remove(&pcopy->instr); - return; - } - - /* The register/source corresponding to the given index */ - NIR_VLA_ZERO(nir_src, values, num_copies * 2); - - /* The current location of a given piece of data. We will use -1 for "null" */ - NIR_VLA_FILL(int, loc, num_copies * 2, -1); - - /* The piece of data that the given piece of data is to be copied from. We will use -1 for "null" */ - NIR_VLA_FILL(int, pred, num_copies * 2, -1); - - /* The destinations we have yet to properly fill */ - NIR_VLA(int, to_do, num_copies * 2); - int to_do_idx = -1; - - /* Now we set everything up: - * - All values get assigned a temporary index - * - Current locations are set from sources - * - Predicessors are recorded from sources and destinations - */ - int num_vals = 0; - nir_foreach_parallel_copy_entry(pcopy, entry) { - /* Sources may be SSA */ - if (!entry->src.is_ssa && entry->src.reg.reg == entry->dest.reg.reg) - continue; - - int src_idx = -1; - for (int i = 0; i < num_vals; ++i) { - if (nir_srcs_equal(values[i], entry->src)) - src_idx = i; - } - if (src_idx < 0) { - src_idx = num_vals++; - values[src_idx] = entry->src; - } - - nir_src dest_src = nir_src_for_reg(entry->dest.reg.reg); - - int dest_idx = -1; - for (int i = 0; i < num_vals; ++i) { - if (nir_srcs_equal(values[i], dest_src)) { - /* Each destination of a parallel copy instruction should be - * unique. A destination may get used as a source, so we still - * have to walk the list. However, the predecessor should not, - * at this point, be set yet, so we should have -1 here. - */ - assert(pred[i] == -1); - dest_idx = i; - } - } - if (dest_idx < 0) { - dest_idx = num_vals++; - values[dest_idx] = dest_src; - } - - loc[src_idx] = src_idx; - pred[dest_idx] = src_idx; - - to_do[++to_do_idx] = dest_idx; - } - - /* Currently empty destinations we can go ahead and fill */ - NIR_VLA(int, ready, num_copies * 2); - int ready_idx = -1; - - /* Mark the ones that are ready for copying. We know an index is a - * destination if it has a predecessor and it's ready for copying if - * it's not marked as containing data. - */ - for (int i = 0; i < num_vals; i++) { - if (pred[i] != -1 && loc[i] == -1) - ready[++ready_idx] = i; - } - - while (to_do_idx >= 0) { - while (ready_idx >= 0) { - int b = ready[ready_idx--]; - int a = pred[b]; - emit_copy(pcopy, values[loc[a]], values[b], state->mem_ctx); - - /* If any other copies want a they can find it at b */ - loc[a] = b; - - /* b has been filled, mark it as not needing to be copied */ - pred[b] = -1; - - /* If a needs to be filled, it's ready for copying now */ - if (pred[a] != -1) - ready[++ready_idx] = a; - } - int b = to_do[to_do_idx--]; - if (pred[b] == -1) - continue; - - /* If we got here, then we don't have any more trivial copies that we - * can do. We have to break a cycle, so we create a new temporary - * register for that purpose. Normally, if going out of SSA after - * register allocation, you would want to avoid creating temporary - * registers. However, we are going out of SSA before register - * allocation, so we would rather not create extra register - * dependencies for the backend to deal with. If it wants, the - * backend can coalesce the (possibly multiple) temporaries. - */ - assert(num_vals < num_copies * 2); - nir_register *reg = nir_local_reg_create(state->impl); - reg->name = "copy_temp"; - reg->num_array_elems = 0; - if (values[b].is_ssa) - reg->num_components = values[b].ssa->num_components; - else - reg->num_components = values[b].reg.reg->num_components; - values[num_vals].is_ssa = false; - values[num_vals].reg.reg = reg; - - emit_copy(pcopy, values[b], values[num_vals], state->mem_ctx); - loc[b] = num_vals; - ready[++ready_idx] = b; - num_vals++; - } - - nir_instr_remove(&pcopy->instr); -} - -/* Resolves the parallel copies in a block. Each block can have at most - * two: One at the beginning, right after all the phi noces, and one at - * the end (or right before the final jump if it exists). - */ -static bool -resolve_parallel_copies_block(nir_block *block, void *void_state) -{ - struct from_ssa_state *state = void_state; - - /* At this point, we have removed all of the phi nodes. If a parallel - * copy existed right after the phi nodes in this block, it is now the - * first instruction. - */ - nir_instr *first_instr = nir_block_first_instr(block); - if (first_instr == NULL) - return true; /* Empty, nothing to do. */ - - if (first_instr->type == nir_instr_type_parallel_copy) { - nir_parallel_copy_instr *pcopy = nir_instr_as_parallel_copy(first_instr); - - resolve_parallel_copy(pcopy, state); - } - - /* It's possible that the above code already cleaned up the end parallel - * copy. However, doing so removed it form the instructions list so we - * won't find it here. Therefore, it's safe to go ahead and just look - * for one and clean it up if it exists. - */ - nir_parallel_copy_instr *end_pcopy = - get_parallel_copy_at_end_of_block(block); - if (end_pcopy) - resolve_parallel_copy(end_pcopy, state); - - return true; -} - -static void -nir_convert_from_ssa_impl(nir_function_impl *impl, bool phi_webs_only) -{ - struct from_ssa_state state; - - state.mem_ctx = ralloc_parent(impl); - state.dead_ctx = ralloc_context(NULL); - state.impl = impl; - state.phi_webs_only = phi_webs_only; - state.merge_node_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - nir_foreach_block(impl, add_parallel_copy_to_end_of_block, &state); - nir_foreach_block(impl, isolate_phi_nodes_block, &state); - - /* Mark metadata as dirty before we ask for liveness analysis */ - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - nir_metadata_require(impl, nir_metadata_live_ssa_defs | - nir_metadata_dominance); - - nir_foreach_block(impl, coalesce_phi_nodes_block, &state); - nir_foreach_block(impl, aggressive_coalesce_block, &state); - - nir_foreach_block(impl, resolve_registers_block, &state); - - nir_foreach_block(impl, resolve_parallel_copies_block, &state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - /* Clean up dead instructions and the hash tables */ - _mesa_hash_table_destroy(state.merge_node_table, NULL); - ralloc_free(state.dead_ctx); -} - -void -nir_convert_from_ssa(nir_shader *shader, bool phi_webs_only) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_convert_from_ssa_impl(function->impl, phi_webs_only); - } -} diff --git a/src/glsl/nir/nir_gather_info.c b/src/glsl/nir/nir_gather_info.c deleted file mode 100644 index b84915c2d2b..00000000000 --- a/src/glsl/nir/nir_gather_info.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" - -static void -gather_intrinsic_info(nir_intrinsic_instr *instr, nir_shader *shader) -{ - switch (instr->intrinsic) { - case nir_intrinsic_discard: - assert(shader->stage == MESA_SHADER_FRAGMENT); - shader->info.fs.uses_discard = true; - break; - - case nir_intrinsic_load_front_face: - case nir_intrinsic_load_vertex_id: - case nir_intrinsic_load_vertex_id_zero_base: - case nir_intrinsic_load_base_vertex: - case nir_intrinsic_load_instance_id: - case nir_intrinsic_load_sample_id: - case nir_intrinsic_load_sample_pos: - case nir_intrinsic_load_sample_mask_in: - case nir_intrinsic_load_primitive_id: - case nir_intrinsic_load_invocation_id: - case nir_intrinsic_load_local_invocation_id: - case nir_intrinsic_load_work_group_id: - case nir_intrinsic_load_num_work_groups: - shader->info.system_values_read |= - (1 << nir_system_value_from_intrinsic(instr->intrinsic)); - break; - - case nir_intrinsic_end_primitive: - case nir_intrinsic_end_primitive_with_counter: - assert(shader->stage == MESA_SHADER_GEOMETRY); - shader->info.gs.uses_end_primitive = 1; - break; - - default: - break; - } -} - -static void -gather_tex_info(nir_tex_instr *instr, nir_shader *shader) -{ - if (instr->op == nir_texop_tg4) - shader->info.uses_texture_gather = true; -} - -static bool -gather_info_block(nir_block *block, void *shader) -{ - nir_foreach_instr(block, instr) { - switch (instr->type) { - case nir_instr_type_intrinsic: - gather_intrinsic_info(nir_instr_as_intrinsic(instr), shader); - break; - case nir_instr_type_tex: - gather_tex_info(nir_instr_as_tex(instr), shader); - break; - case nir_instr_type_call: - assert(!"nir_shader_gather_info only works if functions are inlined"); - break; - default: - break; - } - } - - return true; -} - -void -nir_shader_gather_info(nir_shader *shader, nir_function_impl *entrypoint) -{ - shader->info.inputs_read = 0; - foreach_list_typed(nir_variable, var, node, &shader->inputs) - shader->info.inputs_read |= nir_variable_get_io_mask(var, shader->stage); - - /* TODO: Some day we may need to add stream support to NIR */ - shader->info.outputs_written = 0; - foreach_list_typed(nir_variable, var, node, &shader->outputs) - shader->info.outputs_written |= nir_variable_get_io_mask(var, shader->stage); - - shader->info.system_values_read = 0; - foreach_list_typed(nir_variable, var, node, &shader->system_values) - shader->info.system_values_read |= nir_variable_get_io_mask(var, shader->stage); - - nir_foreach_block(entrypoint, gather_info_block, shader); -} diff --git a/src/glsl/nir/nir_gs_count_vertices.c b/src/glsl/nir/nir_gs_count_vertices.c deleted file mode 100644 index db15d160ee7..00000000000 --- a/src/glsl/nir/nir_gs_count_vertices.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" - -static nir_intrinsic_instr * -as_intrinsic(nir_instr *instr, nir_intrinsic_op op) -{ - if (instr->type != nir_instr_type_intrinsic) - return NULL; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - if (intrin->intrinsic != op) - return NULL; - - return intrin; -} - -static nir_intrinsic_instr * -as_set_vertex_count(nir_instr *instr) -{ - return as_intrinsic(instr, nir_intrinsic_set_vertex_count); -} - -/** - * If a geometry shader emits a constant number of vertices, return the - * number of vertices. Otherwise, return -1 (unknown). - * - * This only works if you've used nir_lower_gs_intrinsics() to do vertex - * counting at the NIR level. - */ -int -nir_gs_count_vertices(const nir_shader *shader) -{ - int count = -1; - - nir_foreach_function(shader, function) { - if (!function->impl) - continue; - - /* set_vertex_count intrinsics only appear in predecessors of the - * end block. So we don't need to walk all of them. - */ - struct set_entry *entry; - set_foreach(function->impl->end_block->predecessors, entry) { - nir_block *block = (nir_block *) entry->key; - - nir_foreach_instr_reverse(block, instr) { - nir_intrinsic_instr *intrin = as_set_vertex_count(instr); - if (!intrin) - continue; - - nir_const_value *val = nir_src_as_const_value(intrin->src[0]); - /* We've found a non-constant value. Bail. */ - if (!val) - return -1; - - if (count == -1) - count = val->i[0]; - - /* We've found contradictory set_vertex_count intrinsics. - * This can happen if there are early-returns in main() and - * different paths emit different numbers of vertices. - */ - if (count != val->i[0]) - return -1; - } - } - } - - return count; -} diff --git a/src/glsl/nir/nir_inline_functions.c b/src/glsl/nir/nir_inline_functions.c deleted file mode 100644 index 3cf83279053..00000000000 --- a/src/glsl/nir/nir_inline_functions.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" -#include "nir_control_flow.h" - -struct inline_functions_state { - struct set *inlined; - nir_builder builder; - bool progress; -}; - -static bool inline_function_impl(nir_function_impl *impl, struct set *inlined); - -static bool -inline_functions_block(nir_block *block, void *void_state) -{ - struct inline_functions_state *state = void_state; - - nir_builder *b = &state->builder; - - /* This is tricky. We're iterating over instructions in a block but, as - * we go, the block and its instruction list are being split into - * pieces. However, this *should* be safe since foreach_safe always - * stashes the next thing in the iteration. That next thing will - * properly get moved to the next block when it gets split, and we - * continue iterating there. - */ - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_call) - continue; - - state->progress = true; - - nir_call_instr *call = nir_instr_as_call(instr); - assert(call->callee->impl); - - inline_function_impl(call->callee->impl, state->inlined); - - nir_function_impl *callee_copy = - nir_function_impl_clone(call->callee->impl); - - exec_list_append(&b->impl->locals, &callee_copy->locals); - exec_list_append(&b->impl->registers, &callee_copy->registers); - - b->cursor = nir_before_instr(&call->instr); - - /* Add copies of all in parameters */ - assert(call->num_params == callee_copy->num_params); - for (unsigned i = 0; i < callee_copy->num_params; i++) { - /* Only in or inout parameters */ - if (call->callee->params[i].param_type == nir_parameter_out) - continue; - - nir_copy_deref_var(b, nir_deref_var_create(b->shader, - callee_copy->params[i]), - call->params[i]); - } - - /* Pluck the body out of the function and place it here */ - nir_cf_list body; - nir_cf_list_extract(&body, &callee_copy->body); - nir_cf_reinsert(&body, b->cursor); - - b->cursor = nir_before_instr(&call->instr); - - /* Add copies of all out parameters and the return */ - assert(call->num_params == callee_copy->num_params); - for (unsigned i = 0; i < callee_copy->num_params; i++) { - /* Only out or inout parameters */ - if (call->callee->params[i].param_type == nir_parameter_in) - continue; - - nir_copy_deref_var(b, call->params[i], - nir_deref_var_create(b->shader, - callee_copy->params[i])); - } - if (!glsl_type_is_void(call->callee->return_type)) { - nir_copy_deref_var(b, call->return_deref, - nir_deref_var_create(b->shader, - callee_copy->return_var)); - } - - nir_instr_remove(&call->instr); - } - - return true; -} - -static bool -inline_function_impl(nir_function_impl *impl, struct set *inlined) -{ - if (_mesa_set_search(inlined, impl)) - return false; /* Already inlined */ - - struct inline_functions_state state; - - state.inlined = inlined; - state.progress = false; - nir_builder_init(&state.builder, impl); - - nir_foreach_block(impl, inline_functions_block, &state); - - if (state.progress) { - /* SSA and register indices are completely messed up now */ - nir_index_ssa_defs(impl); - nir_index_local_regs(impl); - - nir_metadata_preserve(impl, nir_metadata_none); - } - - _mesa_set_add(inlined, impl); - - return state.progress; -} - -bool -nir_inline_functions(nir_shader *shader) -{ - struct set *inlined = _mesa_set_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = inline_function_impl(function->impl, inlined) || progress; - } - - _mesa_set_destroy(inlined, NULL); - - return progress; -} diff --git a/src/glsl/nir/nir_instr_set.c b/src/glsl/nir/nir_instr_set.c deleted file mode 100644 index eb021326097..00000000000 --- a/src/glsl/nir/nir_instr_set.c +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright © 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir_instr_set.h" -#include "nir_vla.h" - -#define HASH(hash, data) _mesa_fnv32_1a_accumulate((hash), (data)) - -static uint32_t -hash_src(uint32_t hash, const nir_src *src) -{ - assert(src->is_ssa); - hash = HASH(hash, src->ssa); - return hash; -} - -static uint32_t -hash_alu_src(uint32_t hash, const nir_alu_src *src, unsigned num_components) -{ - hash = HASH(hash, src->abs); - hash = HASH(hash, src->negate); - - for (unsigned i = 0; i < num_components; i++) - hash = HASH(hash, src->swizzle[i]); - - hash = hash_src(hash, &src->src); - return hash; -} - -static uint32_t -hash_alu(uint32_t hash, const nir_alu_instr *instr) -{ - hash = HASH(hash, instr->op); - hash = HASH(hash, instr->dest.dest.ssa.num_components); - - if (nir_op_infos[instr->op].algebraic_properties & NIR_OP_IS_COMMUTATIVE) { - assert(nir_op_infos[instr->op].num_inputs == 2); - uint32_t hash0 = hash_alu_src(hash, &instr->src[0], - nir_ssa_alu_instr_src_components(instr, 0)); - uint32_t hash1 = hash_alu_src(hash, &instr->src[1], - nir_ssa_alu_instr_src_components(instr, 1)); - /* For commutative operations, we need some commutative way of - * combining the hashes. One option would be to XOR them but that - * means that anything with two identical sources will hash to 0 and - * that's common enough we probably don't want the guaranteed - * collision. Either addition or multiplication will also work. - */ - hash = hash0 * hash1; - } else { - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - hash = hash_alu_src(hash, &instr->src[i], - nir_ssa_alu_instr_src_components(instr, i)); - } - } - - return hash; -} - -static uint32_t -hash_load_const(uint32_t hash, const nir_load_const_instr *instr) -{ - hash = HASH(hash, instr->def.num_components); - - hash = _mesa_fnv32_1a_accumulate_block(hash, instr->value.f, - instr->def.num_components - * sizeof(instr->value.f[0])); - - return hash; -} - -static int -cmp_phi_src(const void *data1, const void *data2) -{ - nir_phi_src *src1 = *(nir_phi_src **)data1; - nir_phi_src *src2 = *(nir_phi_src **)data2; - return src1->pred - src2->pred; -} - -static uint32_t -hash_phi(uint32_t hash, const nir_phi_instr *instr) -{ - hash = HASH(hash, instr->instr.block); - - /* sort sources by predecessor, since the order shouldn't matter */ - unsigned num_preds = instr->instr.block->predecessors->entries; - NIR_VLA(nir_phi_src *, srcs, num_preds); - unsigned i = 0; - nir_foreach_phi_src(instr, src) { - srcs[i++] = src; - } - - qsort(srcs, num_preds, sizeof(nir_phi_src *), cmp_phi_src); - - for (i = 0; i < num_preds; i++) { - hash = hash_src(hash, &srcs[i]->src); - hash = HASH(hash, srcs[i]->pred); - } - - return hash; -} - -static uint32_t -hash_intrinsic(uint32_t hash, const nir_intrinsic_instr *instr) -{ - const nir_intrinsic_info *info = &nir_intrinsic_infos[instr->intrinsic]; - hash = HASH(hash, instr->intrinsic); - - if (info->has_dest) - hash = HASH(hash, instr->dest.ssa.num_components); - - assert(info->num_variables == 0); - - hash = _mesa_fnv32_1a_accumulate_block(hash, instr->const_index, - info->num_indices - * sizeof(instr->const_index[0])); - return hash; -} - -static uint32_t -hash_tex(uint32_t hash, const nir_tex_instr *instr) -{ - hash = HASH(hash, instr->op); - hash = HASH(hash, instr->num_srcs); - - for (unsigned i = 0; i < instr->num_srcs; i++) { - hash = HASH(hash, instr->src[i].src_type); - hash = hash_src(hash, &instr->src[i].src); - } - - hash = HASH(hash, instr->coord_components); - hash = HASH(hash, instr->sampler_dim); - hash = HASH(hash, instr->is_array); - hash = HASH(hash, instr->is_shadow); - hash = HASH(hash, instr->is_new_style_shadow); - hash = HASH(hash, instr->const_offset); - unsigned component = instr->component; - hash = HASH(hash, component); - hash = HASH(hash, instr->texture_index); - hash = HASH(hash, instr->texture_array_size); - hash = HASH(hash, instr->sampler_index); - - assert(!instr->sampler); - - return hash; -} - -/* Computes a hash of an instruction for use in a hash table. Note that this - * will only work for instructions where instr_can_rewrite() returns true, and - * it should return identical hashes for two instructions that are the same - * according nir_instrs_equal(). - */ - -static uint32_t -hash_instr(const void *data) -{ - const nir_instr *instr = data; - uint32_t hash = _mesa_fnv32_1a_offset_bias; - - switch (instr->type) { - case nir_instr_type_alu: - hash = hash_alu(hash, nir_instr_as_alu(instr)); - break; - case nir_instr_type_load_const: - hash = hash_load_const(hash, nir_instr_as_load_const(instr)); - break; - case nir_instr_type_phi: - hash = hash_phi(hash, nir_instr_as_phi(instr)); - break; - case nir_instr_type_intrinsic: - hash = hash_intrinsic(hash, nir_instr_as_intrinsic(instr)); - break; - case nir_instr_type_tex: - hash = hash_tex(hash, nir_instr_as_tex(instr)); - break; - default: - unreachable("Invalid instruction type"); - } - - return hash; -} - -bool -nir_srcs_equal(nir_src src1, nir_src src2) -{ - if (src1.is_ssa) { - if (src2.is_ssa) { - return src1.ssa == src2.ssa; - } else { - return false; - } - } else { - if (src2.is_ssa) { - return false; - } else { - if ((src1.reg.indirect == NULL) != (src2.reg.indirect == NULL)) - return false; - - if (src1.reg.indirect) { - if (!nir_srcs_equal(*src1.reg.indirect, *src2.reg.indirect)) - return false; - } - - return src1.reg.reg == src2.reg.reg && - src1.reg.base_offset == src2.reg.base_offset; - } - } -} - -static bool -nir_alu_srcs_equal(const nir_alu_instr *alu1, const nir_alu_instr *alu2, - unsigned src1, unsigned src2) -{ - if (alu1->src[src1].abs != alu2->src[src2].abs || - alu1->src[src1].negate != alu2->src[src2].negate) - return false; - - for (unsigned i = 0; i < nir_ssa_alu_instr_src_components(alu1, src1); i++) { - if (alu1->src[src1].swizzle[i] != alu2->src[src2].swizzle[i]) - return false; - } - - return nir_srcs_equal(alu1->src[src1].src, alu2->src[src2].src); -} - -/* Returns "true" if two instructions are equal. Note that this will only - * work for the subset of instructions defined by instr_can_rewrite(). Also, - * it should only return "true" for instructions that hash_instr() will return - * the same hash for (ignoring collisions, of course). - */ - -static bool -nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2) -{ - if (instr1->type != instr2->type) - return false; - - switch (instr1->type) { - case nir_instr_type_alu: { - nir_alu_instr *alu1 = nir_instr_as_alu(instr1); - nir_alu_instr *alu2 = nir_instr_as_alu(instr2); - - if (alu1->op != alu2->op) - return false; - - /* TODO: We can probably acutally do something more inteligent such - * as allowing different numbers and taking a maximum or something - * here */ - if (alu1->dest.dest.ssa.num_components != alu2->dest.dest.ssa.num_components) - return false; - - if (nir_op_infos[alu1->op].algebraic_properties & NIR_OP_IS_COMMUTATIVE) { - assert(nir_op_infos[alu1->op].num_inputs == 2); - return (nir_alu_srcs_equal(alu1, alu2, 0, 0) && - nir_alu_srcs_equal(alu1, alu2, 1, 1)) || - (nir_alu_srcs_equal(alu1, alu2, 0, 1) && - nir_alu_srcs_equal(alu1, alu2, 1, 0)); - } else { - for (unsigned i = 0; i < nir_op_infos[alu1->op].num_inputs; i++) { - if (!nir_alu_srcs_equal(alu1, alu2, i, i)) - return false; - } - } - return true; - } - case nir_instr_type_tex: { - nir_tex_instr *tex1 = nir_instr_as_tex(instr1); - nir_tex_instr *tex2 = nir_instr_as_tex(instr2); - - if (tex1->op != tex2->op) - return false; - - if (tex1->num_srcs != tex2->num_srcs) - return false; - for (unsigned i = 0; i < tex1->num_srcs; i++) { - if (tex1->src[i].src_type != tex2->src[i].src_type || - !nir_srcs_equal(tex1->src[i].src, tex2->src[i].src)) { - return false; - } - } - - if (tex1->coord_components != tex2->coord_components || - tex1->sampler_dim != tex2->sampler_dim || - tex1->is_array != tex2->is_array || - tex1->is_shadow != tex2->is_shadow || - tex1->is_new_style_shadow != tex2->is_new_style_shadow || - memcmp(tex1->const_offset, tex2->const_offset, - sizeof(tex1->const_offset)) != 0 || - tex1->component != tex2->component || - tex1->texture_index != tex2->texture_index || - tex1->texture_array_size != tex2->texture_array_size || - tex1->sampler_index != tex2->sampler_index) { - return false; - } - - /* Don't support un-lowered sampler derefs currently. */ - assert(!tex1->texture && !tex1->sampler && - !tex2->texture && !tex2->sampler); - - return true; - } - case nir_instr_type_load_const: { - nir_load_const_instr *load1 = nir_instr_as_load_const(instr1); - nir_load_const_instr *load2 = nir_instr_as_load_const(instr2); - - if (load1->def.num_components != load2->def.num_components) - return false; - - return memcmp(load1->value.f, load2->value.f, - load1->def.num_components * sizeof(*load2->value.f)) == 0; - } - case nir_instr_type_phi: { - nir_phi_instr *phi1 = nir_instr_as_phi(instr1); - nir_phi_instr *phi2 = nir_instr_as_phi(instr2); - - if (phi1->instr.block != phi2->instr.block) - return false; - - nir_foreach_phi_src(phi1, src1) { - nir_foreach_phi_src(phi2, src2) { - if (src1->pred == src2->pred) { - if (!nir_srcs_equal(src1->src, src2->src)) - return false; - - break; - } - } - } - - return true; - } - case nir_instr_type_intrinsic: { - nir_intrinsic_instr *intrinsic1 = nir_instr_as_intrinsic(instr1); - nir_intrinsic_instr *intrinsic2 = nir_instr_as_intrinsic(instr2); - const nir_intrinsic_info *info = - &nir_intrinsic_infos[intrinsic1->intrinsic]; - - if (intrinsic1->intrinsic != intrinsic2->intrinsic || - intrinsic1->num_components != intrinsic2->num_components) - return false; - - if (info->has_dest && intrinsic1->dest.ssa.num_components != - intrinsic2->dest.ssa.num_components) - return false; - - for (unsigned i = 0; i < info->num_srcs; i++) { - if (!nir_srcs_equal(intrinsic1->src[i], intrinsic2->src[i])) - return false; - } - - assert(info->num_variables == 0); - - for (unsigned i = 0; i < info->num_indices; i++) { - if (intrinsic1->const_index[i] != intrinsic2->const_index[i]) - return false; - } - - return true; - } - case nir_instr_type_call: - case nir_instr_type_jump: - case nir_instr_type_ssa_undef: - case nir_instr_type_parallel_copy: - default: - unreachable("Invalid instruction type"); - } - - return false; -} - -static bool -src_is_ssa(nir_src *src, void *data) -{ - (void) data; - return src->is_ssa; -} - -static bool -dest_is_ssa(nir_dest *dest, void *data) -{ - (void) data; - return dest->is_ssa; -} - -/* This function determines if uses of an instruction can safely be rewritten - * to use another identical instruction instead. Note that this function must - * be kept in sync with hash_instr() and nir_instrs_equal() -- only - * instructions that pass this test will be handed on to those functions, and - * conversely they must handle everything that this function returns true for. - */ - -static bool -instr_can_rewrite(nir_instr *instr) -{ - /* We only handle SSA. */ - if (!nir_foreach_dest(instr, dest_is_ssa, NULL) || - !nir_foreach_src(instr, src_is_ssa, NULL)) - return false; - - switch (instr->type) { - case nir_instr_type_alu: - case nir_instr_type_load_const: - case nir_instr_type_phi: - return true; - case nir_instr_type_tex: { - nir_tex_instr *tex = nir_instr_as_tex(instr); - - /* Don't support un-lowered sampler derefs currently. */ - if (tex->texture || tex->sampler) - return false; - - return true; - } - case nir_instr_type_intrinsic: { - const nir_intrinsic_info *info = - &nir_intrinsic_infos[nir_instr_as_intrinsic(instr)->intrinsic]; - return (info->flags & NIR_INTRINSIC_CAN_ELIMINATE) && - (info->flags & NIR_INTRINSIC_CAN_REORDER) && - info->num_variables == 0; /* not implemented yet */ - } - case nir_instr_type_call: - case nir_instr_type_jump: - case nir_instr_type_ssa_undef: - return false; - case nir_instr_type_parallel_copy: - default: - unreachable("Invalid instruction type"); - } - - return false; -} - -static nir_ssa_def * -nir_instr_get_dest_ssa_def(nir_instr *instr) -{ - switch (instr->type) { - case nir_instr_type_alu: - assert(nir_instr_as_alu(instr)->dest.dest.is_ssa); - return &nir_instr_as_alu(instr)->dest.dest.ssa; - case nir_instr_type_load_const: - return &nir_instr_as_load_const(instr)->def; - case nir_instr_type_phi: - assert(nir_instr_as_phi(instr)->dest.is_ssa); - return &nir_instr_as_phi(instr)->dest.ssa; - case nir_instr_type_intrinsic: - assert(nir_instr_as_intrinsic(instr)->dest.is_ssa); - return &nir_instr_as_intrinsic(instr)->dest.ssa; - case nir_instr_type_tex: - assert(nir_instr_as_tex(instr)->dest.is_ssa); - return &nir_instr_as_tex(instr)->dest.ssa; - default: - unreachable("We never ask for any of these"); - } -} - -static bool -cmp_func(const void *data1, const void *data2) -{ - return nir_instrs_equal(data1, data2); -} - -struct set * -nir_instr_set_create(void *mem_ctx) -{ - return _mesa_set_create(mem_ctx, hash_instr, cmp_func); -} - -void -nir_instr_set_destroy(struct set *instr_set) -{ - _mesa_set_destroy(instr_set, NULL); -} - -bool -nir_instr_set_add_or_rewrite(struct set *instr_set, nir_instr *instr) -{ - if (!instr_can_rewrite(instr)) - return false; - - struct set_entry *entry = _mesa_set_search(instr_set, instr); - if (entry) { - nir_ssa_def *def = nir_instr_get_dest_ssa_def(instr); - nir_ssa_def *new_def = - nir_instr_get_dest_ssa_def((nir_instr *) entry->key); - nir_ssa_def_rewrite_uses(def, nir_src_for_ssa(new_def)); - return true; - } - - _mesa_set_add(instr_set, instr); - return false; -} - -void -nir_instr_set_remove(struct set *instr_set, nir_instr *instr) -{ - if (!instr_can_rewrite(instr)) - return; - - struct set_entry *entry = _mesa_set_search(instr_set, instr); - if (entry) - _mesa_set_remove(instr_set, entry); -} - diff --git a/src/glsl/nir/nir_instr_set.h b/src/glsl/nir/nir_instr_set.h deleted file mode 100644 index 939e8ddbf58..00000000000 --- a/src/glsl/nir/nir_instr_set.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright © 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#pragma once - -#include "nir.h" - -/** - * This file defines functions for creating, destroying, and manipulating an - * "instruction set," which is an abstraction for finding duplicate - * instructions using a hash set. Note that the question of whether an - * instruction is actually a duplicate (e.g. whether it has any side effects) - * is handled transparently. The user can pass any instruction to - * nir_instr_set_add_or_rewrite() and nir_instr_set_remove(), and if the - * instruction isn't safe to rewrite or isn't supported, it's silently - * removed. - */ - -/*@{*/ - -/** Creates an instruction set, using a given ralloc mem_ctx */ -struct set *nir_instr_set_create(void *mem_ctx); - -/** Destroys an instruction set. */ -void nir_instr_set_destroy(struct set *instr_set); - -/** - * Adds an instruction to an instruction set if it doesn't exist, or if it - * does already exist, rewrites all uses of it to point to the other - * already-inserted instruction. Returns 'true' if the uses of the instruction - * were rewritten. - */ -bool nir_instr_set_add_or_rewrite(struct set *instr_set, nir_instr *instr); - -/** - * Removes an instruction from an instruction set, so that other instructions - * won't be merged with it. - */ -void nir_instr_set_remove(struct set *instr_set, nir_instr *instr); - -/*@}*/ - diff --git a/src/glsl/nir/nir_intrinsics.c b/src/glsl/nir/nir_intrinsics.c deleted file mode 100644 index a7c868c39af..00000000000 --- a/src/glsl/nir/nir_intrinsics.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -#define OPCODE(name) nir_intrinsic_##name - -#define INTRINSIC(_name, _num_srcs, _src_components, _has_dest, \ - _dest_components, _num_variables, _num_indices, _flags) \ -{ \ - .name = #_name, \ - .num_srcs = _num_srcs, \ - .src_components = _src_components, \ - .has_dest = _has_dest, \ - .dest_components = _dest_components, \ - .num_variables = _num_variables, \ - .num_indices = _num_indices, \ - .flags = _flags \ -}, - -#define LAST_INTRINSIC(name) - -const nir_intrinsic_info nir_intrinsic_infos[nir_num_intrinsics] = { -#include "nir_intrinsics.h" -};
\ No newline at end of file diff --git a/src/glsl/nir/nir_intrinsics.h b/src/glsl/nir/nir_intrinsics.h deleted file mode 100644 index 3e7cf735a1b..00000000000 --- a/src/glsl/nir/nir_intrinsics.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -/** - * This header file defines all the available intrinsics in one place. It - * expands to a list of macros of the form: - * - * INTRINSIC(name, num_srcs, src_components, has_dest, dest_components, - * num_variables, num_indices, flags) - * - * Which should correspond one-to-one with the nir_intrinsic_info structure. It - * is included in both ir.h to create the nir_intrinsic enum (with members of - * the form nir_intrinsic_(name)) and and in opcodes.c to create - * nir_intrinsic_infos, which is a const array of nir_intrinsic_info structures - * for each intrinsic. - */ - -#define ARR(...) { __VA_ARGS__ } - - -INTRINSIC(load_var, 0, ARR(), true, 0, 1, 0, NIR_INTRINSIC_CAN_ELIMINATE) -INTRINSIC(store_var, 1, ARR(0), false, 0, 1, 1, 0) -INTRINSIC(copy_var, 0, ARR(), false, 0, 2, 0, 0) - -/* - * Interpolation of input. The interp_var_at* intrinsics are similar to the - * load_var intrinsic acting an a shader input except that they interpolate - * the input differently. The at_sample and at_offset intrinsics take an - * aditional source that is a integer sample id or a vec2 position offset - * respectively. - */ - -INTRINSIC(interp_var_at_centroid, 0, ARR(0), true, 0, 1, 0, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -INTRINSIC(interp_var_at_sample, 1, ARR(1), true, 0, 1, 0, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -INTRINSIC(interp_var_at_offset, 1, ARR(2), true, 0, 1, 0, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) - -/* - * Ask the driver for the size of a given buffer. It takes the buffer index - * as source. - */ -INTRINSIC(get_buffer_size, 1, ARR(1), true, 1, 0, 0, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) - -/* - * a barrier is an intrinsic with no inputs/outputs but which can't be moved - * around/optimized in general - */ -#define BARRIER(name) INTRINSIC(name, 0, ARR(), false, 0, 0, 0, 0) - -BARRIER(barrier) -BARRIER(discard) - -/* - * Memory barrier with semantics analogous to the memoryBarrier() GLSL - * intrinsic. - */ -BARRIER(memory_barrier) - -/* - * Shader clock intrinsic with semantics analogous to the clock2x32ARB() - * GLSL intrinsic. - * The latter can be used as code motion barrier, which is currently not - * feasible with NIR. - */ -INTRINSIC(shader_clock, 0, ARR(), true, 1, 0, 0, NIR_INTRINSIC_CAN_ELIMINATE) - -/* - * Memory barrier with semantics analogous to the compute shader - * groupMemoryBarrier(), memoryBarrierAtomicCounter(), memoryBarrierBuffer(), - * memoryBarrierImage() and memoryBarrierShared() GLSL intrinsics. - */ -BARRIER(group_memory_barrier) -BARRIER(memory_barrier_atomic_counter) -BARRIER(memory_barrier_buffer) -BARRIER(memory_barrier_image) -BARRIER(memory_barrier_shared) - -/** A conditional discard, with a single boolean source. */ -INTRINSIC(discard_if, 1, ARR(1), false, 0, 0, 0, 0) - -/** - * Basic Geometry Shader intrinsics. - * - * emit_vertex implements GLSL's EmitStreamVertex() built-in. It takes a single - * index, which is the stream ID to write to. - * - * end_primitive implements GLSL's EndPrimitive() built-in. - */ -INTRINSIC(emit_vertex, 0, ARR(), false, 0, 0, 1, 0) -INTRINSIC(end_primitive, 0, ARR(), false, 0, 0, 1, 0) - -/** - * Geometry Shader intrinsics with a vertex count. - * - * Alternatively, drivers may implement these intrinsics, and use - * nir_lower_gs_intrinsics() to convert from the basic intrinsics. - * - * These maintain a count of the number of vertices emitted, as an additional - * unsigned integer source. - */ -INTRINSIC(emit_vertex_with_counter, 1, ARR(1), false, 0, 0, 1, 0) -INTRINSIC(end_primitive_with_counter, 1, ARR(1), false, 0, 0, 1, 0) -INTRINSIC(set_vertex_count, 1, ARR(1), false, 0, 0, 0, 0) - -/* - * Atomic counters - * - * The *_var variants take an atomic_uint nir_variable, while the other, - * lowered, variants take a constant buffer index and register offset. - */ - -#define ATOMIC(name, flags) \ - INTRINSIC(atomic_counter_##name##_var, 0, ARR(), true, 1, 1, 0, flags) \ - INTRINSIC(atomic_counter_##name, 1, ARR(1), true, 1, 0, 1, flags) - -ATOMIC(inc, 0) -ATOMIC(dec, 0) -ATOMIC(read, NIR_INTRINSIC_CAN_ELIMINATE) - -/* - * Image load, store and atomic intrinsics. - * - * All image intrinsics take an image target passed as a nir_variable. Image - * variables contain a number of memory and layout qualifiers that influence - * the semantics of the intrinsic. - * - * All image intrinsics take a four-coordinate vector and a sample index as - * first two sources, determining the location within the image that will be - * accessed by the intrinsic. Components not applicable to the image target - * in use are undefined. Image store takes an additional four-component - * argument with the value to be written, and image atomic operations take - * either one or two additional scalar arguments with the same meaning as in - * the ARB_shader_image_load_store specification. - */ -INTRINSIC(image_load, 2, ARR(4, 1), true, 4, 1, 0, - NIR_INTRINSIC_CAN_ELIMINATE) -INTRINSIC(image_store, 3, ARR(4, 1, 4), false, 0, 1, 0, 0) -INTRINSIC(image_atomic_add, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_min, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_max, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_and, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_or, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_xor, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_exchange, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_atomic_comp_swap, 4, ARR(4, 1, 1, 1), true, 1, 1, 0, 0) -INTRINSIC(image_size, 0, ARR(), true, 4, 1, 0, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -INTRINSIC(image_samples, 0, ARR(), true, 1, 1, 0, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) - -/* - * Vulkan descriptor set intrinsic - * - * The Vulkan API uses a different binding model from GL. In the Vulkan - * API, all external resources are represented by a tripple: - * - * (descriptor set, binding, array index) - * - * where the array index is the only thing allowed to be indirect. The - * vulkan_surface_index intrinsic takes the descriptor set and binding as - * its first two indices and the array index as its source. The third - * index is a nir_variable_mode in case that's useful to the backend. - * - * The intended usage is that the shader will call vulkan_surface_index to - * get an index and then pass that as the buffer index ubo/ssbo calls. - */ -INTRINSIC(vulkan_resource_index, 1, ARR(1), true, 1, 0, 3, - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) - -/* - * variable atomic intrinsics - * - * All of these variable atomic memory operations read a value from memory, - * compute a new value using one of the operations below, write the new value - * to memory, and return the original value read. - * - * All operations take 1 source except CompSwap that takes 2. These sources - * represent: - * - * 0: The data parameter to the atomic function (i.e. the value to add - * in shared_atomic_add, etc). - * 1: For CompSwap only: the second data parameter. - * - * All operations take 1 variable deref. - */ -INTRINSIC(var_atomic_add, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_imin, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_umin, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_imax, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_umax, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_and, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_or, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_xor, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_exchange, 1, ARR(1), true, 1, 1, 0, 0) -INTRINSIC(var_atomic_comp_swap, 2, ARR(1, 1), true, 1, 1, 0, 0) - -/* - * SSBO atomic intrinsics - * - * All of the SSBO atomic memory operations read a value from memory, - * compute a new value using one of the operations below, write the new - * value to memory, and return the original value read. - * - * All operations take 3 sources except CompSwap that takes 4. These - * sources represent: - * - * 0: The SSBO buffer index. - * 1: The offset into the SSBO buffer of the variable that the atomic - * operation will operate on. - * 2: The data parameter to the atomic function (i.e. the value to add - * in ssbo_atomic_add, etc). - * 3: For CompSwap only: the second data parameter. - */ -INTRINSIC(ssbo_atomic_add, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_imin, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_umin, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_imax, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_umax, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_and, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_or, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_xor, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_exchange, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) -INTRINSIC(ssbo_atomic_comp_swap, 4, ARR(1, 1, 1, 1), true, 1, 0, 0, 0) - -/* - * CS shared variable atomic intrinsics - * - * All of the shared variable atomic memory operations read a value from - * memory, compute a new value using one of the operations below, write the - * new value to memory, and return the original value read. - * - * All operations take 2 sources except CompSwap that takes 3. These - * sources represent: - * - * 0: The offset into the shared variable storage region that the atomic - * operation will operate on. - * 1: The data parameter to the atomic function (i.e. the value to add - * in shared_atomic_add, etc). - * 2: For CompSwap only: the second data parameter. - */ -INTRINSIC(shared_atomic_add, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_imin, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_umin, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_imax, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_umax, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_and, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_or, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_xor, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_exchange, 2, ARR(1, 1), true, 1, 0, 0, 0) -INTRINSIC(shared_atomic_comp_swap, 3, ARR(1, 1, 1), true, 1, 0, 0, 0) - -#define SYSTEM_VALUE(name, components, num_indices) \ - INTRINSIC(load_##name, 0, ARR(), true, components, 0, num_indices, \ - NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) - -SYSTEM_VALUE(front_face, 1, 0) -SYSTEM_VALUE(vertex_id, 1, 0) -SYSTEM_VALUE(vertex_id_zero_base, 1, 0) -SYSTEM_VALUE(base_vertex, 1, 0) -SYSTEM_VALUE(instance_id, 1, 0) -SYSTEM_VALUE(base_instance, 1, 0) -SYSTEM_VALUE(draw_id, 1, 0) -SYSTEM_VALUE(sample_id, 1, 0) -SYSTEM_VALUE(sample_pos, 2, 0) -SYSTEM_VALUE(sample_mask_in, 1, 0) -SYSTEM_VALUE(primitive_id, 1, 0) -SYSTEM_VALUE(invocation_id, 1, 0) -SYSTEM_VALUE(tess_coord, 3, 0) -SYSTEM_VALUE(tess_level_outer, 4, 0) -SYSTEM_VALUE(tess_level_inner, 2, 0) -SYSTEM_VALUE(patch_vertices_in, 1, 0) -SYSTEM_VALUE(local_invocation_id, 3, 0) -SYSTEM_VALUE(work_group_id, 3, 0) -SYSTEM_VALUE(user_clip_plane, 4, 1) /* const_index[0] is user_clip_plane[idx] */ -SYSTEM_VALUE(num_work_groups, 3, 0) -SYSTEM_VALUE(helper_invocation, 1, 0) - -/* - * Load operations pull data from some piece of GPU memory. All load - * operations operate in terms of offsets into some piece of theoretical - * memory. Loads from externally visible memory (UBO and SSBO) simply take a - * byte offset as a source. Loads from opaque memory (uniforms, inputs, etc.) - * take a base+offset pair where the base (const_index[0]) gives the location - * of the start of the variable being loaded and and the offset source is a - * offset into that variable. - * - * Uniform load operations have a second index that specifies the size of the - * variable being loaded. If const_index[1] == 0, then the size is unknown. - * - * Some load operations such as UBO/SSBO load and per_vertex loads take an - * additional source to specify which UBO/SSBO/vertex to load from. - * - * The exact address type depends on the lowering pass that generates the - * load/store intrinsics. Typically, this is vec4 units for things such as - * varying slots and float units for fragment shader inputs. UBO and SSBO - * offsets are always in bytes. - */ - -#define LOAD(name, srcs, indices, flags) \ - INTRINSIC(load_##name, srcs, ARR(1, 1, 1, 1), true, 0, 0, indices, flags) - -/* src[] = { offset }. const_index[] = { base, size } */ -LOAD(uniform, 1, 2, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -/* src[] = { buffer_index, offset }. No const_index */ -LOAD(ubo, 2, 0, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -/* src[] = { offset }. const_index[] = { base } */ -LOAD(input, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -/* src[] = { vertex, offset }. const_index[] = { base } */ -LOAD(per_vertex_input, 2, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -/* src[] = { buffer_index, offset }. No const_index */ -LOAD(ssbo, 2, 0, NIR_INTRINSIC_CAN_ELIMINATE) -/* src[] = { offset }. const_index[] = { base } */ -LOAD(output, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE) -/* src[] = { vertex, offset }. const_index[] = { base } */ -LOAD(per_vertex_output, 2, 1, NIR_INTRINSIC_CAN_ELIMINATE) -/* src[] = { offset }. const_index[] = { base } */ -LOAD(shared, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE) -/* src[] = { offset }. const_index[] = { base, size } */ -LOAD(push_constant, 1, 2, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) - -/* - * Stores work the same way as loads, except now the first source is the value - * to store and the second (and possibly third) source specify where to store - * the value. SSBO and shared memory stores also have a write mask as - * const_index[0]. - */ - -#define STORE(name, srcs, indices, flags) \ - INTRINSIC(store_##name, srcs, ARR(0, 1, 1, 1), false, 0, 0, indices, flags) - -/* src[] = { value, offset }. const_index[] = { base, write_mask } */ -STORE(output, 2, 2, 0) -/* src[] = { value, vertex, offset }. const_index[] = { base, write_mask } */ -STORE(per_vertex_output, 3, 2, 0) -/* src[] = { value, block_index, offset }. const_index[] = { write_mask } */ -STORE(ssbo, 3, 1, 0) -/* src[] = { value, offset }. const_index[] = { base, write_mask } */ -STORE(shared, 2, 2, 0) - -LAST_INTRINSIC(store_shared) diff --git a/src/glsl/nir/nir_liveness.c b/src/glsl/nir/nir_liveness.c deleted file mode 100644 index 05f79d7bc61..00000000000 --- a/src/glsl/nir/nir_liveness.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - */ - -#include "nir.h" -#include "nir_worklist.h" -#include "nir_vla.h" - -/* - * Basic liveness analysis. This works only in SSA form. - * - * This liveness pass treats phi nodes as being melded to the space between - * blocks so that the destinations of a phi are in the livein of the block - * in which it resides and the sources are in the liveout of the - * corresponding block. By formulating the liveness information in this - * way, we ensure that the definition of any variable dominates its entire - * live range. This is true because the only way that the definition of an - * SSA value may not dominate a use is if the use is in a phi node and the - * uses in phi no are in the live-out of the corresponding predecessor - * block but not in the live-in of the block containing the phi node. - */ - -struct live_ssa_defs_state { - unsigned num_ssa_defs; - unsigned bitset_words; - - nir_block_worklist worklist; -}; - -static bool -index_ssa_def(nir_ssa_def *def, void *void_state) -{ - struct live_ssa_defs_state *state = void_state; - - if (def->parent_instr->type == nir_instr_type_ssa_undef) - def->live_index = 0; - else - def->live_index = state->num_ssa_defs++; - - return true; -} - -static bool -index_ssa_definitions_block(nir_block *block, void *state) -{ - nir_foreach_instr(block, instr) - nir_foreach_ssa_def(instr, index_ssa_def, state); - - return true; -} - -/* Initialize the liveness data to zero and add the given block to the - * worklist. - */ -static bool -init_liveness_block(nir_block *block, void *void_state) -{ - struct live_ssa_defs_state *state = void_state; - - block->live_in = reralloc(block, block->live_in, BITSET_WORD, - state->bitset_words); - memset(block->live_in, 0, state->bitset_words * sizeof(BITSET_WORD)); - - block->live_out = reralloc(block, block->live_out, BITSET_WORD, - state->bitset_words); - memset(block->live_out, 0, state->bitset_words * sizeof(BITSET_WORD)); - - nir_block_worklist_push_head(&state->worklist, block); - - return true; -} - -static bool -set_src_live(nir_src *src, void *void_live) -{ - BITSET_WORD *live = void_live; - - if (!src->is_ssa) - return true; - - if (src->ssa->live_index == 0) - return true; /* undefined variables are never live */ - - BITSET_SET(live, src->ssa->live_index); - - return true; -} - -static bool -set_ssa_def_dead(nir_ssa_def *def, void *void_live) -{ - BITSET_WORD *live = void_live; - - BITSET_CLEAR(live, def->live_index); - - return true; -} - -/** Propagates the live in of succ across the edge to the live out of pred - * - * Phi nodes exist "between" blocks and all the phi nodes at the start of a - * block act "in parallel". When we propagate from the live_in of one - * block to the live out of the other, we have to kill any writes from phis - * and make live any sources. - * - * Returns true if updating live out of pred added anything - */ -static bool -propagate_across_edge(nir_block *pred, nir_block *succ, - struct live_ssa_defs_state *state) -{ - NIR_VLA(BITSET_WORD, live, state->bitset_words); - memcpy(live, succ->live_in, state->bitset_words * sizeof *live); - - nir_foreach_instr(succ, instr) { - if (instr->type != nir_instr_type_phi) - break; - nir_phi_instr *phi = nir_instr_as_phi(instr); - - assert(phi->dest.is_ssa); - set_ssa_def_dead(&phi->dest.ssa, live); - } - - nir_foreach_instr(succ, instr) { - if (instr->type != nir_instr_type_phi) - break; - nir_phi_instr *phi = nir_instr_as_phi(instr); - - nir_foreach_phi_src(phi, src) { - if (src->pred == pred) { - set_src_live(&src->src, live); - break; - } - } - } - - BITSET_WORD progress = 0; - for (unsigned i = 0; i < state->bitset_words; ++i) { - progress |= live[i] & ~pred->live_out[i]; - pred->live_out[i] |= live[i]; - } - return progress != 0; -} - -void -nir_live_ssa_defs_impl(nir_function_impl *impl) -{ - struct live_ssa_defs_state state; - - /* We start at 1 because we reserve the index value of 0 for ssa_undef - * instructions. Those are never live, so their liveness information - * can be compacted into a single bit. - */ - state.num_ssa_defs = 1; - nir_foreach_block(impl, index_ssa_definitions_block, &state); - - nir_block_worklist_init(&state.worklist, impl->num_blocks, NULL); - - /* We now know how many unique ssa definitions we have and we can go - * ahead and allocate live_in and live_out sets and add all of the - * blocks to the worklist. - */ - state.bitset_words = BITSET_WORDS(state.num_ssa_defs); - nir_foreach_block(impl, init_liveness_block, &state); - - /* We're now ready to work through the worklist and update the liveness - * sets of each of the blocks. By the time we get to this point, every - * block in the function implementation has been pushed onto the - * worklist in reverse order. As long as we keep the worklist - * up-to-date as we go, everything will get covered. - */ - while (!nir_block_worklist_is_empty(&state.worklist)) { - /* We pop them off in the reverse order we pushed them on. This way - * the first walk of the instructions is backwards so we only walk - * once in the case of no control flow. - */ - nir_block *block = nir_block_worklist_pop_head(&state.worklist); - - memcpy(block->live_in, block->live_out, - state.bitset_words * sizeof(BITSET_WORD)); - - nir_if *following_if = nir_block_get_following_if(block); - if (following_if) - set_src_live(&following_if->condition, block->live_in); - - nir_foreach_instr_reverse(block, instr) { - /* Phi nodes are handled seperately so we want to skip them. Since - * we are going backwards and they are at the beginning, we can just - * break as soon as we see one. - */ - if (instr->type == nir_instr_type_phi) - break; - - nir_foreach_ssa_def(instr, set_ssa_def_dead, block->live_in); - nir_foreach_src(instr, set_src_live, block->live_in); - } - - /* Walk over all of the predecessors of the current block updating - * their live in with the live out of this one. If anything has - * changed, add the predecessor to the work list so that we ensure - * that the new information is used. - */ - struct set_entry *entry; - set_foreach(block->predecessors, entry) { - nir_block *pred = (nir_block *)entry->key; - if (propagate_across_edge(pred, block, &state)) - nir_block_worklist_push_tail(&state.worklist, pred); - } - } - - nir_block_worklist_fini(&state.worklist); -} - -static bool -src_does_not_use_def(nir_src *src, void *def) -{ - return !src->is_ssa || src->ssa != (nir_ssa_def *)def; -} - -static bool -search_for_use_after_instr(nir_instr *start, nir_ssa_def *def) -{ - /* Only look for a use strictly after the given instruction */ - struct exec_node *node = start->node.next; - while (!exec_node_is_tail_sentinel(node)) { - nir_instr *instr = exec_node_data(nir_instr, node, node); - if (!nir_foreach_src(instr, src_does_not_use_def, def)) - return true; - node = node->next; - } - return false; -} - -/* Returns true if def is live at instr assuming that def comes before - * instr in a pre DFS search of the dominance tree. - */ -static bool -nir_ssa_def_is_live_at(nir_ssa_def *def, nir_instr *instr) -{ - if (BITSET_TEST(instr->block->live_out, def->live_index)) { - /* Since def dominates instr, if def is in the liveout of the block, - * it's live at instr - */ - return true; - } else { - if (BITSET_TEST(instr->block->live_in, def->live_index) || - def->parent_instr->block == instr->block) { - /* In this case it is either live coming into instr's block or it - * is defined in the same block. In this case, we simply need to - * see if it is used after instr. - */ - return search_for_use_after_instr(instr, def); - } else { - return false; - } - } -} - -bool -nir_ssa_defs_interfere(nir_ssa_def *a, nir_ssa_def *b) -{ - if (a->parent_instr == b->parent_instr) { - /* Two variables defined at the same time interfere assuming at - * least one isn't dead. - */ - return true; - } else if (a->live_index == 0 || b->live_index == 0) { - /* If either variable is an ssa_undef, then there's no interference */ - return false; - } else if (a->live_index < b->live_index) { - return nir_ssa_def_is_live_at(a, b->parent_instr); - } else { - return nir_ssa_def_is_live_at(b, a->parent_instr); - } -} diff --git a/src/glsl/nir/nir_lower_alu_to_scalar.c b/src/glsl/nir/nir_lower_alu_to_scalar.c deleted file mode 100644 index 37cb0221e0b..00000000000 --- a/src/glsl/nir/nir_lower_alu_to_scalar.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright © 2014-2015 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" - -/** @file nir_lower_alu_to_scalar.c - * - * Replaces nir_alu_instr operations with more than one channel used in the - * arguments with individual per-channel operations. - */ - -static void -nir_alu_ssa_dest_init(nir_alu_instr *instr, unsigned num_components) -{ - nir_ssa_dest_init(&instr->instr, &instr->dest.dest, num_components, NULL); - instr->dest.write_mask = (1 << num_components) - 1; -} - -static void -lower_reduction(nir_alu_instr *instr, nir_op chan_op, nir_op merge_op, - nir_builder *builder) -{ - unsigned num_components = nir_op_infos[instr->op].input_sizes[0]; - - nir_ssa_def *last = NULL; - for (unsigned i = 0; i < num_components; i++) { - nir_alu_instr *chan = nir_alu_instr_create(builder->shader, chan_op); - nir_alu_ssa_dest_init(chan, 1); - nir_alu_src_copy(&chan->src[0], &instr->src[0], chan); - chan->src[0].swizzle[0] = chan->src[0].swizzle[i]; - if (nir_op_infos[chan_op].num_inputs > 1) { - assert(nir_op_infos[chan_op].num_inputs == 2); - nir_alu_src_copy(&chan->src[1], &instr->src[1], chan); - chan->src[1].swizzle[0] = chan->src[1].swizzle[i]; - } - - nir_builder_instr_insert(builder, &chan->instr); - - if (i == 0) { - last = &chan->dest.dest.ssa; - } else { - last = nir_build_alu(builder, merge_op, - last, &chan->dest.dest.ssa, NULL, NULL); - } - } - - assert(instr->dest.write_mask == 1); - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(last)); - nir_instr_remove(&instr->instr); -} - -static void -lower_alu_instr_scalar(nir_alu_instr *instr, nir_builder *b) -{ - unsigned num_src = nir_op_infos[instr->op].num_inputs; - unsigned i, chan; - - assert(instr->dest.dest.is_ssa); - assert(instr->dest.write_mask != 0); - - b->cursor = nir_before_instr(&instr->instr); - -#define LOWER_REDUCTION(name, chan, merge) \ - case name##2: \ - case name##3: \ - case name##4: \ - lower_reduction(instr, chan, merge, b); \ - return; - - switch (instr->op) { - case nir_op_vec4: - case nir_op_vec3: - case nir_op_vec2: - /* We don't need to scalarize these ops, they're the ones generated to - * group up outputs into a value that can be SSAed. - */ - return; - - case nir_op_pack_half_2x16: - if (!b->shader->options->lower_pack_half_2x16) - return; - - nir_ssa_def *val = - nir_pack_half_2x16_split(b, nir_channel(b, instr->src[0].src.ssa, - instr->src[0].swizzle[0]), - nir_channel(b, instr->src[0].src.ssa, - instr->src[0].swizzle[1])); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(val)); - nir_instr_remove(&instr->instr); - return; - - case nir_op_unpack_unorm_4x8: - case nir_op_unpack_snorm_4x8: - case nir_op_unpack_unorm_2x16: - case nir_op_unpack_snorm_2x16: - /* There is no scalar version of these ops, unless we were to break it - * down to bitshifts and math (which is definitely not intended). - */ - return; - - case nir_op_unpack_half_2x16: { - if (!b->shader->options->lower_unpack_half_2x16) - return; - - nir_ssa_def *comps[2]; - comps[0] = nir_unpack_half_2x16_split_x(b, instr->src[0].src.ssa); - comps[1] = nir_unpack_half_2x16_split_y(b, instr->src[0].src.ssa); - nir_ssa_def *vec = nir_vec(b, comps, 2); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(vec)); - nir_instr_remove(&instr->instr); - return; - } - - case nir_op_pack_uvec2_to_uint: { - assert(b->shader->options->lower_pack_snorm_2x16 || - b->shader->options->lower_pack_unorm_2x16); - - nir_ssa_def *word = - nir_extract_uword(b, instr->src[0].src.ssa, nir_imm_int(b, 0)); - nir_ssa_def *val = - nir_ior(b, nir_ishl(b, nir_channel(b, word, 1), nir_imm_int(b, 16)), - nir_channel(b, word, 0)); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(val)); - nir_instr_remove(&instr->instr); - break; - } - - case nir_op_pack_uvec4_to_uint: { - assert(b->shader->options->lower_pack_snorm_4x8 || - b->shader->options->lower_pack_unorm_4x8); - - nir_ssa_def *byte = - nir_extract_ubyte(b, instr->src[0].src.ssa, nir_imm_int(b, 0)); - nir_ssa_def *val = - nir_ior(b, nir_ior(b, nir_ishl(b, nir_channel(b, byte, 3), nir_imm_int(b, 24)), - nir_ishl(b, nir_channel(b, byte, 2), nir_imm_int(b, 16))), - nir_ior(b, nir_ishl(b, nir_channel(b, byte, 1), nir_imm_int(b, 8)), - nir_channel(b, byte, 0))); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(val)); - nir_instr_remove(&instr->instr); - break; - } - - case nir_op_fdph: { - nir_ssa_def *sum[4]; - for (unsigned i = 0; i < 3; i++) { - sum[i] = nir_fmul(b, nir_channel(b, instr->src[0].src.ssa, - instr->src[0].swizzle[i]), - nir_channel(b, instr->src[1].src.ssa, - instr->src[1].swizzle[i])); - } - sum[3] = nir_channel(b, instr->src[1].src.ssa, instr->src[1].swizzle[3]); - - nir_ssa_def *val = nir_fadd(b, nir_fadd(b, sum[0], sum[1]), - nir_fadd(b, sum[2], sum[3])); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(val)); - nir_instr_remove(&instr->instr); - return; - } - - LOWER_REDUCTION(nir_op_fdot, nir_op_fmul, nir_op_fadd); - LOWER_REDUCTION(nir_op_ball_fequal, nir_op_feq, nir_op_iand); - LOWER_REDUCTION(nir_op_ball_iequal, nir_op_ieq, nir_op_iand); - LOWER_REDUCTION(nir_op_bany_fnequal, nir_op_fne, nir_op_ior); - LOWER_REDUCTION(nir_op_bany_inequal, nir_op_ine, nir_op_ior); - LOWER_REDUCTION(nir_op_fall_equal, nir_op_seq, nir_op_fand); - LOWER_REDUCTION(nir_op_fany_nequal, nir_op_sne, nir_op_for); - - default: - break; - } - - if (instr->dest.dest.ssa.num_components == 1) - return; - - unsigned num_components = instr->dest.dest.ssa.num_components; - nir_ssa_def *comps[] = { NULL, NULL, NULL, NULL }; - - for (chan = 0; chan < 4; chan++) { - if (!(instr->dest.write_mask & (1 << chan))) - continue; - - nir_alu_instr *lower = nir_alu_instr_create(b->shader, instr->op); - for (i = 0; i < num_src; i++) { - /* We only handle same-size-as-dest (input_sizes[] == 0) or scalar - * args (input_sizes[] == 1). - */ - assert(nir_op_infos[instr->op].input_sizes[i] < 2); - unsigned src_chan = (nir_op_infos[instr->op].input_sizes[i] == 1 ? - 0 : chan); - - nir_alu_src_copy(&lower->src[i], &instr->src[i], lower); - for (int j = 0; j < 4; j++) - lower->src[i].swizzle[j] = instr->src[i].swizzle[src_chan]; - } - - nir_alu_ssa_dest_init(lower, 1); - lower->dest.saturate = instr->dest.saturate; - comps[chan] = &lower->dest.dest.ssa; - - nir_builder_instr_insert(b, &lower->instr); - } - - nir_ssa_def *vec = nir_vec(b, comps, num_components); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(vec)); - - nir_instr_remove(&instr->instr); -} - -static bool -lower_alu_to_scalar_block(nir_block *block, void *builder) -{ - nir_foreach_instr_safe(block, instr) { - if (instr->type == nir_instr_type_alu) - lower_alu_instr_scalar(nir_instr_as_alu(instr), builder); - } - - return true; -} - -static void -nir_lower_alu_to_scalar_impl(nir_function_impl *impl) -{ - nir_builder builder; - nir_builder_init(&builder, impl); - - nir_foreach_block(impl, lower_alu_to_scalar_block, &builder); -} - -void -nir_lower_alu_to_scalar(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_alu_to_scalar_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_atomics.c b/src/glsl/nir/nir_lower_atomics.c deleted file mode 100644 index a9d0ddbbd41..00000000000 --- a/src/glsl/nir/nir_lower_atomics.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "ir_uniform.h" -#include "nir.h" -#include "main/config.h" -#include <assert.h> - -typedef struct { - const struct gl_shader_program *shader_program; - nir_shader *shader; -} lower_atomic_state; - -/* - * replace atomic counter intrinsics that use a variable with intrinsics - * that directly store the buffer index and byte offset - */ - -static void -lower_instr(nir_intrinsic_instr *instr, - lower_atomic_state *state) -{ - nir_intrinsic_op op; - switch (instr->intrinsic) { - case nir_intrinsic_atomic_counter_read_var: - op = nir_intrinsic_atomic_counter_read; - break; - - case nir_intrinsic_atomic_counter_inc_var: - op = nir_intrinsic_atomic_counter_inc; - break; - - case nir_intrinsic_atomic_counter_dec_var: - op = nir_intrinsic_atomic_counter_dec; - break; - - default: - return; - } - - if (instr->variables[0]->var->data.mode != nir_var_uniform && - instr->variables[0]->var->data.mode != nir_var_shader_storage && - instr->variables[0]->var->data.mode != nir_var_shared) - return; /* atomics passed as function arguments can't be lowered */ - - void *mem_ctx = ralloc_parent(instr); - unsigned uniform_loc = instr->variables[0]->var->data.location; - - nir_intrinsic_instr *new_instr = nir_intrinsic_instr_create(mem_ctx, op); - new_instr->const_index[0] = - state->shader_program->UniformStorage[uniform_loc].opaque[state->shader->stage].index; - - nir_load_const_instr *offset_const = nir_load_const_instr_create(mem_ctx, 1); - offset_const->value.u[0] = instr->variables[0]->var->data.offset; - - nir_instr_insert_before(&instr->instr, &offset_const->instr); - - nir_ssa_def *offset_def = &offset_const->def; - - nir_deref *tail = &instr->variables[0]->deref; - while (tail->child != NULL) { - assert(tail->child->deref_type == nir_deref_type_array); - nir_deref_array *deref_array = nir_deref_as_array(tail->child); - tail = tail->child; - - unsigned child_array_elements = tail->child != NULL ? - glsl_get_aoa_size(tail->type) : 1; - - offset_const->value.u[0] += deref_array->base_offset * - child_array_elements * ATOMIC_COUNTER_SIZE; - - if (deref_array->deref_array_type == nir_deref_array_type_indirect) { - nir_load_const_instr *atomic_counter_size = - nir_load_const_instr_create(mem_ctx, 1); - atomic_counter_size->value.u[0] = child_array_elements * ATOMIC_COUNTER_SIZE; - nir_instr_insert_before(&instr->instr, &atomic_counter_size->instr); - - nir_alu_instr *mul = nir_alu_instr_create(mem_ctx, nir_op_imul); - nir_ssa_dest_init(&mul->instr, &mul->dest.dest, 1, NULL); - mul->dest.write_mask = 0x1; - nir_src_copy(&mul->src[0].src, &deref_array->indirect, mul); - mul->src[1].src.is_ssa = true; - mul->src[1].src.ssa = &atomic_counter_size->def; - nir_instr_insert_before(&instr->instr, &mul->instr); - - nir_alu_instr *add = nir_alu_instr_create(mem_ctx, nir_op_iadd); - nir_ssa_dest_init(&add->instr, &add->dest.dest, 1, NULL); - add->dest.write_mask = 0x1; - add->src[0].src.is_ssa = true; - add->src[0].src.ssa = &mul->dest.dest.ssa; - add->src[1].src.is_ssa = true; - add->src[1].src.ssa = offset_def; - nir_instr_insert_before(&instr->instr, &add->instr); - - offset_def = &add->dest.dest.ssa; - } - } - - new_instr->src[0].is_ssa = true; - new_instr->src[0].ssa = offset_def; - - if (instr->dest.is_ssa) { - nir_ssa_dest_init(&new_instr->instr, &new_instr->dest, - instr->dest.ssa.num_components, NULL); - nir_ssa_def_rewrite_uses(&instr->dest.ssa, - nir_src_for_ssa(&new_instr->dest.ssa)); - } else { - nir_dest_copy(&new_instr->dest, &instr->dest, mem_ctx); - } - - nir_instr_insert_before(&instr->instr, &new_instr->instr); - nir_instr_remove(&instr->instr); -} - -static bool -lower_block(nir_block *block, void *state) -{ - nir_foreach_instr_safe(block, instr) { - if (instr->type == nir_instr_type_intrinsic) - lower_instr(nir_instr_as_intrinsic(instr), - (lower_atomic_state *) state); - } - - return true; -} - -void -nir_lower_atomics(nir_shader *shader, - const struct gl_shader_program *shader_program) -{ - lower_atomic_state state = { - .shader = shader, - .shader_program = shader_program, - }; - - nir_foreach_function(shader, function) { - if (function->impl) { - nir_foreach_block(function->impl, lower_block, (void *) &state); - nir_metadata_preserve(function->impl, nir_metadata_block_index | - nir_metadata_dominance); - } - } -} diff --git a/src/glsl/nir/nir_lower_clip.c b/src/glsl/nir/nir_lower_clip.c deleted file mode 100644 index 0ca6a289396..00000000000 --- a/src/glsl/nir/nir_lower_clip.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright © 2015 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Rob Clark <[email protected]> - */ - -#include "nir.h" -#include "nir_builder.h" - -#define MAX_CLIP_PLANES 8 - -/* Generates the lowering code for user-clip-planes, generating CLIPDIST - * from UCP[n] + CLIPVERTEX or POSITION. Additionally, an optional pass - * for fragment shaders to insert conditional kill's based on the inter- - * polated CLIPDIST - * - * NOTE: should be run after nir_lower_outputs_to_temporaries() (or at - * least in scenarios where you can count on each output written once - * and only once). - */ - - -static nir_variable * -create_clipdist_var(nir_shader *shader, unsigned drvloc, - bool output, gl_varying_slot slot) -{ - nir_variable *var = rzalloc(shader, nir_variable); - - var->data.driver_location = drvloc; - var->type = glsl_vec4_type(); - var->data.mode = output ? nir_var_shader_out : nir_var_shader_in; - var->name = ralloc_asprintf(var, "clipdist_%d", drvloc); - var->data.index = 0; - var->data.location = slot; - - if (output) { - exec_list_push_tail(&shader->outputs, &var->node); - shader->num_outputs++; /* TODO use type_size() */ - } - else { - exec_list_push_tail(&shader->inputs, &var->node); - shader->num_inputs++; /* TODO use type_size() */ - } - return var; -} - -static void -store_clipdist_output(nir_builder *b, nir_variable *out, nir_ssa_def **val) -{ - nir_intrinsic_instr *store; - - store = nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_output); - store->num_components = 4; - store->const_index[0] = out->data.driver_location; - store->const_index[1] = 0xf; /* wrmask */ - store->src[0].ssa = nir_vec4(b, val[0], val[1], val[2], val[3]); - store->src[0].is_ssa = true; - store->src[1] = nir_src_for_ssa(nir_imm_int(b, 0)); - nir_builder_instr_insert(b, &store->instr); -} - -static void -load_clipdist_input(nir_builder *b, nir_variable *in, nir_ssa_def **val) -{ - nir_intrinsic_instr *load; - - load = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_input); - load->num_components = 4; - load->const_index[0] = in->data.driver_location; - load->src[0] = nir_src_for_ssa(nir_imm_int(b, 0)); - nir_ssa_dest_init(&load->instr, &load->dest, 4, NULL); - nir_builder_instr_insert(b, &load->instr); - - val[0] = nir_channel(b, &load->dest.ssa, 0); - val[1] = nir_channel(b, &load->dest.ssa, 1); - val[2] = nir_channel(b, &load->dest.ssa, 2); - val[3] = nir_channel(b, &load->dest.ssa, 3); -} - -struct find_output_state -{ - unsigned drvloc; - nir_ssa_def *def; -}; - -static bool -find_output_in_block(nir_block *block, void *void_state) -{ - struct find_output_state *state = void_state; - nir_foreach_instr(block, instr) { - - if (instr->type == nir_instr_type_intrinsic) { - nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); - if ((intr->intrinsic == nir_intrinsic_store_output) && - intr->const_index[0] == state->drvloc) { - assert(state->def == NULL); - assert(intr->src[0].is_ssa); - assert(nir_src_as_const_value(intr->src[1])); - state->def = intr->src[0].ssa; - -#if !defined(DEBUG) - /* for debug builds, scan entire shader to assert - * if output is written multiple times. For release - * builds just assume all is well and bail when we - * find first: - */ - return false; -#endif - } - } - } - - return true; -} - -/* TODO: maybe this would be a useful helper? - * NOTE: assumes each output is written exactly once (and unconditionally) - * so if needed nir_lower_outputs_to_temporaries() - */ -static nir_ssa_def * -find_output(nir_shader *shader, unsigned drvloc) -{ - struct find_output_state state = { - .drvloc = drvloc, - }; - - nir_foreach_function(shader, function) { - if (function->impl) { - nir_foreach_block_reverse(function->impl, - find_output_in_block, &state); - } - } - - return state.def; -} - -/* - * VS lowering - */ - -static void -lower_clip_vs(nir_function_impl *impl, unsigned ucp_enables, - nir_ssa_def *cv, nir_variable **out) -{ - nir_ssa_def *clipdist[MAX_CLIP_PLANES]; - nir_builder b; - - nir_builder_init(&b, impl); - - /* NIR should ensure that, even in case of loops/if-else, there - * should be only a single predecessor block to end_block, which - * makes the perfect place to insert the clipdist calculations. - * - * NOTE: in case of early return's, these would have to be lowered - * to jumps to end_block predecessor in a previous pass. Not sure - * if there is a good way to sanity check this, but for now the - * users of this pass don't support sub-routines. - */ - assert(impl->end_block->predecessors->entries == 1); - b.cursor = nir_after_cf_list(&impl->body); - - for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) { - if (ucp_enables & (1 << plane)) { - nir_ssa_def *ucp = - nir_load_system_value(&b, nir_intrinsic_load_user_clip_plane, plane); - - /* calculate clipdist[plane] - dot(ucp, cv): */ - clipdist[plane] = nir_fdot4(&b, ucp, cv); - } - else { - /* 0.0 == don't-clip == disabled: */ - clipdist[plane] = nir_imm_float(&b, 0.0); - } - } - - if (ucp_enables & 0x0f) - store_clipdist_output(&b, out[0], &clipdist[0]); - if (ucp_enables & 0xf0) - store_clipdist_output(&b, out[1], &clipdist[4]); - - nir_metadata_preserve(impl, nir_metadata_dominance); -} - -/* ucp_enables is bitmask of enabled ucp's. Actual ucp values are - * passed in to shader via user_clip_plane system-values - */ -void -nir_lower_clip_vs(nir_shader *shader, unsigned ucp_enables) -{ - int clipvertex = -1; - int position = -1; - int maxloc = -1; - nir_ssa_def *cv; - nir_variable *out[2] = { NULL }; - - if (!ucp_enables) - return; - - /* find clipvertex/position outputs: */ - nir_foreach_variable(var, &shader->outputs) { - int loc = var->data.driver_location; - - /* keep track of last used driver-location.. we'll be - * appending CLIP_DIST0/CLIP_DIST1 after last existing - * output: - */ - maxloc = MAX2(maxloc, loc); - - switch (var->data.location) { - case VARYING_SLOT_POS: - position = loc; - break; - case VARYING_SLOT_CLIP_VERTEX: - clipvertex = loc; - break; - case VARYING_SLOT_CLIP_DIST0: - case VARYING_SLOT_CLIP_DIST1: - /* if shader is already writing CLIPDIST, then - * there should be no user-clip-planes to deal - * with. - */ - return; - } - } - - if (clipvertex != -1) - cv = find_output(shader, clipvertex); - else if (position != -1) - cv = find_output(shader, position); - else - return; - - /* insert CLIPDIST outputs: */ - if (ucp_enables & 0x0f) - out[0] = - create_clipdist_var(shader, ++maxloc, true, VARYING_SLOT_CLIP_DIST0); - if (ucp_enables & 0xf0) - out[1] = - create_clipdist_var(shader, ++maxloc, true, VARYING_SLOT_CLIP_DIST1); - - nir_foreach_function(shader, function) { - if (!strcmp(function->name, "main")) - lower_clip_vs(function->impl, ucp_enables, cv, out); - } -} - -/* - * FS lowering - */ - -static void -lower_clip_fs(nir_function_impl *impl, unsigned ucp_enables, - nir_variable **in) -{ - nir_ssa_def *clipdist[MAX_CLIP_PLANES]; - nir_builder b; - - nir_builder_init(&b, impl); - b.cursor = nir_before_cf_list(&impl->body); - - if (ucp_enables & 0x0f) - load_clipdist_input(&b, in[0], &clipdist[0]); - if (ucp_enables & 0xf0) - load_clipdist_input(&b, in[1], &clipdist[4]); - - for (int plane = 0; plane < MAX_CLIP_PLANES; plane++) { - if (ucp_enables & (1 << plane)) { - nir_intrinsic_instr *discard; - nir_ssa_def *cond; - - cond = nir_flt(&b, clipdist[plane], nir_imm_float(&b, 0.0)); - - discard = nir_intrinsic_instr_create(b.shader, - nir_intrinsic_discard_if); - discard->src[0] = nir_src_for_ssa(cond); - nir_builder_instr_insert(&b, &discard->instr); - } - } -} - -/* insert conditional kill based on interpolated CLIPDIST - */ -void -nir_lower_clip_fs(nir_shader *shader, unsigned ucp_enables) -{ - nir_variable *in[2]; - int maxloc = -1; - - if (!ucp_enables) - return; - - nir_foreach_variable(var, &shader->inputs) { - int loc = var->data.driver_location; - - /* keep track of last used driver-location.. we'll be - * appending CLIP_DIST0/CLIP_DIST1 after last existing - * input: - */ - maxloc = MAX2(maxloc, loc); - } - - /* The shader won't normally have CLIPDIST inputs, so we - * must add our own: - */ - /* insert CLIPDIST outputs: */ - if (ucp_enables & 0x0f) - in[0] = - create_clipdist_var(shader, ++maxloc, false, - VARYING_SLOT_CLIP_DIST0); - if (ucp_enables & 0xf0) - in[1] = - create_clipdist_var(shader, ++maxloc, false, - VARYING_SLOT_CLIP_DIST1); - - nir_foreach_function(shader, function) { - if (!strcmp(function->name, "main")) - lower_clip_fs(function->impl, ucp_enables, in); - } -} diff --git a/src/glsl/nir/nir_lower_global_vars_to_local.c b/src/glsl/nir/nir_lower_global_vars_to_local.c deleted file mode 100644 index 7b4cd4ee8dc..00000000000 --- a/src/glsl/nir/nir_lower_global_vars_to_local.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -/* - * This lowering pass detects when a global variable is only being used by - * one function and makes it local to that function - */ - -#include "nir.h" - -struct global_to_local_state { - nir_function_impl *impl; - /* A hash table keyed on variable pointers that stores the unique - * nir_function_impl that uses the given variable. If a variable is - * used in multiple functions, the data for the given key will be NULL. - */ - struct hash_table *var_func_table; -}; - -static bool -mark_global_var_uses_block(nir_block *block, void *void_state) -{ - struct global_to_local_state *state = void_state; - - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - unsigned num_vars = nir_intrinsic_infos[intrin->intrinsic].num_variables; - - for (unsigned i = 0; i < num_vars; i++) { - nir_variable *var = intrin->variables[i]->var; - if (var->data.mode != nir_var_global) - continue; - - struct hash_entry *entry = - _mesa_hash_table_search(state->var_func_table, var); - - if (entry) { - if (entry->data != state->impl) - entry->data = NULL; - } else { - _mesa_hash_table_insert(state->var_func_table, var, state->impl); - } - } - } - - return true; -} - -bool -nir_lower_global_vars_to_local(nir_shader *shader) -{ - struct global_to_local_state state; - bool progress = false; - - state.var_func_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - nir_foreach_function(shader, function) { - if (function->impl) { - state.impl = function->impl; - nir_foreach_block(function->impl, mark_global_var_uses_block, &state); - } - } - - struct hash_entry *entry; - hash_table_foreach(state.var_func_table, entry) { - nir_variable *var = (void *)entry->key; - nir_function_impl *impl = entry->data; - - assert(var->data.mode == nir_var_global); - - if (impl != NULL) { - exec_node_remove(&var->node); - var->data.mode = nir_var_local; - exec_list_push_tail(&impl->locals, &var->node); - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance | - nir_metadata_live_ssa_defs); - progress = true; - } - } - - _mesa_hash_table_destroy(state.var_func_table, NULL); - - return progress; -} diff --git a/src/glsl/nir/nir_lower_gs_intrinsics.c b/src/glsl/nir/nir_lower_gs_intrinsics.c deleted file mode 100644 index fdff1656b4d..00000000000 --- a/src/glsl/nir/nir_lower_gs_intrinsics.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" - -/** - * \file nir_lower_gs_intrinsics.c - * - * Geometry Shaders can call EmitVertex()/EmitStreamVertex() to output an - * arbitrary number of vertices. However, the shader must declare the maximum - * number of vertices that it will ever output - further attempts to emit - * vertices result in undefined behavior according to the GLSL specification. - * - * Drivers might use this maximum number of vertices to allocate enough space - * to hold the geometry shader's output. Some drivers (such as i965) need to - * implement "safety checks" which ensure that the shader hasn't emitted too - * many vertices, to avoid overflowing that space and trashing other memory. - * - * The count of emitted vertices can also be useful in buffer offset - * calculations, so drivers know where to write the GS output. - * - * However, for simple geometry shaders that emit a statically determinable - * number of vertices, this extra bookkeeping is unnecessary and inefficient. - * By tracking the vertex count in NIR, we allow constant folding/propagation - * and dead control flow optimizations to eliminate most of it where possible. - * - * This pass introduces a new global variable which stores the current vertex - * count (initialized to 0), and converts emit_vertex/end_primitive intrinsics - * to their *_with_counter variants. emit_vertex is also wrapped in a safety - * check to avoid buffer overflows. Finally, it adds a set_vertex_count - * intrinsic at the end of the program, informing the driver of the final - * vertex count. - */ - -struct state { - nir_builder *builder; - nir_variable *vertex_count_var; - bool progress; -}; - -/** - * Replace emit_vertex intrinsics with: - * - * if (vertex_count < max_vertices) { - * emit_vertex_with_counter vertex_count ... - * vertex_count += 1 - * } - */ -static void -rewrite_emit_vertex(nir_intrinsic_instr *intrin, struct state *state) -{ - nir_builder *b = state->builder; - - /* Load the vertex count */ - b->cursor = nir_before_instr(&intrin->instr); - nir_ssa_def *count = nir_load_var(b, state->vertex_count_var); - - nir_ssa_def *max_vertices = nir_imm_int(b, b->shader->info.gs.vertices_out); - - /* Create: if (vertex_count < max_vertices) and insert it. - * - * The new if statement needs to be hooked up to the control flow graph - * before we start inserting instructions into it. - */ - nir_if *if_stmt = nir_if_create(b->shader); - if_stmt->condition = nir_src_for_ssa(nir_ilt(b, count, max_vertices)); - nir_builder_cf_insert(b, &if_stmt->cf_node); - - /* Fill out the new then-block */ - b->cursor = nir_after_cf_list(&if_stmt->then_list); - - nir_intrinsic_instr *lowered = - nir_intrinsic_instr_create(b->shader, - nir_intrinsic_emit_vertex_with_counter); - lowered->const_index[0] = intrin->const_index[0]; - lowered->src[0] = nir_src_for_ssa(count); - nir_builder_instr_insert(b, &lowered->instr); - - /* Increment the vertex count by 1 */ - nir_store_var(b, state->vertex_count_var, - nir_iadd(b, count, nir_imm_int(b, 1)), - 0x1); /* .x */ - - nir_instr_remove(&intrin->instr); - - state->progress = true; -} - -/** - * Replace end_primitive with end_primitive_with_counter. - */ -static void -rewrite_end_primitive(nir_intrinsic_instr *intrin, struct state *state) -{ - nir_builder *b = state->builder; - - b->cursor = nir_before_instr(&intrin->instr); - nir_ssa_def *count = nir_load_var(b, state->vertex_count_var); - - nir_intrinsic_instr *lowered = - nir_intrinsic_instr_create(b->shader, - nir_intrinsic_end_primitive_with_counter); - lowered->const_index[0] = intrin->const_index[0]; - lowered->src[0] = nir_src_for_ssa(count); - nir_builder_instr_insert(b, &lowered->instr); - - nir_instr_remove(&intrin->instr); - - state->progress = true; -} - -static bool -rewrite_intrinsics(nir_block *block, void *closure) -{ - struct state *state = closure; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - switch (intrin->intrinsic) { - case nir_intrinsic_emit_vertex: - rewrite_emit_vertex(intrin, state); - break; - case nir_intrinsic_end_primitive: - rewrite_end_primitive(intrin, state); - break; - default: - /* not interesting; skip this */ - break; - } - } - - return true; -} - -/** - * Add a set_vertex_count intrinsic at the end of the program - * (representing the final vertex count). - */ -static void -append_set_vertex_count(nir_block *end_block, struct state *state) -{ - nir_builder *b = state->builder; - nir_shader *shader = state->builder->shader; - - /* Insert the new intrinsic in all of the predecessors of the end block, - * but before any jump instructions (return). - */ - struct set_entry *entry; - set_foreach(end_block->predecessors, entry) { - nir_block *pred = (nir_block *) entry->key; - b->cursor = nir_after_block_before_jump(pred); - - nir_ssa_def *count = nir_load_var(b, state->vertex_count_var); - - nir_intrinsic_instr *set_vertex_count = - nir_intrinsic_instr_create(shader, nir_intrinsic_set_vertex_count); - set_vertex_count->src[0] = nir_src_for_ssa(count); - - nir_builder_instr_insert(b, &set_vertex_count->instr); - } -} - -bool -nir_lower_gs_intrinsics(nir_shader *shader) -{ - struct state state; - state.progress = false; - - /* Create the counter variable */ - nir_variable *var = rzalloc(shader, nir_variable); - var->data.mode = nir_var_global; - var->type = glsl_uint_type(); - var->name = "vertex_count"; - var->constant_initializer = rzalloc(shader, nir_constant); /* initialize to 0 */ - - exec_list_push_tail(&shader->globals, &var->node); - state.vertex_count_var = var; - - nir_foreach_function(shader, function) { - if (function->impl) { - nir_builder b; - nir_builder_init(&b, function->impl); - state.builder = &b; - - nir_foreach_block(function->impl, rewrite_intrinsics, &state); - - /* This only works because we have a single main() function. */ - append_set_vertex_count(function->impl->end_block, &state); - - nir_metadata_preserve(function->impl, 0); - } - } - - return state.progress; -} diff --git a/src/glsl/nir/nir_lower_idiv.c b/src/glsl/nir/nir_lower_idiv.c deleted file mode 100644 index a084ad9c0e5..00000000000 --- a/src/glsl/nir/nir_lower_idiv.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright © 2015 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Rob Clark <[email protected]> - */ - -#include "nir.h" -#include "nir_builder.h" - -/* Lowers idiv/udiv/umod - * Based on NV50LegalizeSSA::handleDIV() - * - * Note that this is probably not enough precision for compute shaders. - * Perhaps we want a second higher precision (looping) version of this? - * Or perhaps we assume if you can do compute shaders you can also - * branch out to a pre-optimized shader library routine.. - */ - -static void -convert_instr(nir_builder *bld, nir_alu_instr *alu) -{ - nir_ssa_def *numer, *denom, *af, *bf, *a, *b, *q, *r; - nir_op op = alu->op; - bool is_signed; - - if ((op != nir_op_idiv) && - (op != nir_op_udiv) && - (op != nir_op_umod)) - return; - - is_signed = (op == nir_op_idiv); - - bld->cursor = nir_before_instr(&alu->instr); - - numer = nir_ssa_for_alu_src(bld, alu, 0); - denom = nir_ssa_for_alu_src(bld, alu, 1); - - if (is_signed) { - af = nir_i2f(bld, numer); - bf = nir_i2f(bld, denom); - af = nir_fabs(bld, af); - bf = nir_fabs(bld, bf); - a = nir_iabs(bld, numer); - b = nir_iabs(bld, denom); - } else { - af = nir_u2f(bld, numer); - bf = nir_u2f(bld, denom); - a = numer; - b = denom; - } - - /* get first result: */ - bf = nir_frcp(bld, bf); - bf = nir_isub(bld, bf, nir_imm_int(bld, 2)); /* yes, really */ - q = nir_fmul(bld, af, bf); - - if (is_signed) { - q = nir_f2i(bld, q); - } else { - q = nir_f2u(bld, q); - } - - /* get error of first result: */ - r = nir_imul(bld, q, b); - r = nir_isub(bld, a, r); - r = nir_u2f(bld, r); - r = nir_fmul(bld, r, bf); - r = nir_f2u(bld, r); - - /* add quotients: */ - q = nir_iadd(bld, q, r); - - /* correction: if modulus >= divisor, add 1 */ - r = nir_imul(bld, q, b); - r = nir_isub(bld, a, r); - - r = nir_uge(bld, r, b); - r = nir_b2i(bld, r); - - q = nir_iadd(bld, q, r); - if (is_signed) { - /* fix the sign: */ - r = nir_ixor(bld, numer, denom); - r = nir_ushr(bld, r, nir_imm_int(bld, 31)); - r = nir_i2b(bld, r); - b = nir_ineg(bld, q); - q = nir_bcsel(bld, r, b, q); - } - - if (op == nir_op_umod) { - /* division result in q */ - r = nir_imul(bld, q, b); - q = nir_isub(bld, a, r); - } - - assert(alu->dest.dest.is_ssa); - nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa, nir_src_for_ssa(q)); -} - -static bool -convert_block(nir_block *block, void *state) -{ - nir_builder *b = state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type == nir_instr_type_alu) - convert_instr(b, nir_instr_as_alu(instr)); - } - - return true; -} - -static void -convert_impl(nir_function_impl *impl) -{ - nir_builder b; - nir_builder_init(&b, impl); - - nir_foreach_block(impl, convert_block, &b); - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); -} - -void -nir_lower_idiv(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - convert_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_indirect_derefs.c b/src/glsl/nir/nir_lower_indirect_derefs.c deleted file mode 100644 index 69f2df4ba6d..00000000000 --- a/src/glsl/nir/nir_lower_indirect_derefs.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" - -static void -emit_load_store(nir_builder *b, nir_intrinsic_instr *orig_instr, - nir_deref_var *deref, nir_deref *tail, - nir_ssa_def **dest, nir_ssa_def *src); - -static void -emit_indirect_load_store(nir_builder *b, nir_intrinsic_instr *orig_instr, - nir_deref_var *deref, nir_deref *arr_parent, - int start, int end, - nir_ssa_def **dest, nir_ssa_def *src) -{ - assert(arr_parent->child && - arr_parent->child->deref_type == nir_deref_type_array); - nir_deref_array *arr = nir_deref_as_array(arr_parent->child); - assert(arr->deref_array_type == nir_deref_array_type_indirect); - assert(arr->indirect.is_ssa); - - assert(start < end); - if (start == end - 1) { - /* Base case. Just emit the load/store op */ - nir_deref_array direct = *arr; - direct.deref_array_type = nir_deref_array_type_direct; - direct.base_offset += start; - direct.indirect = NIR_SRC_INIT; - - arr_parent->child = &direct.deref; - emit_load_store(b, orig_instr, deref, &arr->deref, dest, src); - arr_parent->child = &arr->deref; - } else { - int mid = start + (end - start) / 2; - - nir_ssa_def *then_dest, *else_dest; - - nir_if *if_stmt = nir_if_create(b->shader); - if_stmt->condition = nir_src_for_ssa(nir_ilt(b, arr->indirect.ssa, - nir_imm_int(b, mid))); - nir_cf_node_insert(b->cursor, &if_stmt->cf_node); - - b->cursor = nir_after_cf_list(&if_stmt->then_list); - emit_indirect_load_store(b, orig_instr, deref, arr_parent, - start, mid, &then_dest, src); - - b->cursor = nir_after_cf_list(&if_stmt->else_list); - emit_indirect_load_store(b, orig_instr, deref, arr_parent, - mid, end, &else_dest, src); - - b->cursor = nir_after_cf_node(&if_stmt->cf_node); - - if (src == NULL) { - /* We're a load. We need to insert a phi node */ - nir_phi_instr *phi = nir_phi_instr_create(b->shader); - nir_ssa_dest_init(&phi->instr, &phi->dest, - then_dest->num_components, NULL); - - nir_phi_src *src0 = ralloc(phi, nir_phi_src); - src0->pred = nir_cf_node_as_block(nir_if_last_then_node(if_stmt)); - src0->src = nir_src_for_ssa(then_dest); - exec_list_push_tail(&phi->srcs, &src0->node); - - nir_phi_src *src1 = ralloc(phi, nir_phi_src); - src1->pred = nir_cf_node_as_block(nir_if_last_else_node(if_stmt)); - src1->src = nir_src_for_ssa(else_dest); - exec_list_push_tail(&phi->srcs, &src1->node); - - nir_builder_instr_insert(b, &phi->instr); - *dest = &phi->dest.ssa; - } - } -} - -static void -emit_load_store(nir_builder *b, nir_intrinsic_instr *orig_instr, - nir_deref_var *deref, nir_deref *tail, - nir_ssa_def **dest, nir_ssa_def *src) -{ - for (; tail->child; tail = tail->child) { - if (tail->child->deref_type != nir_deref_type_array) - continue; - - nir_deref_array *arr = nir_deref_as_array(tail->child); - if (arr->deref_array_type != nir_deref_array_type_indirect) - continue; - - int length = glsl_get_length(tail->type); - - emit_indirect_load_store(b, orig_instr, deref, tail, -arr->base_offset, - length - arr->base_offset, dest, src); - return; - } - - assert(tail && tail->child == NULL); - - /* We reached the end of the deref chain. Emit the instruction */ - - if (src == NULL) { - /* This is a load instruction */ - nir_intrinsic_instr *load = - nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var); - load->num_components = orig_instr->num_components; - load->variables[0] = - nir_deref_as_var(nir_copy_deref(load, &deref->deref)); - nir_ssa_dest_init(&load->instr, &load->dest, - load->num_components, NULL); - nir_builder_instr_insert(b, &load->instr); - *dest = &load->dest.ssa; - } else { - /* This is a store instruction */ - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var); - store->num_components = orig_instr->num_components; - store->const_index[0] = orig_instr->const_index[0]; /* writemask */ - store->variables[0] = - nir_deref_as_var(nir_copy_deref(store, &deref->deref)); - store->src[0] = nir_src_for_ssa(src); - nir_builder_instr_insert(b, &store->instr); - } -} - -static bool -deref_has_indirect(nir_deref_var *deref) -{ - for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) { - if (tail->deref_type != nir_deref_type_array) - continue; - - nir_deref_array *arr = nir_deref_as_array(tail); - if (arr->deref_array_type == nir_deref_array_type_indirect) - return true; - } - - return false; -} - -struct lower_indirect_state { - nir_builder builder; - uint32_t mode_mask; - bool progress; -}; - -static bool -lower_indirect_block(nir_block *block, void *void_state) -{ - struct lower_indirect_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - if (intrin->intrinsic != nir_intrinsic_load_var && - intrin->intrinsic != nir_intrinsic_store_var) - continue; - - if (!deref_has_indirect(intrin->variables[0])) - continue; - - /* Only lower variables whose mode is in the mask */ - if (!(state->mode_mask & (1 << intrin->variables[0]->var->data.mode))) - continue; - - state->builder.cursor = nir_before_instr(&intrin->instr); - - if (intrin->intrinsic == nir_intrinsic_load_var) { - nir_ssa_def *result; - emit_load_store(&state->builder, intrin, intrin->variables[0], - &intrin->variables[0]->deref, &result, NULL); - nir_ssa_def_rewrite_uses(&intrin->dest.ssa, nir_src_for_ssa(result)); - } else { - assert(intrin->src[0].is_ssa); - emit_load_store(&state->builder, intrin, intrin->variables[0], - &intrin->variables[0]->deref, NULL, intrin->src[0].ssa); - } - nir_instr_remove(&intrin->instr); - state->progress = true; - } - - return true; -} - -static bool -lower_indirects_impl(nir_function_impl *impl, uint32_t mode_mask) -{ - struct lower_indirect_state state; - - state.progress = false; - state.mode_mask = mode_mask; - nir_builder_init(&state.builder, impl); - - nir_foreach_block(impl, lower_indirect_block, &state); - - if (state.progress) - nir_metadata_preserve(impl, nir_metadata_none); - - return state.progress; -} - -/** Lowers indirect variable loads/stores to direct loads/stores. - * - * The pass works by replacing any indirect load or store with an if-ladder - * that does a binary search on the array index. - */ -bool -nir_lower_indirect_derefs(nir_shader *shader, uint32_t mode_mask) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = lower_indirects_impl(function->impl, mode_mask) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_lower_io.c b/src/glsl/nir/nir_lower_io.c deleted file mode 100644 index 2c5fa16af5e..00000000000 --- a/src/glsl/nir/nir_lower_io.c +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * Jason Ekstrand ([email protected]) - * - */ - -/* - * This lowering pass converts references to input/output variables with - * loads/stores to actual input/output intrinsics. - */ - -#include "nir.h" -#include "nir_builder.h" - -struct lower_io_state { - nir_builder builder; - void *mem_ctx; - int (*type_size)(const struct glsl_type *type); - nir_variable_mode mode; -}; - -void -nir_assign_var_locations(struct exec_list *var_list, unsigned *size, - int (*type_size)(const struct glsl_type *)) -{ - unsigned location = 0; - - nir_foreach_variable(var, var_list) { - /* - * UBO's have their own address spaces, so don't count them towards the - * number of global uniforms - */ - if ((var->data.mode == nir_var_uniform || var->data.mode == nir_var_shader_storage) && - var->interface_type != NULL) - continue; - - var->data.driver_location = location; - location += type_size(var->type); - } - - *size = location; -} - -/** - * Returns true if we're processing a stage whose inputs are arrays indexed - * by a vertex number (such as geometry shader inputs). - */ -static bool -is_per_vertex_input(struct lower_io_state *state, nir_variable *var) -{ - gl_shader_stage stage = state->builder.shader->stage; - - return var->data.mode == nir_var_shader_in && !var->data.patch && - (stage == MESA_SHADER_TESS_CTRL || - stage == MESA_SHADER_TESS_EVAL || - stage == MESA_SHADER_GEOMETRY); -} - -static bool -is_per_vertex_output(struct lower_io_state *state, nir_variable *var) -{ - gl_shader_stage stage = state->builder.shader->stage; - return var->data.mode == nir_var_shader_out && !var->data.patch && - stage == MESA_SHADER_TESS_CTRL; -} - -static nir_ssa_def * -get_io_offset(nir_builder *b, nir_deref_var *deref, - nir_ssa_def **vertex_index, - int (*type_size)(const struct glsl_type *)) -{ - nir_deref *tail = &deref->deref; - - /* For per-vertex input arrays (i.e. geometry shader inputs), keep the - * outermost array index separate. Process the rest normally. - */ - if (vertex_index != NULL) { - tail = tail->child; - assert(tail->deref_type == nir_deref_type_array); - nir_deref_array *deref_array = nir_deref_as_array(tail); - - nir_ssa_def *vtx = nir_imm_int(b, deref_array->base_offset); - if (deref_array->deref_array_type == nir_deref_array_type_indirect) { - vtx = nir_iadd(b, vtx, nir_ssa_for_src(b, deref_array->indirect, 1)); - } - *vertex_index = vtx; - } - - /* Just emit code and let constant-folding go to town */ - nir_ssa_def *offset = nir_imm_int(b, 0); - - while (tail->child != NULL) { - const struct glsl_type *parent_type = tail->type; - tail = tail->child; - - if (tail->deref_type == nir_deref_type_array) { - nir_deref_array *deref_array = nir_deref_as_array(tail); - unsigned size = type_size(tail->type); - - offset = nir_iadd(b, offset, - nir_imm_int(b, size * deref_array->base_offset)); - - if (deref_array->deref_array_type == nir_deref_array_type_indirect) { - nir_ssa_def *mul = - nir_imul(b, nir_imm_int(b, size), - nir_ssa_for_src(b, deref_array->indirect, 1)); - - offset = nir_iadd(b, offset, mul); - } - } else if (tail->deref_type == nir_deref_type_struct) { - nir_deref_struct *deref_struct = nir_deref_as_struct(tail); - - unsigned field_offset = 0; - for (unsigned i = 0; i < deref_struct->index; i++) { - field_offset += type_size(glsl_get_struct_field(parent_type, i)); - } - offset = nir_iadd(b, offset, nir_imm_int(b, field_offset)); - } - } - - return offset; -} - -static nir_intrinsic_op -load_op(struct lower_io_state *state, - nir_variable_mode mode, bool per_vertex) -{ - nir_intrinsic_op op; - switch (mode) { - case nir_var_shader_in: - op = per_vertex ? nir_intrinsic_load_per_vertex_input : - nir_intrinsic_load_input; - break; - case nir_var_shader_out: - op = per_vertex ? nir_intrinsic_load_per_vertex_output : - nir_intrinsic_load_output; - break; - case nir_var_uniform: - op = nir_intrinsic_load_uniform; - break; - case nir_var_shared: - op = nir_intrinsic_load_shared; - break; - default: - unreachable("Unknown variable mode"); - } - return op; -} - -static nir_intrinsic_op -store_op(struct lower_io_state *state, - nir_variable_mode mode, bool per_vertex) -{ - nir_intrinsic_op op; - switch (mode) { - case nir_var_shader_in: - case nir_var_shader_out: - op = per_vertex ? nir_intrinsic_store_per_vertex_output : - nir_intrinsic_store_output; - break; - case nir_var_shared: - op = nir_intrinsic_store_shared; - break; - default: - unreachable("Unknown variable mode"); - } - return op; -} - -static nir_intrinsic_op -atomic_op(nir_intrinsic_op opcode) -{ - switch (opcode) { -#define OP(O) case nir_intrinsic_var_##O: return nir_intrinsic_shared_##O; - OP(atomic_exchange) - OP(atomic_comp_swap) - OP(atomic_add) - OP(atomic_imin) - OP(atomic_umin) - OP(atomic_imax) - OP(atomic_umax) - OP(atomic_and) - OP(atomic_or) - OP(atomic_xor) -#undef OP - default: - unreachable("Invalid atomic"); - } -} - -static bool -nir_lower_io_block(nir_block *block, void *void_state) -{ - struct lower_io_state *state = void_state; - - nir_builder *b = &state->builder; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - switch (intrin->intrinsic) { - case nir_intrinsic_load_var: - case nir_intrinsic_store_var: - case nir_intrinsic_var_atomic_add: - case nir_intrinsic_var_atomic_imin: - case nir_intrinsic_var_atomic_umin: - case nir_intrinsic_var_atomic_imax: - case nir_intrinsic_var_atomic_umax: - case nir_intrinsic_var_atomic_and: - case nir_intrinsic_var_atomic_or: - case nir_intrinsic_var_atomic_xor: - case nir_intrinsic_var_atomic_exchange: - case nir_intrinsic_var_atomic_comp_swap: - /* We can lower the io for this nir instrinsic */ - break; - default: - /* We can't lower the io for this nir instrinsic, so skip it */ - continue; - } - - nir_variable_mode mode = intrin->variables[0]->var->data.mode; - - if (state->mode != nir_var_all && state->mode != mode) - continue; - - if (mode != nir_var_shader_in && - mode != nir_var_shader_out && - mode != nir_var_shared && - mode != nir_var_uniform) - continue; - - b->cursor = nir_before_instr(instr); - - switch (intrin->intrinsic) { - case nir_intrinsic_load_var: { - bool per_vertex = - is_per_vertex_input(state, intrin->variables[0]->var) || - is_per_vertex_output(state, intrin->variables[0]->var); - - nir_ssa_def *offset; - nir_ssa_def *vertex_index; - - offset = get_io_offset(b, intrin->variables[0], - per_vertex ? &vertex_index : NULL, - state->type_size); - - nir_intrinsic_instr *load = - nir_intrinsic_instr_create(state->mem_ctx, - load_op(state, mode, per_vertex)); - load->num_components = intrin->num_components; - - load->const_index[0] = - intrin->variables[0]->var->data.driver_location; - - if (load->intrinsic == nir_intrinsic_load_uniform) { - load->const_index[1] = - state->type_size(intrin->variables[0]->var->type); - } - - if (per_vertex) - load->src[0] = nir_src_for_ssa(vertex_index); - - load->src[per_vertex ? 1 : 0] = nir_src_for_ssa(offset); - - if (intrin->dest.is_ssa) { - nir_ssa_dest_init(&load->instr, &load->dest, - intrin->num_components, NULL); - nir_ssa_def_rewrite_uses(&intrin->dest.ssa, - nir_src_for_ssa(&load->dest.ssa)); - } else { - nir_dest_copy(&load->dest, &intrin->dest, state->mem_ctx); - } - - nir_instr_insert_before(&intrin->instr, &load->instr); - nir_instr_remove(&intrin->instr); - break; - } - - case nir_intrinsic_store_var: { - assert(mode == nir_var_shader_out || mode == nir_var_shared); - - nir_ssa_def *offset; - nir_ssa_def *vertex_index; - - bool per_vertex = - is_per_vertex_output(state, intrin->variables[0]->var); - - offset = get_io_offset(b, intrin->variables[0], - per_vertex ? &vertex_index : NULL, - state->type_size); - - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(state->mem_ctx, - store_op(state, mode, per_vertex)); - store->num_components = intrin->num_components; - - nir_src_copy(&store->src[0], &intrin->src[0], store); - - store->const_index[0] = - intrin->variables[0]->var->data.driver_location; - - /* Copy the writemask */ - store->const_index[1] = intrin->const_index[0]; - - if (per_vertex) - store->src[1] = nir_src_for_ssa(vertex_index); - - store->src[per_vertex ? 2 : 1] = nir_src_for_ssa(offset); - - nir_instr_insert_before(&intrin->instr, &store->instr); - nir_instr_remove(&intrin->instr); - break; - } - - case nir_intrinsic_var_atomic_add: - case nir_intrinsic_var_atomic_imin: - case nir_intrinsic_var_atomic_umin: - case nir_intrinsic_var_atomic_imax: - case nir_intrinsic_var_atomic_umax: - case nir_intrinsic_var_atomic_and: - case nir_intrinsic_var_atomic_or: - case nir_intrinsic_var_atomic_xor: - case nir_intrinsic_var_atomic_exchange: - case nir_intrinsic_var_atomic_comp_swap: { - assert(mode == nir_var_shared); - - nir_ssa_def *offset; - - offset = get_io_offset(b, intrin->variables[0], - NULL, state->type_size); - - nir_intrinsic_instr *atomic = - nir_intrinsic_instr_create(state->mem_ctx, - atomic_op(intrin->intrinsic)); - - atomic->src[0] = nir_src_for_ssa(offset); - - atomic->const_index[0] = - intrin->variables[0]->var->data.driver_location; - - nir_src_copy(&atomic->src[1], &intrin->src[0], atomic); - - if (intrin->intrinsic == nir_intrinsic_var_atomic_comp_swap) - nir_src_copy(&atomic->src[2], &intrin->src[1], atomic); - - if (intrin->dest.is_ssa) { - nir_ssa_dest_init(&atomic->instr, &atomic->dest, - intrin->dest.ssa.num_components, NULL); - nir_ssa_def_rewrite_uses(&intrin->dest.ssa, - nir_src_for_ssa(&atomic->dest.ssa)); - } else { - nir_dest_copy(&atomic->dest, &intrin->dest, state->mem_ctx); - } - - nir_instr_insert_before(&intrin->instr, &atomic->instr); - nir_instr_remove(&intrin->instr); - break; - } - - default: - break; - } - } - - return true; -} - -static void -nir_lower_io_impl(nir_function_impl *impl, - nir_variable_mode mode, - int (*type_size)(const struct glsl_type *)) -{ - struct lower_io_state state; - - nir_builder_init(&state.builder, impl); - state.mem_ctx = ralloc_parent(impl); - state.mode = mode; - state.type_size = type_size; - - nir_foreach_block(impl, nir_lower_io_block, &state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); -} - -void -nir_lower_io(nir_shader *shader, nir_variable_mode mode, - int (*type_size)(const struct glsl_type *)) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_io_impl(function->impl, mode, type_size); - } -} - -/** - * Return the offset soruce for a load/store intrinsic. - */ -nir_src * -nir_get_io_offset_src(nir_intrinsic_instr *instr) -{ - switch (instr->intrinsic) { - case nir_intrinsic_load_input: - case nir_intrinsic_load_output: - case nir_intrinsic_load_uniform: - return &instr->src[0]; - case nir_intrinsic_load_ubo: - case nir_intrinsic_load_ssbo: - case nir_intrinsic_load_per_vertex_input: - case nir_intrinsic_load_per_vertex_output: - case nir_intrinsic_store_output: - return &instr->src[1]; - case nir_intrinsic_store_ssbo: - case nir_intrinsic_store_per_vertex_output: - return &instr->src[2]; - default: - return NULL; - } -} - -/** - * Return the vertex index source for a load/store per_vertex intrinsic. - */ -nir_src * -nir_get_io_vertex_index_src(nir_intrinsic_instr *instr) -{ - switch (instr->intrinsic) { - case nir_intrinsic_load_per_vertex_input: - case nir_intrinsic_load_per_vertex_output: - return &instr->src[0]; - case nir_intrinsic_store_per_vertex_output: - return &instr->src[1]; - default: - return NULL; - } -} diff --git a/src/glsl/nir/nir_lower_load_const_to_scalar.c b/src/glsl/nir/nir_lower_load_const_to_scalar.c deleted file mode 100644 index 1eeed13cbac..00000000000 --- a/src/glsl/nir/nir_lower_load_const_to_scalar.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright © 2015 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "util/macros.h" -#include "nir.h" -#include "nir_builder.h" - -/** @file nir_lower_load_const_to_scalar.c - * - * Replaces vector nir_load_const instructions with a series of loads and a - * vec[234] to reconstruct the original vector (on the assumption that - * nir_lower_alu_to_scalar() will then be used to split it up). - * - * This gives NIR a chance to CSE more operations on a scalar shader, when the - * same value was used in different vector contant loads. - */ - -static void -lower_load_const_instr_scalar(nir_load_const_instr *lower) -{ - if (lower->def.num_components == 1) - return; - - nir_builder b; - nir_builder_init(&b, nir_cf_node_get_function(&lower->instr.block->cf_node)); - b.cursor = nir_before_instr(&lower->instr); - - /* Emit the individual loads. */ - nir_ssa_def *loads[4]; - for (unsigned i = 0; i < lower->def.num_components; i++) { - nir_load_const_instr *load_comp = nir_load_const_instr_create(b.shader, 1); - load_comp->value.u[0] = lower->value.u[i]; - nir_builder_instr_insert(&b, &load_comp->instr); - loads[i] = &load_comp->def; - } - - /* Batch things back together into a vector. */ - nir_ssa_def *vec = nir_vec(&b, loads, lower->def.num_components); - - /* Replace the old load with a reference to our reconstructed vector. */ - nir_ssa_def_rewrite_uses(&lower->def, nir_src_for_ssa(vec)); - nir_instr_remove(&lower->instr); -} - -static bool -lower_load_const_to_scalar_block(nir_block *block, void *data) -{ - nir_foreach_instr_safe(block, instr) { - if (instr->type == nir_instr_type_load_const) - lower_load_const_instr_scalar(nir_instr_as_load_const(instr)); - } - - return true; -} - -static void -nir_lower_load_const_to_scalar_impl(nir_function_impl *impl) -{ - nir_foreach_block(impl, lower_load_const_to_scalar_block, NULL); -} - -void -nir_lower_load_const_to_scalar(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_load_const_to_scalar_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_locals_to_regs.c b/src/glsl/nir/nir_lower_locals_to_regs.c deleted file mode 100644 index 51b0fa733f2..00000000000 --- a/src/glsl/nir/nir_lower_locals_to_regs.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" -#include "nir_array.h" - -struct locals_to_regs_state { - nir_shader *shader; - nir_function_impl *impl; - - /* A hash table mapping derefs to registers */ - struct hash_table *regs_table; - - /* A growing array of derefs that we have encountered. There is exactly - * one element of this array per element in the hash table. This is - * used to make adding register initialization code deterministic. - */ - nir_array derefs_array; - - bool progress; -}; - -/* The following two functions implement a hash and equality check for - * variable dreferences. When the hash or equality function encounters an - * array, it ignores the offset and whether it is direct or indirect - * entirely. - */ -static uint32_t -hash_deref(const void *void_deref) -{ - uint32_t hash = _mesa_fnv32_1a_offset_bias; - - const nir_deref_var *deref_var = void_deref; - hash = _mesa_fnv32_1a_accumulate(hash, deref_var->var); - - for (const nir_deref *deref = deref_var->deref.child; - deref; deref = deref->child) { - if (deref->deref_type == nir_deref_type_struct) { - const nir_deref_struct *deref_struct = nir_deref_as_struct(deref); - hash = _mesa_fnv32_1a_accumulate(hash, deref_struct->index); - } - } - - return hash; -} - -static bool -derefs_equal(const void *void_a, const void *void_b) -{ - const nir_deref_var *a_var = void_a; - const nir_deref_var *b_var = void_b; - - if (a_var->var != b_var->var) - return false; - - for (const nir_deref *a = a_var->deref.child, *b = b_var->deref.child; - a != NULL; a = a->child, b = b->child) { - if (a->deref_type != b->deref_type) - return false; - - if (a->deref_type == nir_deref_type_struct) { - if (nir_deref_as_struct(a)->index != nir_deref_as_struct(b)->index) - return false; - } - /* Do nothing for arrays. They're all the same. */ - - assert((a->child == NULL) == (b->child == NULL)); - if((a->child == NULL) != (b->child == NULL)) - return false; - } - - return true; -} - -static nir_register * -get_reg_for_deref(nir_deref_var *deref, struct locals_to_regs_state *state) -{ - uint32_t hash = hash_deref(deref); - - struct hash_entry *entry = - _mesa_hash_table_search_pre_hashed(state->regs_table, hash, deref); - if (entry) - return entry->data; - - unsigned array_size = 1; - nir_deref *tail = &deref->deref; - while (tail->child) { - if (tail->child->deref_type == nir_deref_type_array) - array_size *= glsl_get_length(tail->type); - tail = tail->child; - } - - assert(glsl_type_is_vector(tail->type) || glsl_type_is_scalar(tail->type)); - - nir_register *reg = nir_local_reg_create(state->impl); - reg->num_components = glsl_get_vector_elements(tail->type); - reg->num_array_elems = array_size > 1 ? array_size : 0; - - _mesa_hash_table_insert_pre_hashed(state->regs_table, hash, deref, reg); - nir_array_add(&state->derefs_array, nir_deref_var *, deref); - - return reg; -} - -static nir_src -get_deref_reg_src(nir_deref_var *deref, nir_instr *instr, - struct locals_to_regs_state *state) -{ - nir_src src; - - src.is_ssa = false; - src.reg.reg = get_reg_for_deref(deref, state); - src.reg.base_offset = 0; - src.reg.indirect = NULL; - - /* It is possible for a user to create a shader that has an array with a - * single element and then proceed to access it indirectly. Indirectly - * accessing a non-array register is not allowed in NIR. In order to - * handle this case we just convert it to a direct reference. - */ - if (src.reg.reg->num_array_elems == 0) - return src; - - nir_deref *tail = &deref->deref; - while (tail->child != NULL) { - const struct glsl_type *parent_type = tail->type; - tail = tail->child; - - if (tail->deref_type != nir_deref_type_array) - continue; - - nir_deref_array *deref_array = nir_deref_as_array(tail); - - src.reg.base_offset *= glsl_get_length(parent_type); - src.reg.base_offset += deref_array->base_offset; - - if (src.reg.indirect) { - nir_load_const_instr *load_const = - nir_load_const_instr_create(state->shader, 1); - load_const->value.u[0] = glsl_get_length(parent_type); - nir_instr_insert_before(instr, &load_const->instr); - - nir_alu_instr *mul = nir_alu_instr_create(state->shader, nir_op_imul); - mul->src[0].src = *src.reg.indirect; - mul->src[1].src.is_ssa = true; - mul->src[1].src.ssa = &load_const->def; - mul->dest.write_mask = 1; - nir_ssa_dest_init(&mul->instr, &mul->dest.dest, 1, NULL); - nir_instr_insert_before(instr, &mul->instr); - - src.reg.indirect->is_ssa = true; - src.reg.indirect->ssa = &mul->dest.dest.ssa; - } - - if (deref_array->deref_array_type == nir_deref_array_type_indirect) { - if (src.reg.indirect == NULL) { - src.reg.indirect = ralloc(state->shader, nir_src); - nir_src_copy(src.reg.indirect, &deref_array->indirect, - state->shader); - } else { - nir_alu_instr *add = nir_alu_instr_create(state->shader, - nir_op_iadd); - add->src[0].src = *src.reg.indirect; - nir_src_copy(&add->src[1].src, &deref_array->indirect, add); - add->dest.write_mask = 1; - nir_ssa_dest_init(&add->instr, &add->dest.dest, 1, NULL); - nir_instr_insert_before(instr, &add->instr); - - src.reg.indirect->is_ssa = true; - src.reg.indirect->ssa = &add->dest.dest.ssa; - } - } - } - - return src; -} - -static bool -lower_locals_to_regs_block(nir_block *block, void *void_state) -{ - struct locals_to_regs_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - switch (intrin->intrinsic) { - case nir_intrinsic_load_var: { - if (intrin->variables[0]->var->data.mode != nir_var_local) - continue; - - nir_alu_instr *mov = nir_alu_instr_create(state->shader, nir_op_imov); - mov->src[0].src = get_deref_reg_src(intrin->variables[0], - &intrin->instr, state); - mov->dest.write_mask = (1 << intrin->num_components) - 1; - if (intrin->dest.is_ssa) { - nir_ssa_dest_init(&mov->instr, &mov->dest.dest, - intrin->num_components, NULL); - nir_ssa_def_rewrite_uses(&intrin->dest.ssa, - nir_src_for_ssa(&mov->dest.dest.ssa)); - } else { - nir_dest_copy(&mov->dest.dest, &intrin->dest, &mov->instr); - } - nir_instr_insert_before(&intrin->instr, &mov->instr); - - nir_instr_remove(&intrin->instr); - state->progress = true; - break; - } - - case nir_intrinsic_store_var: { - if (intrin->variables[0]->var->data.mode != nir_var_local) - continue; - - nir_src reg_src = get_deref_reg_src(intrin->variables[0], - &intrin->instr, state); - - nir_alu_instr *mov = nir_alu_instr_create(state->shader, nir_op_imov); - nir_src_copy(&mov->src[0].src, &intrin->src[0], mov); - mov->dest.write_mask = intrin->const_index[0]; - mov->dest.dest.is_ssa = false; - mov->dest.dest.reg.reg = reg_src.reg.reg; - mov->dest.dest.reg.base_offset = reg_src.reg.base_offset; - mov->dest.dest.reg.indirect = reg_src.reg.indirect; - - nir_instr_insert_before(&intrin->instr, &mov->instr); - - nir_instr_remove(&intrin->instr); - state->progress = true; - break; - } - - case nir_intrinsic_copy_var: - unreachable("There should be no copies whatsoever at this point"); - break; - - default: - continue; - } - } - - return true; -} - -static nir_block * -compute_reg_usedef_lca(nir_register *reg) -{ - nir_block *lca = NULL; - - list_for_each_entry(nir_dest, def_dest, ®->defs, reg.def_link) - lca = nir_dominance_lca(lca, def_dest->reg.parent_instr->block); - - list_for_each_entry(nir_src, use_src, ®->uses, use_link) - lca = nir_dominance_lca(lca, use_src->parent_instr->block); - - list_for_each_entry(nir_src, use_src, ®->if_uses, use_link) { - nir_cf_node *prev_node = nir_cf_node_prev(&use_src->parent_if->cf_node); - assert(prev_node->type == nir_cf_node_block); - lca = nir_dominance_lca(lca, nir_cf_node_as_block(prev_node)); - } - - return lca; -} - -static void -insert_constant_initializer(nir_deref_var *deref_head, nir_deref *deref_tail, - nir_block *block, - struct locals_to_regs_state *state) -{ - if (deref_tail->child) { - switch (deref_tail->child->deref_type) { - case nir_deref_type_array: { - unsigned array_elems = glsl_get_length(deref_tail->type); - - nir_deref_array arr_deref; - arr_deref.deref = *deref_tail->child; - arr_deref.deref_array_type = nir_deref_array_type_direct; - - nir_deref *old_child = deref_tail->child; - deref_tail->child = &arr_deref.deref; - for (unsigned i = 0; i < array_elems; i++) { - arr_deref.base_offset = i; - insert_constant_initializer(deref_head, &arr_deref.deref, - block, state); - } - deref_tail->child = old_child; - return; - } - - case nir_deref_type_struct: - insert_constant_initializer(deref_head, deref_tail->child, - block, state); - return; - - default: - unreachable("Invalid deref child type"); - } - } - - assert(deref_tail->child == NULL); - - nir_load_const_instr *load = - nir_deref_get_const_initializer_load(state->shader, deref_head); - nir_instr_insert_before_block(block, &load->instr); - - nir_src reg_src = get_deref_reg_src(deref_head, &load->instr, state); - - nir_alu_instr *mov = nir_alu_instr_create(state->shader, nir_op_imov); - mov->src[0].src = nir_src_for_ssa(&load->def); - mov->dest.write_mask = (1 << load->def.num_components) - 1; - mov->dest.dest.is_ssa = false; - mov->dest.dest.reg.reg = reg_src.reg.reg; - mov->dest.dest.reg.base_offset = reg_src.reg.base_offset; - mov->dest.dest.reg.indirect = reg_src.reg.indirect; - - nir_instr_insert_after(&load->instr, &mov->instr); - state->progress = true; -} - -static bool -nir_lower_locals_to_regs_impl(nir_function_impl *impl) -{ - struct locals_to_regs_state state; - - state.shader = impl->function->shader; - state.impl = impl; - state.progress = false; - state.regs_table = _mesa_hash_table_create(NULL, hash_deref, derefs_equal); - nir_array_init(&state.derefs_array, NULL); - - nir_metadata_require(impl, nir_metadata_dominance); - - nir_foreach_block(impl, lower_locals_to_regs_block, &state); - - nir_array_foreach(&state.derefs_array, nir_deref_var *, deref_ptr) { - nir_deref_var *deref = *deref_ptr; - struct hash_entry *deref_entry = - _mesa_hash_table_search(state.regs_table, deref); - assert(deref_entry && deref_entry->key == deref); - nir_register *reg = (nir_register *)deref_entry->data; - - if (deref->var->constant_initializer == NULL) - continue; - - nir_block *usedef_lca = compute_reg_usedef_lca(reg); - - insert_constant_initializer(deref, &deref->deref, usedef_lca, &state); - } - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - nir_array_fini(&state.derefs_array); - _mesa_hash_table_destroy(state.regs_table, NULL); - - return state.progress; -} - -bool -nir_lower_locals_to_regs(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = nir_lower_locals_to_regs_impl(function->impl) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_lower_outputs_to_temporaries.c b/src/glsl/nir/nir_lower_outputs_to_temporaries.c deleted file mode 100644 index 00ac09114cf..00000000000 --- a/src/glsl/nir/nir_lower_outputs_to_temporaries.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/* - * Implements a pass that lowers output variables to a temporary plus an - * output variable with a single copy at each exit point of the shader. - * This way the output variable is only ever written. - * - * Because valid NIR requires that output variables are never read, this - * pass is more of a helper for NIR producers and must be run before the - * shader is ever validated. - */ - -#include "nir.h" - -struct lower_outputs_state { - nir_shader *shader; - struct exec_list old_outputs; -}; - -static void -emit_output_copies(nir_cursor cursor, struct lower_outputs_state *state) -{ - assert(exec_list_length(&state->shader->outputs) == - exec_list_length(&state->old_outputs)); - - foreach_two_lists(out_node, &state->shader->outputs, - temp_node, &state->old_outputs) { - nir_variable *output = exec_node_data(nir_variable, out_node, node); - nir_variable *temp = exec_node_data(nir_variable, temp_node, node); - - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(state->shader, nir_intrinsic_copy_var); - copy->variables[0] = nir_deref_var_create(copy, output); - copy->variables[1] = nir_deref_var_create(copy, temp); - - nir_instr_insert(cursor, ©->instr); - } -} - -static bool -emit_output_copies_block(nir_block *block, void *state) -{ - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - if (intrin->intrinsic == nir_intrinsic_emit_vertex) - emit_output_copies(nir_before_instr(&intrin->instr), state); - } - - return true; -} - -void -nir_lower_outputs_to_temporaries(nir_shader *shader, nir_function *entrypoint) -{ - struct lower_outputs_state state; - - if (shader->stage == MESA_SHADER_TESS_CTRL) - return; - - state.shader = shader; - exec_list_move_nodes_to(&shader->outputs, &state.old_outputs); - - /* Walk over all of the outputs turn each output into a temporary and - * make a new variable for the actual output. - */ - nir_foreach_variable(var, &state.old_outputs) { - nir_variable *output = ralloc(shader, nir_variable); - memcpy(output, var, sizeof *output); - - /* The orignal is now the temporary */ - nir_variable *temp = var; - - /* Reparent the name to the new variable */ - ralloc_steal(output, output->name); - - /* Reparent the constant initializer (if any) */ - ralloc_steal(output, output->constant_initializer); - - /* Give the output a new name with @out-temp appended */ - temp->name = ralloc_asprintf(var, "%s@out-temp", output->name); - temp->data.mode = nir_var_global; - temp->constant_initializer = NULL; - - exec_list_push_tail(&shader->outputs, &output->node); - } - - nir_foreach_function(shader, function) { - if (function->impl == NULL) - continue; - - if (shader->stage == MESA_SHADER_GEOMETRY) { - /* For geometry shaders, we have to emit the output copies right - * before each EmitVertex call. - */ - nir_foreach_block(function->impl, emit_output_copies_block, &state); - } else if (function == entrypoint) { - /* For all other shader types, we need to do the copies right before - * the jumps to the end block. - */ - struct set_entry *block_entry; - set_foreach(function->impl->end_block->predecessors, block_entry) { - struct nir_block *block = (void *)block_entry->key; - emit_output_copies(nir_after_block_before_jump(block), &state); - } - } - - nir_metadata_preserve(function->impl, nir_metadata_block_index | - nir_metadata_dominance); - } - - exec_list_append(&shader->globals, &state.old_outputs); -} diff --git a/src/glsl/nir/nir_lower_phis_to_scalar.c b/src/glsl/nir/nir_lower_phis_to_scalar.c deleted file mode 100644 index dd2abcf72f8..00000000000 --- a/src/glsl/nir/nir_lower_phis_to_scalar.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" - -/* - * Implements a pass that lowers vector phi nodes to scalar phi nodes when - * we don't think it will hurt anything. - */ - -struct lower_phis_to_scalar_state { - void *mem_ctx; - void *dead_ctx; - - /* Hash table marking which phi nodes are scalarizable. The key is - * pointers to phi instructions and the entry is either NULL for not - * scalarizable or non-null for scalarizable. - */ - struct hash_table *phi_table; -}; - -static bool -should_lower_phi(nir_phi_instr *phi, struct lower_phis_to_scalar_state *state); - -static bool -is_phi_src_scalarizable(nir_phi_src *src, - struct lower_phis_to_scalar_state *state) -{ - /* Don't know what to do with non-ssa sources */ - if (!src->src.is_ssa) - return false; - - nir_instr *src_instr = src->src.ssa->parent_instr; - switch (src_instr->type) { - case nir_instr_type_alu: { - nir_alu_instr *src_alu = nir_instr_as_alu(src_instr); - - /* ALU operations with output_size == 0 should be scalarized. We - * will also see a bunch of vecN operations from scalarizing ALU - * operations and, since they can easily be copy-propagated, they - * are ok too. - */ - return nir_op_infos[src_alu->op].output_size == 0 || - src_alu->op == nir_op_vec2 || - src_alu->op == nir_op_vec3 || - src_alu->op == nir_op_vec4; - } - - case nir_instr_type_phi: - /* A phi is scalarizable if we're going to lower it */ - return should_lower_phi(nir_instr_as_phi(src_instr), state); - - case nir_instr_type_load_const: - case nir_instr_type_ssa_undef: - /* These are trivially scalarizable */ - return true; - - case nir_instr_type_intrinsic: { - nir_intrinsic_instr *src_intrin = nir_instr_as_intrinsic(src_instr); - - switch (src_intrin->intrinsic) { - case nir_intrinsic_load_var: - return src_intrin->variables[0]->var->data.mode == nir_var_shader_in || - src_intrin->variables[0]->var->data.mode == nir_var_uniform; - - case nir_intrinsic_interp_var_at_centroid: - case nir_intrinsic_interp_var_at_sample: - case nir_intrinsic_interp_var_at_offset: - case nir_intrinsic_load_uniform: - case nir_intrinsic_load_ubo: - case nir_intrinsic_load_ssbo: - case nir_intrinsic_load_input: - return true; - default: - break; - } - } - - default: - /* We can't scalarize this type of instruction */ - return false; - } -} - -/** - * Determines if the given phi node should be lowered. The only phi nodes - * we will scalarize at the moment are those where all of the sources are - * scalarizable. - * - * The reason for this comes down to coalescing. Since phi sources can't - * swizzle, swizzles on phis have to be resolved by inserting a mov right - * before the phi. The choice then becomes between movs to pick off - * components for a scalar phi or potentially movs to recombine components - * for a vector phi. The problem is that the movs generated to pick off - * the components are almost uncoalescable. We can't coalesce them in NIR - * because we need them to pick off components and we can't coalesce them - * in the backend because the source register is a vector and the - * destination is a scalar that may be used at other places in the program. - * On the other hand, if we have a bunch of scalars going into a vector - * phi, the situation is much better. In this case, if the SSA def is - * generated in the predecessor block to the corresponding phi source, the - * backend code will be an ALU op into a temporary and then a mov into the - * given vector component; this move can almost certainly be coalesced - * away. - */ -static bool -should_lower_phi(nir_phi_instr *phi, struct lower_phis_to_scalar_state *state) -{ - /* Already scalar */ - if (phi->dest.ssa.num_components == 1) - return false; - - struct hash_entry *entry = _mesa_hash_table_search(state->phi_table, phi); - if (entry) - return entry->data != NULL; - - /* Insert an entry and mark it as scalarizable for now. That way - * we don't recurse forever and a cycle in the dependence graph - * won't automatically make us fail to scalarize. - */ - entry = _mesa_hash_table_insert(state->phi_table, phi, (void *)(intptr_t)1); - - bool scalarizable = true; - - nir_foreach_phi_src(phi, src) { - scalarizable = is_phi_src_scalarizable(src, state); - if (!scalarizable) - break; - } - - /* The hash table entry for 'phi' may have changed while recursing the - * dependence graph, so we need to reset it */ - entry = _mesa_hash_table_search(state->phi_table, phi); - assert(entry); - - entry->data = (void *)(intptr_t)scalarizable; - - return scalarizable; -} - -static bool -lower_phis_to_scalar_block(nir_block *block, void *void_state) -{ - struct lower_phis_to_scalar_state *state = void_state; - - /* Find the last phi node in the block */ - nir_phi_instr *last_phi = NULL; - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - last_phi = nir_instr_as_phi(instr); - } - - /* We have to handle the phi nodes in their own pass due to the way - * we're modifying the linked list of instructions. - */ - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - - if (!should_lower_phi(phi, state)) - continue; - - /* Create a vecN operation to combine the results. Most of these - * will be redundant, but copy propagation should clean them up for - * us. No need to add the complexity here. - */ - nir_op vec_op; - switch (phi->dest.ssa.num_components) { - case 2: vec_op = nir_op_vec2; break; - case 3: vec_op = nir_op_vec3; break; - case 4: vec_op = nir_op_vec4; break; - default: unreachable("Invalid number of components"); - } - - nir_alu_instr *vec = nir_alu_instr_create(state->mem_ctx, vec_op); - nir_ssa_dest_init(&vec->instr, &vec->dest.dest, - phi->dest.ssa.num_components, NULL); - vec->dest.write_mask = (1 << phi->dest.ssa.num_components) - 1; - - for (unsigned i = 0; i < phi->dest.ssa.num_components; i++) { - nir_phi_instr *new_phi = nir_phi_instr_create(state->mem_ctx); - nir_ssa_dest_init(&new_phi->instr, &new_phi->dest, 1, NULL); - - vec->src[i].src = nir_src_for_ssa(&new_phi->dest.ssa); - - nir_foreach_phi_src(phi, src) { - /* We need to insert a mov to grab the i'th component of src */ - nir_alu_instr *mov = nir_alu_instr_create(state->mem_ctx, - nir_op_imov); - nir_ssa_dest_init(&mov->instr, &mov->dest.dest, 1, NULL); - mov->dest.write_mask = 1; - nir_src_copy(&mov->src[0].src, &src->src, state->mem_ctx); - mov->src[0].swizzle[0] = i; - - /* Insert at the end of the predecessor but before the jump */ - nir_instr *pred_last_instr = nir_block_last_instr(src->pred); - if (pred_last_instr && pred_last_instr->type == nir_instr_type_jump) - nir_instr_insert_before(pred_last_instr, &mov->instr); - else - nir_instr_insert_after_block(src->pred, &mov->instr); - - nir_phi_src *new_src = ralloc(new_phi, nir_phi_src); - new_src->pred = src->pred; - new_src->src = nir_src_for_ssa(&mov->dest.dest.ssa); - - exec_list_push_tail(&new_phi->srcs, &new_src->node); - } - - nir_instr_insert_before(&phi->instr, &new_phi->instr); - } - - nir_instr_insert_after(&last_phi->instr, &vec->instr); - - nir_ssa_def_rewrite_uses(&phi->dest.ssa, - nir_src_for_ssa(&vec->dest.dest.ssa)); - - ralloc_steal(state->dead_ctx, phi); - nir_instr_remove(&phi->instr); - - /* We're using the safe iterator and inserting all the newly - * scalarized phi nodes before their non-scalarized version so that's - * ok. However, we are also inserting vec operations after all of - * the last phi node so once we get here, we can't trust even the - * safe iterator to stop properly. We have to break manually. - */ - if (instr == &last_phi->instr) - break; - } - - return true; -} - -static void -lower_phis_to_scalar_impl(nir_function_impl *impl) -{ - struct lower_phis_to_scalar_state state; - - state.mem_ctx = ralloc_parent(impl); - state.dead_ctx = ralloc_context(NULL); - state.phi_table = _mesa_hash_table_create(state.dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - nir_foreach_block(impl, lower_phis_to_scalar_block, &state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - ralloc_free(state.dead_ctx); -} - -/** A pass that lowers vector phi nodes to scalar - * - * This pass loops through the blocks and lowers looks for vector phi nodes - * it can lower to scalar phi nodes. Not all phi nodes are lowered. For - * instance, if one of the sources is a non-scalarizable vector, then we - * don't bother lowering because that would generate hard-to-coalesce movs. - */ -void -nir_lower_phis_to_scalar(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - lower_phis_to_scalar_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_returns.c b/src/glsl/nir/nir_lower_returns.c deleted file mode 100644 index 91bb2f7dfeb..00000000000 --- a/src/glsl/nir/nir_lower_returns.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" -#include "nir_control_flow.h" - -struct lower_returns_state { - nir_builder builder; - struct exec_list *cf_list; - nir_loop *loop; - nir_variable *return_flag; -}; - -static bool lower_returns_in_cf_list(struct exec_list *cf_list, - struct lower_returns_state *state); - -static void -predicate_following(nir_cf_node *node, struct lower_returns_state *state) -{ - nir_builder *b = &state->builder; - b->cursor = nir_after_cf_node_and_phis(node); - - if (nir_cursors_equal(b->cursor, nir_after_cf_list(state->cf_list))) - return; /* Nothing to predicate */ - - assert(state->return_flag); - - nir_if *if_stmt = nir_if_create(b->shader); - if_stmt->condition = nir_src_for_ssa(nir_load_var(b, state->return_flag)); - nir_cf_node_insert(b->cursor, &if_stmt->cf_node); - - if (state->loop) { - /* If we're inside of a loop, then all we need to do is insert a - * conditional break. - */ - nir_jump_instr *brk = - nir_jump_instr_create(state->builder.shader, nir_jump_break); - nir_instr_insert(nir_before_cf_list(&if_stmt->then_list), &brk->instr); - } else { - /* Otherwise, we need to actually move everything into the else case - * of the if statement. - */ - nir_cf_list list; - nir_cf_extract(&list, nir_after_cf_node(&if_stmt->cf_node), - nir_after_cf_list(state->cf_list)); - assert(!exec_list_is_empty(&list.list)); - nir_cf_reinsert(&list, nir_before_cf_list(&if_stmt->else_list)); - } -} - -static bool -lower_returns_in_loop(nir_loop *loop, struct lower_returns_state *state) -{ - nir_loop *parent = state->loop; - state->loop = loop; - bool progress = lower_returns_in_cf_list(&loop->body, state); - state->loop = parent; - - /* If the recursive call made progress, then there were returns inside - * of the loop. These would have been lowered to breaks with the return - * flag set to true. We need to predicate everything following the loop - * on the return flag. - */ - if (progress) - predicate_following(&loop->cf_node, state); - - return progress; -} - -static bool -lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) -{ - bool progress; - - progress = lower_returns_in_cf_list(&if_stmt->then_list, state); - progress = lower_returns_in_cf_list(&if_stmt->else_list, state) || progress; - - /* If either of the recursive calls made progress, then there were - * returns inside of the body of the if. If we're in a loop, then these - * were lowered to breaks which automatically skip to the end of the - * loop so we don't have to do anything. If we're not in a loop, then - * all we know is that the return flag is set appropreately and that the - * recursive calls ensured that nothing gets executed *inside* the if - * after a return. In order to ensure nothing outside gets executed - * after a return, we need to predicate everything following on the - * return flag. - */ - if (progress && !state->loop) - predicate_following(&if_stmt->cf_node, state); - - return progress; -} - -static bool -lower_returns_in_block(nir_block *block, struct lower_returns_state *state) -{ - if (block->predecessors->entries == 0 && - block != nir_start_block(state->builder.impl)) { - /* This block is unreachable. Delete it and everything after it. */ - nir_cf_list list; - nir_cf_extract(&list, nir_before_cf_node(&block->cf_node), - nir_after_cf_list(state->cf_list)); - - if (exec_list_is_empty(&list.list)) { - /* There's nothing here, which also means there's nothing in this - * block so we have nothing to do. - */ - return false; - } else { - nir_cf_delete(&list); - return true; - } - } - - nir_instr *last_instr = nir_block_last_instr(block); - if (last_instr == NULL) - return false; - - if (last_instr->type != nir_instr_type_jump) - return false; - - nir_jump_instr *jump = nir_instr_as_jump(last_instr); - if (jump->type != nir_jump_return) - return false; - - nir_instr_remove(&jump->instr); - - nir_builder *b = &state->builder; - b->cursor = nir_after_block(block); - - /* Set the return flag */ - if (state->return_flag == NULL) { - state->return_flag = - nir_local_variable_create(b->impl, glsl_bool_type(), "return"); - - /* Set a default value of false */ - state->return_flag->constant_initializer = - rzalloc(state->return_flag, nir_constant); - } - nir_store_var(b, state->return_flag, nir_imm_int(b, NIR_TRUE), 1); - - if (state->loop) { - /* We're in a loop; we need to break out of it. */ - nir_jump(b, nir_jump_break); - } else { - /* Not in a loop; we'll deal with predicating later*/ - assert(nir_cf_node_next(&block->cf_node) == NULL); - } - - return true; -} - -static bool -lower_returns_in_cf_list(struct exec_list *cf_list, - struct lower_returns_state *state) -{ - bool progress = false; - - struct exec_list *parent_list = state->cf_list; - state->cf_list = cf_list; - - /* We iterate over the list backwards because any given lower call may - * take everything following the given CF node and predicate it. In - * order to avoid recursion/iteration problems, we want everything after - * a given node to already be lowered before this happens. - */ - foreach_list_typed_reverse_safe(nir_cf_node, node, node, cf_list) { - switch (node->type) { - case nir_cf_node_block: - if (lower_returns_in_block(nir_cf_node_as_block(node), state)) - progress = true; - break; - - case nir_cf_node_if: - if (lower_returns_in_if(nir_cf_node_as_if(node), state)) - progress = true; - break; - - case nir_cf_node_loop: - if (lower_returns_in_loop(nir_cf_node_as_loop(node), state)) - progress = true; - break; - - default: - unreachable("Invalid inner CF node type"); - } - } - - state->cf_list = parent_list; - - return progress; -} - -bool -nir_lower_returns_impl(nir_function_impl *impl) -{ - struct lower_returns_state state; - - state.cf_list = &impl->body; - state.loop = NULL; - state.return_flag = NULL; - nir_builder_init(&state.builder, impl); - - bool progress = lower_returns_in_cf_list(&impl->body, &state); - - if (progress) { - nir_metadata_preserve(impl, nir_metadata_none); - nir_repair_ssa_impl(impl); - } - - return progress; -} - -bool -nir_lower_returns(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = nir_lower_returns_impl(function->impl) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_lower_samplers.c b/src/glsl/nir/nir_lower_samplers.c deleted file mode 100644 index e4cd415a9c3..00000000000 --- a/src/glsl/nir/nir_lower_samplers.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2005-2007 Brian Paul All Rights Reserved. - * Copyright (C) 2008 VMware, Inc. All Rights Reserved. - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_builder.h" -#include "program/hash_table.h" -#include "ir_uniform.h" - -#include "main/compiler.h" -#include "main/mtypes.h" -#include "program/prog_parameter.h" -#include "program/program.h" - -/* Calculate the sampler index based on array indicies and also - * calculate the base uniform location for struct members. - */ -static void -calc_sampler_offsets(nir_deref *tail, nir_tex_instr *instr, - unsigned *array_elements, nir_ssa_def **indirect, - nir_builder *b, unsigned *location) -{ - if (tail->child == NULL) - return; - - switch (tail->child->deref_type) { - case nir_deref_type_array: { - nir_deref_array *deref_array = nir_deref_as_array(tail->child); - - assert(deref_array->deref_array_type != nir_deref_array_type_wildcard); - - calc_sampler_offsets(tail->child, instr, array_elements, - indirect, b, location); - instr->sampler_index += deref_array->base_offset * *array_elements; - - if (deref_array->deref_array_type == nir_deref_array_type_indirect) { - nir_ssa_def *mul = - nir_imul(b, nir_imm_int(b, *array_elements), - nir_ssa_for_src(b, deref_array->indirect, 1)); - - nir_instr_rewrite_src(&instr->instr, &deref_array->indirect, - NIR_SRC_INIT); - - if (*indirect) { - *indirect = nir_iadd(b, *indirect, mul); - } else { - *indirect = mul; - } - } - - *array_elements *= glsl_get_length(tail->type); - break; - } - - case nir_deref_type_struct: { - nir_deref_struct *deref_struct = nir_deref_as_struct(tail->child); - *location += glsl_get_record_location_offset(tail->type, deref_struct->index); - calc_sampler_offsets(tail->child, instr, array_elements, - indirect, b, location); - break; - } - - default: - unreachable("Invalid deref type"); - break; - } -} - -static void -lower_sampler(nir_tex_instr *instr, const struct gl_shader_program *shader_program, - gl_shader_stage stage, nir_builder *builder) -{ - if (instr->sampler == NULL) - return; - - /* GLSL only has combined textures/samplers */ - assert(instr->texture == NULL); - - instr->sampler_index = 0; - unsigned location = instr->sampler->var->data.location; - unsigned array_elements = 1; - nir_ssa_def *indirect = NULL; - - builder->cursor = nir_before_instr(&instr->instr); - calc_sampler_offsets(&instr->sampler->deref, instr, &array_elements, - &indirect, builder, &location); - - if (indirect) { - /* First, we have to resize the array of texture sources */ - nir_tex_src *new_srcs = rzalloc_array(instr, nir_tex_src, - instr->num_srcs + 2); - - for (unsigned i = 0; i < instr->num_srcs; i++) { - new_srcs[i].src_type = instr->src[i].src_type; - nir_instr_move_src(&instr->instr, &new_srcs[i].src, - &instr->src[i].src); - } - - ralloc_free(instr->src); - instr->src = new_srcs; - - /* Now we can go ahead and move the source over to being a - * first-class texture source. - */ - instr->src[instr->num_srcs].src_type = nir_tex_src_texture_offset; - instr->num_srcs++; - nir_instr_rewrite_src(&instr->instr, - &instr->src[instr->num_srcs - 1].src, - nir_src_for_ssa(indirect)); - - instr->src[instr->num_srcs].src_type = nir_tex_src_sampler_offset; - instr->num_srcs++; - nir_instr_rewrite_src(&instr->instr, - &instr->src[instr->num_srcs - 1].src, - nir_src_for_ssa(indirect)); - - instr->texture_array_size = array_elements; - } - - if (location > shader_program->NumUniformStorage - 1 || - !shader_program->UniformStorage[location].opaque[stage].active) { - assert(!"cannot return a sampler"); - return; - } - - instr->sampler_index += - shader_program->UniformStorage[location].opaque[stage].index; - - instr->sampler = NULL; - - instr->texture_index = instr->sampler_index; -} - -typedef struct { - nir_builder builder; - const struct gl_shader_program *shader_program; - gl_shader_stage stage; -} lower_state; - -static bool -lower_block_cb(nir_block *block, void *_state) -{ - lower_state *state = (lower_state *) _state; - - nir_foreach_instr(block, instr) { - if (instr->type == nir_instr_type_tex) { - nir_tex_instr *tex_instr = nir_instr_as_tex(instr); - lower_sampler(tex_instr, state->shader_program, state->stage, - &state->builder); - } - } - - return true; -} - -static void -lower_impl(nir_function_impl *impl, const struct gl_shader_program *shader_program, - gl_shader_stage stage) -{ - lower_state state; - - nir_builder_init(&state.builder, impl); - state.shader_program = shader_program; - state.stage = stage; - - nir_foreach_block(impl, lower_block_cb, &state); -} - -void -nir_lower_samplers(nir_shader *shader, - const struct gl_shader_program *shader_program) -{ - nir_foreach_function(shader, function) { - if (function->impl) - lower_impl(function->impl, shader_program, shader->stage); - } -} diff --git a/src/glsl/nir/nir_lower_system_values.c b/src/glsl/nir/nir_lower_system_values.c deleted file mode 100644 index 79f6bedc990..00000000000 --- a/src/glsl/nir/nir_lower_system_values.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include "nir_builder.h" - -struct lower_system_values_state { - nir_builder builder; - bool progress; -}; - -static bool -convert_block(nir_block *block, void *void_state) -{ - struct lower_system_values_state *state = void_state; - - nir_builder *b = &state->builder; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *load_var = nir_instr_as_intrinsic(instr); - - if (load_var->intrinsic != nir_intrinsic_load_var) - continue; - - nir_variable *var = load_var->variables[0]->var; - if (var->data.mode != nir_var_system_value) - continue; - - b->cursor = nir_after_instr(&load_var->instr); - - nir_ssa_def *sysval; - switch (var->data.location) { - case SYSTEM_VALUE_GLOBAL_INVOCATION_ID: { - /* From the GLSL man page for gl_GlobalInvocationID: - * - * "The value of gl_GlobalInvocationID is equal to - * gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID" - */ - - nir_const_value local_size; - local_size.u[0] = b->shader->info.cs.local_size[0]; - local_size.u[1] = b->shader->info.cs.local_size[1]; - local_size.u[2] = b->shader->info.cs.local_size[2]; - - nir_ssa_def *group_id = - nir_load_system_value(b, nir_intrinsic_load_work_group_id, 0); - nir_ssa_def *local_id = - nir_load_system_value(b, nir_intrinsic_load_local_invocation_id, 0); - - sysval = nir_iadd(b, nir_imul(b, group_id, - nir_build_imm(b, 3, local_size)), - local_id); - break; - } - - case SYSTEM_VALUE_LOCAL_INVOCATION_INDEX: { - /* From the GLSL man page for gl_LocalInvocationIndex: - * - * ?The value of gl_LocalInvocationIndex is equal to - * gl_LocalInvocationID.z * gl_WorkGroupSize.x * - * gl_WorkGroupSize.y + gl_LocalInvocationID.y * - * gl_WorkGroupSize.x + gl_LocalInvocationID.x" - */ - nir_ssa_def *local_id = - nir_load_system_value(b, nir_intrinsic_load_local_invocation_id, 0); - - unsigned stride_y = b->shader->info.cs.local_size[0]; - unsigned stride_z = b->shader->info.cs.local_size[0] * - b->shader->info.cs.local_size[1]; - - sysval = nir_iadd(b, nir_imul(b, nir_channel(b, local_id, 2), - nir_imm_int(b, stride_z)), - nir_iadd(b, nir_imul(b, nir_channel(b, local_id, 1), - nir_imm_int(b, stride_y)), - nir_channel(b, local_id, 0))); - break; - } - - case SYSTEM_VALUE_VERTEX_ID: - if (b->shader->options->vertex_id_zero_based) { - sysval = nir_iadd(b, - nir_load_system_value(b, nir_intrinsic_load_vertex_id_zero_base, 0), - nir_load_system_value(b, nir_intrinsic_load_base_vertex, 0)); - } else { - sysval = nir_load_system_value(b, nir_intrinsic_load_vertex_id, 0); - } - break; - - case SYSTEM_VALUE_INSTANCE_INDEX: - sysval = nir_iadd(b, - nir_load_system_value(b, nir_intrinsic_load_instance_id, 0), - nir_load_system_value(b, nir_intrinsic_load_base_instance, 0)); - break; - - default: { - nir_intrinsic_op sysval_op = - nir_intrinsic_from_system_value(var->data.location); - sysval = nir_load_system_value(b, sysval_op, 0); - break; - } /* default */ - } - - nir_ssa_def_rewrite_uses(&load_var->dest.ssa, nir_src_for_ssa(sysval)); - nir_instr_remove(&load_var->instr); - - state->progress = true; - } - - return true; -} - -static bool -convert_impl(nir_function_impl *impl) -{ - struct lower_system_values_state state; - - state.progress = false; - nir_builder_init(&state.builder, impl); - - nir_foreach_block(impl, convert_block, &state); - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - return state.progress; -} - -bool -nir_lower_system_values(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = convert_impl(function->impl) || progress; - } - - exec_list_make_empty(&shader->system_values); - - return progress; -} diff --git a/src/glsl/nir/nir_lower_tex.c b/src/glsl/nir/nir_lower_tex.c deleted file mode 100644 index ae24fb2e16a..00000000000 --- a/src/glsl/nir/nir_lower_tex.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright © 2015 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/* - * This lowering pass supports (as configured via nir_lower_tex_options) - * various texture related conversions: - * + texture projector lowering: converts the coordinate division for - * texture projection to be done in ALU instructions instead of - * asking the texture operation to do so. - * + lowering RECT: converts the un-normalized RECT texture coordinates - * to normalized coordinates with txs plus ALU instructions - * + saturate s/t/r coords: to emulate certain texture clamp/wrap modes, - * inserts instructions to clamp specified coordinates to [0.0, 1.0]. - * Note that this automatically triggers texture projector lowering if - * needed, since clamping must happen after projector lowering. - */ - -#include "nir.h" -#include "nir_builder.h" - -typedef struct { - nir_builder b; - const nir_lower_tex_options *options; - bool progress; -} lower_tex_state; - -static void -project_src(nir_builder *b, nir_tex_instr *tex) -{ - /* Find the projector in the srcs list, if present. */ - unsigned proj_index; - for (proj_index = 0; proj_index < tex->num_srcs; proj_index++) { - if (tex->src[proj_index].src_type == nir_tex_src_projector) - break; - } - if (proj_index == tex->num_srcs) - return; - - b->cursor = nir_before_instr(&tex->instr); - - nir_ssa_def *inv_proj = - nir_frcp(b, nir_ssa_for_src(b, tex->src[proj_index].src, 1)); - - /* Walk through the sources projecting the arguments. */ - for (unsigned i = 0; i < tex->num_srcs; i++) { - switch (tex->src[i].src_type) { - case nir_tex_src_coord: - case nir_tex_src_comparitor: - break; - default: - continue; - } - nir_ssa_def *unprojected = - nir_ssa_for_src(b, tex->src[i].src, nir_tex_instr_src_size(tex, i)); - nir_ssa_def *projected = nir_fmul(b, unprojected, inv_proj); - - /* Array indices don't get projected, so make an new vector with the - * coordinate's array index untouched. - */ - if (tex->is_array && tex->src[i].src_type == nir_tex_src_coord) { - switch (tex->coord_components) { - case 4: - projected = nir_vec4(b, - nir_channel(b, projected, 0), - nir_channel(b, projected, 1), - nir_channel(b, projected, 2), - nir_channel(b, unprojected, 3)); - break; - case 3: - projected = nir_vec3(b, - nir_channel(b, projected, 0), - nir_channel(b, projected, 1), - nir_channel(b, unprojected, 2)); - break; - case 2: - projected = nir_vec2(b, - nir_channel(b, projected, 0), - nir_channel(b, unprojected, 1)); - break; - default: - unreachable("bad texture coord count for array"); - break; - } - } - - nir_instr_rewrite_src(&tex->instr, - &tex->src[i].src, - nir_src_for_ssa(projected)); - } - - /* Now move the later tex sources down the array so that the projector - * disappears. - */ - nir_instr_rewrite_src(&tex->instr, &tex->src[proj_index].src, - NIR_SRC_INIT); - for (unsigned i = proj_index + 1; i < tex->num_srcs; i++) { - tex->src[i-1].src_type = tex->src[i].src_type; - nir_instr_move_src(&tex->instr, &tex->src[i-1].src, &tex->src[i].src); - } - tex->num_srcs--; -} - -static nir_ssa_def * -get_texture_size(nir_builder *b, nir_tex_instr *tex) -{ - b->cursor = nir_before_instr(&tex->instr); - - /* RECT textures should not be array: */ - assert(!tex->is_array); - - nir_tex_instr *txs; - - txs = nir_tex_instr_create(b->shader, 1); - txs->op = nir_texop_txs; - txs->sampler_dim = GLSL_SAMPLER_DIM_RECT; - txs->sampler_index = tex->sampler_index; - txs->dest_type = nir_type_int; - - /* only single src, the lod: */ - txs->src[0].src = nir_src_for_ssa(nir_imm_int(b, 0)); - txs->src[0].src_type = nir_tex_src_lod; - - nir_ssa_dest_init(&txs->instr, &txs->dest, 2, NULL); - nir_builder_instr_insert(b, &txs->instr); - - return nir_i2f(b, &txs->dest.ssa); -} - -static void -lower_rect(nir_builder *b, nir_tex_instr *tex) -{ - nir_ssa_def *txs = get_texture_size(b, tex); - nir_ssa_def *scale = nir_frcp(b, txs); - - /* Walk through the sources normalizing the requested arguments. */ - for (unsigned i = 0; i < tex->num_srcs; i++) { - if (tex->src[i].src_type != nir_tex_src_coord) - continue; - - nir_ssa_def *coords = - nir_ssa_for_src(b, tex->src[i].src, tex->coord_components); - nir_instr_rewrite_src(&tex->instr, - &tex->src[i].src, - nir_src_for_ssa(nir_fmul(b, coords, scale))); - } - - tex->sampler_dim = GLSL_SAMPLER_DIM_2D; -} - -static void -saturate_src(nir_builder *b, nir_tex_instr *tex, unsigned sat_mask) -{ - b->cursor = nir_before_instr(&tex->instr); - - /* Walk through the sources saturating the requested arguments. */ - for (unsigned i = 0; i < tex->num_srcs; i++) { - if (tex->src[i].src_type != nir_tex_src_coord) - continue; - - nir_ssa_def *src = - nir_ssa_for_src(b, tex->src[i].src, tex->coord_components); - - /* split src into components: */ - nir_ssa_def *comp[4]; - - for (unsigned j = 0; j < tex->coord_components; j++) - comp[j] = nir_channel(b, src, j); - - /* clamp requested components, array index does not get clamped: */ - unsigned ncomp = tex->coord_components; - if (tex->is_array) - ncomp--; - - for (unsigned j = 0; j < ncomp; j++) { - if ((1 << j) & sat_mask) { - if (tex->sampler_dim == GLSL_SAMPLER_DIM_RECT) { - /* non-normalized texture coords, so clamp to texture - * size rather than [0.0, 1.0] - */ - nir_ssa_def *txs = get_texture_size(b, tex); - comp[j] = nir_fmax(b, comp[j], nir_imm_float(b, 0.0)); - comp[j] = nir_fmin(b, comp[j], nir_channel(b, txs, j)); - } else { - comp[j] = nir_fsat(b, comp[j]); - } - } - } - - /* and move the result back into a single vecN: */ - src = nir_vec(b, comp, tex->coord_components); - - nir_instr_rewrite_src(&tex->instr, - &tex->src[i].src, - nir_src_for_ssa(src)); - } -} - -static nir_ssa_def * -get_zero_or_one(nir_builder *b, nir_alu_type type, uint8_t swizzle_val) -{ - nir_const_value v; - - memset(&v, 0, sizeof(v)); - - if (swizzle_val == 4) { - v.u[0] = v.u[1] = v.u[2] = v.u[3] = 0; - } else { - assert(swizzle_val == 5); - if (type == nir_type_float) - v.f[0] = v.f[1] = v.f[2] = v.f[3] = 1.0; - else - v.u[0] = v.u[1] = v.u[2] = v.u[3] = 1; - } - - return nir_build_imm(b, 4, v); -} - -static void -swizzle_result(nir_builder *b, nir_tex_instr *tex, const uint8_t swizzle[4]) -{ - assert(tex->dest.is_ssa); - - b->cursor = nir_after_instr(&tex->instr); - - nir_ssa_def *swizzled; - if (tex->op == nir_texop_tg4) { - if (swizzle[tex->component] < 4) { - /* This one's easy */ - tex->component = swizzle[tex->component]; - return; - } else { - swizzled = get_zero_or_one(b, tex->dest_type, swizzle[tex->component]); - } - } else { - assert(nir_tex_instr_dest_size(tex) == 4); - if (swizzle[0] < 4 && swizzle[1] < 4 && - swizzle[2] < 4 && swizzle[3] < 4) { - unsigned swiz[4] = { swizzle[0], swizzle[1], swizzle[2], swizzle[3] }; - /* We have no 0's or 1's, just emit a swizzling MOV */ - swizzled = nir_swizzle(b, &tex->dest.ssa, swiz, 4, false); - } else { - nir_ssa_def *srcs[4]; - for (unsigned i = 0; i < 4; i++) { - if (swizzle[i] < 4) { - srcs[i] = nir_channel(b, &tex->dest.ssa, swizzle[i]); - } else { - srcs[i] = get_zero_or_one(b, tex->dest_type, swizzle[i]); - } - } - swizzled = nir_vec(b, srcs, 4); - } - } - - nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, nir_src_for_ssa(swizzled), - swizzled->parent_instr); -} - -static bool -nir_lower_tex_block(nir_block *block, void *void_state) -{ - lower_tex_state *state = void_state; - nir_builder *b = &state->b; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_tex) - continue; - - nir_tex_instr *tex = nir_instr_as_tex(instr); - bool lower_txp = !!(state->options->lower_txp & (1 << tex->sampler_dim)); - - /* mask of src coords to saturate (clamp): */ - unsigned sat_mask = 0; - - if ((1 << tex->sampler_index) & state->options->saturate_r) - sat_mask |= (1 << 2); /* .z */ - if ((1 << tex->sampler_index) & state->options->saturate_t) - sat_mask |= (1 << 1); /* .y */ - if ((1 << tex->sampler_index) & state->options->saturate_s) - sat_mask |= (1 << 0); /* .x */ - - /* If we are clamping any coords, we must lower projector first - * as clamping happens *after* projection: - */ - if (lower_txp || sat_mask) { - project_src(b, tex); - state->progress = true; - } - - if ((tex->sampler_dim == GLSL_SAMPLER_DIM_RECT) && - state->options->lower_rect) { - lower_rect(b, tex); - state->progress = true; - } - - if (sat_mask) { - saturate_src(b, tex, sat_mask); - state->progress = true; - } - - if (((1 << tex->sampler_index) & state->options->swizzle_result) && - !nir_tex_instr_is_query(tex) && - !(tex->is_shadow && tex->is_new_style_shadow)) { - swizzle_result(b, tex, state->options->swizzles[tex->sampler_index]); - state->progress = true; - } - } - - return true; -} - -static void -nir_lower_tex_impl(nir_function_impl *impl, lower_tex_state *state) -{ - nir_builder_init(&state->b, impl); - - nir_foreach_block(impl, nir_lower_tex_block, state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); -} - -bool -nir_lower_tex(nir_shader *shader, const nir_lower_tex_options *options) -{ - lower_tex_state state; - state.options = options; - state.progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_tex_impl(function->impl, &state); - } - - return state.progress; -} diff --git a/src/glsl/nir/nir_lower_to_source_mods.c b/src/glsl/nir/nir_lower_to_source_mods.c deleted file mode 100644 index 6c4e1f0d3f3..00000000000 --- a/src/glsl/nir/nir_lower_to_source_mods.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" - -/* - * This pass lowers the neg, abs, and sat operations to source modifiers on - * ALU operations to make things nicer for the backend. It's just much - * easier to not have them when we're doing optimizations. - */ - -static bool -nir_lower_to_source_mods_block(nir_block *block, void *state) -{ - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_alu) - continue; - - nir_alu_instr *alu = nir_instr_as_alu(instr); - - for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) { - if (!alu->src[i].src.is_ssa) - continue; - - if (alu->src[i].src.ssa->parent_instr->type != nir_instr_type_alu) - continue; - - nir_alu_instr *parent = nir_instr_as_alu(alu->src[i].src.ssa->parent_instr); - - if (parent->dest.saturate) - continue; - - switch (nir_op_infos[alu->op].input_types[i]) { - case nir_type_float: - if (parent->op != nir_op_fmov) - continue; - break; - case nir_type_int: - if (parent->op != nir_op_imov) - continue; - break; - default: - continue; - } - - /* We can only do a rewrite if the source we are copying is SSA. - * Otherwise, moving the read might invalidly reorder reads/writes - * on a register. - */ - if (!parent->src[0].src.is_ssa) - continue; - - nir_instr_rewrite_src(instr, &alu->src[i].src, parent->src[0].src); - if (alu->src[i].abs) { - /* abs trumps both neg and abs, do nothing */ - } else { - alu->src[i].negate = (alu->src[i].negate != parent->src[0].negate); - alu->src[i].abs |= parent->src[0].abs; - } - - for (int j = 0; j < 4; ++j) { - if (!nir_alu_instr_channel_used(alu, i, j)) - continue; - alu->src[i].swizzle[j] = parent->src[0].swizzle[alu->src[i].swizzle[j]]; - } - - if (list_empty(&parent->dest.dest.ssa.uses) && - list_empty(&parent->dest.dest.ssa.if_uses)) - nir_instr_remove(&parent->instr); - } - - switch (alu->op) { - case nir_op_fsat: - alu->op = nir_op_fmov; - alu->dest.saturate = true; - break; - case nir_op_ineg: - alu->op = nir_op_imov; - alu->src[0].negate = !alu->src[0].negate; - break; - case nir_op_fneg: - alu->op = nir_op_fmov; - alu->src[0].negate = !alu->src[0].negate; - break; - case nir_op_iabs: - alu->op = nir_op_imov; - alu->src[0].abs = true; - alu->src[0].negate = false; - break; - case nir_op_fabs: - alu->op = nir_op_fmov; - alu->src[0].abs = true; - alu->src[0].negate = false; - break; - default: - break; - } - - /* We've covered sources. Now we're going to try and saturate the - * destination if we can. - */ - - if (!alu->dest.dest.is_ssa) - continue; - - /* We can only saturate float destinations */ - if (nir_op_infos[alu->op].output_type != nir_type_float) - continue; - - if (!list_empty(&alu->dest.dest.ssa.if_uses)) - continue; - - bool all_children_are_sat = true; - nir_foreach_use(&alu->dest.dest.ssa, child_src) { - assert(child_src->is_ssa); - nir_instr *child = child_src->parent_instr; - if (child->type != nir_instr_type_alu) { - all_children_are_sat = false; - continue; - } - - nir_alu_instr *child_alu = nir_instr_as_alu(child); - if (child_alu->src[0].negate || child_alu->src[0].abs) { - all_children_are_sat = false; - continue; - } - - if (child_alu->op != nir_op_fsat && - !(child_alu->op == nir_op_fmov && child_alu->dest.saturate)) { - all_children_are_sat = false; - continue; - } - } - - if (!all_children_are_sat) - continue; - - alu->dest.saturate = true; - - nir_foreach_use(&alu->dest.dest.ssa, child_src) { - assert(child_src->is_ssa); - nir_instr *child = child_src->parent_instr; - assert(child->type == nir_instr_type_alu); - nir_alu_instr *child_alu = nir_instr_as_alu(child); - - child_alu->op = nir_op_fmov; - child_alu->dest.saturate = false; - /* We could propagate the dest of our instruction to the - * destinations of the uses here. However, one quick round of - * copy propagation will clean that all up and then we don't have - * the complexity. - */ - } - } - - return true; -} - -static void -nir_lower_to_source_mods_impl(nir_function_impl *impl) -{ - nir_foreach_block(impl, nir_lower_to_source_mods_block, NULL); -} - -void -nir_lower_to_source_mods(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_to_source_mods_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_two_sided_color.c b/src/glsl/nir/nir_lower_two_sided_color.c deleted file mode 100644 index 1294cb89004..00000000000 --- a/src/glsl/nir/nir_lower_two_sided_color.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright © 2015 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Rob Clark <[email protected]> - */ - -#include "nir.h" -#include "nir_builder.h" - -#define MAX_COLORS 2 /* VARYING_SLOT_COL0/COL1 */ - -typedef struct { - nir_builder b; - nir_shader *shader; - nir_variable *face; - struct { - nir_variable *front; /* COLn */ - nir_variable *back; /* BFCn */ - } colors[MAX_COLORS]; - int colors_count; -} lower_2side_state; - - -/* Lowering pass for fragment shaders to emulated two-sided-color. For - * each COLOR input, a corresponding BCOLOR input is created, and bcsel - * instruction used to select front or back color based on FACE. - */ - -static nir_variable * -create_input(nir_shader *shader, unsigned drvloc, gl_varying_slot slot) -{ - nir_variable *var = rzalloc(shader, nir_variable); - - var->data.driver_location = drvloc; - var->type = glsl_vec4_type(); - var->data.mode = nir_var_shader_in; - var->name = ralloc_asprintf(var, "in_%d", drvloc); - var->data.index = 0; - var->data.location = slot; - - exec_list_push_tail(&shader->inputs, &var->node); - - shader->num_inputs++; /* TODO use type_size() */ - - return var; -} - -static nir_ssa_def * -load_input(nir_builder *b, nir_variable *in) -{ - nir_intrinsic_instr *load; - - load = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_input); - load->num_components = 4; - load->const_index[0] = in->data.driver_location; - load->src[0] = nir_src_for_ssa(nir_imm_int(b, 0)); - nir_ssa_dest_init(&load->instr, &load->dest, 4, NULL); - nir_builder_instr_insert(b, &load->instr); - - return &load->dest.ssa; -} - -static int -setup_inputs(lower_2side_state *state) -{ - int maxloc = -1; - - /* find color/face inputs: */ - nir_foreach_variable(var, &state->shader->inputs) { - int loc = var->data.driver_location; - - /* keep track of last used driver-location.. we'll be - * appending BCLr/FACE after last existing input: - */ - maxloc = MAX2(maxloc, loc); - - switch (var->data.location) { - case VARYING_SLOT_COL0: - case VARYING_SLOT_COL1: - assert(state->colors_count < ARRAY_SIZE(state->colors)); - state->colors[state->colors_count].front = var; - state->colors_count++; - break; - case VARYING_SLOT_FACE: - state->face = var; - break; - } - } - - /* if we don't have any color inputs, nothing to do: */ - if (state->colors_count == 0) - return -1; - - /* if we don't already have one, insert a FACE input: */ - if (!state->face) { - state->face = create_input(state->shader, ++maxloc, VARYING_SLOT_FACE); - state->face->data.interpolation = INTERP_QUALIFIER_FLAT; - } - - /* add required back-face color inputs: */ - for (int i = 0; i < state->colors_count; i++) { - gl_varying_slot slot; - - if (state->colors[i].front->data.location == VARYING_SLOT_COL0) - slot = VARYING_SLOT_BFC0; - else - slot = VARYING_SLOT_BFC1; - - state->colors[i].back = create_input(state->shader, ++maxloc, slot); - } - - return 0; -} - -static bool -nir_lower_two_sided_color_block(nir_block *block, void *void_state) -{ - lower_2side_state *state = void_state; - nir_builder *b = &state->b; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); - - if (intr->intrinsic != nir_intrinsic_load_input) - continue; - - int idx; - for (idx = 0; idx < state->colors_count; idx++) { - unsigned drvloc = - state->colors[idx].front->data.driver_location; - if (intr->const_index[0] == drvloc) { - assert(nir_src_as_const_value(intr->src[0])); - break; - } - } - - if (idx == state->colors_count) - continue; - - /* replace load_input(COLn) with - * bcsel(load_input(FACE), load_input(COLn), load_input(BFCn)) - */ - b->cursor = nir_before_instr(&intr->instr); - nir_ssa_def *face = nir_channel(b, load_input(b, state->face), 0); - nir_ssa_def *front = load_input(b, state->colors[idx].front); - nir_ssa_def *back = load_input(b, state->colors[idx].back); - nir_ssa_def *cond = nir_flt(b, face, nir_imm_float(b, 0.0)); - nir_ssa_def *color = nir_bcsel(b, cond, back, front); - - assert(intr->dest.is_ssa); - nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(color)); - } - - return true; -} - -static void -nir_lower_two_sided_color_impl(nir_function_impl *impl, - lower_2side_state *state) -{ - nir_builder *b = &state->b; - - nir_builder_init(b, impl); - - nir_foreach_block(impl, nir_lower_two_sided_color_block, state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); -} - -void -nir_lower_two_sided_color(nir_shader *shader) -{ - lower_2side_state state = { - .shader = shader, - }; - - if (shader->stage != MESA_SHADER_FRAGMENT) - return; - - if (setup_inputs(&state) != 0) - return; - - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_two_sided_color_impl(function->impl, &state); - } - -} diff --git a/src/glsl/nir/nir_lower_var_copies.c b/src/glsl/nir/nir_lower_var_copies.c deleted file mode 100644 index 350e99c3423..00000000000 --- a/src/glsl/nir/nir_lower_var_copies.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" -#include "nir_types.h" - -/* - * Lowers all copy intrinsics to sequences of load/store intrinsics. - */ - -/* Walks down the deref chain and returns the next deref in the chain whose - * child is a wildcard. In other words, given the chain a[1].foo[*].bar, - * this function will return the deref to foo. Calling it a second time - * with the [*].bar, it will return NULL. - */ -static nir_deref * -deref_next_wildcard_parent(nir_deref *deref) -{ - for (nir_deref *tail = deref; tail->child; tail = tail->child) { - if (tail->child->deref_type != nir_deref_type_array) - continue; - - nir_deref_array *arr = nir_deref_as_array(tail->child); - - if (arr->deref_array_type == nir_deref_array_type_wildcard) - return tail; - } - - return NULL; -} - -/* This function recursively walks the given deref chain and replaces the - * given copy instruction with an equivalent sequence load/store - * operations. - * - * @copy_instr The copy instruction to replace; new instructions will be - * inserted before this one - * - * @dest_head The head of the destination variable deref chain - * - * @src_head The head of the source variable deref chain - * - * @dest_tail The current tail of the destination variable deref chain; - * this is used for recursion and external callers of this - * function should call it with tail == head - * - * @src_tail The current tail of the source variable deref chain; - * this is used for recursion and external callers of this - * function should call it with tail == head - * - * @state The current variable lowering state - */ -static void -emit_copy_load_store(nir_intrinsic_instr *copy_instr, - nir_deref_var *dest_head, nir_deref_var *src_head, - nir_deref *dest_tail, nir_deref *src_tail, void *mem_ctx) -{ - /* Find the next pair of wildcards */ - nir_deref *src_arr_parent = deref_next_wildcard_parent(src_tail); - nir_deref *dest_arr_parent = deref_next_wildcard_parent(dest_tail); - - if (src_arr_parent || dest_arr_parent) { - /* Wildcards had better come in matched pairs */ - assert(dest_arr_parent && dest_arr_parent); - - nir_deref_array *src_arr = nir_deref_as_array(src_arr_parent->child); - nir_deref_array *dest_arr = nir_deref_as_array(dest_arr_parent->child); - - unsigned length = glsl_get_length(src_arr_parent->type); - /* The wildcards should represent the same number of elements */ - assert(length == glsl_get_length(dest_arr_parent->type)); - assert(length > 0); - - /* Walk over all of the elements that this wildcard refers to and - * call emit_copy_load_store on each one of them */ - src_arr->deref_array_type = nir_deref_array_type_direct; - dest_arr->deref_array_type = nir_deref_array_type_direct; - for (unsigned i = 0; i < length; i++) { - src_arr->base_offset = i; - dest_arr->base_offset = i; - emit_copy_load_store(copy_instr, dest_head, src_head, - &dest_arr->deref, &src_arr->deref, mem_ctx); - } - src_arr->deref_array_type = nir_deref_array_type_wildcard; - dest_arr->deref_array_type = nir_deref_array_type_wildcard; - } else { - /* In this case, we have no wildcards anymore, so all we have to do - * is just emit the load and store operations. */ - src_tail = nir_deref_tail(src_tail); - dest_tail = nir_deref_tail(dest_tail); - - assert(src_tail->type == dest_tail->type); - - unsigned num_components = glsl_get_vector_elements(src_tail->type); - - nir_intrinsic_instr *load = - nir_intrinsic_instr_create(mem_ctx, nir_intrinsic_load_var); - load->num_components = num_components; - load->variables[0] = nir_deref_as_var(nir_copy_deref(load, &src_head->deref)); - nir_ssa_dest_init(&load->instr, &load->dest, num_components, NULL); - - nir_instr_insert_before(©_instr->instr, &load->instr); - - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(mem_ctx, nir_intrinsic_store_var); - store->num_components = num_components; - store->const_index[0] = (1 << num_components) - 1; - store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest_head->deref)); - - store->src[0].is_ssa = true; - store->src[0].ssa = &load->dest.ssa; - - nir_instr_insert_before(©_instr->instr, &store->instr); - } -} - -/* Lowers a copy instruction to a sequence of load/store instructions - * - * The new instructions are placed before the copy instruction in the IR. - */ -void -nir_lower_var_copy_instr(nir_intrinsic_instr *copy, void *mem_ctx) -{ - assert(copy->intrinsic == nir_intrinsic_copy_var); - emit_copy_load_store(copy, copy->variables[0], copy->variables[1], - ©->variables[0]->deref, - ©->variables[1]->deref, mem_ctx); -} - -static bool -lower_var_copies_block(nir_block *block, void *mem_ctx) -{ - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *copy = nir_instr_as_intrinsic(instr); - if (copy->intrinsic != nir_intrinsic_copy_var) - continue; - - nir_lower_var_copy_instr(copy, mem_ctx); - - nir_instr_remove(©->instr); - ralloc_free(copy); - } - - return true; -} - -static void -lower_var_copies_impl(nir_function_impl *impl) -{ - nir_foreach_block(impl, lower_var_copies_block, ralloc_parent(impl)); -} - -/* Lowers every copy_var instruction in the program to a sequence of - * load/store instructions. - */ -void -nir_lower_var_copies(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - lower_var_copies_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_vars_to_ssa.c b/src/glsl/nir/nir_lower_vars_to_ssa.c deleted file mode 100644 index e1f368d2f2b..00000000000 --- a/src/glsl/nir/nir_lower_vars_to_ssa.c +++ /dev/null @@ -1,751 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" -#include "nir_builder.h" -#include "nir_phi_builder.h" -#include "nir_vla.h" - - -struct deref_node { - struct deref_node *parent; - const struct glsl_type *type; - - bool lower_to_ssa; - - /* Only valid for things that end up in the direct list. - * Note that multiple nir_deref_vars may correspond to this node, but they - * will all be equivalent, so any is as good as the other. - */ - nir_deref_var *deref; - struct exec_node direct_derefs_link; - - struct set *loads; - struct set *stores; - struct set *copies; - - struct nir_phi_builder_value *pb_value; - - struct deref_node *wildcard; - struct deref_node *indirect; - struct deref_node *children[0]; -}; - -struct lower_variables_state { - nir_shader *shader; - void *dead_ctx; - nir_function_impl *impl; - - /* A hash table mapping variables to deref_node data */ - struct hash_table *deref_var_nodes; - - /* A hash table mapping fully-qualified direct dereferences, i.e. - * dereferences with no indirect or wildcard array dereferences, to - * deref_node data. - * - * At the moment, we only lower loads, stores, and copies that can be - * trivially lowered to loads and stores, i.e. copies with no indirects - * and no wildcards. If a part of a variable that is being loaded from - * and/or stored into is also involved in a copy operation with - * wildcards, then we lower that copy operation to loads and stores, but - * otherwise we leave copies with wildcards alone. Since the only derefs - * used in these loads, stores, and trivial copies are ones with no - * wildcards and no indirects, these are precisely the derefs that we - * can actually consider lowering. - */ - struct exec_list direct_deref_nodes; - - /* Controls whether get_deref_node will add variables to the - * direct_deref_nodes table. This is turned on when we are initially - * scanning for load/store instructions. It is then turned off so we - * don't accidentally change the direct_deref_nodes table while we're - * iterating throug it. - */ - bool add_to_direct_deref_nodes; - - struct nir_phi_builder *phi_builder; -}; - -static struct deref_node * -deref_node_create(struct deref_node *parent, - const struct glsl_type *type, nir_shader *shader) -{ - size_t size = sizeof(struct deref_node) + - glsl_get_length(type) * sizeof(struct deref_node *); - - struct deref_node *node = rzalloc_size(shader, size); - node->type = type; - node->parent = parent; - node->deref = NULL; - exec_node_init(&node->direct_derefs_link); - - return node; -} - -/* Returns the deref node associated with the given variable. This will be - * the root of the tree representing all of the derefs of the given variable. - */ -static struct deref_node * -get_deref_node_for_var(nir_variable *var, struct lower_variables_state *state) -{ - struct deref_node *node; - - struct hash_entry *var_entry = - _mesa_hash_table_search(state->deref_var_nodes, var); - - if (var_entry) { - return var_entry->data; - } else { - node = deref_node_create(NULL, var->type, state->dead_ctx); - _mesa_hash_table_insert(state->deref_var_nodes, var, node); - return node; - } -} - -/* Gets the deref_node for the given deref chain and creates it if it - * doesn't yet exist. If the deref is fully-qualified and direct and - * state->add_to_direct_deref_nodes is true, it will be added to the hash - * table of of fully-qualified direct derefs. - */ -static struct deref_node * -get_deref_node(nir_deref_var *deref, struct lower_variables_state *state) -{ - bool is_direct = true; - - /* Start at the base of the chain. */ - struct deref_node *node = get_deref_node_for_var(deref->var, state); - assert(deref->deref.type == node->type); - - for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) { - switch (tail->deref_type) { - case nir_deref_type_struct: { - nir_deref_struct *deref_struct = nir_deref_as_struct(tail); - - assert(deref_struct->index < glsl_get_length(node->type)); - - if (node->children[deref_struct->index] == NULL) - node->children[deref_struct->index] = - deref_node_create(node, tail->type, state->dead_ctx); - - node = node->children[deref_struct->index]; - break; - } - - case nir_deref_type_array: { - nir_deref_array *arr = nir_deref_as_array(tail); - - switch (arr->deref_array_type) { - case nir_deref_array_type_direct: - /* This is possible if a loop unrolls and generates an - * out-of-bounds offset. We need to handle this at least - * somewhat gracefully. - */ - if (arr->base_offset >= glsl_get_length(node->type)) - return NULL; - - if (node->children[arr->base_offset] == NULL) - node->children[arr->base_offset] = - deref_node_create(node, tail->type, state->dead_ctx); - - node = node->children[arr->base_offset]; - break; - - case nir_deref_array_type_indirect: - if (node->indirect == NULL) - node->indirect = deref_node_create(node, tail->type, - state->dead_ctx); - - node = node->indirect; - is_direct = false; - break; - - case nir_deref_array_type_wildcard: - if (node->wildcard == NULL) - node->wildcard = deref_node_create(node, tail->type, - state->dead_ctx); - - node = node->wildcard; - is_direct = false; - break; - - default: - unreachable("Invalid array deref type"); - } - break; - } - default: - unreachable("Invalid deref type"); - } - } - - assert(node); - - /* Only insert if it isn't already in the list. */ - if (is_direct && state->add_to_direct_deref_nodes && - node->direct_derefs_link.next == NULL) { - node->deref = deref; - assert(deref->var != NULL); - exec_list_push_tail(&state->direct_deref_nodes, - &node->direct_derefs_link); - } - - return node; -} - -/* \sa foreach_deref_node_match */ -static bool -foreach_deref_node_worker(struct deref_node *node, nir_deref *deref, - bool (* cb)(struct deref_node *node, - struct lower_variables_state *state), - struct lower_variables_state *state) -{ - if (deref->child == NULL) { - return cb(node, state); - } else { - switch (deref->child->deref_type) { - case nir_deref_type_array: { - nir_deref_array *arr = nir_deref_as_array(deref->child); - assert(arr->deref_array_type == nir_deref_array_type_direct); - if (node->children[arr->base_offset] && - !foreach_deref_node_worker(node->children[arr->base_offset], - deref->child, cb, state)) - return false; - - if (node->wildcard && - !foreach_deref_node_worker(node->wildcard, - deref->child, cb, state)) - return false; - - return true; - } - - case nir_deref_type_struct: { - nir_deref_struct *str = nir_deref_as_struct(deref->child); - return foreach_deref_node_worker(node->children[str->index], - deref->child, cb, state); - } - - default: - unreachable("Invalid deref child type"); - } - } -} - -/* Walks over every "matching" deref_node and calls the callback. A node - * is considered to "match" if either refers to that deref or matches up t - * a wildcard. In other words, the following would match a[6].foo[3].bar: - * - * a[6].foo[3].bar - * a[*].foo[3].bar - * a[6].foo[*].bar - * a[*].foo[*].bar - * - * The given deref must be a full-length and fully qualified (no wildcards - * or indirects) deref chain. - */ -static bool -foreach_deref_node_match(nir_deref_var *deref, - bool (* cb)(struct deref_node *node, - struct lower_variables_state *state), - struct lower_variables_state *state) -{ - nir_deref_var var_deref = *deref; - var_deref.deref.child = NULL; - struct deref_node *node = get_deref_node(&var_deref, state); - - if (node == NULL) - return false; - - return foreach_deref_node_worker(node, &deref->deref, cb, state); -} - -/* \sa deref_may_be_aliased */ -static bool -deref_may_be_aliased_node(struct deref_node *node, nir_deref *deref, - struct lower_variables_state *state) -{ - if (deref->child == NULL) { - return false; - } else { - switch (deref->child->deref_type) { - case nir_deref_type_array: { - nir_deref_array *arr = nir_deref_as_array(deref->child); - if (arr->deref_array_type == nir_deref_array_type_indirect) - return true; - - /* If there is an indirect at this level, we're aliased. */ - if (node->indirect) - return true; - - assert(arr->deref_array_type == nir_deref_array_type_direct); - - if (node->children[arr->base_offset] && - deref_may_be_aliased_node(node->children[arr->base_offset], - deref->child, state)) - return true; - - if (node->wildcard && - deref_may_be_aliased_node(node->wildcard, deref->child, state)) - return true; - - return false; - } - - case nir_deref_type_struct: { - nir_deref_struct *str = nir_deref_as_struct(deref->child); - if (node->children[str->index]) { - return deref_may_be_aliased_node(node->children[str->index], - deref->child, state); - } else { - return false; - } - } - - default: - unreachable("Invalid nir_deref child type"); - } - } -} - -/* Returns true if there are no indirects that can ever touch this deref. - * - * For example, if the given deref is a[6].foo, then any uses of a[i].foo - * would cause this to return false, but a[i].bar would not affect it - * because it's a different structure member. A var_copy involving of - * a[*].bar also doesn't affect it because that can be lowered to entirely - * direct load/stores. - * - * We only support asking this question about fully-qualified derefs. - * Obviously, it's pointless to ask this about indirects, but we also - * rule-out wildcards. Handling Wildcard dereferences would involve - * checking each array index to make sure that there aren't any indirect - * references. - */ -static bool -deref_may_be_aliased(nir_deref_var *deref, - struct lower_variables_state *state) -{ - return deref_may_be_aliased_node(get_deref_node_for_var(deref->var, state), - &deref->deref, state); -} - -static void -register_load_instr(nir_intrinsic_instr *load_instr, - struct lower_variables_state *state) -{ - struct deref_node *node = get_deref_node(load_instr->variables[0], state); - if (node == NULL) - return; - - if (node->loads == NULL) - node->loads = _mesa_set_create(state->dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - _mesa_set_add(node->loads, load_instr); -} - -static void -register_store_instr(nir_intrinsic_instr *store_instr, - struct lower_variables_state *state) -{ - struct deref_node *node = get_deref_node(store_instr->variables[0], state); - if (node == NULL) - return; - - if (node->stores == NULL) - node->stores = _mesa_set_create(state->dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - _mesa_set_add(node->stores, store_instr); -} - -static void -register_copy_instr(nir_intrinsic_instr *copy_instr, - struct lower_variables_state *state) -{ - for (unsigned idx = 0; idx < 2; idx++) { - struct deref_node *node = - get_deref_node(copy_instr->variables[idx], state); - - if (node == NULL) - continue; - - if (node->copies == NULL) - node->copies = _mesa_set_create(state->dead_ctx, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - _mesa_set_add(node->copies, copy_instr); - } -} - -/* Registers all variable uses in the given block. */ -static bool -register_variable_uses_block(nir_block *block, void *void_state) -{ - struct lower_variables_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - switch (intrin->intrinsic) { - case nir_intrinsic_load_var: - register_load_instr(intrin, state); - break; - - case nir_intrinsic_store_var: - register_store_instr(intrin, state); - break; - - case nir_intrinsic_copy_var: - register_copy_instr(intrin, state); - break; - - default: - continue; - } - } - - return true; -} - -/* Walks over all of the copy instructions to or from the given deref_node - * and lowers them to load/store intrinsics. - */ -static bool -lower_copies_to_load_store(struct deref_node *node, - struct lower_variables_state *state) -{ - if (!node->copies) - return true; - - struct set_entry *copy_entry; - set_foreach(node->copies, copy_entry) { - nir_intrinsic_instr *copy = (void *)copy_entry->key; - - nir_lower_var_copy_instr(copy, state->shader); - - for (unsigned i = 0; i < 2; ++i) { - struct deref_node *arg_node = - get_deref_node(copy->variables[i], state); - - /* Only bother removing copy entries for other nodes */ - if (arg_node == NULL || arg_node == node) - continue; - - struct set_entry *arg_entry = _mesa_set_search(arg_node->copies, copy); - assert(arg_entry); - _mesa_set_remove(node->copies, arg_entry); - } - - nir_instr_remove(©->instr); - } - - node->copies = NULL; - - return true; -} - -/* Performs variable renaming by doing a DFS of the dominance tree - * - * This algorithm is very similar to the one outlined in "Efficiently - * Computing Static Single Assignment Form and the Control Dependence - * Graph" by Cytron et. al. The primary difference is that we only put one - * SSA def on the stack per block. - */ -static bool -rename_variables_block(nir_block *block, struct lower_variables_state *state) -{ - nir_builder b; - nir_builder_init(&b, state->impl); - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - switch (intrin->intrinsic) { - case nir_intrinsic_load_var: { - struct deref_node *node = - get_deref_node(intrin->variables[0], state); - - if (node == NULL) { - /* If we hit this path then we are referencing an invalid - * value. Most likely, we unrolled something and are - * reading past the end of some array. In any case, this - * should result in an undefined value. - */ - nir_ssa_undef_instr *undef = - nir_ssa_undef_instr_create(state->shader, - intrin->num_components); - - nir_instr_insert_before(&intrin->instr, &undef->instr); - nir_instr_remove(&intrin->instr); - - nir_ssa_def_rewrite_uses(&intrin->dest.ssa, - nir_src_for_ssa(&undef->def)); - continue; - } - - if (!node->lower_to_ssa) - continue; - - nir_alu_instr *mov = nir_alu_instr_create(state->shader, - nir_op_imov); - mov->src[0].src = nir_src_for_ssa( - nir_phi_builder_value_get_block_def(node->pb_value, block)); - for (unsigned i = intrin->num_components; i < 4; i++) - mov->src[0].swizzle[i] = 0; - - assert(intrin->dest.is_ssa); - - mov->dest.write_mask = (1 << intrin->num_components) - 1; - nir_ssa_dest_init(&mov->instr, &mov->dest.dest, - intrin->num_components, NULL); - - nir_instr_insert_before(&intrin->instr, &mov->instr); - nir_instr_remove(&intrin->instr); - - nir_ssa_def_rewrite_uses(&intrin->dest.ssa, - nir_src_for_ssa(&mov->dest.dest.ssa)); - break; - } - - case nir_intrinsic_store_var: { - struct deref_node *node = - get_deref_node(intrin->variables[0], state); - - if (node == NULL) { - /* Probably an out-of-bounds array store. That should be a - * no-op. */ - nir_instr_remove(&intrin->instr); - continue; - } - - if (!node->lower_to_ssa) - continue; - - assert(intrin->num_components == - glsl_get_vector_elements(node->type)); - - assert(intrin->src[0].is_ssa); - - nir_ssa_def *new_def; - b.cursor = nir_before_instr(&intrin->instr); - - if (intrin->const_index[0] == (1 << intrin->num_components) - 1) { - /* Whole variable store - just copy the source. Note that - * intrin->num_components and intrin->src[0].ssa->num_components - * may differ. - */ - unsigned swiz[4]; - for (unsigned i = 0; i < 4; i++) - swiz[i] = i < intrin->num_components ? i : 0; - - new_def = nir_swizzle(&b, intrin->src[0].ssa, swiz, - intrin->num_components, false); - } else { - nir_ssa_def *old_def = - nir_phi_builder_value_get_block_def(node->pb_value, block); - /* For writemasked store_var intrinsics, we combine the newly - * written values with the existing contents of unwritten - * channels, creating a new SSA value for the whole vector. - */ - nir_ssa_def *srcs[4]; - for (unsigned i = 0; i < intrin->num_components; i++) { - if (intrin->const_index[0] & (1 << i)) { - srcs[i] = nir_channel(&b, intrin->src[0].ssa, i); - } else { - srcs[i] = nir_channel(&b, old_def, i); - } - } - new_def = nir_vec(&b, srcs, intrin->num_components); - } - - assert(new_def->num_components == intrin->num_components); - - nir_phi_builder_value_set_block_def(node->pb_value, block, new_def); - nir_instr_remove(&intrin->instr); - break; - } - - default: - break; - } - } - - for (unsigned i = 0; i < block->num_dom_children; ++i) - rename_variables_block(block->dom_children[i], state); - - return true; -} - -/** Implements a pass to lower variable uses to SSA values - * - * This path walks the list of instructions and tries to lower as many - * local variable load/store operations to SSA defs and uses as it can. - * The process involves four passes: - * - * 1) Iterate over all of the instructions and mark where each local - * variable deref is used in a load, store, or copy. While we're at - * it, we keep track of all of the fully-qualified (no wildcards) and - * fully-direct references we see and store them in the - * direct_deref_nodes hash table. - * - * 2) Walk over the the list of fully-qualified direct derefs generated in - * the previous pass. For each deref, we determine if it can ever be - * aliased, i.e. if there is an indirect reference anywhere that may - * refer to it. If it cannot be aliased, we mark it for lowering to an - * SSA value. At this point, we lower any var_copy instructions that - * use the given deref to load/store operations and, if the deref has a - * constant initializer, we go ahead and add a load_const value at the - * beginning of the function with the initialized value. - * - * 3) Walk over the list of derefs we plan to lower to SSA values and - * insert phi nodes as needed. - * - * 4) Perform "variable renaming" by replacing the load/store instructions - * with SSA definitions and SSA uses. - */ -static bool -nir_lower_vars_to_ssa_impl(nir_function_impl *impl) -{ - struct lower_variables_state state; - - state.shader = impl->function->shader; - state.dead_ctx = ralloc_context(state.shader); - state.impl = impl; - - state.deref_var_nodes = _mesa_hash_table_create(state.dead_ctx, - _mesa_hash_pointer, - _mesa_key_pointer_equal); - exec_list_make_empty(&state.direct_deref_nodes); - - /* Build the initial deref structures and direct_deref_nodes table */ - state.add_to_direct_deref_nodes = true; - nir_foreach_block(impl, register_variable_uses_block, &state); - - bool progress = false; - - nir_metadata_require(impl, nir_metadata_block_index); - - /* We're about to iterate through direct_deref_nodes. Don't modify it. */ - state.add_to_direct_deref_nodes = false; - - foreach_list_typed_safe(struct deref_node, node, direct_derefs_link, - &state.direct_deref_nodes) { - nir_deref_var *deref = node->deref; - - if (deref->var->data.mode != nir_var_local) { - exec_node_remove(&node->direct_derefs_link); - continue; - } - - if (deref_may_be_aliased(deref, &state)) { - exec_node_remove(&node->direct_derefs_link); - continue; - } - - node->lower_to_ssa = true; - progress = true; - - foreach_deref_node_match(deref, lower_copies_to_load_store, &state); - } - - if (!progress) - return false; - - nir_metadata_require(impl, nir_metadata_dominance); - - /* We may have lowered some copy instructions to load/store - * instructions. The uses from the copy instructions hav already been - * removed but we need to rescan to ensure that the uses from the newly - * added load/store instructions are registered. We need this - * information for phi node insertion below. - */ - nir_foreach_block(impl, register_variable_uses_block, &state); - - state.phi_builder = nir_phi_builder_create(state.impl); - - NIR_VLA(BITSET_WORD, store_blocks, BITSET_WORDS(state.impl->num_blocks)); - foreach_list_typed(struct deref_node, node, direct_derefs_link, - &state.direct_deref_nodes) { - if (!node->lower_to_ssa) - continue; - - memset(store_blocks, 0, - BITSET_WORDS(state.impl->num_blocks) * sizeof(*store_blocks)); - - if (node->stores) { - struct set_entry *store_entry; - set_foreach(node->stores, store_entry) { - nir_intrinsic_instr *store = - (nir_intrinsic_instr *)store_entry->key; - BITSET_SET(store_blocks, store->instr.block->index); - } - } - - if (node->deref->var->constant_initializer) - BITSET_SET(store_blocks, 0); - - node->pb_value = - nir_phi_builder_add_value(state.phi_builder, - glsl_get_vector_elements(node->type), - store_blocks); - - if (node->deref->var->constant_initializer) { - nir_load_const_instr *load = - nir_deref_get_const_initializer_load(state.shader, node->deref); - nir_instr_insert_before_cf_list(&impl->body, &load->instr); - nir_phi_builder_value_set_block_def(node->pb_value, - nir_start_block(impl), &load->def); - } - } - - rename_variables_block(nir_start_block(impl), &state); - - nir_phi_builder_finish(state.phi_builder); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - ralloc_free(state.dead_ctx); - - return progress; -} - -void -nir_lower_vars_to_ssa(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_lower_vars_to_ssa_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_lower_vec_to_movs.c b/src/glsl/nir/nir_lower_vec_to_movs.c deleted file mode 100644 index 06d627900c6..00000000000 --- a/src/glsl/nir/nir_lower_vec_to_movs.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" - -/* - * Implements a simple pass that lowers vecN instructions to a series of - * moves with partial writes. - */ - -struct vec_to_movs_state { - nir_function_impl *impl; - bool progress; -}; - -static bool -src_matches_dest_reg(nir_dest *dest, nir_src *src) -{ - if (dest->is_ssa || src->is_ssa) - return false; - - return (dest->reg.reg == src->reg.reg && - dest->reg.base_offset == src->reg.base_offset && - !dest->reg.indirect && - !src->reg.indirect); -} - -/** - * For a given starting writemask channel and corresponding source index in - * the vec instruction, insert a MOV to the vec instruction's dest of all the - * writemask channels that get read from the same src reg. - * - * Returns the writemask of our MOV, so the parent loop calling this knows - * which ones have been processed. - */ -static unsigned -insert_mov(nir_alu_instr *vec, unsigned start_idx, nir_shader *shader) -{ - assert(start_idx < nir_op_infos[vec->op].num_inputs); - - nir_alu_instr *mov = nir_alu_instr_create(shader, nir_op_imov); - nir_alu_src_copy(&mov->src[0], &vec->src[start_idx], mov); - nir_alu_dest_copy(&mov->dest, &vec->dest, mov); - - mov->dest.write_mask = (1u << start_idx); - mov->src[0].swizzle[start_idx] = vec->src[start_idx].swizzle[0]; - mov->src[0].negate = vec->src[start_idx].negate; - mov->src[0].abs = vec->src[start_idx].abs; - - for (unsigned i = start_idx + 1; i < 4; i++) { - if (!(vec->dest.write_mask & (1 << i))) - continue; - - if (nir_srcs_equal(vec->src[i].src, vec->src[start_idx].src) && - vec->src[i].negate == vec->src[start_idx].negate && - vec->src[i].abs == vec->src[start_idx].abs) { - mov->dest.write_mask |= (1 << i); - mov->src[0].swizzle[i] = vec->src[i].swizzle[0]; - } - } - - /* In some situations (if the vecN is involved in a phi-web), we can end - * up with a mov from a register to itself. Some of those channels may end - * up doing nothing and there's no reason to have them as part of the mov. - */ - if (src_matches_dest_reg(&mov->dest.dest, &mov->src[0].src) && - !mov->src[0].abs && !mov->src[0].negate) { - for (unsigned i = 0; i < 4; i++) { - if (mov->src[0].swizzle[i] == i) { - mov->dest.write_mask &= ~(1 << i); - } - } - } - - /* Only emit the instruction if it actually does something */ - if (mov->dest.write_mask) { - nir_instr_insert_before(&vec->instr, &mov->instr); - } else { - ralloc_free(mov); - } - - return mov->dest.write_mask; -} - -static bool -has_replicated_dest(nir_alu_instr *alu) -{ - return alu->op == nir_op_fdot_replicated2 || - alu->op == nir_op_fdot_replicated3 || - alu->op == nir_op_fdot_replicated4 || - alu->op == nir_op_fdph_replicated; -} - -/* Attempts to coalesce the "move" from the given source of the vec to the - * destination of the instruction generating the value. If, for whatever - * reason, we cannot coalesce the mmove, it does nothing and returns 0. We - * can then call insert_mov as normal. - */ -static unsigned -try_coalesce(nir_alu_instr *vec, unsigned start_idx, nir_shader *shader) -{ - assert(start_idx < nir_op_infos[vec->op].num_inputs); - - /* We will only even try if the source is SSA */ - if (!vec->src[start_idx].src.is_ssa) - return 0; - - assert(vec->src[start_idx].src.ssa); - - /* If we are going to do a reswizzle, then the vecN operation must be the - * only use of the source value. We also can't have any source modifiers. - */ - nir_foreach_use(vec->src[start_idx].src.ssa, src) { - if (src->parent_instr != &vec->instr) - return 0; - - nir_alu_src *alu_src = exec_node_data(nir_alu_src, src, src); - if (alu_src->abs || alu_src->negate) - return 0; - } - - if (!list_empty(&vec->src[start_idx].src.ssa->if_uses)) - return 0; - - if (vec->src[start_idx].src.ssa->parent_instr->type != nir_instr_type_alu) - return 0; - - nir_alu_instr *src_alu = - nir_instr_as_alu(vec->src[start_idx].src.ssa->parent_instr); - - if (has_replicated_dest(src_alu)) { - /* The fdot instruction is special: It replicates its result to all - * components. This means that we can always rewrite its destination - * and we don't need to swizzle anything. - */ - } else { - /* We only care about being able to re-swizzle the instruction if it is - * something that we can reswizzle. It must be per-component. The one - * exception to this is the fdotN instructions which implicitly splat - * their result out to all channels. - */ - if (nir_op_infos[src_alu->op].output_size != 0) - return 0; - - /* If we are going to reswizzle the instruction, we can't have any - * non-per-component sources either. - */ - for (unsigned j = 0; j < nir_op_infos[src_alu->op].num_inputs; j++) - if (nir_op_infos[src_alu->op].input_sizes[j] != 0) - return 0; - } - - /* Stash off all of the ALU instruction's swizzles. */ - uint8_t swizzles[4][4]; - for (unsigned j = 0; j < nir_op_infos[src_alu->op].num_inputs; j++) - for (unsigned i = 0; i < 4; i++) - swizzles[j][i] = src_alu->src[j].swizzle[i]; - - unsigned write_mask = 0; - for (unsigned i = start_idx; i < 4; i++) { - if (!(vec->dest.write_mask & (1 << i))) - continue; - - if (!vec->src[i].src.is_ssa || - vec->src[i].src.ssa != &src_alu->dest.dest.ssa) - continue; - - /* At this point, the give vec source matchese up with the ALU - * instruction so we can re-swizzle that component to match. - */ - write_mask |= 1 << i; - if (has_replicated_dest(src_alu)) { - /* Since the destination is a single replicated value, we don't need - * to do any reswizzling - */ - } else { - for (unsigned j = 0; j < nir_op_infos[src_alu->op].num_inputs; j++) - src_alu->src[j].swizzle[i] = swizzles[j][vec->src[i].swizzle[0]]; - } - - /* Clear the no longer needed vec source */ - nir_instr_rewrite_src(&vec->instr, &vec->src[i].src, NIR_SRC_INIT); - } - - nir_instr_rewrite_dest(&src_alu->instr, &src_alu->dest.dest, vec->dest.dest); - src_alu->dest.write_mask = write_mask; - - return write_mask; -} - -static bool -lower_vec_to_movs_block(nir_block *block, void *void_state) -{ - struct vec_to_movs_state *state = void_state; - nir_function_impl *impl = state->impl; - nir_shader *shader = impl->function->shader; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_alu) - continue; - - nir_alu_instr *vec = nir_instr_as_alu(instr); - - switch (vec->op) { - case nir_op_vec2: - case nir_op_vec3: - case nir_op_vec4: - break; - default: - continue; /* The loop */ - } - - if (vec->dest.dest.is_ssa) { - /* Since we insert multiple MOVs, we have a register destination. */ - nir_register *reg = nir_local_reg_create(impl); - reg->num_components = vec->dest.dest.ssa.num_components; - - nir_ssa_def_rewrite_uses(&vec->dest.dest.ssa, nir_src_for_reg(reg)); - - nir_instr_rewrite_dest(&vec->instr, &vec->dest.dest, - nir_dest_for_reg(reg)); - } - - unsigned finished_write_mask = 0; - - /* First, emit a MOV for all the src channels that are in the - * destination reg, in case other values we're populating in the dest - * might overwrite them. - */ - for (unsigned i = 0; i < 4; i++) { - if (!(vec->dest.write_mask & (1 << i))) - continue; - - if (src_matches_dest_reg(&vec->dest.dest, &vec->src[i].src)) { - finished_write_mask |= insert_mov(vec, i, shader); - break; - } - } - - /* Now, emit MOVs for all the other src channels. */ - for (unsigned i = 0; i < 4; i++) { - if (!(vec->dest.write_mask & (1 << i))) - continue; - - if (!(finished_write_mask & (1 << i))) - finished_write_mask |= try_coalesce(vec, i, shader); - - if (!(finished_write_mask & (1 << i))) - finished_write_mask |= insert_mov(vec, i, shader); - } - - nir_instr_remove(&vec->instr); - ralloc_free(vec); - state->progress = true; - } - - return true; -} - -static bool -nir_lower_vec_to_movs_impl(nir_function_impl *impl) -{ - struct vec_to_movs_state state = { impl, false }; - - nir_foreach_block(impl, lower_vec_to_movs_block, &state); - - if (state.progress) { - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - } - - return state.progress; -} - -bool -nir_lower_vec_to_movs(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = nir_lower_vec_to_movs_impl(function->impl) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_metadata.c b/src/glsl/nir/nir_metadata.c deleted file mode 100644 index 61aae73221e..00000000000 --- a/src/glsl/nir/nir_metadata.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - */ - -#include "nir.h" - -/* - * Handles management of the metadata. - */ - -void -nir_metadata_require(nir_function_impl *impl, nir_metadata required) -{ -#define NEEDS_UPDATE(X) ((required & ~impl->valid_metadata) & (X)) - - if (NEEDS_UPDATE(nir_metadata_block_index)) - nir_index_blocks(impl); - if (NEEDS_UPDATE(nir_metadata_dominance)) - nir_calc_dominance_impl(impl); - if (NEEDS_UPDATE(nir_metadata_live_ssa_defs)) - nir_live_ssa_defs_impl(impl); - -#undef NEEDS_UPDATE - - impl->valid_metadata |= required; -} - -void -nir_metadata_preserve(nir_function_impl *impl, nir_metadata preserved) -{ - impl->valid_metadata &= preserved; -} - -#ifdef DEBUG -/** - * Make sure passes properly invalidate metadata (part 1). - * - * Call this before running a pass to set a bogus metadata flag, which will - * only be preserved if the pass forgets to call nir_metadata_preserve(). - */ -void -nir_metadata_set_validation_flag(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) { - function->impl->valid_metadata |= nir_metadata_not_properly_reset; - } - } -} - -/** - * Make sure passes properly invalidate metadata (part 2). - * - * Call this after a pass makes progress to verify that the bogus metadata set by - * the earlier function was properly thrown away. Note that passes may not call - * nir_metadata_preserve() if they don't actually make any changes at all. - */ -void -nir_metadata_check_validation_flag(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) { - assert(!(function->impl->valid_metadata & - nir_metadata_not_properly_reset)); - } - } -} -#endif diff --git a/src/glsl/nir/nir_move_vec_src_uses_to_dest.c b/src/glsl/nir/nir_move_vec_src_uses_to_dest.c deleted file mode 100644 index b5186e6e944..00000000000 --- a/src/glsl/nir/nir_move_vec_src_uses_to_dest.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" - -/* - * Implements a pass that tries to move uses vecN sources to their - * destinations. This is kind of like an inverse copy-propagation pass. - * For instance, if you have - * - * ssa_1 = vec4(a, b, c, d) - * ssa_2 = fadd(a, b) - * - * This will be turned into - * - * ssa_1 = vec4(a, b, c, d) - * ssa_2 = fadd(ssa_1.x, ssa_1.y) - * - * While this is "worse" because it adds a bunch of unneeded dependencies, it - * actually makes it much easier for vec4-based backends to coalesce the MOV's - * that result from the vec4 operation because it doesn't have to worry about - * quite as many reads. - */ - -/* Returns true if the given SSA def dominates the instruction. An SSA def is - * considered to *not* dominate the instruction that defines it. - */ -static bool -ssa_def_dominates_instr(nir_ssa_def *def, nir_instr *instr) -{ - if (instr->index <= def->parent_instr->index) { - return false; - } else if (def->parent_instr->block == instr->block) { - return def->parent_instr->index < instr->index; - } else { - return nir_block_dominates(def->parent_instr->block, instr->block); - } -} - -static bool -move_vec_src_uses_to_dest_block(nir_block *block, void *shader) -{ - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_alu) - continue; - - nir_alu_instr *vec = nir_instr_as_alu(instr); - - switch (vec->op) { - case nir_op_vec2: - case nir_op_vec3: - case nir_op_vec4: - break; - default: - continue; /* The loop */ - } - - /* Can't handle non-SSA vec operations */ - if (!vec->dest.dest.is_ssa) - continue; - - /* Can't handle saturation */ - if (vec->dest.saturate) - continue; - - /* First, mark all of the sources we are going to consider for rewriting - * to the destination - */ - int srcs_remaining = 0; - for (unsigned i = 0; i < nir_op_infos[vec->op].num_inputs; i++) { - /* We can't rewrite a source if it's not in SSA form */ - if (!vec->src[i].src.is_ssa) - continue; - - /* We can't rewrite a source if it has modifiers */ - if (vec->src[i].abs || vec->src[i].negate) - continue; - - srcs_remaining |= 1 << i; - } - - /* We can't actually do anything with this instruction */ - if (srcs_remaining == 0) - continue; - - for (unsigned i; i = ffs(srcs_remaining) - 1, srcs_remaining;) { - int8_t swizzle[4] = { -1, -1, -1, -1 }; - - for (unsigned j = i; j < nir_op_infos[vec->op].num_inputs; j++) { - if (vec->src[j].src.ssa != vec->src[i].src.ssa) - continue; - - /* Mark the given chanle as having been handled */ - srcs_remaining &= ~(1 << j); - - /* Mark the appropreate channel as coming from src j */ - swizzle[vec->src[j].swizzle[0]] = j; - } - - nir_foreach_use_safe(vec->src[i].src.ssa, use) { - if (use->parent_instr == &vec->instr) - continue; - - /* We need to dominate the use if we are going to rewrite it */ - if (!ssa_def_dominates_instr(&vec->dest.dest.ssa, use->parent_instr)) - continue; - - /* For now, we'll just rewrite ALU instructions */ - if (use->parent_instr->type != nir_instr_type_alu) - continue; - - assert(use->is_ssa); - - nir_alu_instr *use_alu = nir_instr_as_alu(use->parent_instr); - - /* Figure out which source we're actually looking at */ - nir_alu_src *use_alu_src = exec_node_data(nir_alu_src, use, src); - unsigned src_idx = use_alu_src - use_alu->src; - assert(src_idx < nir_op_infos[use_alu->op].num_inputs); - - bool can_reswizzle = true; - for (unsigned j = 0; j < 4; j++) { - if (!nir_alu_instr_channel_used(use_alu, src_idx, j)) - continue; - - if (swizzle[use_alu_src->swizzle[j]] == -1) { - can_reswizzle = false; - break; - } - } - - if (!can_reswizzle) - continue; - - /* At this point, we have determined that the given use can be - * reswizzled to actually use the destination of the vecN operation. - * Go ahead and rewrite it as needed. - */ - nir_instr_rewrite_src(use->parent_instr, use, - nir_src_for_ssa(&vec->dest.dest.ssa)); - for (unsigned j = 0; j < 4; j++) { - if (!nir_alu_instr_channel_used(use_alu, src_idx, j)) - continue; - - use_alu_src->swizzle[j] = swizzle[use_alu_src->swizzle[j]]; - } - } - } - } - - return true; -} - -static void -nir_move_vec_src_uses_to_dest_impl(nir_shader *shader, nir_function_impl *impl) -{ - nir_metadata_require(impl, nir_metadata_dominance); - - nir_index_instrs(impl); - nir_foreach_block(impl, move_vec_src_uses_to_dest_block, shader); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); -} - -void -nir_move_vec_src_uses_to_dest(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_move_vec_src_uses_to_dest_impl(shader, function->impl); - } -} diff --git a/src/glsl/nir/nir_normalize_cubemap_coords.c b/src/glsl/nir/nir_normalize_cubemap_coords.c deleted file mode 100644 index 9c15eb8c15c..00000000000 --- a/src/glsl/nir/nir_normalize_cubemap_coords.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand <[email protected]> - */ - -#include "nir.h" -#include "nir_builder.h" - -/** - * This file implements a NIR lowering pass to perform the normalization of - * the cubemap coordinates to have the largest magnitude component be -1.0 - * or 1.0. This is based on the old GLSL IR based pass by Eric. - */ - -struct normalize_cubemap_state { - nir_builder b; - bool progress; -}; - -static bool -normalize_cubemap_coords_block(nir_block *block, void *void_state) -{ - struct normalize_cubemap_state *state = void_state; - nir_builder *b = &state->b; - - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_tex) - continue; - - nir_tex_instr *tex = nir_instr_as_tex(instr); - if (tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE) - continue; - - b->cursor = nir_before_instr(&tex->instr); - - for (unsigned i = 0; i < tex->num_srcs; i++) { - if (tex->src[i].src_type != nir_tex_src_coord) - continue; - - nir_ssa_def *orig_coord = - nir_ssa_for_src(b, tex->src[i].src, nir_tex_instr_src_size(tex, i)); - assert(orig_coord->num_components >= 3); - - nir_ssa_def *abs = nir_fabs(b, orig_coord); - nir_ssa_def *norm = nir_fmax(b, nir_channel(b, abs, 0), - nir_fmax(b, nir_channel(b, abs, 1), - nir_channel(b, abs, 2))); - - nir_ssa_def *normalized = nir_fmul(b, orig_coord, nir_frcp(b, norm)); - - /* Array indices don't have to be normalized, so make a new vector - * with the coordinate's array index untouched. - */ - if (tex->coord_components == 4) { - normalized = nir_vec4(b, - nir_channel(b, normalized, 0), - nir_channel(b, normalized, 1), - nir_channel(b, normalized, 2), - nir_channel(b, orig_coord, 3)); - } - - nir_instr_rewrite_src(&tex->instr, - &tex->src[i].src, - nir_src_for_ssa(normalized)); - - state->progress = true; - } - } - - return true; -} - -static bool -normalize_cubemap_coords_impl(nir_function_impl *impl) -{ - struct normalize_cubemap_state state; - nir_builder_init(&state.b, impl); - state.progress = false; - - nir_foreach_block(impl, normalize_cubemap_coords_block, &state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - return state.progress; -} - -bool -nir_normalize_cubemap_coords(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = normalize_cubemap_coords_impl(function->impl) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_opcodes.py b/src/glsl/nir/nir_opcodes.py deleted file mode 100644 index 0eff89783dd..00000000000 --- a/src/glsl/nir/nir_opcodes.py +++ /dev/null @@ -1,702 +0,0 @@ -#! /usr/bin/env python -# -# Copyright (C) 2014 Connor Abbott -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# -# Authors: -# Connor Abbott ([email protected]) - - -# Class that represents all the information we have about the opcode -# NOTE: this must be kept in sync with nir_op_info - -class Opcode(object): - """Class that represents all the information we have about the opcode - NOTE: this must be kept in sync with nir_op_info - """ - def __init__(self, name, output_size, output_type, input_sizes, - input_types, algebraic_properties, const_expr): - """Parameters: - - - name is the name of the opcode (prepend nir_op_ for the enum name) - - all types are strings that get nir_type_ prepended to them - - input_types is a list of types - - algebraic_properties is a space-seperated string, where nir_op_is_ is - prepended before each entry - - const_expr is an expression or series of statements that computes the - constant value of the opcode given the constant values of its inputs. - - Constant expressions are formed from the variables src0, src1, ..., - src(N-1), where N is the number of arguments. The output of the - expression should be stored in the dst variable. Per-component input - and output variables will be scalars and non-per-component input and - output variables will be a struct with fields named x, y, z, and w - all of the correct type. Input and output variables can be assumed - to already be of the correct type and need no conversion. In - particular, the conversion from the C bool type to/from NIR_TRUE and - NIR_FALSE happens automatically. - - For per-component instructions, the entire expression will be - executed once for each component. For non-per-component - instructions, the expression is expected to store the correct values - in dst.x, dst.y, etc. If "dst" does not exist anywhere in the - constant expression, an assignment to dst will happen automatically - and the result will be equivalent to "dst = <expression>" for - per-component instructions and "dst.x = dst.y = ... = <expression>" - for non-per-component instructions. - """ - assert isinstance(name, str) - assert isinstance(output_size, int) - assert isinstance(output_type, str) - assert isinstance(input_sizes, list) - assert isinstance(input_sizes[0], int) - assert isinstance(input_types, list) - assert isinstance(input_types[0], str) - assert isinstance(algebraic_properties, str) - assert isinstance(const_expr, str) - assert len(input_sizes) == len(input_types) - assert 0 <= output_size <= 4 - for size in input_sizes: - assert 0 <= size <= 4 - if output_size != 0: - assert size != 0 - self.name = name - self.num_inputs = len(input_sizes) - self.output_size = output_size - self.output_type = output_type - self.input_sizes = input_sizes - self.input_types = input_types - self.algebraic_properties = algebraic_properties - self.const_expr = const_expr - -# helper variables for strings -tfloat = "float" -tint = "int" -tbool = "bool" -tuint = "uint" - -commutative = "commutative " -associative = "associative " - -# global dictionary of opcodes -opcodes = {} - -def opcode(name, output_size, output_type, input_sizes, input_types, - algebraic_properties, const_expr): - assert name not in opcodes - opcodes[name] = Opcode(name, output_size, output_type, input_sizes, - input_types, algebraic_properties, const_expr) - -def unop_convert(name, out_type, in_type, const_expr): - opcode(name, 0, out_type, [0], [in_type], "", const_expr) - -def unop(name, ty, const_expr): - opcode(name, 0, ty, [0], [ty], "", const_expr) - -def unop_horiz(name, output_size, output_type, input_size, input_type, - const_expr): - opcode(name, output_size, output_type, [input_size], [input_type], "", - const_expr) - -def unop_reduce(name, output_size, output_type, input_type, prereduce_expr, - reduce_expr, final_expr): - def prereduce(src): - return "(" + prereduce_expr.format(src=src) + ")" - def final(src): - return final_expr.format(src="(" + src + ")") - def reduce_(src0, src1): - return reduce_expr.format(src0=src0, src1=src1) - src0 = prereduce("src0.x") - src1 = prereduce("src0.y") - src2 = prereduce("src0.z") - src3 = prereduce("src0.w") - unop_horiz(name + "2", output_size, output_type, 2, input_type, - final(reduce_(src0, src1))) - unop_horiz(name + "3", output_size, output_type, 3, input_type, - final(reduce_(reduce_(src0, src1), src2))) - unop_horiz(name + "4", output_size, output_type, 4, input_type, - final(reduce_(reduce_(src0, src1), reduce_(src2, src3)))) - - -# These two move instructions differ in what modifiers they support and what -# the negate modifier means. Otherwise, they are identical. -unop("fmov", tfloat, "src0") -unop("imov", tint, "src0") - -unop("ineg", tint, "-src0") -unop("fneg", tfloat, "-src0") -unop("inot", tint, "~src0") # invert every bit of the integer -unop("fnot", tfloat, "(src0 == 0.0f) ? 1.0f : 0.0f") -unop("fsign", tfloat, "(src0 == 0.0f) ? 0.0f : ((src0 > 0.0f) ? 1.0f : -1.0f)") -unop("isign", tint, "(src0 == 0) ? 0 : ((src0 > 0) ? 1 : -1)") -unop("iabs", tint, "(src0 < 0) ? -src0 : src0") -unop("fabs", tfloat, "fabsf(src0)") -unop("fsat", tfloat, "(src0 > 1.0f) ? 1.0f : ((src0 <= 0.0f) ? 0.0f : src0)") -unop("frcp", tfloat, "1.0f / src0") -unop("frsq", tfloat, "1.0f / sqrtf(src0)") -unop("fsqrt", tfloat, "sqrtf(src0)") -unop("fexp2", tfloat, "exp2f(src0)") -unop("flog2", tfloat, "log2f(src0)") -unop_convert("f2i", tint, tfloat, "src0") # Float-to-integer conversion. -unop_convert("f2u", tuint, tfloat, "src0") # Float-to-unsigned conversion -unop_convert("i2f", tfloat, tint, "src0") # Integer-to-float conversion. -# Float-to-boolean conversion -unop_convert("f2b", tbool, tfloat, "src0 != 0.0f") -# Boolean-to-float conversion -unop_convert("b2f", tfloat, tbool, "src0 ? 1.0f : 0.0f") -# Int-to-boolean conversion -unop_convert("i2b", tbool, tint, "src0 != 0") -unop_convert("b2i", tint, tbool, "src0 ? 1 : 0") # Boolean-to-int conversion -unop_convert("u2f", tfloat, tuint, "src0") # Unsigned-to-float conversion. - -# Unary floating-point rounding operations. - - -unop("ftrunc", tfloat, "truncf(src0)") -unop("fceil", tfloat, "ceilf(src0)") -unop("ffloor", tfloat, "floorf(src0)") -unop("ffract", tfloat, "src0 - floorf(src0)") -unop("fround_even", tfloat, "_mesa_roundevenf(src0)") - -unop("fquantize2f16", tfloat, "(fabs(src0) < ldexpf(1.0, -14)) ? copysignf(0.0f, src0) : _mesa_half_to_float(_mesa_float_to_half(src0))") - -# Trigonometric operations. - - -unop("fsin", tfloat, "sinf(src0)") -unop("fcos", tfloat, "cosf(src0)") - - -# Partial derivatives. - - -unop("fddx", tfloat, "0.0f") # the derivative of a constant is 0. -unop("fddy", tfloat, "0.0f") -unop("fddx_fine", tfloat, "0.0f") -unop("fddy_fine", tfloat, "0.0f") -unop("fddx_coarse", tfloat, "0.0f") -unop("fddy_coarse", tfloat, "0.0f") - - -# Floating point pack and unpack operations. - -def pack_2x16(fmt): - unop_horiz("pack_" + fmt + "_2x16", 1, tuint, 2, tfloat, """ -dst.x = (uint32_t) pack_fmt_1x16(src0.x); -dst.x |= ((uint32_t) pack_fmt_1x16(src0.y)) << 16; -""".replace("fmt", fmt)) - -def pack_4x8(fmt): - unop_horiz("pack_" + fmt + "_4x8", 1, tuint, 4, tfloat, """ -dst.x = (uint32_t) pack_fmt_1x8(src0.x); -dst.x |= ((uint32_t) pack_fmt_1x8(src0.y)) << 8; -dst.x |= ((uint32_t) pack_fmt_1x8(src0.z)) << 16; -dst.x |= ((uint32_t) pack_fmt_1x8(src0.w)) << 24; -""".replace("fmt", fmt)) - -def unpack_2x16(fmt): - unop_horiz("unpack_" + fmt + "_2x16", 2, tfloat, 1, tuint, """ -dst.x = unpack_fmt_1x16((uint16_t)(src0.x & 0xffff)); -dst.y = unpack_fmt_1x16((uint16_t)(src0.x << 16)); -""".replace("fmt", fmt)) - -def unpack_4x8(fmt): - unop_horiz("unpack_" + fmt + "_4x8", 4, tfloat, 1, tuint, """ -dst.x = unpack_fmt_1x8((uint8_t)(src0.x & 0xff)); -dst.y = unpack_fmt_1x8((uint8_t)((src0.x >> 8) & 0xff)); -dst.z = unpack_fmt_1x8((uint8_t)((src0.x >> 16) & 0xff)); -dst.w = unpack_fmt_1x8((uint8_t)(src0.x >> 24)); -""".replace("fmt", fmt)) - - -pack_2x16("snorm") -pack_4x8("snorm") -pack_2x16("unorm") -pack_4x8("unorm") -pack_2x16("half") -unpack_2x16("snorm") -unpack_4x8("snorm") -unpack_2x16("unorm") -unpack_4x8("unorm") -unpack_2x16("half") - -unop_horiz("pack_uvec2_to_uint", 0, tuint, 2, tuint, """ -dst = (src0.x & 0xffff) | (src0.y >> 16); -""") - -unop_horiz("pack_uvec4_to_uint", 0, tuint, 4, tuint, """ -dst = (src0.x << 0) | - (src0.y << 8) | - (src0.z << 16) | - (src0.w << 24); -""") - -# Lowered floating point unpacking operations. - - -unop_horiz("unpack_half_2x16_split_x", 1, tfloat, 1, tuint, - "unpack_half_1x16((uint16_t)(src0.x & 0xffff))") -unop_horiz("unpack_half_2x16_split_y", 1, tfloat, 1, tuint, - "unpack_half_1x16((uint16_t)(src0.x >> 16))") - - -# Bit operations, part of ARB_gpu_shader5. - - -unop("bitfield_reverse", tuint, """ -/* we're not winning any awards for speed here, but that's ok */ -dst = 0; -for (unsigned bit = 0; bit < 32; bit++) - dst |= ((src0 >> bit) & 1) << (31 - bit); -""") -unop("bit_count", tuint, """ -dst = 0; -for (unsigned bit = 0; bit < 32; bit++) { - if ((src0 >> bit) & 1) - dst++; -} -""") - -unop_convert("ufind_msb", tint, tuint, """ -dst = -1; -for (int bit = 31; bit > 0; bit--) { - if ((src0 >> bit) & 1) { - dst = bit; - break; - } -} -""") - -unop("ifind_msb", tint, """ -dst = -1; -for (int bit = 31; bit >= 0; bit--) { - /* If src0 < 0, we're looking for the first 0 bit. - * if src0 >= 0, we're looking for the first 1 bit. - */ - if ((((src0 >> bit) & 1) && (src0 >= 0)) || - (!((src0 >> bit) & 1) && (src0 < 0))) { - dst = bit; - break; - } -} -""") - -unop("find_lsb", tint, """ -dst = -1; -for (unsigned bit = 0; bit < 32; bit++) { - if ((src0 >> bit) & 1) { - dst = bit; - break; - } -} -""") - - -for i in xrange(1, 5): - for j in xrange(1, 5): - unop_horiz("fnoise{0}_{1}".format(i, j), i, tfloat, j, tfloat, "0.0f") - -def binop_convert(name, out_type, in_type, alg_props, const_expr): - opcode(name, 0, out_type, [0, 0], [in_type, in_type], alg_props, const_expr) - -def binop(name, ty, alg_props, const_expr): - binop_convert(name, ty, ty, alg_props, const_expr) - -def binop_compare(name, ty, alg_props, const_expr): - binop_convert(name, tbool, ty, alg_props, const_expr) - -def binop_horiz(name, out_size, out_type, src1_size, src1_type, src2_size, - src2_type, const_expr): - opcode(name, out_size, out_type, [src1_size, src2_size], [src1_type, src2_type], - "", const_expr) - -def binop_reduce(name, output_size, output_type, src_type, prereduce_expr, - reduce_expr, final_expr): - def final(src): - return final_expr.format(src= "(" + src + ")") - def reduce_(src0, src1): - return reduce_expr.format(src0=src0, src1=src1) - def prereduce(src0, src1): - return "(" + prereduce_expr.format(src0=src0, src1=src1) + ")" - src0 = prereduce("src0.x", "src1.x") - src1 = prereduce("src0.y", "src1.y") - src2 = prereduce("src0.z", "src1.z") - src3 = prereduce("src0.w", "src1.w") - opcode(name + "2", output_size, output_type, - [2, 2], [src_type, src_type], commutative, - final(reduce_(src0, src1))) - opcode(name + "3", output_size, output_type, - [3, 3], [src_type, src_type], commutative, - final(reduce_(reduce_(src0, src1), src2))) - opcode(name + "4", output_size, output_type, - [4, 4], [src_type, src_type], commutative, - final(reduce_(reduce_(src0, src1), reduce_(src2, src3)))) - -binop("fadd", tfloat, commutative + associative, "src0 + src1") -binop("iadd", tint, commutative + associative, "src0 + src1") -binop("fsub", tfloat, "", "src0 - src1") -binop("isub", tint, "", "src0 - src1") - -binop("fmul", tfloat, commutative + associative, "src0 * src1") -# low 32-bits of signed/unsigned integer multiply -binop("imul", tint, commutative + associative, "src0 * src1") -# high 32-bits of signed integer multiply -binop("imul_high", tint, commutative, - "(int32_t)(((int64_t) src0 * (int64_t) src1) >> 32)") -# high 32-bits of unsigned integer multiply -binop("umul_high", tuint, commutative, - "(uint32_t)(((uint64_t) src0 * (uint64_t) src1) >> 32)") - -binop("fdiv", tfloat, "", "src0 / src1") -binop("idiv", tint, "", "src0 / src1") -binop("udiv", tuint, "", "src0 / src1") - -# returns a boolean representing the carry resulting from the addition of -# the two unsigned arguments. - -binop_convert("uadd_carry", tuint, tuint, commutative, "src0 + src1 < src0") - -# returns a boolean representing the borrow resulting from the subtraction -# of the two unsigned arguments. - -binop_convert("usub_borrow", tuint, tuint, "", "src0 < src1") - -binop("umod", tuint, "", "src1 == 0 ? 0 : src0 % src1") - -# For signed integers, there are several different possible definitions of -# "modulus" or "remainder". We follow the conventions used by LLVM and -# SPIR-V. The irem opcode implements the standard C/C++ signed "%" -# operation while the imod opcode implements the more mathematical -# "modulus" operation. For details on the difference, see -# -# http://mathforum.org/library/drmath/view/52343.html - -binop("irem", tint, "", "src1 == 0 ? 0 : src0 % src1") -binop("imod", tint, "", - "src1 == 0 ? 0 : ((src0 % src1 == 0 || (src0 >= 0) == (src1 >= 0)) ?" - " src0 % src1 : src0 % src1 + src1)") -binop("fmod", tfloat, "", "src0 - src1 * floorf(src0 / src1)") -binop("frem", tfloat, "", "src0 - src1 * truncf(src0 / src1)") - -# -# Comparisons -# - - -# these integer-aware comparisons return a boolean (0 or ~0) - -binop_compare("flt", tfloat, "", "src0 < src1") -binop_compare("fge", tfloat, "", "src0 >= src1") -binop_compare("feq", tfloat, commutative, "src0 == src1") -binop_compare("fne", tfloat, commutative, "src0 != src1") -binop_compare("ilt", tint, "", "src0 < src1") -binop_compare("ige", tint, "", "src0 >= src1") -binop_compare("ieq", tint, commutative, "src0 == src1") -binop_compare("ine", tint, commutative, "src0 != src1") -binop_compare("ult", tuint, "", "src0 < src1") -binop_compare("uge", tuint, "", "src0 >= src1") - -# integer-aware GLSL-style comparisons that compare floats and ints - -binop_reduce("ball_fequal", 1, tbool, tfloat, "{src0} == {src1}", - "{src0} && {src1}", "{src}") -binop_reduce("bany_fnequal", 1, tbool, tfloat, "{src0} != {src1}", - "{src0} || {src1}", "{src}") -binop_reduce("ball_iequal", 1, tbool, tint, "{src0} == {src1}", - "{src0} && {src1}", "{src}") -binop_reduce("bany_inequal", 1, tbool, tint, "{src0} != {src1}", - "{src0} || {src1}", "{src}") - -# non-integer-aware GLSL-style comparisons that return 0.0 or 1.0 - -binop_reduce("fall_equal", 1, tfloat, tfloat, "{src0} == {src1}", - "{src0} && {src1}", "{src} ? 1.0f : 0.0f") -binop_reduce("fany_nequal", 1, tfloat, tfloat, "{src0} != {src1}", - "{src0} || {src1}", "{src} ? 1.0f : 0.0f") - -# These comparisons for integer-less hardware return 1.0 and 0.0 for true -# and false respectively - -binop("slt", tfloat, "", "(src0 < src1) ? 1.0f : 0.0f") # Set on Less Than -binop("sge", tfloat, "", "(src0 >= src1) ? 1.0f : 0.0f") # Set on Greater or Equal -binop("seq", tfloat, commutative, "(src0 == src1) ? 1.0f : 0.0f") # Set on Equal -binop("sne", tfloat, commutative, "(src0 != src1) ? 1.0f : 0.0f") # Set on Not Equal - - -binop("ishl", tint, "", "src0 << src1") -binop("ishr", tint, "", "src0 >> src1") -binop("ushr", tuint, "", "src0 >> src1") - -# bitwise logic operators -# -# These are also used as boolean and, or, xor for hardware supporting -# integers. - - -binop("iand", tuint, commutative + associative, "src0 & src1") -binop("ior", tuint, commutative + associative, "src0 | src1") -binop("ixor", tuint, commutative + associative, "src0 ^ src1") - - -# floating point logic operators -# -# These use (src != 0.0) for testing the truth of the input, and output 1.0 -# for true and 0.0 for false - -binop("fand", tfloat, commutative, - "((src0 != 0.0f) && (src1 != 0.0f)) ? 1.0f : 0.0f") -binop("for", tfloat, commutative, - "((src0 != 0.0f) || (src1 != 0.0f)) ? 1.0f : 0.0f") -binop("fxor", tfloat, commutative, - "(src0 != 0.0f && src1 == 0.0f) || (src0 == 0.0f && src1 != 0.0f) ? 1.0f : 0.0f") - -binop_reduce("fdot", 1, tfloat, tfloat, "{src0} * {src1}", "{src0} + {src1}", - "{src}") - -binop_reduce("fdot_replicated", 4, tfloat, tfloat, - "{src0} * {src1}", "{src0} + {src1}", "{src}") - -opcode("fdph", 1, tfloat, [3, 4], [tfloat, tfloat], "", - "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w") -opcode("fdph_replicated", 4, tfloat, [3, 4], [tfloat, tfloat], "", - "src0.x * src1.x + src0.y * src1.y + src0.z * src1.z + src1.w") - -binop("fmin", tfloat, "", "fminf(src0, src1)") -binop("imin", tint, commutative + associative, "src1 > src0 ? src0 : src1") -binop("umin", tuint, commutative + associative, "src1 > src0 ? src0 : src1") -binop("fmax", tfloat, "", "fmaxf(src0, src1)") -binop("imax", tint, commutative + associative, "src1 > src0 ? src1 : src0") -binop("umax", tuint, commutative + associative, "src1 > src0 ? src1 : src0") - -# Saturated vector add for 4 8bit ints. -binop("usadd_4x8", tint, commutative + associative, """ -dst = 0; -for (int i = 0; i < 32; i += 8) { - dst |= MIN2(((src0 >> i) & 0xff) + ((src1 >> i) & 0xff), 0xff) << i; -} -""") - -# Saturated vector subtract for 4 8bit ints. -binop("ussub_4x8", tint, "", """ -dst = 0; -for (int i = 0; i < 32; i += 8) { - int src0_chan = (src0 >> i) & 0xff; - int src1_chan = (src1 >> i) & 0xff; - if (src0_chan > src1_chan) - dst |= (src0_chan - src1_chan) << i; -} -""") - -# vector min for 4 8bit ints. -binop("umin_4x8", tint, commutative + associative, """ -dst = 0; -for (int i = 0; i < 32; i += 8) { - dst |= MIN2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i; -} -""") - -# vector max for 4 8bit ints. -binop("umax_4x8", tint, commutative + associative, """ -dst = 0; -for (int i = 0; i < 32; i += 8) { - dst |= MAX2((src0 >> i) & 0xff, (src1 >> i) & 0xff) << i; -} -""") - -# unorm multiply: (a * b) / 255. -binop("umul_unorm_4x8", tint, commutative + associative, """ -dst = 0; -for (int i = 0; i < 32; i += 8) { - int src0_chan = (src0 >> i) & 0xff; - int src1_chan = (src1 >> i) & 0xff; - dst |= ((src0_chan * src1_chan) / 255) << i; -} -""") - -binop("fpow", tfloat, "", "powf(src0, src1)") - -binop_horiz("pack_half_2x16_split", 1, tuint, 1, tfloat, 1, tfloat, - "pack_half_1x16(src0.x) | (pack_half_1x16(src1.x) << 16)") - -# bfm implements the behavior of the first operation of the SM5 "bfi" assembly -# and that of the "bfi1" i965 instruction. That is, it has undefined behavior -# if either of its arguments are 32. -binop_convert("bfm", tuint, tint, "", """ -int bits = src0, offset = src1; -if (offset < 0 || bits < 0 || offset > 31 || bits > 31 || offset + bits > 32) - dst = 0; /* undefined */ -else - dst = ((1u << bits) - 1) << offset; -""") - -opcode("ldexp", 0, tfloat, [0, 0], [tfloat, tint], "", """ -dst = ldexpf(src0, src1); -/* flush denormals to zero. */ -if (!isnormal(dst)) - dst = copysignf(0.0f, src0); -""") - -# Combines the first component of each input to make a 2-component vector. - -binop_horiz("vec2", 2, tuint, 1, tuint, 1, tuint, """ -dst.x = src0.x; -dst.y = src1.x; -""") - -# Byte extraction -binop("extract_ubyte", tuint, "", "(uint8_t)(src0 >> (src1 * 8))") -binop("extract_ibyte", tint, "", "(int8_t)(src0 >> (src1 * 8))") - -# Word extraction -binop("extract_uword", tuint, "", "(uint16_t)(src0 >> (src1 * 16))") -binop("extract_iword", tint, "", "(int16_t)(src0 >> (src1 * 16))") - - -def triop(name, ty, const_expr): - opcode(name, 0, ty, [0, 0, 0], [ty, ty, ty], "", const_expr) -def triop_horiz(name, output_size, src1_size, src2_size, src3_size, const_expr): - opcode(name, output_size, tuint, - [src1_size, src2_size, src3_size], - [tuint, tuint, tuint], "", const_expr) - -triop("ffma", tfloat, "src0 * src1 + src2") - -triop("flrp", tfloat, "src0 * (1 - src2) + src1 * src2") - -# Conditional Select -# -# A vector conditional select instruction (like ?:, but operating per- -# component on vectors). There are two versions, one for floating point -# bools (0.0 vs 1.0) and one for integer bools (0 vs ~0). - - -triop("fcsel", tfloat, "(src0 != 0.0f) ? src1 : src2") -opcode("bcsel", 0, tuint, [0, 0, 0], - [tbool, tuint, tuint], "", "src0 ? src1 : src2") - -# SM5 bfi assembly -triop("bfi", tuint, """ -unsigned mask = src0, insert = src1, base = src2; -if (mask == 0) { - dst = base; -} else { - unsigned tmp = mask; - while (!(tmp & 1)) { - tmp >>= 1; - insert <<= 1; - } - dst = (base & ~mask) | (insert & mask); -} -""") - -# SM5 ubfe/ibfe assembly -opcode("ubfe", 0, tuint, - [0, 0, 0], [tuint, tint, tint], "", """ -unsigned base = src0; -int offset = src1, bits = src2; -if (bits == 0) { - dst = 0; -} else if (bits < 0 || offset < 0) { - dst = 0; /* undefined */ -} else if (offset + bits < 32) { - dst = (base << (32 - bits - offset)) >> (32 - bits); -} else { - dst = base >> offset; -} -""") -opcode("ibfe", 0, tint, - [0, 0, 0], [tint, tint, tint], "", """ -int base = src0; -int offset = src1, bits = src2; -if (bits == 0) { - dst = 0; -} else if (bits < 0 || offset < 0) { - dst = 0; /* undefined */ -} else if (offset + bits < 32) { - dst = (base << (32 - bits - offset)) >> (32 - bits); -} else { - dst = base >> offset; -} -""") - -# GLSL bitfieldExtract() -opcode("ubitfield_extract", 0, tuint, - [0, 0, 0], [tuint, tint, tint], "", """ -unsigned base = src0; -int offset = src1, bits = src2; -if (bits == 0) { - dst = 0; -} else if (bits < 0 || offset < 0 || offset + bits > 32) { - dst = 0; /* undefined per the spec */ -} else { - dst = (base >> offset) & ((1ull << bits) - 1); -} -""") -opcode("ibitfield_extract", 0, tint, - [0, 0, 0], [tint, tint, tint], "", """ -int base = src0; -int offset = src1, bits = src2; -if (bits == 0) { - dst = 0; -} else if (offset < 0 || bits < 0 || offset + bits > 32) { - dst = 0; -} else { - dst = (base << (32 - offset - bits)) >> offset; /* use sign-extending shift */ -} -""") - -# Combines the first component of each input to make a 3-component vector. - -triop_horiz("vec3", 3, 1, 1, 1, """ -dst.x = src0.x; -dst.y = src1.x; -dst.z = src2.x; -""") - -def quadop_horiz(name, output_size, src1_size, src2_size, src3_size, - src4_size, const_expr): - opcode(name, output_size, tuint, - [src1_size, src2_size, src3_size, src4_size], - [tuint, tuint, tuint, tuint], - "", const_expr) - -opcode("bitfield_insert", 0, tuint, [0, 0, 0, 0], - [tuint, tuint, tint, tint], "", """ -unsigned base = src0, insert = src1; -int offset = src2, bits = src3; -if (bits == 0) { - dst = 0; -} else if (offset < 0 || bits < 0 || bits + offset > 32) { - dst = 0; -} else { - unsigned mask = ((1ull << bits) - 1) << offset; - dst = (base & ~mask) | ((insert << bits) & mask); -} -""") - -quadop_horiz("vec4", 4, 1, 1, 1, 1, """ -dst.x = src0.x; -dst.y = src1.x; -dst.z = src2.x; -dst.w = src3.x; -""") - - diff --git a/src/glsl/nir/nir_opcodes_c.py b/src/glsl/nir/nir_opcodes_c.py deleted file mode 100644 index 7049c5be676..00000000000 --- a/src/glsl/nir/nir_opcodes_c.py +++ /dev/null @@ -1,55 +0,0 @@ -#! /usr/bin/env python -# -# Copyright (C) 2014 Connor Abbott -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# -# Authors: -# Connor Abbott ([email protected]) - -from nir_opcodes import opcodes -from mako.template import Template - -template = Template(""" -#include "nir.h" - -const nir_op_info nir_op_infos[nir_num_opcodes] = { -% for name, opcode in sorted(opcodes.iteritems()): -{ - .name = "${name}", - .num_inputs = ${opcode.num_inputs}, - .output_size = ${opcode.output_size}, - .output_type = ${"nir_type_" + opcode.output_type}, - .input_sizes = { - ${ ", ".join(str(size) for size in opcode.input_sizes) } - }, - .input_types = { - ${ ", ".join("nir_type_" + type for type in opcode.input_types) } - }, - .algebraic_properties = - ${ "0" if opcode.algebraic_properties == "" else " | ".join( - "NIR_OP_IS_" + prop.upper() for prop in - opcode.algebraic_properties.strip().split(" ")) } -}, -% endfor -}; -""") - -print template.render(opcodes=opcodes) diff --git a/src/glsl/nir/nir_opcodes_h.py b/src/glsl/nir/nir_opcodes_h.py deleted file mode 100644 index be15a96d236..00000000000 --- a/src/glsl/nir/nir_opcodes_h.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python - -template = """\ -/* Copyright (C) 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - */ - -#ifndef _NIR_OPCODES_ -#define _NIR_OPCODES_ - -<% opcode_names = sorted(opcodes.iterkeys()) %> - -typedef enum { -% for name in opcode_names: - nir_op_${name}, -% endfor - nir_last_opcode = nir_op_${opcode_names[-1]}, - nir_num_opcodes = nir_last_opcode + 1 -} nir_op; - -#endif /* _NIR_OPCODES_ */""" - -from nir_opcodes import opcodes -from mako.template import Template - -print Template(template).render(opcodes=opcodes) diff --git a/src/glsl/nir/nir_opt_algebraic.py b/src/glsl/nir/nir_opt_algebraic.py deleted file mode 100644 index f4bfd3a921a..00000000000 --- a/src/glsl/nir/nir_opt_algebraic.py +++ /dev/null @@ -1,354 +0,0 @@ -#! /usr/bin/env python -# -*- encoding: utf-8 -*- -# -# Copyright (C) 2014 Intel Corporation -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice (including the next -# paragraph) shall be included in all copies or substantial portions of the -# Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. -# -# Authors: -# Jason Ekstrand ([email protected]) - -import nir_algebraic - -# Convenience variables -a = 'a' -b = 'b' -c = 'c' -d = 'd' - -# Written in the form (<search>, <replace>) where <search> is an expression -# and <replace> is either an expression or a value. An expression is -# defined as a tuple of the form (<op>, <src0>, <src1>, <src2>, <src3>) -# where each source is either an expression or a value. A value can be -# either a numeric constant or a string representing a variable name. -# -# Variable names are specified as "[#]name[@type]" where "#" inicates that -# the given variable will only match constants and the type indicates that -# the given variable will only match values from ALU instructions with the -# given output type. -# -# For constants, you have to be careful to make sure that it is the right -# type because python is unaware of the source and destination types of the -# opcodes. - -optimizations = [ - (('fneg', ('fneg', a)), a), - (('ineg', ('ineg', a)), a), - (('fabs', ('fabs', a)), ('fabs', a)), - (('fabs', ('fneg', a)), ('fabs', a)), - (('iabs', ('iabs', a)), ('iabs', a)), - (('iabs', ('ineg', a)), ('iabs', a)), - (('fadd', a, 0.0), a), - (('iadd', a, 0), a), - (('usadd_4x8', a, 0), a), - (('usadd_4x8', a, ~0), ~0), - (('fadd', ('fmul', a, b), ('fmul', a, c)), ('fmul', a, ('fadd', b, c))), - (('iadd', ('imul', a, b), ('imul', a, c)), ('imul', a, ('iadd', b, c))), - (('fadd', ('fneg', a), a), 0.0), - (('iadd', ('ineg', a), a), 0), - (('iadd', ('ineg', a), ('iadd', a, b)), b), - (('iadd', a, ('iadd', ('ineg', a), b)), b), - (('fadd', ('fneg', a), ('fadd', a, b)), b), - (('fadd', a, ('fadd', ('fneg', a), b)), b), - (('fmul', a, 0.0), 0.0), - (('imul', a, 0), 0), - (('umul_unorm_4x8', a, 0), 0), - (('umul_unorm_4x8', a, ~0), a), - (('fmul', a, 1.0), a), - (('imul', a, 1), a), - (('fmul', a, -1.0), ('fneg', a)), - (('imul', a, -1), ('ineg', a)), - (('fdiv', a, b), ('fmul', a, ('frcp', b)), 'options->lower_fdiv'), - (('ffma', 0.0, a, b), b), - (('ffma', a, 0.0, b), b), - (('ffma', a, b, 0.0), ('fmul', a, b)), - (('ffma', a, 1.0, b), ('fadd', a, b)), - (('ffma', 1.0, a, b), ('fadd', a, b)), - (('flrp', a, b, 0.0), a), - (('flrp', a, b, 1.0), b), - (('flrp', a, a, b), a), - (('flrp', 0.0, a, b), ('fmul', a, b)), - (('flrp', a, b, c), ('fadd', ('fmul', c, ('fsub', b, a)), a), 'options->lower_flrp'), - (('ffract', a), ('fsub', a, ('ffloor', a)), 'options->lower_ffract'), - (('fadd', ('fmul', a, ('fadd', 1.0, ('fneg', c))), ('fmul', b, c)), ('flrp', a, b, c), '!options->lower_flrp'), - (('fadd', a, ('fmul', c, ('fadd', b, ('fneg', a)))), ('flrp', a, b, c), '!options->lower_flrp'), - (('ffma', a, b, c), ('fadd', ('fmul', a, b), c), 'options->lower_ffma'), - (('fadd', ('fmul', a, b), c), ('ffma', a, b, c), '!options->lower_ffma'), - # Comparison simplifications - (('inot', ('flt', a, b)), ('fge', a, b)), - (('inot', ('fge', a, b)), ('flt', a, b)), - (('inot', ('feq', a, b)), ('fne', a, b)), - (('inot', ('fne', a, b)), ('feq', a, b)), - (('inot', ('ilt', a, b)), ('ige', a, b)), - (('inot', ('ige', a, b)), ('ilt', a, b)), - (('inot', ('ieq', a, b)), ('ine', a, b)), - (('inot', ('ine', a, b)), ('ieq', a, b)), - (('fge', ('fneg', ('fabs', a)), 0.0), ('feq', a, 0.0)), - (('bcsel', ('flt', a, b), a, b), ('fmin', a, b)), - (('bcsel', ('flt', a, b), b, a), ('fmax', a, b)), - (('bcsel', ('inot', 'a@bool'), b, c), ('bcsel', a, c, b)), - (('bcsel', a, ('bcsel', a, b, c), d), ('bcsel', a, b, d)), - (('fmin', a, a), a), - (('fmax', a, a), a), - (('imin', a, a), a), - (('imax', a, a), a), - (('umin', a, a), a), - (('umax', a, a), a), - (('fmin', ('fmax', a, 0.0), 1.0), ('fsat', a), '!options->lower_fsat'), - (('fmax', ('fmin', a, 1.0), 0.0), ('fsat', a), '!options->lower_fsat'), - (('fsat', a), ('fmin', ('fmax', a, 0.0), 1.0), 'options->lower_fsat'), - (('fsat', ('fsat', a)), ('fsat', a)), - (('fmin', ('fmax', ('fmin', ('fmax', a, 0.0), 1.0), 0.0), 1.0), ('fmin', ('fmax', a, 0.0), 1.0)), - (('ior', ('flt', a, b), ('flt', a, c)), ('flt', a, ('fmax', b, c))), - (('ior', ('flt', a, c), ('flt', b, c)), ('flt', ('fmin', a, b), c)), - (('ior', ('fge', a, b), ('fge', a, c)), ('fge', a, ('fmin', b, c))), - (('ior', ('fge', a, c), ('fge', b, c)), ('fge', ('fmax', a, b), c)), - (('slt', a, b), ('b2f', ('flt', a, b)), 'options->lower_scmp'), - (('sge', a, b), ('b2f', ('fge', a, b)), 'options->lower_scmp'), - (('seq', a, b), ('b2f', ('feq', a, b)), 'options->lower_scmp'), - (('sne', a, b), ('b2f', ('fne', a, b)), 'options->lower_scmp'), - (('fne', ('fneg', a), a), ('fne', a, 0.0)), - (('feq', ('fneg', a), a), ('feq', a, 0.0)), - # Emulating booleans - (('imul', ('b2i', a), ('b2i', b)), ('b2i', ('iand', a, b))), - (('fmul', ('b2f', a), ('b2f', b)), ('b2f', ('iand', a, b))), - (('fsat', ('fadd', ('b2f', a), ('b2f', b))), ('b2f', ('ior', a, b))), - (('iand', 'a@bool', 1.0), ('b2f', a)), - (('flt', ('fneg', ('b2f', a)), 0), a), # Generated by TGSI KILL_IF. - (('flt', ('fsub', 0.0, ('b2f', a)), 0), a), # Generated by TGSI KILL_IF. - # Comparison with the same args. Note that these are not done for - # the float versions because NaN always returns false on float - # inequalities. - (('ilt', a, a), False), - (('ige', a, a), True), - (('ieq', a, a), True), - (('ine', a, a), False), - (('ult', a, a), False), - (('uge', a, a), True), - # Logical and bit operations - (('fand', a, 0.0), 0.0), - (('iand', a, a), a), - (('iand', a, ~0), a), - (('iand', a, 0), 0), - (('ior', a, a), a), - (('ior', a, 0), a), - (('fxor', a, a), 0.0), - (('ixor', a, a), 0), - (('inot', ('inot', a)), a), - # DeMorgan's Laws - (('iand', ('inot', a), ('inot', b)), ('inot', ('ior', a, b))), - (('ior', ('inot', a), ('inot', b)), ('inot', ('iand', a, b))), - # Shift optimizations - (('ishl', 0, a), 0), - (('ishl', a, 0), a), - (('ishr', 0, a), 0), - (('ishr', a, 0), a), - (('ushr', 0, a), 0), - (('ushr', a, 0), a), - # Exponential/logarithmic identities - (('fexp2', ('flog2', a)), a), # 2^lg2(a) = a - (('flog2', ('fexp2', a)), a), # lg2(2^a) = a - (('fpow', a, b), ('fexp2', ('fmul', ('flog2', a), b)), 'options->lower_fpow'), # a^b = 2^(lg2(a)*b) - (('fexp2', ('fmul', ('flog2', a), b)), ('fpow', a, b), '!options->lower_fpow'), # 2^(lg2(a)*b) = a^b - (('fpow', a, 1.0), a), - (('fpow', a, 2.0), ('fmul', a, a)), - (('fpow', a, 4.0), ('fmul', ('fmul', a, a), ('fmul', a, a))), - (('fpow', 2.0, a), ('fexp2', a)), - (('fpow', ('fpow', a, 2.2), 0.454545), a), - (('fpow', ('fabs', ('fpow', a, 2.2)), 0.454545), ('fabs', a)), - (('fsqrt', ('fexp2', a)), ('fexp2', ('fmul', 0.5, a))), - (('frcp', ('fexp2', a)), ('fexp2', ('fneg', a))), - (('frsq', ('fexp2', a)), ('fexp2', ('fmul', -0.5, a))), - (('flog2', ('fsqrt', a)), ('fmul', 0.5, ('flog2', a))), - (('flog2', ('frcp', a)), ('fneg', ('flog2', a))), - (('flog2', ('frsq', a)), ('fmul', -0.5, ('flog2', a))), - (('flog2', ('fpow', a, b)), ('fmul', b, ('flog2', a))), - (('fadd', ('flog2', a), ('flog2', b)), ('flog2', ('fmul', a, b))), - (('fadd', ('flog2', a), ('fneg', ('flog2', b))), ('flog2', ('fdiv', a, b))), - (('fmul', ('fexp2', a), ('fexp2', b)), ('fexp2', ('fadd', a, b))), - # Division and reciprocal - (('fdiv', 1.0, a), ('frcp', a)), - (('fdiv', a, b), ('fmul', a, ('frcp', b)), 'options->lower_fdiv'), - (('frcp', ('frcp', a)), a), - (('frcp', ('fsqrt', a)), ('frsq', a)), - (('fsqrt', a), ('frcp', ('frsq', a)), 'options->lower_fsqrt'), - (('frcp', ('frsq', a)), ('fsqrt', a), '!options->lower_fsqrt'), - # Boolean simplifications - (('ieq', 'a@bool', True), a), - (('ine', 'a@bool', True), ('inot', a)), - (('ine', 'a@bool', False), a), - (('ieq', 'a@bool', False), ('inot', 'a')), - (('bcsel', a, True, False), ('ine', a, 0)), - (('bcsel', a, False, True), ('ieq', a, 0)), - (('bcsel', True, b, c), b), - (('bcsel', False, b, c), c), - # The result of this should be hit by constant propagation and, in the - # next round of opt_algebraic, get picked up by one of the above two. - (('bcsel', '#a', b, c), ('bcsel', ('ine', 'a', 0), b, c)), - - (('bcsel', a, b, b), b), - (('fcsel', a, b, b), b), - - # Conversions - (('i2b', ('b2i', a)), a), - (('f2i', ('ftrunc', a)), ('f2i', a)), - (('f2u', ('ftrunc', a)), ('f2u', a)), - - # Subtracts - (('fsub', a, ('fsub', 0.0, b)), ('fadd', a, b)), - (('isub', a, ('isub', 0, b)), ('iadd', a, b)), - (('ussub_4x8', a, 0), a), - (('ussub_4x8', a, ~0), 0), - (('fsub', a, b), ('fadd', a, ('fneg', b)), 'options->lower_sub'), - (('isub', a, b), ('iadd', a, ('ineg', b)), 'options->lower_sub'), - (('fneg', a), ('fsub', 0.0, a), 'options->lower_negate'), - (('ineg', a), ('isub', 0, a), 'options->lower_negate'), - (('fadd', a, ('fsub', 0.0, b)), ('fsub', a, b)), - (('iadd', a, ('isub', 0, b)), ('isub', a, b)), - (('fabs', ('fsub', 0.0, a)), ('fabs', a)), - (('iabs', ('isub', 0, a)), ('iabs', a)), - - # Misc. lowering - (('fmod', a, b), ('fsub', a, ('fmul', b, ('ffloor', ('fdiv', a, b)))), 'options->lower_fmod'), - (('frem', a, b), ('fsub', a, ('fmul', b, ('ftrunc', ('fdiv', a, b)))), 'options->lower_fmod'), - (('uadd_carry', a, b), ('b2i', ('ult', ('iadd', a, b), a)), 'options->lower_uadd_carry'), - (('usub_borrow', a, b), ('b2i', ('ult', a, b)), 'options->lower_usub_borrow'), - (('ldexp', 'x', 'exp'), - ('fmul', 'x', ('ishl', ('imin', ('imax', ('iadd', 'exp', 0x7f), 0), 0xff), 23))), - - (('bitfield_insert', 'base', 'insert', 'offset', 'bits'), - ('bcsel', ('ilt', 31, 'bits'), 'insert', - ('bfi', ('bfm', 'bits', 'offset'), 'insert', 'base')), - 'options->lower_bitfield_insert'), - - (('ibitfield_extract', 'value', 'offset', 'bits'), - ('bcsel', ('ilt', 31, 'bits'), 'value', - ('ibfe', 'value', 'offset', 'bits')), - 'options->lower_bitfield_extract'), - - (('ubitfield_extract', 'value', 'offset', 'bits'), - ('bcsel', ('ult', 31, 'bits'), 'value', - ('ubfe', 'value', 'offset', 'bits')), - 'options->lower_bitfield_extract'), - - (('extract_ibyte', a, b), - ('ishr', ('ishl', a, ('imul', ('isub', 3, b), 8)), 8), - 'options->lower_extract_byte'), - - (('extract_ubyte', a, b), - ('iand', ('ushr', a, ('imul', b, 8)), 0xff), - 'options->lower_extract_byte'), - - (('extract_iword', a, b), - ('ishr', ('ishl', a, ('imul', ('isub', 1, b), 16)), 16), - 'options->lower_extract_word'), - - (('extract_uword', a, b), - ('iand', ('ushr', a, ('imul', b, 16)), 0xffff), - 'options->lower_extract_word'), - - (('pack_unorm_2x16', 'v'), - ('pack_uvec2_to_uint', - ('f2u', ('fround_even', ('fmul', ('fsat', 'v'), 65535.0)))), - 'options->lower_pack_unorm_2x16'), - - (('pack_unorm_4x8', 'v'), - ('pack_uvec4_to_uint', - ('f2u', ('fround_even', ('fmul', ('fsat', 'v'), 255.0)))), - 'options->lower_pack_unorm_4x8'), - - (('pack_snorm_2x16', 'v'), - ('pack_uvec2_to_uint', - ('f2i', ('fround_even', ('fmul', ('fmin', 1.0, ('fmax', -1.0, 'v')), 32767.0)))), - 'options->lower_pack_snorm_2x16'), - - (('pack_snorm_4x8', 'v'), - ('pack_uvec4_to_uint', - ('f2i', ('fround_even', ('fmul', ('fmin', 1.0, ('fmax', -1.0, 'v')), 127.0)))), - 'options->lower_pack_snorm_4x8'), - - (('unpack_unorm_2x16', 'v'), - ('fdiv', ('u2f', ('vec4', ('extract_uword', 'v', 0), - ('extract_uword', 'v', 1), 0, 0)), - 65535.0), - 'options->lower_unpack_unorm_2x16'), - - (('unpack_unorm_4x8', 'v'), - ('fdiv', ('u2f', ('vec4', ('extract_ubyte', 'v', 0), - ('extract_ubyte', 'v', 1), - ('extract_ubyte', 'v', 2), - ('extract_ubyte', 'v', 3))), - 255.0), - 'options->lower_unpack_unorm_4x8'), - - (('unpack_snorm_2x16', 'v'), - ('fmin', 1.0, ('fmax', -1.0, ('fdiv', ('i2f', ('vec4', ('extract_iword', 'v', 0), - ('extract_iword', 'v', 1), 0, 0)), - 32767.0))), - 'options->lower_unpack_snorm_2x16'), - - (('unpack_snorm_4x8', 'v'), - ('fmin', 1.0, ('fmax', -1.0, ('fdiv', ('i2f', ('vec4', ('extract_ibyte', 'v', 0), - ('extract_ibyte', 'v', 1), - ('extract_ibyte', 'v', 2), - ('extract_ibyte', 'v', 3))), - 127.0))), - 'options->lower_unpack_snorm_4x8'), -] - -# Add optimizations to handle the case where the result of a ternary is -# compared to a constant. This way we can take things like -# -# (a ? 0 : 1) > 0 -# -# and turn it into -# -# a ? (0 > 0) : (1 > 0) -# -# which constant folding will eat for lunch. The resulting ternary will -# further get cleaned up by the boolean reductions above and we will be -# left with just the original variable "a". -for op in ['flt', 'fge', 'feq', 'fne', - 'ilt', 'ige', 'ieq', 'ine', 'ult', 'uge']: - optimizations += [ - ((op, ('bcsel', 'a', '#b', '#c'), '#d'), - ('bcsel', 'a', (op, 'b', 'd'), (op, 'c', 'd'))), - ((op, '#d', ('bcsel', a, '#b', '#c')), - ('bcsel', 'a', (op, 'd', 'b'), (op, 'd', 'c'))), - ] - -# This section contains "late" optimizations that should be run after the -# regular optimizations have finished. Optimizations should go here if -# they help code generation but do not necessarily produce code that is -# more easily optimizable. -late_optimizations = [ - (('flt', ('fadd', a, b), 0.0), ('flt', a, ('fneg', b))), - (('fge', ('fadd', a, b), 0.0), ('fge', a, ('fneg', b))), - (('feq', ('fadd', a, b), 0.0), ('feq', a, ('fneg', b))), - (('fne', ('fadd', a, b), 0.0), ('fne', a, ('fneg', b))), - (('fdot2', a, b), ('fdot_replicated2', a, b), 'options->fdot_replicates'), - (('fdot3', a, b), ('fdot_replicated3', a, b), 'options->fdot_replicates'), - (('fdot4', a, b), ('fdot_replicated4', a, b), 'options->fdot_replicates'), - (('fdph', a, b), ('fdph_replicated', a, b), 'options->fdot_replicates'), -] - -print nir_algebraic.AlgebraicPass("nir_opt_algebraic", optimizations).render() -print nir_algebraic.AlgebraicPass("nir_opt_algebraic_late", - late_optimizations).render() diff --git a/src/glsl/nir/nir_opt_constant_folding.c b/src/glsl/nir/nir_opt_constant_folding.c deleted file mode 100644 index 28a73f86f95..00000000000 --- a/src/glsl/nir/nir_opt_constant_folding.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir_constant_expressions.h" -#include <math.h> - -/* - * Implements SSA-based constant folding. - */ - -struct constant_fold_state { - void *mem_ctx; - nir_function_impl *impl; - bool progress; -}; - -static bool -constant_fold_alu_instr(nir_alu_instr *instr, void *mem_ctx) -{ - nir_const_value src[4]; - - if (!instr->dest.dest.is_ssa) - return false; - - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - if (!instr->src[i].src.is_ssa) - return false; - - nir_instr *src_instr = instr->src[i].src.ssa->parent_instr; - - if (src_instr->type != nir_instr_type_load_const) - return false; - nir_load_const_instr* load_const = nir_instr_as_load_const(src_instr); - - for (unsigned j = 0; j < nir_ssa_alu_instr_src_components(instr, i); - j++) { - src[i].u[j] = load_const->value.u[instr->src[i].swizzle[j]]; - } - - /* We shouldn't have any source modifiers in the optimization loop. */ - assert(!instr->src[i].abs && !instr->src[i].negate); - } - - /* We shouldn't have any saturate modifiers in the optimization loop. */ - assert(!instr->dest.saturate); - - nir_const_value dest = - nir_eval_const_opcode(instr->op, instr->dest.dest.ssa.num_components, - src); - - nir_load_const_instr *new_instr = - nir_load_const_instr_create(mem_ctx, - instr->dest.dest.ssa.num_components); - - new_instr->value = dest; - - nir_instr_insert_before(&instr->instr, &new_instr->instr); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, - nir_src_for_ssa(&new_instr->def)); - - nir_instr_remove(&instr->instr); - ralloc_free(instr); - - return true; -} - -static bool -constant_fold_deref(nir_instr *instr, nir_deref_var *deref) -{ - bool progress = false; - - for (nir_deref *tail = deref->deref.child; tail; tail = tail->child) { - if (tail->deref_type != nir_deref_type_array) - continue; - - nir_deref_array *arr = nir_deref_as_array(tail); - - if (arr->deref_array_type == nir_deref_array_type_indirect && - arr->indirect.is_ssa && - arr->indirect.ssa->parent_instr->type == nir_instr_type_load_const) { - nir_load_const_instr *indirect = - nir_instr_as_load_const(arr->indirect.ssa->parent_instr); - - arr->base_offset += indirect->value.u[0]; - - /* Clear out the source */ - nir_instr_rewrite_src(instr, &arr->indirect, nir_src_for_ssa(NULL)); - - arr->deref_array_type = nir_deref_array_type_direct; - - progress = true; - } - } - - return progress; -} - -static bool -constant_fold_intrinsic_instr(nir_intrinsic_instr *instr) -{ - bool progress = false; - - unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables; - for (unsigned i = 0; i < num_vars; i++) { - progress |= constant_fold_deref(&instr->instr, instr->variables[i]); - } - - return progress; -} - -static bool -constant_fold_tex_instr(nir_tex_instr *instr) -{ - if (instr->sampler) - return constant_fold_deref(&instr->instr, instr->sampler); - else - return false; -} - -static bool -constant_fold_block(nir_block *block, void *void_state) -{ - struct constant_fold_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - switch (instr->type) { - case nir_instr_type_alu: - state->progress |= constant_fold_alu_instr(nir_instr_as_alu(instr), - state->mem_ctx); - break; - case nir_instr_type_intrinsic: - state->progress |= - constant_fold_intrinsic_instr(nir_instr_as_intrinsic(instr)); - break; - case nir_instr_type_tex: - state->progress |= constant_fold_tex_instr(nir_instr_as_tex(instr)); - break; - default: - /* Don't know how to constant fold */ - break; - } - } - - return true; -} - -static bool -nir_opt_constant_folding_impl(nir_function_impl *impl) -{ - struct constant_fold_state state; - - state.mem_ctx = ralloc_parent(impl); - state.impl = impl; - state.progress = false; - - nir_foreach_block(impl, constant_fold_block, &state); - - if (state.progress) - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - return state.progress; -} - -bool -nir_opt_constant_folding(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress |= nir_opt_constant_folding_impl(function->impl); - } - - return progress; -} diff --git a/src/glsl/nir/nir_opt_copy_propagate.c b/src/glsl/nir/nir_opt_copy_propagate.c deleted file mode 100644 index d99f78ddb36..00000000000 --- a/src/glsl/nir/nir_opt_copy_propagate.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include <main/imports.h> - -/** - * SSA-based copy propagation - */ - -static bool is_move(nir_alu_instr *instr) -{ - if (instr->op != nir_op_fmov && - instr->op != nir_op_imov) - return false; - - if (instr->dest.saturate) - return false; - - /* we handle modifiers in a separate pass */ - - if (instr->src[0].abs || instr->src[0].negate) - return false; - - if (!instr->src[0].src.is_ssa) - return false; - - return true; - -} - -static bool is_vec(nir_alu_instr *instr) -{ - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - if (!instr->src[i].src.is_ssa) - return false; - - /* we handle modifiers in a separate pass */ - if (instr->src[i].abs || instr->src[i].negate) - return false; - } - - return instr->op == nir_op_vec2 || - instr->op == nir_op_vec3 || - instr->op == nir_op_vec4; -} - -static bool -is_swizzleless_move(nir_alu_instr *instr) -{ - if (is_move(instr)) { - for (unsigned i = 0; i < 4; i++) { - if (!((instr->dest.write_mask >> i) & 1)) - break; - if (instr->src[0].swizzle[i] != i) - return false; - } - return true; - } else if (is_vec(instr)) { - nir_ssa_def *def = NULL; - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - if (instr->src[i].swizzle[0] != i) - return false; - - if (def == NULL) { - def = instr->src[i].src.ssa; - } else if (instr->src[i].src.ssa != def) { - return false; - } - } - return true; - } else { - return false; - } -} - -static bool -copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if) -{ - if (!src->is_ssa) { - if (src->reg.indirect) - return copy_prop_src(src, parent_instr, parent_if); - return false; - } - - nir_instr *src_instr = src->ssa->parent_instr; - if (src_instr->type != nir_instr_type_alu) - return false; - - nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr); - if (!is_swizzleless_move(alu_instr)) - return false; - - /* Don't let copy propagation land us with a phi that has more - * components in its source than it has in its destination. That badly - * messes up out-of-ssa. - */ - if (parent_instr && parent_instr->type == nir_instr_type_phi) { - nir_phi_instr *phi = nir_instr_as_phi(parent_instr); - assert(phi->dest.is_ssa); - if (phi->dest.ssa.num_components != - alu_instr->src[0].src.ssa->num_components) - return false; - } - - if (parent_instr) { - nir_instr_rewrite_src(parent_instr, src, - nir_src_for_ssa(alu_instr->src[0].src.ssa)); - } else { - assert(src == &parent_if->condition); - nir_if_rewrite_condition(parent_if, - nir_src_for_ssa(alu_instr->src[0].src.ssa)); - } - - return true; -} - -static bool -copy_prop_alu_src(nir_alu_instr *parent_alu_instr, unsigned index) -{ - nir_alu_src *src = &parent_alu_instr->src[index]; - if (!src->src.is_ssa) { - if (src->src.reg.indirect) - return copy_prop_src(src->src.reg.indirect, &parent_alu_instr->instr, - NULL); - return false; - } - - nir_instr *src_instr = src->src.ssa->parent_instr; - if (src_instr->type != nir_instr_type_alu) - return false; - - nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr); - if (!is_move(alu_instr) && !is_vec(alu_instr)) - return false; - - nir_ssa_def *def; - unsigned new_swizzle[4] = {0, 0, 0, 0}; - - if (alu_instr->op == nir_op_fmov || - alu_instr->op == nir_op_imov) { - for (unsigned i = 0; i < 4; i++) - new_swizzle[i] = alu_instr->src[0].swizzle[src->swizzle[i]]; - def = alu_instr->src[0].src.ssa; - } else { - def = NULL; - - for (unsigned i = 0; i < 4; i++) { - if (!nir_alu_instr_channel_used(parent_alu_instr, index, i)) - continue; - - nir_ssa_def *new_def = alu_instr->src[src->swizzle[i]].src.ssa; - if (def == NULL) - def = new_def; - else { - if (def != new_def) - return false; - } - new_swizzle[i] = alu_instr->src[src->swizzle[i]].swizzle[0]; - } - } - - for (unsigned i = 0; i < 4; i++) - src->swizzle[i] = new_swizzle[i]; - - nir_instr_rewrite_src(&parent_alu_instr->instr, &src->src, - nir_src_for_ssa(def)); - - return true; -} - -typedef struct { - nir_instr *parent_instr; - bool progress; -} copy_prop_state; - -static bool -copy_prop_src_cb(nir_src *src, void *_state) -{ - copy_prop_state *state = (copy_prop_state *) _state; - while (copy_prop_src(src, state->parent_instr, NULL)) - state->progress = true; - - return true; -} - -static bool -copy_prop_instr(nir_instr *instr) -{ - if (instr->type == nir_instr_type_alu) { - nir_alu_instr *alu_instr = nir_instr_as_alu(instr); - bool progress = false; - - for (unsigned i = 0; i < nir_op_infos[alu_instr->op].num_inputs; i++) - while (copy_prop_alu_src(alu_instr, i)) - progress = true; - - if (!alu_instr->dest.dest.is_ssa && alu_instr->dest.dest.reg.indirect) - while (copy_prop_src(alu_instr->dest.dest.reg.indirect, instr, NULL)) - progress = true; - - return progress; - } - - copy_prop_state state; - state.parent_instr = instr; - state.progress = false; - nir_foreach_src(instr, copy_prop_src_cb, &state); - - return state.progress; -} - -static bool -copy_prop_if(nir_if *if_stmt) -{ - return copy_prop_src(&if_stmt->condition, NULL, if_stmt); -} - -static bool -copy_prop_block(nir_block *block, void *_state) -{ - bool *progress = (bool *) _state; - - nir_foreach_instr(block, instr) { - if (copy_prop_instr(instr)) - *progress = true; - } - - if (block->cf_node.node.next != NULL && /* check that we aren't the end node */ - !nir_cf_node_is_last(&block->cf_node) && - nir_cf_node_next(&block->cf_node)->type == nir_cf_node_if) { - nir_if *if_stmt = nir_cf_node_as_if(nir_cf_node_next(&block->cf_node)); - if (copy_prop_if(if_stmt)) - *progress = true; - } - - return true; -} - -static bool -nir_copy_prop_impl(nir_function_impl *impl) -{ - bool progress = false; - - nir_foreach_block(impl, copy_prop_block, &progress); - - if (progress) { - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - } - - return progress; -} - -bool -nir_copy_prop(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl && nir_copy_prop_impl(function->impl)) - progress = true; - } - - return progress; -} diff --git a/src/glsl/nir/nir_opt_cse.c b/src/glsl/nir/nir_opt_cse.c deleted file mode 100644 index 364fb023dce..00000000000 --- a/src/glsl/nir/nir_opt_cse.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * Connor Abbott ([email protected]) - * - */ - -#include "nir_instr_set.h" - -/* - * Implements common subexpression elimination - */ - -/* - * Visits and CSE's the given block and all its descendants in the dominance - * tree recursively. Note that the instr_set is guaranteed to only ever - * contain instructions that dominate the current block. - */ - -static bool -cse_block(nir_block *block, struct set *instr_set) -{ - bool progress = false; - - nir_foreach_instr_safe(block, instr) { - if (nir_instr_set_add_or_rewrite(instr_set, instr)) { - progress = true; - nir_instr_remove(instr); - } - } - - for (unsigned i = 0; i < block->num_dom_children; i++) { - nir_block *child = block->dom_children[i]; - progress |= cse_block(child, instr_set); - } - - nir_foreach_instr(block, instr) - nir_instr_set_remove(instr_set, instr); - - return progress; -} - -static bool -nir_opt_cse_impl(nir_function_impl *impl) -{ - struct set *instr_set = nir_instr_set_create(NULL); - - nir_metadata_require(impl, nir_metadata_dominance); - - bool progress = cse_block(nir_start_block(impl), instr_set); - - if (progress) - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - nir_instr_set_destroy(instr_set); - return progress; -} - -bool -nir_opt_cse(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress |= nir_opt_cse_impl(function->impl); - } - - return progress; -} - diff --git a/src/glsl/nir/nir_opt_dce.c b/src/glsl/nir/nir_opt_dce.c deleted file mode 100644 index 32436c18b60..00000000000 --- a/src/glsl/nir/nir_opt_dce.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -/* SSA-based mark-and-sweep dead code elimination */ - -typedef struct { - struct exec_node node; - nir_instr *instr; -} worklist_elem; - -static void -worklist_push(struct exec_list *worklist, nir_instr *instr) -{ - worklist_elem *elem = ralloc(worklist, worklist_elem); - elem->instr = instr; - instr->pass_flags = 1; - exec_list_push_tail(worklist, &elem->node); -} - -static nir_instr * -worklist_pop(struct exec_list *worklist) -{ - struct exec_node *node = exec_list_pop_head(worklist); - worklist_elem *elem = exec_node_data(worklist_elem, node, node); - return elem->instr; -} - -static bool -mark_live_cb(nir_src *src, void *_state) -{ - struct exec_list *worklist = (struct exec_list *) _state; - - if (src->is_ssa && !src->ssa->parent_instr->pass_flags) { - worklist_push(worklist, src->ssa->parent_instr); - } - - return true; -} - -static void -init_instr(nir_instr *instr, struct exec_list *worklist) -{ - nir_alu_instr *alu_instr; - nir_intrinsic_instr *intrin_instr; - nir_tex_instr *tex_instr; - - /* We use the pass_flags to store the live/dead information. In DCE, we - * just treat it as a zero/non-zerl boolean for whether or not the - * instruction is live. - */ - instr->pass_flags = 0; - - switch (instr->type) { - case nir_instr_type_call: - case nir_instr_type_jump: - worklist_push(worklist, instr); - break; - - case nir_instr_type_alu: - alu_instr = nir_instr_as_alu(instr); - if (!alu_instr->dest.dest.is_ssa) - worklist_push(worklist, instr); - break; - - case nir_instr_type_intrinsic: - intrin_instr = nir_instr_as_intrinsic(instr); - if (nir_intrinsic_infos[intrin_instr->intrinsic].flags & - NIR_INTRINSIC_CAN_ELIMINATE) { - if (nir_intrinsic_infos[intrin_instr->intrinsic].has_dest && - !intrin_instr->dest.is_ssa) { - worklist_push(worklist, instr); - } - } else { - worklist_push(worklist, instr); - } - break; - - case nir_instr_type_tex: - tex_instr = nir_instr_as_tex(instr); - if (!tex_instr->dest.is_ssa) - worklist_push(worklist, instr); - break; - - default: - break; - } -} - -static bool -init_block_cb(nir_block *block, void *_state) -{ - struct exec_list *worklist = (struct exec_list *) _state; - - nir_foreach_instr(block, instr) - init_instr(instr, worklist); - - nir_if *following_if = nir_block_get_following_if(block); - if (following_if) { - if (following_if->condition.is_ssa && - !following_if->condition.ssa->parent_instr->pass_flags) - worklist_push(worklist, following_if->condition.ssa->parent_instr); - } - - return true; -} - -static bool -delete_block_cb(nir_block *block, void *_state) -{ - bool *progress = (bool *) _state; - - nir_foreach_instr_safe(block, instr) { - if (!instr->pass_flags) { - nir_instr_remove(instr); - *progress = true; - } - } - - return true; -} - -static bool -nir_opt_dce_impl(nir_function_impl *impl) -{ - struct exec_list *worklist = ralloc(NULL, struct exec_list); - exec_list_make_empty(worklist); - - nir_foreach_block(impl, init_block_cb, worklist); - - while (!exec_list_is_empty(worklist)) { - nir_instr *instr = worklist_pop(worklist); - nir_foreach_src(instr, mark_live_cb, worklist); - } - - ralloc_free(worklist); - - bool progress = false; - nir_foreach_block(impl, delete_block_cb, &progress); - - if (progress) - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - return progress; -} - -bool -nir_opt_dce(nir_shader *shader) -{ - bool progress = false; - nir_foreach_function(shader, function) { - if (function->impl && nir_opt_dce_impl(function->impl)) - progress = true; - } - - return progress; -} diff --git a/src/glsl/nir/nir_opt_dead_cf.c b/src/glsl/nir/nir_opt_dead_cf.c deleted file mode 100644 index 4cc6798702b..00000000000 --- a/src/glsl/nir/nir_opt_dead_cf.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright © 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include "nir_control_flow.h" - -/* - * This file implements an optimization that deletes statically - * unreachable/dead code. In NIR, one way this can happen if if an if - * statement has a constant condition: - * - * if (true) { - * ... - * } - * - * We delete the if statement and paste the contents of the always-executed - * branch into the surrounding control flow, possibly removing more code if - * the branch had a jump at the end. - * - * Another way is that control flow can end in a jump so that code after it - * never gets executed. In particular, this can happen after optimizing - * something like: - * - * if (true) { - * ... - * break; - * } - * ... - * - * We also consider the case where both branches of an if end in a jump, e.g.: - * - * if (...) { - * break; - * } else { - * continue; - * } - * ... - * - * Finally, we also handle removing useless loops, i.e. loops with no side - * effects and without any definitions that are used elsewhere. This case is a - * little different from the first two in that the code is actually run (it - * just never does anything), but there are similar issues with needing to - * be careful with restarting after deleting the cf_node (see dead_cf_list()) - * so this is a convenient place to remove them. - */ - -static void -remove_after_cf_node(nir_cf_node *node) -{ - nir_cf_node *end = node; - while (!nir_cf_node_is_last(end)) - end = nir_cf_node_next(end); - - nir_cf_list list; - nir_cf_extract(&list, nir_after_cf_node(node), nir_after_cf_node(end)); - nir_cf_delete(&list); -} - -static void -opt_constant_if(nir_if *if_stmt, bool condition) -{ - /* First, we need to remove any phi nodes after the if by rewriting uses to - * point to the correct source. - */ - nir_block *after = nir_cf_node_as_block(nir_cf_node_next(&if_stmt->cf_node)); - nir_block *last_block = - nir_cf_node_as_block(condition ? nir_if_last_then_node(if_stmt) - : nir_if_last_else_node(if_stmt)); - - nir_foreach_instr_safe(after, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - nir_ssa_def *def = NULL; - nir_foreach_phi_src(phi, phi_src) { - if (phi_src->pred != last_block) - continue; - - assert(phi_src->src.is_ssa); - def = phi_src->src.ssa; - } - - assert(def); - assert(phi->dest.is_ssa); - nir_ssa_def_rewrite_uses(&phi->dest.ssa, nir_src_for_ssa(def)); - nir_instr_remove(instr); - } - - /* The control flow list we're about to paste in may include a jump at the - * end, and in that case we have to delete the rest of the control flow - * list after the if since it's unreachable and the validator will balk if - * we don't. - */ - - if (!exec_list_is_empty(&last_block->instr_list)) { - nir_instr *last_instr = nir_block_last_instr(last_block); - if (last_instr->type == nir_instr_type_jump) - remove_after_cf_node(&if_stmt->cf_node); - } - - /* Finally, actually paste in the then or else branch and delete the if. */ - struct exec_list *cf_list = condition ? &if_stmt->then_list - : &if_stmt->else_list; - - nir_cf_list list; - nir_cf_extract(&list, nir_before_cf_list(cf_list), - nir_after_cf_list(cf_list)); - nir_cf_reinsert(&list, nir_after_cf_node(&if_stmt->cf_node)); - nir_cf_node_remove(&if_stmt->cf_node); -} - -static bool -block_has_no_side_effects(nir_block *block, void *state) -{ - (void) state; - - nir_foreach_instr(block, instr) { - if (instr->type == nir_instr_type_call) - return false; - - /* Return instructions can cause us to skip over other side-effecting - * instructions after the loop, so consider them to have side effects - * here. - */ - - if (instr->type == nir_instr_type_jump && - nir_instr_as_jump(instr)->type == nir_jump_return) - return false; - - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - if (!nir_intrinsic_infos[intrin->intrinsic].flags & - NIR_INTRINSIC_CAN_ELIMINATE) - return false; - } - - return true; -} - -static bool -def_not_live_out(nir_ssa_def *def, void *state) -{ - nir_block *after = state; - - return !BITSET_TEST(after->live_in, def->live_index); -} - -/* - * Test if a loop is dead. A loop is dead if: - * - * 1) It has no side effects (i.e. intrinsics which could possibly affect the - * state of the program aside from producing an SSA value, indicated by a lack - * of NIR_INTRINSIC_CAN_ELIMINATE). - * - * 2) It has no phi nodes after it, since those indicate values inside the - * loop being used after the loop. - * - * 3) If there are no phi nodes after the loop, then the only way a value - * defined inside the loop can be used outside the loop is if its definition - * dominates the block after the loop. If none of the definitions that - * dominate the loop exit are used outside the loop, then the loop is dead - * and it can be deleted. - */ - -static bool -loop_is_dead(nir_loop *loop) -{ - nir_block *before = nir_cf_node_as_block(nir_cf_node_prev(&loop->cf_node)); - nir_block *after = nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node)); - - if (!exec_list_is_empty(&after->instr_list) && - nir_block_first_instr(after)->type == nir_instr_type_phi) - return false; - - if (!nir_foreach_block_in_cf_node(&loop->cf_node, block_has_no_side_effects, - NULL)) - return false; - - nir_function_impl *impl = nir_cf_node_get_function(&loop->cf_node); - nir_metadata_require(impl, nir_metadata_live_ssa_defs | - nir_metadata_dominance); - - for (nir_block *cur = after->imm_dom; cur != before; cur = cur->imm_dom) { - nir_foreach_instr(cur, instr) { - if (!nir_foreach_ssa_def(instr, def_not_live_out, after)) - return false; - } - } - - return true; -} - -static bool -dead_cf_block(nir_block *block) -{ - nir_if *following_if = nir_block_get_following_if(block); - if (following_if) { - nir_const_value *const_value = - nir_src_as_const_value(following_if->condition); - - if (!const_value) - return false; - - opt_constant_if(following_if, const_value->u[0] != 0); - return true; - } - - nir_loop *following_loop = nir_block_get_following_loop(block); - if (!following_loop) - return false; - - if (!loop_is_dead(following_loop)) - return false; - - nir_cf_node_remove(&following_loop->cf_node); - return true; -} - -static bool -ends_in_jump(nir_block *block) -{ - if (exec_list_is_empty(&block->instr_list)) - return false; - - nir_instr *instr = nir_block_last_instr(block); - return instr->type == nir_instr_type_jump; -} - -static bool -dead_cf_list(struct exec_list *list, bool *list_ends_in_jump) -{ - bool progress = false; - *list_ends_in_jump = false; - - nir_cf_node *prev = NULL; - - foreach_list_typed(nir_cf_node, cur, node, list) { - switch (cur->type) { - case nir_cf_node_block: { - nir_block *block = nir_cf_node_as_block(cur); - if (dead_cf_block(block)) { - /* We just deleted the if or loop after this block, so we may have - * deleted the block before or after it -- which one is an - * implementation detail. Therefore, to recover the place we were - * at, we have to use the previous cf_node. - */ - - if (prev) { - cur = nir_cf_node_next(prev); - } else { - cur = exec_node_data(nir_cf_node, exec_list_get_head(list), - node); - } - - block = nir_cf_node_as_block(cur); - - progress = true; - } - - if (ends_in_jump(block)) { - *list_ends_in_jump = true; - - if (!exec_node_is_tail_sentinel(cur->node.next)) { - remove_after_cf_node(cur); - return true; - } - } - - break; - } - - case nir_cf_node_if: { - nir_if *if_stmt = nir_cf_node_as_if(cur); - bool then_ends_in_jump, else_ends_in_jump; - progress |= dead_cf_list(&if_stmt->then_list, &then_ends_in_jump); - progress |= dead_cf_list(&if_stmt->else_list, &else_ends_in_jump); - - if (then_ends_in_jump && else_ends_in_jump) { - *list_ends_in_jump = true; - nir_block *next = nir_cf_node_as_block(nir_cf_node_next(cur)); - if (!exec_list_is_empty(&next->instr_list) || - !exec_node_is_tail_sentinel(next->cf_node.node.next)) { - remove_after_cf_node(cur); - return true; - } - } - - break; - } - - case nir_cf_node_loop: { - nir_loop *loop = nir_cf_node_as_loop(cur); - bool dummy; - progress |= dead_cf_list(&loop->body, &dummy); - - break; - } - - default: - unreachable("unknown cf node type"); - } - - prev = cur; - } - - return progress; -} - -static bool -opt_dead_cf_impl(nir_function_impl *impl) -{ - bool dummy; - bool progress = dead_cf_list(&impl->body, &dummy); - - if (progress) - nir_metadata_preserve(impl, nir_metadata_none); - - return progress; -} - -bool -nir_opt_dead_cf(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) - if (function->impl) - progress |= opt_dead_cf_impl(function->impl); - - return progress; -} diff --git a/src/glsl/nir/nir_opt_gcm.c b/src/glsl/nir/nir_opt_gcm.c deleted file mode 100644 index a8779ce5b84..00000000000 --- a/src/glsl/nir/nir_opt_gcm.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" - -/* - * Implements Global Code Motion. A description of GCM can be found in - * "Global Code Motion; Global Value Numbering" by Cliff Click. - * Unfortunately, the algorithm presented in the paper is broken in a - * number of ways. The algorithm used here differs substantially from the - * one in the paper but it is, in my opinion, much easier to read and - * verify correcness. - */ - -struct gcm_block_info { - /* Number of loops this block is inside */ - unsigned loop_depth; - - /* The last instruction inserted into this block. This is used as we - * traverse the instructions and insert them back into the program to - * put them in the right order. - */ - nir_instr *last_instr; -}; - -/* Flags used in the instr->pass_flags field for various instruction states */ -enum { - GCM_INSTR_PINNED = (1 << 0), - GCM_INSTR_SCHEDULED_EARLY = (1 << 1), - GCM_INSTR_SCHEDULED_LATE = (1 << 2), - GCM_INSTR_PLACED = (1 << 3), -}; - -struct gcm_state { - nir_function_impl *impl; - nir_instr *instr; - - /* The list of non-pinned instructions. As we do the late scheduling, - * we pull non-pinned instructions out of their blocks and place them in - * this list. This saves us from having linked-list problems when we go - * to put instructions back in their blocks. - */ - struct exec_list instrs; - - struct gcm_block_info *blocks; -}; - -/* Recursively walks the CFG and builds the block_info structure */ -static void -gcm_build_block_info(struct exec_list *cf_list, struct gcm_state *state, - unsigned loop_depth) -{ - foreach_list_typed(nir_cf_node, node, node, cf_list) { - switch (node->type) { - case nir_cf_node_block: { - nir_block *block = nir_cf_node_as_block(node); - state->blocks[block->index].loop_depth = loop_depth; - break; - } - case nir_cf_node_if: { - nir_if *if_stmt = nir_cf_node_as_if(node); - gcm_build_block_info(&if_stmt->then_list, state, loop_depth); - gcm_build_block_info(&if_stmt->else_list, state, loop_depth); - break; - } - case nir_cf_node_loop: { - nir_loop *loop = nir_cf_node_as_loop(node); - gcm_build_block_info(&loop->body, state, loop_depth + 1); - break; - } - default: - unreachable("Invalid CF node type"); - } - } -} - -/* Walks the instruction list and marks immovable instructions as pinned - * - * This function also serves to initialize the instr->pass_flags field. - * After this is completed, all instructions' pass_flags fields will be set - * to either GCM_INSTR_PINNED or 0. - */ -static bool -gcm_pin_instructions_block(nir_block *block, void *void_state) -{ - struct gcm_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - switch (instr->type) { - case nir_instr_type_alu: - switch (nir_instr_as_alu(instr)->op) { - case nir_op_fddx: - case nir_op_fddy: - case nir_op_fddx_fine: - case nir_op_fddy_fine: - case nir_op_fddx_coarse: - case nir_op_fddy_coarse: - /* These can only go in uniform control flow; pin them for now */ - instr->pass_flags = GCM_INSTR_PINNED; - break; - - default: - instr->pass_flags = 0; - break; - } - break; - - case nir_instr_type_tex: - switch (nir_instr_as_tex(instr)->op) { - case nir_texop_tex: - case nir_texop_txb: - case nir_texop_lod: - /* These two take implicit derivatives so they need to be pinned */ - instr->pass_flags = GCM_INSTR_PINNED; - break; - - default: - instr->pass_flags = 0; - break; - } - break; - - case nir_instr_type_load_const: - instr->pass_flags = 0; - break; - - case nir_instr_type_intrinsic: { - const nir_intrinsic_info *info = - &nir_intrinsic_infos[nir_instr_as_intrinsic(instr)->intrinsic]; - - if ((info->flags & NIR_INTRINSIC_CAN_ELIMINATE) && - (info->flags & NIR_INTRINSIC_CAN_REORDER)) { - instr->pass_flags = 0; - } else { - instr->pass_flags = GCM_INSTR_PINNED; - } - break; - } - - case nir_instr_type_jump: - case nir_instr_type_ssa_undef: - case nir_instr_type_phi: - instr->pass_flags = GCM_INSTR_PINNED; - break; - - default: - unreachable("Invalid instruction type in GCM"); - } - - if (!(instr->pass_flags & GCM_INSTR_PINNED)) { - /* If this is an unpinned instruction, go ahead and pull it out of - * the program and put it on the instrs list. This has a couple - * of benifits. First, it makes the scheduling algorithm more - * efficient because we can avoid walking over basic blocks and - * pinned instructions. Second, it keeps us from causing linked - * list confusion when we're trying to put everything in its - * proper place at the end of the pass. - * - * Note that we don't use nir_instr_remove here because that also - * cleans up uses and defs and we want to keep that information. - */ - exec_node_remove(&instr->node); - exec_list_push_tail(&state->instrs, &instr->node); - } - } - - return true; -} - -static void -gcm_schedule_early_instr(nir_instr *instr, struct gcm_state *state); - -/** Update an instructions schedule for the given source - * - * This function is called iteratively as we walk the sources of an - * instruction. It ensures that the given source instruction has been - * scheduled and then update this instruction's block if the source - * instruction is lower down the tree. - */ -static bool -gcm_schedule_early_src(nir_src *src, void *void_state) -{ - struct gcm_state *state = void_state; - nir_instr *instr = state->instr; - - assert(src->is_ssa); - - gcm_schedule_early_instr(src->ssa->parent_instr, void_state); - - /* While the index isn't a proper dominance depth, it does have the - * property that if A dominates B then A->index <= B->index. Since we - * know that this instruction must have been dominated by all of its - * sources at some point (even if it's gone through value-numbering), - * all of the sources must lie on the same branch of the dominance tree. - * Therefore, we can just go ahead and just compare indices. - */ - if (instr->block->index < src->ssa->parent_instr->block->index) - instr->block = src->ssa->parent_instr->block; - - /* We need to restore the state instruction because it may have been - * changed through the gcm_schedule_early_instr call above. Since we - * may still be iterating through sources and future calls to - * gcm_schedule_early_src for the same instruction will still need it. - */ - state->instr = instr; - - return true; -} - -/** Schedules an instruction early - * - * This function performs a recursive depth-first search starting at the - * given instruction and proceeding through the sources to schedule - * instructions as early as they can possibly go in the dominance tree. - * The instructions are "scheduled" by updating their instr->block field. - */ -static void -gcm_schedule_early_instr(nir_instr *instr, struct gcm_state *state) -{ - if (instr->pass_flags & GCM_INSTR_SCHEDULED_EARLY) - return; - - instr->pass_flags |= GCM_INSTR_SCHEDULED_EARLY; - - /* Pinned instructions are already scheduled so we don't need to do - * anything. Also, bailing here keeps us from ever following the - * sources of phi nodes which can be back-edges. - */ - if (instr->pass_flags & GCM_INSTR_PINNED) - return; - - /* Start with the instruction at the top. As we iterate over the - * sources, it will get moved down as needed. - */ - instr->block = nir_start_block(state->impl); - state->instr = instr; - - nir_foreach_src(instr, gcm_schedule_early_src, state); -} - -static void -gcm_schedule_late_instr(nir_instr *instr, struct gcm_state *state); - -/** Schedules the instruction associated with the given SSA def late - * - * This function works by first walking all of the uses of the given SSA - * definition, ensuring that they are scheduled, and then computing the LCA - * (least common ancestor) of its uses. It then schedules this instruction - * as close to the LCA as possible while trying to stay out of loops. - */ -static bool -gcm_schedule_late_def(nir_ssa_def *def, void *void_state) -{ - struct gcm_state *state = void_state; - - nir_block *lca = NULL; - - nir_foreach_use(def, use_src) { - nir_instr *use_instr = use_src->parent_instr; - - gcm_schedule_late_instr(use_instr, state); - - /* Phi instructions are a bit special. SSA definitions don't have to - * dominate the sources of the phi nodes that use them; instead, they - * have to dominate the predecessor block corresponding to the phi - * source. We handle this by looking through the sources, finding - * any that are usingg this SSA def, and using those blocks instead - * of the one the phi lives in. - */ - if (use_instr->type == nir_instr_type_phi) { - nir_phi_instr *phi = nir_instr_as_phi(use_instr); - - nir_foreach_phi_src(phi, phi_src) { - if (phi_src->src.ssa == def) - lca = nir_dominance_lca(lca, phi_src->pred); - } - } else { - lca = nir_dominance_lca(lca, use_instr->block); - } - } - - nir_foreach_if_use(def, use_src) { - nir_if *if_stmt = use_src->parent_if; - - /* For if statements, we consider the block to be the one immediately - * preceding the if CF node. - */ - nir_block *pred_block = - nir_cf_node_as_block(nir_cf_node_prev(&if_stmt->cf_node)); - - lca = nir_dominance_lca(lca, pred_block); - } - - /* Some instructions may never be used. We'll just leave them scheduled - * early and let dead code clean them up. - */ - if (lca == NULL) - return true; - - /* We know have the LCA of all of the uses. If our invariants hold, - * this is dominated by the block that we chose when scheduling early. - * We now walk up the dominance tree and pick the lowest block that is - * as far outside loops as we can get. - */ - nir_block *best = lca; - while (lca != def->parent_instr->block) { - assert(lca); - if (state->blocks[lca->index].loop_depth < - state->blocks[best->index].loop_depth) - best = lca; - lca = lca->imm_dom; - } - def->parent_instr->block = best; - - return true; -} - -/** Schedules an instruction late - * - * This function performs a depth-first search starting at the given - * instruction and proceeding through its uses to schedule instructions as - * late as they can reasonably go in the dominance tree. The instructions - * are "scheduled" by updating their instr->block field. - * - * The name of this function is actually a bit of a misnomer as it doesn't - * schedule them "as late as possible" as the paper implies. Instead, it - * first finds the lates possible place it can schedule the instruction and - * then possibly schedules it earlier than that. The actual location is as - * far down the tree as we can go while trying to stay out of loops. - */ -static void -gcm_schedule_late_instr(nir_instr *instr, struct gcm_state *state) -{ - if (instr->pass_flags & GCM_INSTR_SCHEDULED_LATE) - return; - - instr->pass_flags |= GCM_INSTR_SCHEDULED_LATE; - - /* Pinned instructions are already scheduled so we don't need to do - * anything. Also, bailing here keeps us from ever following phi nodes - * which can be back-edges. - */ - if (instr->pass_flags & GCM_INSTR_PINNED) - return; - - nir_foreach_ssa_def(instr, gcm_schedule_late_def, state); -} - -static void -gcm_place_instr(nir_instr *instr, struct gcm_state *state); - -static bool -gcm_place_instr_def(nir_ssa_def *def, void *state) -{ - nir_foreach_use(def, use_src) - gcm_place_instr(use_src->parent_instr, state); - - return false; -} - -/** Places an instrution back into the program - * - * The earlier passes of GCM simply choose blocks for each instruction and - * otherwise leave them alone. This pass actually places the instructions - * into their chosen blocks. - * - * To do so, we use a standard post-order depth-first search linearization - * algorithm. We walk over the uses of the given instruction and ensure - * that they are placed and then place this instruction. Because we are - * working on multiple blocks at a time, we keep track of the last inserted - * instruction per-block in the state structure's block_info array. When - * we insert an instruction in a block we insert it before the last - * instruction inserted in that block rather than the last instruction - * inserted globally. - */ -static void -gcm_place_instr(nir_instr *instr, struct gcm_state *state) -{ - if (instr->pass_flags & GCM_INSTR_PLACED) - return; - - instr->pass_flags |= GCM_INSTR_PLACED; - - /* Phi nodes are our once source of back-edges. Since right now we are - * only doing scheduling within blocks, we don't need to worry about - * them since they are always at the top. Just skip them completely. - */ - if (instr->type == nir_instr_type_phi) { - assert(instr->pass_flags & GCM_INSTR_PINNED); - return; - } - - nir_foreach_ssa_def(instr, gcm_place_instr_def, state); - - if (instr->pass_flags & GCM_INSTR_PINNED) { - /* Pinned instructions have an implicit dependence on the pinned - * instructions that come after them in the block. Since the pinned - * instructions will naturally "chain" together, we only need to - * explicitly visit one of them. - */ - for (nir_instr *after = nir_instr_next(instr); - after; - after = nir_instr_next(after)) { - if (after->pass_flags & GCM_INSTR_PINNED) { - gcm_place_instr(after, state); - break; - } - } - } - - struct gcm_block_info *block_info = &state->blocks[instr->block->index]; - if (!(instr->pass_flags & GCM_INSTR_PINNED)) { - exec_node_remove(&instr->node); - - if (block_info->last_instr) { - exec_node_insert_node_before(&block_info->last_instr->node, - &instr->node); - } else { - /* Schedule it at the end of the block */ - nir_instr *jump_instr = nir_block_last_instr(instr->block); - if (jump_instr && jump_instr->type == nir_instr_type_jump) { - exec_node_insert_node_before(&jump_instr->node, &instr->node); - } else { - exec_list_push_tail(&instr->block->instr_list, &instr->node); - } - } - } - - block_info->last_instr = instr; -} - -static void -opt_gcm_impl(nir_function_impl *impl) -{ - struct gcm_state state; - - state.impl = impl; - state.instr = NULL; - exec_list_make_empty(&state.instrs); - state.blocks = rzalloc_array(NULL, struct gcm_block_info, impl->num_blocks); - - nir_metadata_require(impl, nir_metadata_block_index | - nir_metadata_dominance); - - gcm_build_block_info(&impl->body, &state, 0); - nir_foreach_block(impl, gcm_pin_instructions_block, &state); - - foreach_list_typed(nir_instr, instr, node, &state.instrs) - gcm_schedule_early_instr(instr, &state); - - foreach_list_typed(nir_instr, instr, node, &state.instrs) - gcm_schedule_late_instr(instr, &state); - - while (!exec_list_is_empty(&state.instrs)) { - nir_instr *instr = exec_node_data(nir_instr, - state.instrs.tail_pred, node); - gcm_place_instr(instr, &state); - } - - ralloc_free(state.blocks); -} - -void -nir_opt_gcm(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - opt_gcm_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_opt_global_to_local.c b/src/glsl/nir/nir_opt_global_to_local.c deleted file mode 100644 index bccb45b6237..00000000000 --- a/src/glsl/nir/nir_opt_global_to_local.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -static bool -global_to_local(nir_register *reg) -{ - nir_function_impl *impl = NULL; - - assert(reg->is_global); - - nir_foreach_def(reg, def_dest) { - nir_instr *instr = def_dest->reg.parent_instr; - nir_function_impl *instr_impl = - nir_cf_node_get_function(&instr->block->cf_node); - if (impl != NULL) { - if (impl != instr_impl) - return false; - } else { - impl = instr_impl; - } - } - - nir_foreach_use(reg, use_src) { - nir_instr *instr = use_src->parent_instr; - nir_function_impl *instr_impl = - nir_cf_node_get_function(&instr->block->cf_node); - if (impl != NULL) { - if (impl != instr_impl) - return false; - } else { - impl = instr_impl; - } - } - - nir_foreach_if_use(reg, use_src) { - nir_if *if_stmt = use_src->parent_if; - nir_function_impl *if_impl = nir_cf_node_get_function(&if_stmt->cf_node); - if (impl != NULL) { - if (impl != if_impl) - return false; - } else { - impl = if_impl; - } - } - - if (impl == NULL) { - /* this instruction is never used/defined, delete it */ - nir_reg_remove(reg); - return true; - } - - /* - * if we've gotten to this point, the register is always used/defined in - * the same implementation so we can move it to be local to that - * implementation. - */ - - exec_node_remove(®->node); - exec_list_push_tail(&impl->registers, ®->node); - reg->index = impl->reg_alloc++; - reg->is_global = false; - return true; -} - -bool -nir_opt_global_to_local(nir_shader *shader) -{ - bool progress = false; - - foreach_list_typed_safe(nir_register, reg, node, &shader->registers) { - if (global_to_local(reg)) - progress = true; - } - - return progress; -} diff --git a/src/glsl/nir/nir_opt_peephole_select.c b/src/glsl/nir/nir_opt_peephole_select.c deleted file mode 100644 index 0fc658df861..00000000000 --- a/src/glsl/nir/nir_opt_peephole_select.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" -#include "nir_control_flow.h" - -/* - * Implements a small peephole optimization that looks for - * - * if (cond) { - * <empty> - * } else { - * <empty> - * } - * phi - * ... - * phi - * - * and replaces it with a series of selects. It can also handle the case - * where, instead of being empty, the if may contain some move operations - * whose only use is one of the following phi nodes. This happens all the - * time when the SSA form comes from a conditional assignment with a - * swizzle. - */ - -struct peephole_select_state { - void *mem_ctx; - bool progress; -}; - -static bool -block_check_for_allowed_instrs(nir_block *block) -{ - nir_foreach_instr(block, instr) { - switch (instr->type) { - case nir_instr_type_intrinsic: { - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - - switch (intrin->intrinsic) { - case nir_intrinsic_load_var: - switch (intrin->variables[0]->var->data.mode) { - case nir_var_shader_in: - case nir_var_uniform: - break; - - default: - return false; - } - break; - - default: - return false; - } - - break; - } - - case nir_instr_type_load_const: - break; - - case nir_instr_type_alu: { - nir_alu_instr *mov = nir_instr_as_alu(instr); - switch (mov->op) { - case nir_op_fmov: - case nir_op_imov: - case nir_op_fneg: - case nir_op_ineg: - case nir_op_fabs: - case nir_op_iabs: - case nir_op_vec2: - case nir_op_vec3: - case nir_op_vec4: - /* It must be a move-like operation. */ - break; - default: - return false; - } - - /* Can't handle saturate */ - if (mov->dest.saturate) - return false; - - /* It must be SSA */ - if (!mov->dest.dest.is_ssa) - return false; - - /* It cannot have any if-uses */ - if (!list_empty(&mov->dest.dest.ssa.if_uses)) - return false; - - /* The only uses of this definition must be phi's in the successor */ - nir_foreach_use(&mov->dest.dest.ssa, use) { - if (use->parent_instr->type != nir_instr_type_phi || - use->parent_instr->block != block->successors[0]) - return false; - } - break; - } - - default: - return false; - } - } - - return true; -} - -static bool -nir_opt_peephole_select_block(nir_block *block, void *void_state) -{ - struct peephole_select_state *state = void_state; - - /* If the block is empty, then it certainly doesn't have any phi nodes, - * so we can skip it. This also ensures that we do an early skip on the - * end block of the function which isn't actually attached to the CFG. - */ - if (exec_list_is_empty(&block->instr_list)) - return true; - - if (nir_cf_node_is_first(&block->cf_node)) - return true; - - nir_cf_node *prev_node = nir_cf_node_prev(&block->cf_node); - if (prev_node->type != nir_cf_node_if) - return true; - - nir_if *if_stmt = nir_cf_node_as_if(prev_node); - nir_cf_node *then_node = nir_if_first_then_node(if_stmt); - nir_cf_node *else_node = nir_if_first_else_node(if_stmt); - - /* We can only have one block in each side ... */ - if (nir_if_last_then_node(if_stmt) != then_node || - nir_if_last_else_node(if_stmt) != else_node) - return true; - - nir_block *then_block = nir_cf_node_as_block(then_node); - nir_block *else_block = nir_cf_node_as_block(else_node); - - /* ... and those blocks must only contain "allowed" instructions. */ - if (!block_check_for_allowed_instrs(then_block) || - !block_check_for_allowed_instrs(else_block)) - return true; - - /* At this point, we know that the previous CFG node is an if-then - * statement containing only moves to phi nodes in this block. We can - * just remove that entire CF node and replace all of the phi nodes with - * selects. - */ - - nir_block *prev_block = nir_cf_node_as_block(nir_cf_node_prev(prev_node)); - assert(prev_block->cf_node.type == nir_cf_node_block); - - /* First, we move the remaining instructions from the blocks to the - * block before. We have already guaranteed that this is safe by - * calling block_check_for_allowed_instrs() - */ - nir_foreach_instr_safe(then_block, instr) { - exec_node_remove(&instr->node); - instr->block = prev_block; - exec_list_push_tail(&prev_block->instr_list, &instr->node); - } - - nir_foreach_instr_safe(else_block, instr) { - exec_node_remove(&instr->node); - instr->block = prev_block; - exec_list_push_tail(&prev_block->instr_list, &instr->node); - } - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - nir_alu_instr *sel = nir_alu_instr_create(state->mem_ctx, nir_op_bcsel); - nir_src_copy(&sel->src[0].src, &if_stmt->condition, sel); - /* Splat the condition to all channels */ - memset(sel->src[0].swizzle, 0, sizeof sel->src[0].swizzle); - - assert(exec_list_length(&phi->srcs) == 2); - nir_foreach_phi_src(phi, src) { - assert(src->pred == then_block || src->pred == else_block); - assert(src->src.is_ssa); - - unsigned idx = src->pred == then_block ? 1 : 2; - nir_src_copy(&sel->src[idx].src, &src->src, sel); - } - - nir_ssa_dest_init(&sel->instr, &sel->dest.dest, - phi->dest.ssa.num_components, phi->dest.ssa.name); - sel->dest.write_mask = (1 << phi->dest.ssa.num_components) - 1; - - nir_ssa_def_rewrite_uses(&phi->dest.ssa, - nir_src_for_ssa(&sel->dest.dest.ssa)); - - nir_instr_insert_before(&phi->instr, &sel->instr); - nir_instr_remove(&phi->instr); - } - - nir_cf_node_remove(&if_stmt->cf_node); - state->progress = true; - - return true; -} - -static bool -nir_opt_peephole_select_impl(nir_function_impl *impl) -{ - struct peephole_select_state state; - - state.mem_ctx = ralloc_parent(impl); - state.progress = false; - - nir_foreach_block(impl, nir_opt_peephole_select_block, &state); - - if (state.progress) - nir_metadata_preserve(impl, nir_metadata_none); - - return state.progress; -} - -bool -nir_opt_peephole_select(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress |= nir_opt_peephole_select_impl(function->impl); - } - - return progress; -} diff --git a/src/glsl/nir/nir_opt_remove_phis.c b/src/glsl/nir/nir_opt_remove_phis.c deleted file mode 100644 index 646183707bd..00000000000 --- a/src/glsl/nir/nir_opt_remove_phis.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright © 2015 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -/* - * This is a pass for removing phi nodes that look like: - * a = phi(b, b, b, ...) - * - * Note that we can't ignore undef sources here, or else we may create a - * situation where the definition of b isn't dominated by its uses. We're - * allowed to do this since the definition of b must dominate all of the - * phi node's predecessors, which means it must dominate the phi node as well - * as all of the phi node's uses. In essence, the phi node acts as a copy - * instruction. b can't be another phi node in the same block, since the only - * time when phi nodes can source other phi nodes defined in the same block is - * at the loop header, and in that case one of the sources of the phi has to - * be from before the loop and that source can't be b. - */ - -static bool -remove_phis_block(nir_block *block, void *state) -{ - bool *progress = state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi = nir_instr_as_phi(instr); - - nir_ssa_def *def = NULL; - bool srcs_same = true; - - nir_foreach_phi_src(phi, src) { - assert(src->src.is_ssa); - - /* For phi nodes at the beginning of loops, we may encounter some - * sources from backedges that point back to the destination of the - * same phi, i.e. something like: - * - * a = phi(a, b, ...) - * - * We can safely ignore these sources, since if all of the normal - * sources point to the same definition, then that definition must - * still dominate the phi node, and the phi will still always take - * the value of that definition. - */ - if (src->src.ssa == &phi->dest.ssa) - continue; - - if (def == NULL) { - def = src->src.ssa; - } else { - if (src->src.ssa != def) { - srcs_same = false; - break; - } - } - } - - if (!srcs_same) - continue; - - /* We must have found at least one definition, since there must be at - * least one forward edge. - */ - assert(def != NULL); - - assert(phi->dest.is_ssa); - nir_ssa_def_rewrite_uses(&phi->dest.ssa, nir_src_for_ssa(def)); - nir_instr_remove(instr); - - *progress = true; - } - - return true; -} - -static bool -remove_phis_impl(nir_function_impl *impl) -{ - bool progress = false; - - nir_foreach_block(impl, remove_phis_block, &progress); - - if (progress) { - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - } - - return progress; -} - -bool -nir_opt_remove_phis(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) - if (function->impl) - progress = remove_phis_impl(function->impl) || progress; - - return progress; -} - diff --git a/src/glsl/nir/nir_opt_undef.c b/src/glsl/nir/nir_opt_undef.c deleted file mode 100644 index 374564d34c5..00000000000 --- a/src/glsl/nir/nir_opt_undef.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright © 2015 Broadcom - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" - -/** @file nir_opt_undef.c - * - * Handles optimization of operations involving ssa_undef. For now, we just - * make sure that csels between undef and some other value just give the other - * value (on the assumption that the condition's going to be choosing the - * defined value). This reduces work after if flattening when each side of - * the if is defining a variable. - * - * Some day, we may find some use for making other operations consuming an - * undef arg output undef, but I don't know of any cases currently. - */ - -static bool -opt_undef_alu(nir_alu_instr *instr) -{ - if (instr->op != nir_op_bcsel && instr->op != nir_op_fcsel) - return false; - - assert(instr->dest.dest.is_ssa); - - for (int i = 1; i <= 2; i++) { - if (!instr->src[i].src.is_ssa) - continue; - - nir_instr *parent = instr->src[i].src.ssa->parent_instr; - if (parent->type != nir_instr_type_ssa_undef) - continue; - - /* We can't just use nir_alu_src_copy, because we need the def/use - * updated. - */ - nir_instr_rewrite_src(&instr->instr, &instr->src[0].src, - instr->src[i == 1 ? 2 : 1].src); - nir_alu_src_copy(&instr->src[0], &instr->src[i == 1 ? 2 : 1], - ralloc_parent(instr)); - - nir_src empty_src; - memset(&empty_src, 0, sizeof(empty_src)); - nir_instr_rewrite_src(&instr->instr, &instr->src[1].src, empty_src); - nir_instr_rewrite_src(&instr->instr, &instr->src[2].src, empty_src); - instr->op = nir_op_imov; - - return true; - } - - return false; -} - -static bool -opt_undef_block(nir_block *block, void *data) -{ - bool *progress = data; - - nir_foreach_instr_safe(block, instr) { - if (instr->type == nir_instr_type_alu) - if (opt_undef_alu(nir_instr_as_alu(instr))) - (*progress) = true; - } - - return true; -} - -bool -nir_opt_undef(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) { - nir_foreach_block(function->impl, opt_undef_block, &progress); - if (progress) - nir_metadata_preserve(function->impl, - nir_metadata_block_index | - nir_metadata_dominance); - } - } - - return progress; -} diff --git a/src/glsl/nir/nir_phi_builder.c b/src/glsl/nir/nir_phi_builder.c deleted file mode 100644 index 5429083e5c8..00000000000 --- a/src/glsl/nir/nir_phi_builder.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir_phi_builder.h" -#include "nir/nir_vla.h" - -struct nir_phi_builder { - nir_shader *shader; - nir_function_impl *impl; - - /* Copied from the impl for easy access */ - unsigned num_blocks; - - /* Array of all blocks indexed by block->index. */ - nir_block **blocks; - - /* Hold on to the values so we can easily iterate over them. */ - struct exec_list values; - - /* Worklist for phi adding */ - unsigned iter_count; - unsigned *work; - nir_block **W; -}; - -#define NEEDS_PHI ((nir_ssa_def *)(intptr_t)-1) - -struct nir_phi_builder_value { - struct exec_node node; - - struct nir_phi_builder *builder; - - /* Needed so we can create phis and undefs */ - unsigned num_components; - - /* The list of phi nodes associated with this value. Phi nodes are not - * added directly. Instead, they are created, the instr->block pointer - * set, and then added to this list. Later, in phi_builder_finish, we - * set up their sources and add them to the top of their respective - * blocks. - */ - struct exec_list phis; - - /* Array of SSA defs, indexed by block. If a phi needs to be inserted - * in a given block, it will have the magic value NEEDS_PHI. - */ - nir_ssa_def *defs[0]; -}; - -static bool -fill_block_array(nir_block *block, void *void_data) -{ - nir_block **blocks = void_data; - blocks[block->index] = block; - return true; -} - -struct nir_phi_builder * -nir_phi_builder_create(nir_function_impl *impl) -{ - struct nir_phi_builder *pb = ralloc(NULL, struct nir_phi_builder); - - pb->shader = impl->function->shader; - pb->impl = impl; - - assert(impl->valid_metadata & (nir_metadata_block_index | - nir_metadata_dominance)); - - pb->num_blocks = impl->num_blocks; - pb->blocks = ralloc_array(pb, nir_block *, pb->num_blocks); - nir_foreach_block(impl, fill_block_array, pb->blocks); - - exec_list_make_empty(&pb->values); - - pb->iter_count = 0; - pb->work = rzalloc_array(pb, unsigned, pb->num_blocks); - pb->W = ralloc_array(pb, nir_block *, pb->num_blocks); - - return pb; -} - -struct nir_phi_builder_value * -nir_phi_builder_add_value(struct nir_phi_builder *pb, unsigned num_components, - const BITSET_WORD *defs) -{ - struct nir_phi_builder_value *val; - unsigned i, w_start = 0, w_end = 0; - - val = rzalloc_size(pb, sizeof(*val) + sizeof(val->defs[0]) * pb->num_blocks); - val->builder = pb; - val->num_components = num_components; - exec_list_make_empty(&val->phis); - exec_list_push_tail(&pb->values, &val->node); - - pb->iter_count++; - - BITSET_WORD tmp; - BITSET_FOREACH_SET(i, tmp, defs, pb->num_blocks) { - if (pb->work[i] < pb->iter_count) - pb->W[w_end++] = pb->blocks[i]; - pb->work[i] = pb->iter_count; - } - - while (w_start != w_end) { - nir_block *cur = pb->W[w_start++]; - struct set_entry *dom_entry; - set_foreach(cur->dom_frontier, dom_entry) { - nir_block *next = (nir_block *) dom_entry->key; - - /* - * If there's more than one return statement, then the end block - * can be a join point for some definitions. However, there are - * no instructions in the end block, so nothing would use those - * phi nodes. Of course, we couldn't place those phi nodes - * anyways due to the restriction of having no instructions in the - * end block... - */ - if (next == pb->impl->end_block) - continue; - - if (val->defs[next->index] == NULL) { - val->defs[next->index] = NEEDS_PHI; - - if (pb->work[next->index] < pb->iter_count) { - pb->work[next->index] = pb->iter_count; - pb->W[w_end++] = next; - } - } - } - } - - return val; -} - -void -nir_phi_builder_value_set_block_def(struct nir_phi_builder_value *val, - nir_block *block, nir_ssa_def *def) -{ - val->defs[block->index] = def; -} - -nir_ssa_def * -nir_phi_builder_value_get_block_def(struct nir_phi_builder_value *val, - nir_block *block) -{ - if (val->defs[block->index] == NULL) { - if (block->imm_dom) { - /* Grab it from our immediate dominator. We'll stash it here for - * easy access later. - */ - val->defs[block->index] = - nir_phi_builder_value_get_block_def(val, block->imm_dom); - return val->defs[block->index]; - } else { - /* No immediate dominator means that this block is either the - * start block or unreachable. In either case, the value is - * undefined so we need an SSA undef. - */ - nir_ssa_undef_instr *undef = - nir_ssa_undef_instr_create(val->builder->shader, - val->num_components); - nir_instr_insert(nir_before_cf_list(&val->builder->impl->body), - &undef->instr); - val->defs[block->index] = &undef->def; - return &undef->def; - } - } else if (val->defs[block->index] == NEEDS_PHI) { - /* If we need a phi instruction, go ahead and create one but don't - * add it to the program yet. Later, we'll go through and set up phi - * sources and add the instructions will be added at that time. - */ - nir_phi_instr *phi = nir_phi_instr_create(val->builder->shader); - nir_ssa_dest_init(&phi->instr, &phi->dest, val->num_components, NULL); - phi->instr.block = block; - exec_list_push_tail(&val->phis, &phi->instr.node); - val->defs[block->index] = &phi->dest.ssa; - return &phi->dest.ssa; - } else { - return val->defs[block->index]; - } -} - -static int -compare_blocks(const void *_a, const void *_b) -{ - nir_block * const * a = _a; - nir_block * const * b = _b; - - return (*a)->index - (*b)->index; -} - -void -nir_phi_builder_finish(struct nir_phi_builder *pb) -{ - const unsigned num_blocks = pb->num_blocks; - NIR_VLA(nir_block *, preds, num_blocks); - - foreach_list_typed(struct nir_phi_builder_value, val, node, &pb->values) { - /* We can't iterate over the list of phis normally because we are - * removing them as we go and, in some cases, adding new phis as we - * build the source lists of others. - */ - while (!exec_list_is_empty(&val->phis)) { - struct exec_node *head = exec_list_get_head(&val->phis); - nir_phi_instr *phi = exec_node_data(nir_phi_instr, head, instr.node); - assert(phi->instr.type == nir_instr_type_phi); - - exec_node_remove(&phi->instr.node); - - /* Construct an array of predecessors. We sort it to ensure - * determinism in the phi insertion algorithm. - * - * XXX: Calling qsort this many times seems expensive. - */ - int num_preds = 0; - struct set_entry *entry; - set_foreach(phi->instr.block->predecessors, entry) - preds[num_preds++] = (nir_block *)entry->key; - qsort(preds, num_preds, sizeof(*preds), compare_blocks); - - for (unsigned i = 0; i < num_preds; i++) { - nir_phi_src *src = ralloc(phi, nir_phi_src); - src->pred = preds[i]; - src->src = nir_src_for_ssa( - nir_phi_builder_value_get_block_def(val, preds[i])); - exec_list_push_tail(&phi->srcs, &src->node); - } - - nir_instr_insert(nir_before_block(phi->instr.block), &phi->instr); - } - } - - ralloc_free(pb); -} diff --git a/src/glsl/nir/nir_phi_builder.h b/src/glsl/nir/nir_phi_builder.h deleted file mode 100644 index 50251bf1ba3..00000000000 --- a/src/glsl/nir/nir_phi_builder.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#pragma once - -#include "nir.h" - -struct nir_phi_builder; -struct nir_phi_builder_value; - -/* Create a new phi builder. - * - * While this is fairly cheap, it does allocate some memory and walk the list - * of blocks so it's recommended that you only call it once and use it to - * build phis for several values. - */ -struct nir_phi_builder *nir_phi_builder_create(nir_function_impl *impl); - -/* Register a value with the builder. - * - * The 'defs' parameter specifies a bitset of blocks in which the given value - * is defined. This is used to determine where to place the phi nodes. - */ -struct nir_phi_builder_value * -nir_phi_builder_add_value(struct nir_phi_builder *pb, unsigned num_components, - const BITSET_WORD *defs); - -/* Register a definition for the given value and block. - * - * It is safe to call this function as many times as you wish for any given - * block/value pair. However, it always replaces whatever was there - * previously even if that definition is from a phi node. The phi builder - * always uses the latest information it has, so you must be careful about the - * order in which you register definitions. The final value at the end of the - * block must be the last value registered. - */ -void -nir_phi_builder_value_set_block_def(struct nir_phi_builder_value *val, - nir_block *block, nir_ssa_def *def); - -/* Get the definition for the given value in the given block. - * - * This definition will always be the latest definition known for the given - * block. If no definition is immediately available, it will crawl up the - * dominance tree and insert phi nodes as needed until it finds one. In the - * case that no suitable definition is found, it will return the result of a - * nir_ssa_undef_instr with the correct number of components. - * - * Because this function only uses the latest available information for any - * given block, you must have already finished registering definitions for any - * blocks that dominate the current block in order to get the correct result. - */ -nir_ssa_def * -nir_phi_builder_value_get_block_def(struct nir_phi_builder_value *val, - nir_block *block); - -/* Finish building phi nodes and free the builder. - * - * This function does far more than just free memory. Prior to calling - * nir_phi_builder_finish, no phi nodes have actually been inserted in the - * program. This function is what finishes setting up phi node sources and - * adds the phi nodes to the program. - */ -void nir_phi_builder_finish(struct nir_phi_builder *pb); diff --git a/src/glsl/nir/nir_print.c b/src/glsl/nir/nir_print.c deleted file mode 100644 index a137706b15b..00000000000 --- a/src/glsl/nir/nir_print.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include "shader_enums.h" -#include <stdio.h> -#include <stdlib.h> - -static void -print_tabs(unsigned num_tabs, FILE *fp) -{ - for (unsigned i = 0; i < num_tabs; i++) - fprintf(fp, "\t"); -} - -typedef struct { - FILE *fp; - nir_shader *shader; - /** map from nir_variable -> printable name */ - struct hash_table *ht; - - /** set of names used so far for nir_variables */ - struct set *syms; - - /* an index used to make new non-conflicting names */ - unsigned index; -} print_state; - -static void -print_register(nir_register *reg, print_state *state) -{ - FILE *fp = state->fp; - if (reg->name != NULL) - fprintf(fp, "/* %s */ ", reg->name); - if (reg->is_global) - fprintf(fp, "gr%u", reg->index); - else - fprintf(fp, "r%u", reg->index); -} - -static const char *sizes[] = { "error", "vec1", "vec2", "vec3", "vec4" }; - -static void -print_register_decl(nir_register *reg, print_state *state) -{ - FILE *fp = state->fp; - fprintf(fp, "decl_reg %s ", sizes[reg->num_components]); - if (reg->is_packed) - fprintf(fp, "(packed) "); - print_register(reg, state); - if (reg->num_array_elems != 0) - fprintf(fp, "[%u]", reg->num_array_elems); - fprintf(fp, "\n"); -} - -static void -print_ssa_def(nir_ssa_def *def, print_state *state) -{ - FILE *fp = state->fp; - if (def->name != NULL) - fprintf(fp, "/* %s */ ", def->name); - fprintf(fp, "%s ssa_%u", sizes[def->num_components], def->index); -} - -static void -print_ssa_use(nir_ssa_def *def, print_state *state) -{ - FILE *fp = state->fp; - if (def->name != NULL) - fprintf(fp, "/* %s */ ", def->name); - fprintf(fp, "ssa_%u", def->index); -} - -static void print_src(nir_src *src, print_state *state); - -static void -print_reg_src(nir_reg_src *src, print_state *state) -{ - FILE *fp = state->fp; - print_register(src->reg, state); - if (src->reg->num_array_elems != 0) { - fprintf(fp, "[%u", src->base_offset); - if (src->indirect != NULL) { - fprintf(fp, " + "); - print_src(src->indirect, state); - } - fprintf(fp, "]"); - } -} - -static void -print_reg_dest(nir_reg_dest *dest, print_state *state) -{ - FILE *fp = state->fp; - print_register(dest->reg, state); - if (dest->reg->num_array_elems != 0) { - fprintf(fp, "[%u", dest->base_offset); - if (dest->indirect != NULL) { - fprintf(fp, " + "); - print_src(dest->indirect, state); - } - fprintf(fp, "]"); - } -} - -static void -print_src(nir_src *src, print_state *state) -{ - if (src->is_ssa) - print_ssa_use(src->ssa, state); - else - print_reg_src(&src->reg, state); -} - -static void -print_dest(nir_dest *dest, print_state *state) -{ - if (dest->is_ssa) - print_ssa_def(&dest->ssa, state); - else - print_reg_dest(&dest->reg, state); -} - -static void -print_alu_src(nir_alu_instr *instr, unsigned src, print_state *state) -{ - FILE *fp = state->fp; - - if (instr->src[src].negate) - fprintf(fp, "-"); - if (instr->src[src].abs) - fprintf(fp, "abs("); - - print_src(&instr->src[src].src, state); - - bool print_swizzle = false; - for (unsigned i = 0; i < 4; i++) { - if (!nir_alu_instr_channel_used(instr, src, i)) - continue; - - if (instr->src[src].swizzle[i] != i) { - print_swizzle = true; - break; - } - } - - if (print_swizzle) { - fprintf(fp, "."); - for (unsigned i = 0; i < 4; i++) { - if (!nir_alu_instr_channel_used(instr, src, i)) - continue; - - fprintf(fp, "%c", "xyzw"[instr->src[src].swizzle[i]]); - } - } - - if (instr->src[src].abs) - fprintf(fp, ")"); -} - -static void -print_alu_dest(nir_alu_dest *dest, print_state *state) -{ - FILE *fp = state->fp; - /* we're going to print the saturate modifier later, after the opcode */ - - print_dest(&dest->dest, state); - - if (!dest->dest.is_ssa && - dest->write_mask != (1 << dest->dest.reg.reg->num_components) - 1) { - fprintf(fp, "."); - for (unsigned i = 0; i < 4; i++) - if ((dest->write_mask >> i) & 1) - fprintf(fp, "%c", "xyzw"[i]); - } -} - -static void -print_alu_instr(nir_alu_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - - print_alu_dest(&instr->dest, state); - - fprintf(fp, " = %s", nir_op_infos[instr->op].name); - if (instr->dest.saturate) - fprintf(fp, ".sat"); - fprintf(fp, " "); - - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - if (i != 0) - fprintf(fp, ", "); - - print_alu_src(instr, i, state); - } -} - -static const char * -get_var_name(nir_variable *var, print_state *state) -{ - if (state->ht == NULL) - return var->name; - - assert(state->syms); - - struct hash_entry *entry = _mesa_hash_table_search(state->ht, var); - if (entry) - return entry->data; - - char *name; - if (var->name == NULL) { - name = ralloc_asprintf(state->syms, "@%u", state->index++); - } else { - struct set_entry *set_entry = _mesa_set_search(state->syms, var->name); - if (set_entry != NULL) { - /* we have a collision with another name, append an @ + a unique - * index */ - name = ralloc_asprintf(state->syms, "%s@%u", var->name, - state->index++); - } else { - /* Mark this one as seen */ - _mesa_set_add(state->syms, var->name); - name = var->name; - } - } - - _mesa_hash_table_insert(state->ht, var, name); - - return name; -} - -static void -print_constant(nir_constant *c, const struct glsl_type *type, print_state *state) -{ - FILE *fp = state->fp; - unsigned total_elems = glsl_get_components(type); - unsigned i; - - switch (glsl_get_base_type(type)) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_BOOL: - for (i = 0; i < total_elems; i++) { - if (i > 0) fprintf(fp, ", "); - fprintf(fp, "0x%08x", c->value.u[i]); - } - break; - - case GLSL_TYPE_FLOAT: - for (i = 0; i < total_elems; i++) { - if (i > 0) fprintf(fp, ", "); - fprintf(fp, "%f", c->value.f[i]); - } - break; - - case GLSL_TYPE_STRUCT: - for (i = 0; i < c->num_elements; i++) { - if (i > 0) fprintf(fp, ", "); - fprintf(fp, "{ "); - print_constant(c->elements[i], glsl_get_struct_field(type, i), state); - fprintf(fp, " }"); - } - break; - - case GLSL_TYPE_ARRAY: - for (i = 0; i < c->num_elements; i++) { - if (i > 0) fprintf(fp, ", "); - fprintf(fp, "{ "); - print_constant(c->elements[i], glsl_get_array_element(type), state); - fprintf(fp, " }"); - } - break; - - default: - unreachable("not reached"); - } -} - -static void -print_var_decl(nir_variable *var, print_state *state) -{ - FILE *fp = state->fp; - - fprintf(fp, "decl_var "); - - const char *const cent = (var->data.centroid) ? "centroid " : ""; - const char *const samp = (var->data.sample) ? "sample " : ""; - const char *const patch = (var->data.patch) ? "patch " : ""; - const char *const inv = (var->data.invariant) ? "invariant " : ""; - const char *const mode[] = { "shader_in ", "shader_out ", "", "", - "uniform ", "shader_storage ", "shared ", - "system "}; - - fprintf(fp, "%s%s%s%s%s%s ", - cent, samp, patch, inv, mode[var->data.mode], - glsl_interp_qualifier_name(var->data.interpolation)); - - glsl_print_type(var->type, fp); - - fprintf(fp, " %s", get_var_name(var, state)); - - if (var->data.mode == nir_var_shader_in || - var->data.mode == nir_var_shader_out || - var->data.mode == nir_var_uniform || - var->data.mode == nir_var_shader_storage) { - const char *loc = NULL; - char buf[4]; - - switch (state->shader->stage) { - case MESA_SHADER_VERTEX: - if (var->data.mode == nir_var_shader_in) - loc = gl_vert_attrib_name(var->data.location); - else if (var->data.mode == nir_var_shader_out) - loc = gl_varying_slot_name(var->data.location); - break; - case MESA_SHADER_GEOMETRY: - if ((var->data.mode == nir_var_shader_in) || - (var->data.mode == nir_var_shader_out)) - loc = gl_varying_slot_name(var->data.location); - break; - case MESA_SHADER_FRAGMENT: - if (var->data.mode == nir_var_shader_in) - loc = gl_varying_slot_name(var->data.location); - else if (var->data.mode == nir_var_shader_out) - loc = gl_frag_result_name(var->data.location); - break; - case MESA_SHADER_TESS_CTRL: - case MESA_SHADER_TESS_EVAL: - case MESA_SHADER_COMPUTE: - default: - /* TODO */ - break; - } - - if (!loc) { - snprintf(buf, sizeof(buf), "%u", var->data.location); - loc = buf; - } - - fprintf(fp, " (%s, %u)", loc, var->data.driver_location); - } - - if (var->constant_initializer) { - fprintf(fp, " = { "); - print_constant(var->constant_initializer, var->type, state); - fprintf(fp, " }"); - } - - fprintf(fp, "\n"); -} - -static void -print_var(nir_variable *var, print_state *state) -{ - FILE *fp = state->fp; - fprintf(fp, "%s", get_var_name(var, state)); -} - -static void -print_deref_var(nir_deref_var *deref, print_state *state) -{ - print_var(deref->var, state); -} - -static void -print_deref_array(nir_deref_array *deref, print_state *state) -{ - FILE *fp = state->fp; - fprintf(fp, "["); - switch (deref->deref_array_type) { - case nir_deref_array_type_direct: - fprintf(fp, "%u", deref->base_offset); - break; - case nir_deref_array_type_indirect: - if (deref->base_offset != 0) - fprintf(fp, "%u + ", deref->base_offset); - print_src(&deref->indirect, state); - break; - case nir_deref_array_type_wildcard: - fprintf(fp, "*"); - break; - } - fprintf(fp, "]"); -} - -static void -print_deref_struct(nir_deref_struct *deref, const struct glsl_type *parent_type, - print_state *state) -{ - FILE *fp = state->fp; - fprintf(fp, ".%s", glsl_get_struct_elem_name(parent_type, deref->index)); -} - -static void -print_deref(nir_deref_var *deref, print_state *state) -{ - nir_deref *tail = &deref->deref; - nir_deref *pretail = NULL; - while (tail != NULL) { - switch (tail->deref_type) { - case nir_deref_type_var: - assert(pretail == NULL); - assert(tail == &deref->deref); - print_deref_var(deref, state); - break; - - case nir_deref_type_array: - assert(pretail != NULL); - print_deref_array(nir_deref_as_array(tail), state); - break; - - case nir_deref_type_struct: - assert(pretail != NULL); - print_deref_struct(nir_deref_as_struct(tail), - pretail->type, state); - break; - - default: - unreachable("Invalid deref type"); - } - - pretail = tail; - tail = pretail->child; - } -} - -static void -print_intrinsic_instr(nir_intrinsic_instr *instr, print_state *state) -{ - unsigned num_srcs = nir_intrinsic_infos[instr->intrinsic].num_srcs; - FILE *fp = state->fp; - - if (nir_intrinsic_infos[instr->intrinsic].has_dest) { - print_dest(&instr->dest, state); - fprintf(fp, " = "); - } - - fprintf(fp, "intrinsic %s (", nir_intrinsic_infos[instr->intrinsic].name); - - for (unsigned i = 0; i < num_srcs; i++) { - if (i != 0) - fprintf(fp, ", "); - - print_src(&instr->src[i], state); - } - - fprintf(fp, ") ("); - - unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables; - - for (unsigned i = 0; i < num_vars; i++) { - if (i != 0) - fprintf(fp, ", "); - - print_deref(instr->variables[i], state); - } - - fprintf(fp, ") ("); - - unsigned num_indices = nir_intrinsic_infos[instr->intrinsic].num_indices; - - for (unsigned i = 0; i < num_indices; i++) { - if (i != 0) - fprintf(fp, ", "); - - fprintf(fp, "%d", instr->const_index[i]); - } - - fprintf(fp, ")"); - - if (!state->shader) - return; - - struct exec_list *var_list = NULL; - - switch (instr->intrinsic) { - case nir_intrinsic_load_uniform: - var_list = &state->shader->uniforms; - break; - case nir_intrinsic_load_input: - case nir_intrinsic_load_per_vertex_input: - var_list = &state->shader->inputs; - break; - case nir_intrinsic_load_output: - case nir_intrinsic_store_output: - case nir_intrinsic_store_per_vertex_output: - var_list = &state->shader->outputs; - break; - default: - return; - } - - nir_foreach_variable(var, var_list) { - if ((var->data.driver_location == instr->const_index[0]) && - var->name) { - fprintf(fp, "\t/* %s */", var->name); - break; - } - } -} - -static void -print_tex_instr(nir_tex_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - - print_dest(&instr->dest, state); - - fprintf(fp, " = "); - - switch (instr->op) { - case nir_texop_tex: - fprintf(fp, "tex "); - break; - case nir_texop_txb: - fprintf(fp, "txb "); - break; - case nir_texop_txl: - fprintf(fp, "txl "); - break; - case nir_texop_txd: - fprintf(fp, "txd "); - break; - case nir_texop_txf: - fprintf(fp, "txf "); - break; - case nir_texop_txf_ms: - fprintf(fp, "txf_ms "); - break; - case nir_texop_txs: - fprintf(fp, "txs "); - break; - case nir_texop_lod: - fprintf(fp, "lod "); - break; - case nir_texop_tg4: - fprintf(fp, "tg4 "); - break; - case nir_texop_query_levels: - fprintf(fp, "query_levels "); - break; - case nir_texop_texture_samples: - fprintf(fp, "texture_samples "); - break; - case nir_texop_samples_identical: - fprintf(fp, "samples_identical "); - break; - default: - unreachable("Invalid texture operation"); - break; - } - - for (unsigned i = 0; i < instr->num_srcs; i++) { - print_src(&instr->src[i].src, state); - - fprintf(fp, " "); - - switch(instr->src[i].src_type) { - case nir_tex_src_coord: - fprintf(fp, "(coord)"); - break; - case nir_tex_src_projector: - fprintf(fp, "(projector)"); - break; - case nir_tex_src_comparitor: - fprintf(fp, "(comparitor)"); - break; - case nir_tex_src_offset: - fprintf(fp, "(offset)"); - break; - case nir_tex_src_bias: - fprintf(fp, "(bias)"); - break; - case nir_tex_src_lod: - fprintf(fp, "(lod)"); - break; - case nir_tex_src_ms_index: - fprintf(fp, "(ms_index)"); - break; - case nir_tex_src_ddx: - fprintf(fp, "(ddx)"); - break; - case nir_tex_src_ddy: - fprintf(fp, "(ddy)"); - break; - case nir_tex_src_texture_offset: - fprintf(fp, "(texture_offset)"); - break; - case nir_tex_src_sampler_offset: - fprintf(fp, "(sampler_offset)"); - break; - - default: - unreachable("Invalid texture source type"); - break; - } - - fprintf(fp, ", "); - } - - bool has_nonzero_offset = false; - for (unsigned i = 0; i < 4; i++) { - if (instr->const_offset[i] != 0) { - has_nonzero_offset = true; - break; - } - } - - if (has_nonzero_offset) { - fprintf(fp, "[%i %i %i %i] (offset), ", - instr->const_offset[0], instr->const_offset[1], - instr->const_offset[2], instr->const_offset[3]); - } - - if (instr->op == nir_texop_tg4) { - fprintf(fp, "%u (gather_component), ", instr->component); - } - - if (instr->texture) { - assert(instr->sampler); - fprintf(fp, " (texture)"); - } - if (instr->sampler) { - print_deref(instr->sampler, state); - fprintf(fp, " (sampler)"); - } else { - assert(instr->texture == NULL); - fprintf(fp, "%u (texture) %u (sampler)", - instr->texture_index, instr->sampler_index); - } -} - -static void -print_call_instr(nir_call_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - - fprintf(fp, "call %s ", instr->callee->name); - - for (unsigned i = 0; i < instr->num_params; i++) { - if (i != 0) - fprintf(fp, ", "); - - print_deref(instr->params[i], state); - } - - if (instr->return_deref != NULL) { - if (instr->num_params != 0) - fprintf(fp, ", "); - fprintf(fp, "returning "); - print_deref(instr->return_deref, state); - } -} - -static void -print_load_const_instr(nir_load_const_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - - print_ssa_def(&instr->def, state); - - fprintf(fp, " = load_const ("); - - for (unsigned i = 0; i < instr->def.num_components; i++) { - if (i != 0) - fprintf(fp, ", "); - - /* - * we don't really know the type of the constant (if it will be used as a - * float or an int), so just print the raw constant in hex for fidelity - * and then print the float in a comment for readability. - */ - - fprintf(fp, "0x%08x /* %f */", instr->value.u[i], instr->value.f[i]); - } - - fprintf(fp, ")"); -} - -static void -print_jump_instr(nir_jump_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - - switch (instr->type) { - case nir_jump_break: - fprintf(fp, "break"); - break; - - case nir_jump_continue: - fprintf(fp, "continue"); - break; - - case nir_jump_return: - fprintf(fp, "return"); - break; - } -} - -static void -print_ssa_undef_instr(nir_ssa_undef_instr* instr, print_state *state) -{ - FILE *fp = state->fp; - print_ssa_def(&instr->def, state); - fprintf(fp, " = undefined"); -} - -static void -print_phi_instr(nir_phi_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - print_dest(&instr->dest, state); - fprintf(fp, " = phi "); - nir_foreach_phi_src(instr, src) { - if (&src->node != exec_list_get_head(&instr->srcs)) - fprintf(fp, ", "); - - fprintf(fp, "block_%u: ", src->pred->index); - print_src(&src->src, state); - } -} - -static void -print_parallel_copy_instr(nir_parallel_copy_instr *instr, print_state *state) -{ - FILE *fp = state->fp; - nir_foreach_parallel_copy_entry(instr, entry) { - if (&entry->node != exec_list_get_head(&instr->entries)) - fprintf(fp, "; "); - - print_dest(&entry->dest, state); - fprintf(fp, " = "); - print_src(&entry->src, state); - } -} - -static void -print_instr(const nir_instr *instr, print_state *state, unsigned tabs) -{ - FILE *fp = state->fp; - print_tabs(tabs, fp); - - switch (instr->type) { - case nir_instr_type_alu: - print_alu_instr(nir_instr_as_alu(instr), state); - break; - - case nir_instr_type_call: - print_call_instr(nir_instr_as_call(instr), state); - break; - - case nir_instr_type_intrinsic: - print_intrinsic_instr(nir_instr_as_intrinsic(instr), state); - break; - - case nir_instr_type_tex: - print_tex_instr(nir_instr_as_tex(instr), state); - break; - - case nir_instr_type_load_const: - print_load_const_instr(nir_instr_as_load_const(instr), state); - break; - - case nir_instr_type_jump: - print_jump_instr(nir_instr_as_jump(instr), state); - break; - - case nir_instr_type_ssa_undef: - print_ssa_undef_instr(nir_instr_as_ssa_undef(instr), state); - break; - - case nir_instr_type_phi: - print_phi_instr(nir_instr_as_phi(instr), state); - break; - - case nir_instr_type_parallel_copy: - print_parallel_copy_instr(nir_instr_as_parallel_copy(instr), state); - break; - - default: - unreachable("Invalid instruction type"); - break; - } -} - -static int -compare_block_index(const void *p1, const void *p2) -{ - const nir_block *block1 = *((const nir_block **) p1); - const nir_block *block2 = *((const nir_block **) p2); - - return (int) block1->index - (int) block2->index; -} - -static void print_cf_node(nir_cf_node *node, print_state *state, - unsigned tabs); - -static void -print_block(nir_block *block, print_state *state, unsigned tabs) -{ - FILE *fp = state->fp; - - print_tabs(tabs, fp); - fprintf(fp, "block block_%u:\n", block->index); - - /* sort the predecessors by index so we consistently print the same thing */ - - nir_block **preds = - malloc(block->predecessors->entries * sizeof(nir_block *)); - - struct set_entry *entry; - unsigned i = 0; - set_foreach(block->predecessors, entry) { - preds[i++] = (nir_block *) entry->key; - } - - qsort(preds, block->predecessors->entries, sizeof(nir_block *), - compare_block_index); - - print_tabs(tabs, fp); - fprintf(fp, "/* preds: "); - for (unsigned i = 0; i < block->predecessors->entries; i++) { - fprintf(fp, "block_%u ", preds[i]->index); - } - fprintf(fp, "*/\n"); - - free(preds); - - nir_foreach_instr(block, instr) { - print_instr(instr, state, tabs); - fprintf(fp, "\n"); - } - - print_tabs(tabs, fp); - fprintf(fp, "/* succs: "); - for (unsigned i = 0; i < 2; i++) - if (block->successors[i]) { - fprintf(fp, "block_%u ", block->successors[i]->index); - } - fprintf(fp, "*/\n"); -} - -static void -print_if(nir_if *if_stmt, print_state *state, unsigned tabs) -{ - FILE *fp = state->fp; - - print_tabs(tabs, fp); - fprintf(fp, "if "); - print_src(&if_stmt->condition, state); - fprintf(fp, " {\n"); - foreach_list_typed(nir_cf_node, node, node, &if_stmt->then_list) { - print_cf_node(node, state, tabs + 1); - } - print_tabs(tabs, fp); - fprintf(fp, "} else {\n"); - foreach_list_typed(nir_cf_node, node, node, &if_stmt->else_list) { - print_cf_node(node, state, tabs + 1); - } - print_tabs(tabs, fp); - fprintf(fp, "}\n"); -} - -static void -print_loop(nir_loop *loop, print_state *state, unsigned tabs) -{ - FILE *fp = state->fp; - - print_tabs(tabs, fp); - fprintf(fp, "loop {\n"); - foreach_list_typed(nir_cf_node, node, node, &loop->body) { - print_cf_node(node, state, tabs + 1); - } - print_tabs(tabs, fp); - fprintf(fp, "}\n"); -} - -static void -print_cf_node(nir_cf_node *node, print_state *state, unsigned int tabs) -{ - switch (node->type) { - case nir_cf_node_block: - print_block(nir_cf_node_as_block(node), state, tabs); - break; - - case nir_cf_node_if: - print_if(nir_cf_node_as_if(node), state, tabs); - break; - - case nir_cf_node_loop: - print_loop(nir_cf_node_as_loop(node), state, tabs); - break; - - default: - unreachable("Invalid CFG node type"); - } -} - -static void -print_function_impl(nir_function_impl *impl, print_state *state) -{ - FILE *fp = state->fp; - - fprintf(fp, "\nimpl %s ", impl->function->name); - - for (unsigned i = 0; i < impl->num_params; i++) { - if (i != 0) - fprintf(fp, ", "); - - print_var(impl->params[i], state); - } - - if (impl->return_var != NULL) { - if (impl->num_params != 0) - fprintf(fp, ", "); - fprintf(fp, "returning "); - print_var(impl->return_var, state); - } - - fprintf(fp, "{\n"); - - nir_foreach_variable(var, &impl->locals) { - fprintf(fp, "\t"); - print_var_decl(var, state); - } - - foreach_list_typed(nir_register, reg, node, &impl->registers) { - fprintf(fp, "\t"); - print_register_decl(reg, state); - } - - nir_index_blocks(impl); - - foreach_list_typed(nir_cf_node, node, node, &impl->body) { - print_cf_node(node, state, 1); - } - - fprintf(fp, "\tblock block_%u:\n}\n\n", impl->end_block->index); -} - -static void -print_function(nir_function *function, print_state *state) -{ - FILE *fp = state->fp; - - fprintf(fp, "decl_function %s ", function->name); - - for (unsigned i = 0; i < function->num_params; i++) { - if (i != 0) - fprintf(fp, ", "); - - switch (function->params[i].param_type) { - case nir_parameter_in: - fprintf(fp, "in "); - break; - case nir_parameter_out: - fprintf(fp, "out "); - break; - case nir_parameter_inout: - fprintf(fp, "inout "); - break; - default: - unreachable("Invalid parameter type"); - } - - glsl_print_type(function->params[i].type, fp); - } - - if (function->return_type != NULL) { - if (function->num_params != 0) - fprintf(fp, ", "); - fprintf(fp, "returning "); - glsl_print_type(function->return_type, fp); - } - - fprintf(fp, "\n"); - - if (function->impl != NULL) { - print_function_impl(function->impl, state); - return; - } -} - -static void -init_print_state(print_state *state, nir_shader *shader, FILE *fp) -{ - state->fp = fp; - state->shader = shader; - state->ht = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - state->syms = _mesa_set_create(NULL, _mesa_key_hash_string, - _mesa_key_string_equal); - state->index = 0; -} - -static void -destroy_print_state(print_state *state) -{ - _mesa_hash_table_destroy(state->ht, NULL); - _mesa_set_destroy(state->syms, NULL); -} - -void -nir_print_shader(nir_shader *shader, FILE *fp) -{ - print_state state; - init_print_state(&state, shader, fp); - - fprintf(fp, "shader: %s\n", gl_shader_stage_name(shader->stage)); - - if (shader->info.name) - fprintf(fp, "name: %s\n", shader->info.name); - - if (shader->info.label) - fprintf(fp, "label: %s\n", shader->info.label); - - fprintf(fp, "inputs: %u\n", shader->num_inputs); - fprintf(fp, "outputs: %u\n", shader->num_outputs); - fprintf(fp, "uniforms: %u\n", shader->num_uniforms); - fprintf(fp, "shared: %u\n", shader->num_shared); - - nir_foreach_variable(var, &shader->uniforms) { - print_var_decl(var, &state); - } - - nir_foreach_variable(var, &shader->inputs) { - print_var_decl(var, &state); - } - - nir_foreach_variable(var, &shader->outputs) { - print_var_decl(var, &state); - } - - nir_foreach_variable(var, &shader->shared) { - print_var_decl(var, &state); - } - - nir_foreach_variable(var, &shader->globals) { - print_var_decl(var, &state); - } - - nir_foreach_variable(var, &shader->system_values) { - print_var_decl(var, &state); - } - - foreach_list_typed(nir_register, reg, node, &shader->registers) { - print_register_decl(reg, &state); - } - - foreach_list_typed(nir_function, func, node, &shader->functions) { - print_function(func, &state); - } - - destroy_print_state(&state); -} - -void -nir_print_instr(const nir_instr *instr, FILE *fp) -{ - print_state state = { - .fp = fp, - }; - print_instr(instr, &state, 0); - -} diff --git a/src/glsl/nir/nir_remove_dead_variables.c b/src/glsl/nir/nir_remove_dead_variables.c deleted file mode 100644 index 792c5d4aae6..00000000000 --- a/src/glsl/nir/nir_remove_dead_variables.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" - -static void -add_var_use_intrinsic(nir_intrinsic_instr *instr, struct set *live) -{ - unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables; - for (unsigned i = 0; i < num_vars; i++) { - nir_variable *var = instr->variables[i]->var; - _mesa_set_add(live, var); - } -} - -static void -add_var_use_call(nir_call_instr *instr, struct set *live) -{ - if (instr->return_deref != NULL) { - nir_variable *var = instr->return_deref->var; - _mesa_set_add(live, var); - } - - for (unsigned i = 0; i < instr->num_params; i++) { - nir_variable *var = instr->params[i]->var; - _mesa_set_add(live, var); - } -} - -static void -add_var_use_tex(nir_tex_instr *instr, struct set *live) -{ - if (instr->sampler != NULL) { - nir_variable *var = instr->sampler->var; - _mesa_set_add(live, var); - } -} - -static bool -add_var_use_block(nir_block *block, void *state) -{ - struct set *live = state; - - nir_foreach_instr(block, instr) { - switch(instr->type) { - case nir_instr_type_intrinsic: - add_var_use_intrinsic(nir_instr_as_intrinsic(instr), live); - break; - - case nir_instr_type_call: - add_var_use_call(nir_instr_as_call(instr), live); - break; - - case nir_instr_type_tex: - add_var_use_tex(nir_instr_as_tex(instr), live); - break; - - default: - break; - } - } - - return true; -} - -static void -add_var_use_shader(nir_shader *shader, struct set *live) -{ - nir_foreach_function(shader, function) { - if (function->impl) { - nir_foreach_block(function->impl, add_var_use_block, live); - } - } -} - -static bool -remove_dead_vars(struct exec_list *var_list, struct set *live) -{ - bool progress = false; - - foreach_list_typed_safe(nir_variable, var, node, var_list) { - struct set_entry *entry = _mesa_set_search(live, var); - if (entry == NULL) { - exec_node_remove(&var->node); - ralloc_free(var); - progress = true; - } - } - - return progress; -} - -bool -nir_remove_dead_variables(nir_shader *shader, nir_variable_mode mode) -{ - bool progress = false; - struct set *live = - _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); - - add_var_use_shader(shader, live); - - if (mode == nir_var_uniform || mode == nir_var_all) - progress = remove_dead_vars(&shader->uniforms, live) || progress; - - if (mode == nir_var_shader_in || mode == nir_var_all) - progress = remove_dead_vars(&shader->inputs, live) || progress; - - if (mode == nir_var_shader_out || mode == nir_var_all) - progress = remove_dead_vars(&shader->outputs, live) || progress; - - if (mode == nir_var_global || mode == nir_var_all) - progress = remove_dead_vars(&shader->globals, live) || progress; - - if (mode == nir_var_system_value || mode == nir_var_all) - progress = remove_dead_vars(&shader->system_values, live) || progress; - - if (mode == nir_var_local || mode == nir_var_all) { - nir_foreach_function(shader, function) { - if (function->impl) { - if (remove_dead_vars(&function->impl->locals, live)) { - nir_metadata_preserve(function->impl, nir_metadata_block_index | - nir_metadata_dominance | - nir_metadata_live_ssa_defs); - progress = true; - } - } - } - } - - _mesa_set_destroy(live, NULL); - return progress; -} diff --git a/src/glsl/nir/nir_repair_ssa.c b/src/glsl/nir/nir_repair_ssa.c deleted file mode 100644 index 3ab4f0f6db7..00000000000 --- a/src/glsl/nir/nir_repair_ssa.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" -#include "nir_phi_builder.h" - -struct repair_ssa_state { - nir_function_impl *impl; - - BITSET_WORD *def_set; - struct nir_phi_builder *phi_builder; - - bool progress; -}; - -/* Get ready to build a phi and return the builder */ -static struct nir_phi_builder * -prep_build_phi(struct repair_ssa_state *state) -{ - const unsigned num_words = BITSET_WORDS(state->impl->num_blocks); - - /* We create the phi builder on-demand. */ - if (state->phi_builder == NULL) { - state->phi_builder = nir_phi_builder_create(state->impl); - state->def_set = ralloc_array(NULL, BITSET_WORD, num_words); - } - - /* We're going to build a phi. That's progress. */ - state->progress = true; - - /* Set the defs set to empty */ - memset(state->def_set, 0, num_words * sizeof(*state->def_set)); - - return state->phi_builder; -} - -static nir_block * -get_src_block(nir_src *src) -{ - if (src->parent_instr->type == nir_instr_type_phi) { - return exec_node_data(nir_phi_src, src, src)->pred; - } else { - return src->parent_instr->block; - } -} - -static bool -repair_ssa_def(nir_ssa_def *def, void *void_state) -{ - struct repair_ssa_state *state = void_state; - - bool is_valid = true; - nir_foreach_use(def, src) { - if (!nir_block_dominates(def->parent_instr->block, get_src_block(src))) { - is_valid = false; - break; - } - } - - if (is_valid) - return true; - - struct nir_phi_builder *pb = prep_build_phi(state); - - BITSET_SET(state->def_set, def->parent_instr->block->index); - - struct nir_phi_builder_value *val = - nir_phi_builder_add_value(pb, def->num_components, state->def_set); - - nir_phi_builder_value_set_block_def(val, def->parent_instr->block, def); - - nir_foreach_use_safe(def, src) { - nir_block *src_block = get_src_block(src); - if (!nir_block_dominates(def->parent_instr->block, src_block)) { - nir_instr_rewrite_src(src->parent_instr, src, nir_src_for_ssa( - nir_phi_builder_value_get_block_def(val, src_block))); - } - } - - return true; -} - -static bool -repair_ssa_block(nir_block *block, void *state) -{ - nir_foreach_instr_safe(block, instr) { - nir_foreach_ssa_def(instr, repair_ssa_def, state); - } - - return true; -} - -bool -nir_repair_ssa_impl(nir_function_impl *impl) -{ - struct repair_ssa_state state; - - state.impl = impl; - state.phi_builder = NULL; - state.progress = false; - - nir_metadata_require(impl, nir_metadata_block_index | - nir_metadata_dominance); - - nir_foreach_block(impl, repair_ssa_block, &state); - - if (state.progress) - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - if (state.phi_builder) { - nir_phi_builder_finish(state.phi_builder); - ralloc_free(state.def_set); - } - - return state.progress; -} - -/** This pass can be used to repair SSA form in a shader. - * - * Sometimes a transformation (such as return lowering) will have to make - * changes to a shader which, while still correct, break some of NIR's SSA - * invariants. This pass will insert ssa_undefs and phi nodes as needed to - * get the shader back into SSA that the validator will like. - */ -bool -nir_repair_ssa(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = nir_repair_ssa_impl(function->impl) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_search.c b/src/glsl/nir/nir_search.c deleted file mode 100644 index 56d7e8162f3..00000000000 --- a/src/glsl/nir/nir_search.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir_search.h" - -struct match_state { - unsigned variables_seen; - nir_alu_src variables[NIR_SEARCH_MAX_VARIABLES]; -}; - -static bool -match_expression(const nir_search_expression *expr, nir_alu_instr *instr, - unsigned num_components, const uint8_t *swizzle, - struct match_state *state); - -static const uint8_t identity_swizzle[] = { 0, 1, 2, 3 }; - -static bool alu_instr_is_bool(nir_alu_instr *instr); - -static bool -src_is_bool(nir_src src) -{ - if (!src.is_ssa) - return false; - if (src.ssa->parent_instr->type != nir_instr_type_alu) - return false; - return alu_instr_is_bool(nir_instr_as_alu(src.ssa->parent_instr)); -} - -static bool -alu_instr_is_bool(nir_alu_instr *instr) -{ - switch (instr->op) { - case nir_op_iand: - case nir_op_ior: - case nir_op_ixor: - return src_is_bool(instr->src[0].src) && src_is_bool(instr->src[1].src); - case nir_op_inot: - return src_is_bool(instr->src[0].src); - default: - return nir_op_infos[instr->op].output_type == nir_type_bool; - } -} - -static bool -match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src, - unsigned num_components, const uint8_t *swizzle, - struct match_state *state) -{ - uint8_t new_swizzle[4]; - - /* If the source is an explicitly sized source, then we need to reset - * both the number of components and the swizzle. - */ - if (nir_op_infos[instr->op].input_sizes[src] != 0) { - num_components = nir_op_infos[instr->op].input_sizes[src]; - swizzle = identity_swizzle; - } - - for (unsigned i = 0; i < num_components; ++i) - new_swizzle[i] = instr->src[src].swizzle[swizzle[i]]; - - switch (value->type) { - case nir_search_value_expression: - if (!instr->src[src].src.is_ssa) - return false; - - if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_alu) - return false; - - return match_expression(nir_search_value_as_expression(value), - nir_instr_as_alu(instr->src[src].src.ssa->parent_instr), - num_components, new_swizzle, state); - - case nir_search_value_variable: { - nir_search_variable *var = nir_search_value_as_variable(value); - assert(var->variable < NIR_SEARCH_MAX_VARIABLES); - - if (state->variables_seen & (1 << var->variable)) { - if (!nir_srcs_equal(state->variables[var->variable].src, - instr->src[src].src)) - return false; - - assert(!instr->src[src].abs && !instr->src[src].negate); - - for (unsigned i = 0; i < num_components; ++i) { - if (state->variables[var->variable].swizzle[i] != new_swizzle[i]) - return false; - } - - return true; - } else { - if (var->is_constant && - instr->src[src].src.ssa->parent_instr->type != nir_instr_type_load_const) - return false; - - if (var->type != nir_type_invalid) { - if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_alu) - return false; - - nir_alu_instr *src_alu = - nir_instr_as_alu(instr->src[src].src.ssa->parent_instr); - - if (nir_op_infos[src_alu->op].output_type != var->type && - !(var->type == nir_type_bool && alu_instr_is_bool(src_alu))) - return false; - } - - state->variables_seen |= (1 << var->variable); - state->variables[var->variable].src = instr->src[src].src; - state->variables[var->variable].abs = false; - state->variables[var->variable].negate = false; - - for (unsigned i = 0; i < 4; ++i) { - if (i < num_components) - state->variables[var->variable].swizzle[i] = new_swizzle[i]; - else - state->variables[var->variable].swizzle[i] = 0; - } - - return true; - } - } - - case nir_search_value_constant: { - nir_search_constant *const_val = nir_search_value_as_constant(value); - - if (!instr->src[src].src.is_ssa) - return false; - - if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_load_const) - return false; - - nir_load_const_instr *load = - nir_instr_as_load_const(instr->src[src].src.ssa->parent_instr); - - switch (nir_op_infos[instr->op].input_types[src]) { - case nir_type_float: - for (unsigned i = 0; i < num_components; ++i) { - if (load->value.f[new_swizzle[i]] != const_val->data.f) - return false; - } - return true; - case nir_type_int: - case nir_type_uint: - case nir_type_bool: - for (unsigned i = 0; i < num_components; ++i) { - if (load->value.i[new_swizzle[i]] != const_val->data.i) - return false; - } - return true; - default: - unreachable("Invalid alu source type"); - } - } - - default: - unreachable("Invalid search value type"); - } -} - -static bool -match_expression(const nir_search_expression *expr, nir_alu_instr *instr, - unsigned num_components, const uint8_t *swizzle, - struct match_state *state) -{ - if (instr->op != expr->opcode) - return false; - - assert(!instr->dest.saturate); - assert(nir_op_infos[instr->op].num_inputs > 0); - - /* If we have an explicitly sized destination, we can only handle the - * identity swizzle. While dot(vec3(a, b, c).zxy) is a valid - * expression, we don't have the information right now to propagate that - * swizzle through. We can only properly propagate swizzles if the - * instruction is vectorized. - */ - if (nir_op_infos[instr->op].output_size != 0) { - for (unsigned i = 0; i < num_components; i++) { - if (swizzle[i] != i) - return false; - } - } - - /* Stash off the current variables_seen bitmask. This way we can - * restore it prior to matching in the commutative case below. - */ - unsigned variables_seen_stash = state->variables_seen; - - bool matched = true; - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - if (!match_value(expr->srcs[i], instr, i, num_components, - swizzle, state)) { - matched = false; - break; - } - } - - if (matched) - return true; - - if (nir_op_infos[instr->op].algebraic_properties & NIR_OP_IS_COMMUTATIVE) { - assert(nir_op_infos[instr->op].num_inputs == 2); - - /* Restore the variables_seen bitmask. If we don't do this, then we - * could end up with an erroneous failure due to variables found in the - * first match attempt above not matching those in the second. - */ - state->variables_seen = variables_seen_stash; - - if (!match_value(expr->srcs[0], instr, 1, num_components, - swizzle, state)) - return false; - - return match_value(expr->srcs[1], instr, 0, num_components, - swizzle, state); - } else { - return false; - } -} - -static nir_alu_src -construct_value(const nir_search_value *value, nir_alu_type type, - unsigned num_components, struct match_state *state, - nir_instr *instr, void *mem_ctx) -{ - switch (value->type) { - case nir_search_value_expression: { - const nir_search_expression *expr = nir_search_value_as_expression(value); - - if (nir_op_infos[expr->opcode].output_size != 0) - num_components = nir_op_infos[expr->opcode].output_size; - - nir_alu_instr *alu = nir_alu_instr_create(mem_ctx, expr->opcode); - nir_ssa_dest_init(&alu->instr, &alu->dest.dest, num_components, NULL); - alu->dest.write_mask = (1 << num_components) - 1; - alu->dest.saturate = false; - - for (unsigned i = 0; i < nir_op_infos[expr->opcode].num_inputs; i++) { - /* If the source is an explicitly sized source, then we need to reset - * the number of components to match. - */ - if (nir_op_infos[alu->op].input_sizes[i] != 0) - num_components = nir_op_infos[alu->op].input_sizes[i]; - - alu->src[i] = construct_value(expr->srcs[i], - nir_op_infos[alu->op].input_types[i], - num_components, - state, instr, mem_ctx); - } - - nir_instr_insert_before(instr, &alu->instr); - - nir_alu_src val; - val.src = nir_src_for_ssa(&alu->dest.dest.ssa); - val.negate = false; - val.abs = false, - memcpy(val.swizzle, identity_swizzle, sizeof val.swizzle); - - return val; - } - - case nir_search_value_variable: { - const nir_search_variable *var = nir_search_value_as_variable(value); - assert(state->variables_seen & (1 << var->variable)); - - nir_alu_src val = { NIR_SRC_INIT }; - nir_alu_src_copy(&val, &state->variables[var->variable], mem_ctx); - - assert(!var->is_constant); - - return val; - } - - case nir_search_value_constant: { - const nir_search_constant *c = nir_search_value_as_constant(value); - nir_load_const_instr *load = nir_load_const_instr_create(mem_ctx, 1); - - switch (type) { - case nir_type_float: - load->def.name = ralloc_asprintf(mem_ctx, "%f", c->data.f); - load->value.f[0] = c->data.f; - break; - case nir_type_int: - load->def.name = ralloc_asprintf(mem_ctx, "%d", c->data.i); - load->value.i[0] = c->data.i; - break; - case nir_type_uint: - case nir_type_bool: - load->value.u[0] = c->data.u; - break; - default: - unreachable("Invalid alu source type"); - } - - nir_instr_insert_before(instr, &load->instr); - - nir_alu_src val; - val.src = nir_src_for_ssa(&load->def); - val.negate = false; - val.abs = false, - memset(val.swizzle, 0, sizeof val.swizzle); - - return val; - } - - default: - unreachable("Invalid search value type"); - } -} - -nir_alu_instr * -nir_replace_instr(nir_alu_instr *instr, const nir_search_expression *search, - const nir_search_value *replace, void *mem_ctx) -{ - uint8_t swizzle[4] = { 0, 0, 0, 0 }; - - for (unsigned i = 0; i < instr->dest.dest.ssa.num_components; ++i) - swizzle[i] = i; - - assert(instr->dest.dest.is_ssa); - - struct match_state state; - state.variables_seen = 0; - - if (!match_expression(search, instr, instr->dest.dest.ssa.num_components, - swizzle, &state)) - return NULL; - - /* Inserting a mov may be unnecessary. However, it's much easier to - * simply let copy propagation clean this up than to try to go through - * and rewrite swizzles ourselves. - */ - nir_alu_instr *mov = nir_alu_instr_create(mem_ctx, nir_op_imov); - mov->dest.write_mask = instr->dest.write_mask; - nir_ssa_dest_init(&mov->instr, &mov->dest.dest, - instr->dest.dest.ssa.num_components, NULL); - - mov->src[0] = construct_value(replace, nir_op_infos[instr->op].output_type, - instr->dest.dest.ssa.num_components, &state, - &instr->instr, mem_ctx); - nir_instr_insert_before(&instr->instr, &mov->instr); - - nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, - nir_src_for_ssa(&mov->dest.dest.ssa)); - - /* We know this one has no more uses because we just rewrote them all, - * so we can remove it. The rest of the matched expression, however, we - * don't know so much about. We'll just let dead code clean them up. - */ - nir_instr_remove(&instr->instr); - - return mov; -} diff --git a/src/glsl/nir/nir_search.h b/src/glsl/nir/nir_search.h deleted file mode 100644 index 7d47792945e..00000000000 --- a/src/glsl/nir/nir_search.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#ifndef _NIR_SEARCH_ -#define _NIR_SEARCH_ - -#include "nir.h" - -#define NIR_SEARCH_MAX_VARIABLES 16 - -typedef enum { - nir_search_value_expression, - nir_search_value_variable, - nir_search_value_constant, -} nir_search_value_type; - -typedef struct { - nir_search_value_type type; -} nir_search_value; - -typedef struct { - nir_search_value value; - - /** The variable index; Must be less than NIR_SEARCH_MAX_VARIABLES */ - unsigned variable; - - /** Indicates that the given variable must be a constant - * - * This is only alloed in search expressions and indicates that the - * given variable is only allowed to match constant values. - */ - bool is_constant; - - /** Indicates that the given variable must have a certain type - * - * This is only allowed in search expressions and indicates that the - * given variable is only allowed to match values that come from an ALU - * instruction with the given output type. A type of nir_type_void - * means it can match any type. - * - * Note: A variable that is both constant and has a non-void type will - * never match anything. - */ - nir_alu_type type; -} nir_search_variable; - -typedef struct { - nir_search_value value; - - union { - uint32_t u; - int32_t i; - float f; - } data; -} nir_search_constant; - -typedef struct { - nir_search_value value; - - nir_op opcode; - const nir_search_value *srcs[4]; -} nir_search_expression; - -NIR_DEFINE_CAST(nir_search_value_as_variable, nir_search_value, - nir_search_variable, value) -NIR_DEFINE_CAST(nir_search_value_as_constant, nir_search_value, - nir_search_constant, value) -NIR_DEFINE_CAST(nir_search_value_as_expression, nir_search_value, - nir_search_expression, value) - -nir_alu_instr * -nir_replace_instr(nir_alu_instr *instr, const nir_search_expression *search, - const nir_search_value *replace, void *mem_ctx); - -#endif /* _NIR_SEARCH_ */ diff --git a/src/glsl/nir/nir_split_var_copies.c b/src/glsl/nir/nir_split_var_copies.c deleted file mode 100644 index 6fdaefa32c8..00000000000 --- a/src/glsl/nir/nir_split_var_copies.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir.h" - -/* - * Implements "copy splitting" which is similar to structure splitting only - * it works on copy operations rather than the datatypes themselves. The - * GLSL language allows you to copy one variable to another an entire - * structure (which may contain arrays or other structures) at a time. - * Normally, in a language such as C this would be handled by a "structure - * splitting" pass that breaks up the structures. Unfortunately for us, - * structures used in inputs or outputs can't be split. Therefore, - * regardlesss of what we do, we have to be able to copy to/from - * structures. - * - * The primary purpose of structure splitting is to allow you to better - * optimize variable access and lower things to registers where you can. - * The primary issue here is that, if you lower the copy to a bunch of - * loads and stores, you loose a lot of information about the copy - * operation that you would like to keep around. To solve this problem, we - * have a "copy splitting" pass that, instead of splitting the structures - * or lowering the copy into loads and storres, splits the copy operation - * into a bunch of copy operations one for each leaf of the structure tree. - * If an intermediate array is encountered, it is referenced with a - * wildcard reference to indicate that the entire array is to be copied. - * - * As things become direct, array copies may be able to be losslessly - * lowered to having fewer and fewer wildcards. However, until that - * happens we want to keep the information about the arrays intact. - * - * Prior to the copy splitting pass, there are no wildcard references but - * there may be incomplete references where the tail of the deref chain is - * an array or a structure and not a specific element. After the copy - * splitting pass has completed, every variable deref will be a full-length - * dereference pointing to a single leaf in the structure type tree with - * possibly a few wildcard array dereferences. - */ - -struct split_var_copies_state { - void *mem_ctx; - void *dead_ctx; - bool progress; -}; - -/* Recursively constructs deref chains to split a copy instruction into - * multiple (if needed) copy instructions with full-length deref chains. - * External callers of this function should pass the tail and head of the - * deref chains found as the source and destination of the copy instruction - * into this function. - * - * \param old_copy The copy instruction we are splitting - * \param dest_head The head of the destination deref chain we are building - * \param src_head The head of the source deref chain we are building - * \param dest_tail The tail of the destination deref chain we are building - * \param src_tail The tail of the source deref chain we are building - * \param state The current split_var_copies_state object - */ -static void -split_var_copy_instr(nir_intrinsic_instr *old_copy, - nir_deref *dest_head, nir_deref *src_head, - nir_deref *dest_tail, nir_deref *src_tail, - struct split_var_copies_state *state) -{ - assert(src_tail->type == dest_tail->type); - - /* Make sure these really are the tails of the deref chains */ - assert(dest_tail->child == NULL); - assert(src_tail->child == NULL); - - switch (glsl_get_base_type(src_tail->type)) { - case GLSL_TYPE_ARRAY: { - /* Make a wildcard dereference */ - nir_deref_array *deref = nir_deref_array_create(state->dead_ctx); - deref->deref.type = glsl_get_array_element(src_tail->type); - deref->deref_array_type = nir_deref_array_type_wildcard; - - /* Set the tail of both as the newly created wildcard deref. It is - * safe to use the same wildcard in both places because a) we will be - * copying it before we put it in an actual instruction and b) - * everything that will potentially add another link in the deref - * chain will also add the same thing to both chains. - */ - src_tail->child = &deref->deref; - dest_tail->child = &deref->deref; - - split_var_copy_instr(old_copy, dest_head, src_head, - dest_tail->child, src_tail->child, state); - - /* Set it back to the way we found it */ - src_tail->child = NULL; - dest_tail->child = NULL; - break; - } - - case GLSL_TYPE_STRUCT: - /* This is the only part that actually does any interesting - * splitting. For array types, we just use wildcards and resolve - * them later. For structure types, we need to emit one copy - * instruction for every structure element. Because we may have - * structs inside structs, we just recurse and let the next level - * take care of any additional structures. - */ - for (unsigned i = 0; i < glsl_get_length(src_tail->type); i++) { - nir_deref_struct *deref = nir_deref_struct_create(state->dead_ctx, i); - deref->deref.type = glsl_get_struct_field(src_tail->type, i); - - /* Set the tail of both as the newly created structure deref. It - * is safe to use the same wildcard in both places because a) we - * will be copying it before we put it in an actual instruction - * and b) everything that will potentially add another link in the - * deref chain will also add the same thing to both chains. - */ - src_tail->child = &deref->deref; - dest_tail->child = &deref->deref; - - split_var_copy_instr(old_copy, dest_head, src_head, - dest_tail->child, src_tail->child, state); - } - /* Set it back to the way we found it */ - src_tail->child = NULL; - dest_tail->child = NULL; - break; - - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - if (glsl_type_is_matrix(src_tail->type)) { - nir_deref_array *deref = nir_deref_array_create(state->dead_ctx); - deref->deref.type = glsl_get_column_type(src_tail->type); - deref->deref_array_type = nir_deref_array_type_wildcard; - - /* Set the tail of both as the newly created wildcard deref. It - * is safe to use the same wildcard in both places because a) we - * will be copying it before we put it in an actual instruction - * and b) everything that will potentially add another link in the - * deref chain will also add the same thing to both chains. - */ - src_tail->child = &deref->deref; - dest_tail->child = &deref->deref; - - split_var_copy_instr(old_copy, dest_head, src_head, - dest_tail->child, src_tail->child, state); - - /* Set it back to the way we found it */ - src_tail->child = NULL; - dest_tail->child = NULL; - } else { - /* At this point, we have fully built our deref chains and can - * actually add the new copy instruction. - */ - nir_intrinsic_instr *new_copy = - nir_intrinsic_instr_create(state->mem_ctx, nir_intrinsic_copy_var); - - /* We need to make copies because a) this deref chain actually - * belongs to the copy instruction and b) the deref chains may - * have some of the same links due to the way we constructed them - */ - nir_deref *src = nir_copy_deref(new_copy, src_head); - nir_deref *dest = nir_copy_deref(new_copy, dest_head); - - new_copy->variables[0] = nir_deref_as_var(dest); - new_copy->variables[1] = nir_deref_as_var(src); - - /* Emit the copy instruction after the old instruction. We'll - * remove the old one later. - */ - nir_instr_insert_after(&old_copy->instr, &new_copy->instr); - state->progress = true; - } - break; - - case GLSL_TYPE_SAMPLER: - case GLSL_TYPE_IMAGE: - case GLSL_TYPE_ATOMIC_UINT: - case GLSL_TYPE_INTERFACE: - default: - unreachable("Cannot copy these types"); - } -} - -static bool -split_var_copies_block(nir_block *block, void *void_state) -{ - struct split_var_copies_state *state = void_state; - - nir_foreach_instr_safe(block, instr) { - if (instr->type != nir_instr_type_intrinsic) - continue; - - nir_intrinsic_instr *intrinsic = nir_instr_as_intrinsic(instr); - if (intrinsic->intrinsic != nir_intrinsic_copy_var) - continue; - - nir_deref *dest_head = &intrinsic->variables[0]->deref; - nir_deref *src_head = &intrinsic->variables[1]->deref; - nir_deref *dest_tail = nir_deref_tail(dest_head); - nir_deref *src_tail = nir_deref_tail(src_head); - - switch (glsl_get_base_type(src_tail->type)) { - case GLSL_TYPE_ARRAY: - case GLSL_TYPE_STRUCT: - split_var_copy_instr(intrinsic, dest_head, src_head, - dest_tail, src_tail, state); - nir_instr_remove(&intrinsic->instr); - ralloc_steal(state->dead_ctx, instr); - break; - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_INT: - case GLSL_TYPE_UINT: - case GLSL_TYPE_BOOL: - if (glsl_type_is_matrix(src_tail->type)) { - split_var_copy_instr(intrinsic, dest_head, src_head, - dest_tail, src_tail, state); - nir_instr_remove(&intrinsic->instr); - ralloc_steal(state->dead_ctx, instr); - } - break; - default: - unreachable("Invalid type"); - break; - } - } - - return true; -} - -static bool -split_var_copies_impl(nir_function_impl *impl) -{ - struct split_var_copies_state state; - - state.mem_ctx = ralloc_parent(impl); - state.dead_ctx = ralloc_context(NULL); - state.progress = false; - - nir_foreach_block(impl, split_var_copies_block, &state); - - ralloc_free(state.dead_ctx); - - if (state.progress) { - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - } - - return state.progress; -} - -bool -nir_split_var_copies(nir_shader *shader) -{ - bool progress = false; - - nir_foreach_function(shader, function) { - if (function->impl) - progress = split_var_copies_impl(function->impl) || progress; - } - - return progress; -} diff --git a/src/glsl/nir/nir_sweep.c b/src/glsl/nir/nir_sweep.c deleted file mode 100644 index 5c62154ec7f..00000000000 --- a/src/glsl/nir/nir_sweep.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "nir.h" - -/** - * \file nir_sweep.c - * - * The nir_sweep() pass performs a mark and sweep pass over a nir_shader's associated - * memory - anything still connected to the program will be kept, and any dead memory - * we dropped on the floor will be freed. - * - * The expectation is that drivers should call this when finished compiling the shader - * (after any optimization, lowering, and so on). However, it's also fine to call it - * earlier, and even many times, trading CPU cycles for memory savings. - */ - -#define steal_list(mem_ctx, type, list) \ - foreach_list_typed(type, obj, node, list) { ralloc_steal(mem_ctx, obj); } - -static void sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node); - -static bool -sweep_src_indirect(nir_src *src, void *nir) -{ - if (!src->is_ssa && src->reg.indirect) - ralloc_steal(nir, src->reg.indirect); - - return true; -} - -static bool -sweep_dest_indirect(nir_dest *dest, void *nir) -{ - if (!dest->is_ssa && dest->reg.indirect) - ralloc_steal(nir, dest->reg.indirect); - - return true; -} - -static void -sweep_block(nir_shader *nir, nir_block *block) -{ - ralloc_steal(nir, block); - - nir_foreach_instr(block, instr) { - ralloc_steal(nir, instr); - - nir_foreach_src(instr, sweep_src_indirect, nir); - nir_foreach_dest(instr, sweep_dest_indirect, nir); - } -} - -static void -sweep_if(nir_shader *nir, nir_if *iff) -{ - ralloc_steal(nir, iff); - - foreach_list_typed(nir_cf_node, cf_node, node, &iff->then_list) { - sweep_cf_node(nir, cf_node); - } - - foreach_list_typed(nir_cf_node, cf_node, node, &iff->else_list) { - sweep_cf_node(nir, cf_node); - } -} - -static void -sweep_loop(nir_shader *nir, nir_loop *loop) -{ - ralloc_steal(nir, loop); - - foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) { - sweep_cf_node(nir, cf_node); - } -} - -static void -sweep_cf_node(nir_shader *nir, nir_cf_node *cf_node) -{ - switch (cf_node->type) { - case nir_cf_node_block: - sweep_block(nir, nir_cf_node_as_block(cf_node)); - break; - case nir_cf_node_if: - sweep_if(nir, nir_cf_node_as_if(cf_node)); - break; - case nir_cf_node_loop: - sweep_loop(nir, nir_cf_node_as_loop(cf_node)); - break; - default: - unreachable("Invalid CF node type"); - } -} - -static void -sweep_impl(nir_shader *nir, nir_function_impl *impl) -{ - ralloc_steal(nir, impl); - - ralloc_steal(nir, impl->params); - ralloc_steal(nir, impl->return_var); - steal_list(nir, nir_variable, &impl->locals); - steal_list(nir, nir_register, &impl->registers); - - foreach_list_typed(nir_cf_node, cf_node, node, &impl->body) { - sweep_cf_node(nir, cf_node); - } - - sweep_block(nir, impl->end_block); - - /* Wipe out all the metadata, if any. */ - nir_metadata_preserve(impl, nir_metadata_none); -} - -static void -sweep_function(nir_shader *nir, nir_function *f) -{ - ralloc_steal(nir, f); - ralloc_steal(nir, f->params); - - if (f->impl) - sweep_impl(nir, f->impl); -} - -void -nir_sweep(nir_shader *nir) -{ - void *rubbish = ralloc_context(NULL); - - /* First, move ownership of all the memory to a temporary context; assume dead. */ - ralloc_adopt(rubbish, nir); - - ralloc_steal(nir, (char *)nir->info.name); - if (nir->info.label) - ralloc_steal(nir, (char *)nir->info.label); - - /* Variables and registers are not dead. Steal them back. */ - steal_list(nir, nir_variable, &nir->uniforms); - steal_list(nir, nir_variable, &nir->inputs); - steal_list(nir, nir_variable, &nir->outputs); - steal_list(nir, nir_variable, &nir->shared); - steal_list(nir, nir_variable, &nir->globals); - steal_list(nir, nir_variable, &nir->system_values); - steal_list(nir, nir_register, &nir->registers); - - /* Recurse into functions, stealing their contents back. */ - foreach_list_typed(nir_function, func, node, &nir->functions) { - sweep_function(nir, func); - } - - /* Free everything we didn't steal back. */ - ralloc_free(rubbish); -} diff --git a/src/glsl/nir/nir_to_ssa.c b/src/glsl/nir/nir_to_ssa.c deleted file mode 100644 index 44a50547738..00000000000 --- a/src/glsl/nir/nir_to_ssa.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include <stdlib.h> -#include <unistd.h> - -/* - * Implements the classic to-SSA algorithm described by Cytron et. al. in - * "Efficiently Computing Static Single Assignment Form and the Control - * Dependence Graph." - */ - -/* inserts a phi node of the form reg = phi(reg, reg, reg, ...) */ - -static void -insert_trivial_phi(nir_register *reg, nir_block *block, void *mem_ctx) -{ - nir_phi_instr *instr = nir_phi_instr_create(mem_ctx); - - instr->dest.reg.reg = reg; - struct set_entry *entry; - set_foreach(block->predecessors, entry) { - nir_block *pred = (nir_block *) entry->key; - - nir_phi_src *src = ralloc(instr, nir_phi_src); - src->pred = pred; - src->src.is_ssa = false; - src->src.reg.base_offset = 0; - src->src.reg.indirect = NULL; - src->src.reg.reg = reg; - exec_list_push_tail(&instr->srcs, &src->node); - } - - nir_instr_insert_before_block(block, &instr->instr); -} - -static void -insert_phi_nodes(nir_function_impl *impl) -{ - void *mem_ctx = ralloc_parent(impl); - - unsigned *work = calloc(impl->num_blocks, sizeof(unsigned)); - unsigned *has_already = calloc(impl->num_blocks, sizeof(unsigned)); - - /* - * Since the work flags already prevent us from inserting a node that has - * ever been inserted into W, we don't need to use a set to represent W. - * Also, since no block can ever be inserted into W more than once, we know - * that the maximum size of W is the number of basic blocks in the - * function. So all we need to handle W is an array and a pointer to the - * next element to be inserted and the next element to be removed. - */ - nir_block **W = malloc(impl->num_blocks * sizeof(nir_block *)); - unsigned w_start, w_end; - - unsigned iter_count = 0; - - nir_index_blocks(impl); - - foreach_list_typed(nir_register, reg, node, &impl->registers) { - if (reg->num_array_elems != 0) - continue; - - w_start = w_end = 0; - iter_count++; - - nir_foreach_def(reg, dest) { - nir_instr *def = dest->reg.parent_instr; - if (work[def->block->index] < iter_count) - W[w_end++] = def->block; - work[def->block->index] = iter_count; - } - - while (w_start != w_end) { - nir_block *cur = W[w_start++]; - struct set_entry *entry; - set_foreach(cur->dom_frontier, entry) { - nir_block *next = (nir_block *) entry->key; - - /* - * If there's more than one return statement, then the end block - * can be a join point for some definitions. However, there are - * no instructions in the end block, so nothing would use those - * phi nodes. Of course, we couldn't place those phi nodes - * anyways due to the restriction of having no instructions in the - * end block... - */ - if (next == impl->end_block) - continue; - - if (has_already[next->index] < iter_count) { - insert_trivial_phi(reg, next, mem_ctx); - has_already[next->index] = iter_count; - if (work[next->index] < iter_count) { - work[next->index] = iter_count; - W[w_end++] = next; - } - } - } - } - } - - free(work); - free(has_already); - free(W); -} - -typedef struct { - nir_ssa_def **stack; - int index; - unsigned num_defs; /** < used to add indices to debug names */ -#ifndef NDEBUG - unsigned stack_size; -#endif -} reg_state; - -typedef struct { - reg_state *states; - void *mem_ctx; - nir_instr *parent_instr; - nir_if *parent_if; - nir_function_impl *impl; - - /* map from SSA value -> original register */ - struct hash_table *ssa_map; -} rewrite_state; - -static nir_ssa_def *get_ssa_src(nir_register *reg, rewrite_state *state) -{ - unsigned index = reg->index; - - if (state->states[index].index == -1) { - /* - * We're using an undefined register, create a new undefined SSA value - * to preserve the information that this source is undefined - */ - nir_ssa_undef_instr *instr = - nir_ssa_undef_instr_create(state->mem_ctx, reg->num_components); - - /* - * We could just insert the undefined instruction before the instruction - * we're rewriting, but we could be rewriting a phi source in which case - * we can't do that, so do the next easiest thing - insert it at the - * beginning of the program. In the end, it doesn't really matter where - * the undefined instructions are because they're going to be ignored - * in the backend. - */ - nir_instr_insert_before_cf_list(&state->impl->body, &instr->instr); - return &instr->def; - } - - return state->states[index].stack[state->states[index].index]; -} - -static bool -rewrite_use(nir_src *src, void *_state) -{ - rewrite_state *state = (rewrite_state *) _state; - - if (src->is_ssa) - return true; - - unsigned index = src->reg.reg->index; - - if (state->states[index].stack == NULL) - return true; - - nir_ssa_def *def = get_ssa_src(src->reg.reg, state); - if (state->parent_instr) - nir_instr_rewrite_src(state->parent_instr, src, nir_src_for_ssa(def)); - else - nir_if_rewrite_condition(state->parent_if, nir_src_for_ssa(def)); - - return true; -} - -static bool -rewrite_def_forwards(nir_dest *dest, void *_state) -{ - rewrite_state *state = (rewrite_state *) _state; - - if (dest->is_ssa) - return true; - - nir_register *reg = dest->reg.reg; - unsigned index = reg->index; - - if (state->states[index].stack == NULL) - return true; - - char *name = NULL; - if (dest->reg.reg->name) - name = ralloc_asprintf(state->mem_ctx, "%s_%u", dest->reg.reg->name, - state->states[index].num_defs); - - list_del(&dest->reg.def_link); - nir_ssa_dest_init(state->parent_instr, dest, reg->num_components, name); - - /* push our SSA destination on the stack */ - state->states[index].index++; - assert(state->states[index].index < state->states[index].stack_size); - state->states[index].stack[state->states[index].index] = &dest->ssa; - state->states[index].num_defs++; - - _mesa_hash_table_insert(state->ssa_map, &dest->ssa, reg); - - return true; -} - -static void -rewrite_alu_instr_forward(nir_alu_instr *instr, rewrite_state *state) -{ - state->parent_instr = &instr->instr; - - nir_foreach_src(&instr->instr, rewrite_use, state); - - if (instr->dest.dest.is_ssa) - return; - - nir_register *reg = instr->dest.dest.reg.reg; - unsigned index = reg->index; - - if (state->states[index].stack == NULL) - return; - - unsigned write_mask = instr->dest.write_mask; - if (write_mask != (1 << instr->dest.dest.reg.reg->num_components) - 1) { - /* - * Calculate the number of components the final instruction, which for - * per-component things is the number of output components of the - * instruction and non-per-component things is the number of enabled - * channels in the write mask. - */ - unsigned num_components; - if (nir_op_infos[instr->op].output_size == 0) { - unsigned temp = (write_mask & 0x5) + ((write_mask >> 1) & 0x5); - num_components = (temp & 0x3) + ((temp >> 2) & 0x3); - } else { - num_components = nir_op_infos[instr->op].output_size; - } - - char *name = NULL; - if (instr->dest.dest.reg.reg->name) - name = ralloc_asprintf(state->mem_ctx, "%s_%u", - reg->name, state->states[index].num_defs); - - instr->dest.write_mask = (1 << num_components) - 1; - list_del(&instr->dest.dest.reg.def_link); - nir_ssa_dest_init(&instr->instr, &instr->dest.dest, num_components, name); - - if (nir_op_infos[instr->op].output_size == 0) { - /* - * When we change the output writemask, we need to change the - * swizzles for per-component inputs too - */ - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - if (nir_op_infos[instr->op].input_sizes[i] != 0) - continue; - - unsigned new_swizzle[4] = {0, 0, 0, 0}; - - /* - * We keep two indices: - * 1. The index of the original (non-SSA) component - * 2. The index of the post-SSA, compacted, component - * - * We need to map the swizzle component at index 1 to the swizzle - * component at index 2. - */ - - unsigned ssa_index = 0; - for (unsigned index = 0; index < 4; index++) { - if (!((write_mask >> index) & 1)) - continue; - - new_swizzle[ssa_index] = instr->src[i].swizzle[index]; - ssa_index++; - } - - for (unsigned j = 0; j < 4; j++) - instr->src[i].swizzle[j] = new_swizzle[j]; - } - } - - nir_op op; - switch (reg->num_components) { - case 2: op = nir_op_vec2; break; - case 3: op = nir_op_vec3; break; - case 4: op = nir_op_vec4; break; - default: unreachable("not reached"); - } - - nir_alu_instr *vec = nir_alu_instr_create(state->mem_ctx, op); - - vec->dest.dest.reg.reg = reg; - vec->dest.write_mask = (1 << reg->num_components) - 1; - - nir_ssa_def *old_src = get_ssa_src(reg, state); - nir_ssa_def *new_src = &instr->dest.dest.ssa; - - unsigned ssa_index = 0; - for (unsigned i = 0; i < reg->num_components; i++) { - vec->src[i].src.is_ssa = true; - if ((write_mask >> i) & 1) { - vec->src[i].src.ssa = new_src; - if (nir_op_infos[instr->op].output_size == 0) - vec->src[i].swizzle[0] = ssa_index; - else - vec->src[i].swizzle[0] = i; - ssa_index++; - } else { - vec->src[i].src.ssa = old_src; - vec->src[i].swizzle[0] = i; - } - } - - nir_instr_insert_after(&instr->instr, &vec->instr); - - state->parent_instr = &vec->instr; - rewrite_def_forwards(&vec->dest.dest, state); - } else { - rewrite_def_forwards(&instr->dest.dest, state); - } -} - -static void -rewrite_phi_instr(nir_phi_instr *instr, rewrite_state *state) -{ - state->parent_instr = &instr->instr; - rewrite_def_forwards(&instr->dest, state); -} - -static void -rewrite_instr_forward(nir_instr *instr, rewrite_state *state) -{ - if (instr->type == nir_instr_type_alu) { - rewrite_alu_instr_forward(nir_instr_as_alu(instr), state); - return; - } - - if (instr->type == nir_instr_type_phi) { - rewrite_phi_instr(nir_instr_as_phi(instr), state); - return; - } - - state->parent_instr = instr; - - nir_foreach_src(instr, rewrite_use, state); - nir_foreach_dest(instr, rewrite_def_forwards, state); -} - -static void -rewrite_phi_sources(nir_block *block, nir_block *pred, rewrite_state *state) -{ - nir_foreach_instr(block, instr) { - if (instr->type != nir_instr_type_phi) - break; - - nir_phi_instr *phi_instr = nir_instr_as_phi(instr); - - state->parent_instr = instr; - - nir_foreach_phi_src(phi_instr, src) { - if (src->pred == pred) { - rewrite_use(&src->src, state); - break; - } - } - } -} - -static bool -rewrite_def_backwards(nir_dest *dest, void *_state) -{ - rewrite_state *state = (rewrite_state *) _state; - - if (!dest->is_ssa) - return true; - - struct hash_entry *entry = - _mesa_hash_table_search(state->ssa_map, &dest->ssa); - - if (!entry) - return true; - - nir_register *reg = (nir_register *) entry->data; - unsigned index = reg->index; - - state->states[index].index--; - assert(state->states[index].index >= -1); - - return true; -} - -static void -rewrite_instr_backwards(nir_instr *instr, rewrite_state *state) -{ - nir_foreach_dest(instr, rewrite_def_backwards, state); -} - -static void -rewrite_block(nir_block *block, rewrite_state *state) -{ - /* This will skip over any instructions after the current one, which is - * what we want because those instructions (vector gather, conditional - * select) will already be in SSA form. - */ - nir_foreach_instr_safe(block, instr) { - rewrite_instr_forward(instr, state); - } - - if (block != state->impl->end_block && - !nir_cf_node_is_last(&block->cf_node) && - nir_cf_node_next(&block->cf_node)->type == nir_cf_node_if) { - nir_if *if_stmt = nir_cf_node_as_if(nir_cf_node_next(&block->cf_node)); - state->parent_instr = NULL; - state->parent_if = if_stmt; - rewrite_use(&if_stmt->condition, state); - } - - if (block->successors[0]) - rewrite_phi_sources(block->successors[0], block, state); - if (block->successors[1]) - rewrite_phi_sources(block->successors[1], block, state); - - for (unsigned i = 0; i < block->num_dom_children; i++) - rewrite_block(block->dom_children[i], state); - - nir_foreach_instr_reverse(block, instr) { - rewrite_instr_backwards(instr, state); - } -} - -static void -remove_unused_regs(nir_function_impl *impl, rewrite_state *state) -{ - foreach_list_typed_safe(nir_register, reg, node, &impl->registers) { - if (state->states[reg->index].stack != NULL) - exec_node_remove(®->node); - } -} - -static void -init_rewrite_state(nir_function_impl *impl, rewrite_state *state) -{ - state->impl = impl; - state->mem_ctx = ralloc_parent(impl); - state->ssa_map = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - state->states = ralloc_array(NULL, reg_state, impl->reg_alloc); - - foreach_list_typed(nir_register, reg, node, &impl->registers) { - assert(reg->index < impl->reg_alloc); - if (reg->num_array_elems > 0) { - state->states[reg->index].stack = NULL; - } else { - /* - * Calculate a conservative estimate of the stack size based on the - * number of definitions there are. Note that this function *must* be - * called after phi nodes are inserted so we can count phi node - * definitions too. - */ - unsigned stack_size = list_length(®->defs); - - state->states[reg->index].stack = ralloc_array(state->states, - nir_ssa_def *, - stack_size); -#ifndef NDEBUG - state->states[reg->index].stack_size = stack_size; -#endif - state->states[reg->index].index = -1; - state->states[reg->index].num_defs = 0; - } - } -} - -static void -destroy_rewrite_state(rewrite_state *state) -{ - _mesa_hash_table_destroy(state->ssa_map, NULL); - ralloc_free(state->states); -} - -void -nir_convert_to_ssa_impl(nir_function_impl *impl) -{ - nir_metadata_require(impl, nir_metadata_dominance); - - insert_phi_nodes(impl); - - rewrite_state state; - init_rewrite_state(impl, &state); - - rewrite_block(nir_start_block(impl), &state); - - remove_unused_regs(impl, &state); - - nir_metadata_preserve(impl, nir_metadata_block_index | - nir_metadata_dominance); - - destroy_rewrite_state(&state); -} - -void -nir_convert_to_ssa(nir_shader *shader) -{ - nir_foreach_function(shader, function) { - if (function->impl) - nir_convert_to_ssa_impl(function->impl); - } -} diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp deleted file mode 100644 index f4408def9a0..00000000000 --- a/src/glsl/nir/nir_types.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir_types.h" -#include "ir.h" - -void -glsl_print_type(const glsl_type *type, FILE *fp) -{ - if (type->base_type == GLSL_TYPE_ARRAY) { - glsl_print_type(type->fields.array, fp); - fprintf(fp, "[%u]", type->length); - } else if ((type->base_type == GLSL_TYPE_STRUCT) - && !is_gl_identifier(type->name)) { - fprintf(fp, "%s@%p", type->name, (void *) type); - } else { - fprintf(fp, "%s", type->name); - } -} - -void -glsl_print_struct(const glsl_type *type, FILE *fp) -{ - assert(type->base_type == GLSL_TYPE_STRUCT); - - fprintf(fp, "struct {\n"); - for (unsigned i = 0; i < type->length; i++) { - fprintf(fp, "\t"); - glsl_print_type(type->fields.structure[i].type, fp); - fprintf(fp, " %s;\n", type->fields.structure[i].name); - } - fprintf(fp, "}\n"); -} - -const glsl_type * -glsl_get_array_element(const glsl_type* type) -{ - if (type->is_matrix()) - return type->column_type(); - return type->fields.array; -} - -const glsl_type * -glsl_get_struct_field(const glsl_type *type, unsigned index) -{ - return type->fields.structure[index].type; -} - -const glsl_type * -glsl_get_function_return_type(const glsl_type *type) -{ - return type->fields.parameters[0].type; -} - -const glsl_function_param * -glsl_get_function_param(const glsl_type *type, unsigned index) -{ - return &type->fields.parameters[index + 1]; -} - -const struct glsl_type * -glsl_get_column_type(const struct glsl_type *type) -{ - return type->column_type(); -} - -enum glsl_base_type -glsl_get_base_type(const struct glsl_type *type) -{ - return type->base_type; -} - -unsigned -glsl_get_vector_elements(const struct glsl_type *type) -{ - return type->vector_elements; -} - -unsigned -glsl_get_components(const struct glsl_type *type) -{ - return type->components(); -} - -unsigned -glsl_get_matrix_columns(const struct glsl_type *type) -{ - return type->matrix_columns; -} - -unsigned -glsl_get_length(const struct glsl_type *type) -{ - return type->is_matrix() ? type->matrix_columns : type->length; -} - -unsigned -glsl_get_aoa_size(const struct glsl_type *type) -{ - return type->arrays_of_arrays_size(); -} - -unsigned -glsl_count_attribute_slots(const struct glsl_type *type, - bool vertex_input_slots) -{ - return type->count_attribute_slots(vertex_input_slots); -} - -const char * -glsl_get_struct_elem_name(const struct glsl_type *type, unsigned index) -{ - return type->fields.structure[index].name; -} - -glsl_sampler_dim -glsl_get_sampler_dim(const struct glsl_type *type) -{ - assert(glsl_type_is_sampler(type) || glsl_type_is_image(type)); - return (glsl_sampler_dim)type->sampler_dimensionality; -} - -glsl_base_type -glsl_get_sampler_result_type(const struct glsl_type *type) -{ - assert(glsl_type_is_sampler(type) || glsl_type_is_image(type)); - return (glsl_base_type)type->sampler_type; -} - -unsigned -glsl_get_record_location_offset(const struct glsl_type *type, - unsigned length) -{ - return type->record_location_offset(length); -} - -bool -glsl_type_is_void(const glsl_type *type) -{ - return type->is_void(); -} - -bool -glsl_type_is_error(const glsl_type *type) -{ - return type->is_error(); -} - -bool -glsl_type_is_vector(const struct glsl_type *type) -{ - return type->is_vector(); -} - -bool -glsl_type_is_scalar(const struct glsl_type *type) -{ - return type->is_scalar(); -} - -bool -glsl_type_is_vector_or_scalar(const struct glsl_type *type) -{ - return type->is_vector() || type->is_scalar(); -} - -bool -glsl_type_is_matrix(const struct glsl_type *type) -{ - return type->is_matrix(); -} - -bool -glsl_type_is_array(const struct glsl_type *type) -{ - return type->is_array(); -} - -bool -glsl_type_is_struct(const struct glsl_type *type) -{ - return type->is_record() || type->is_interface(); -} - -bool -glsl_type_is_sampler(const struct glsl_type *type) -{ - return type->is_sampler(); -} - -bool -glsl_type_is_image(const struct glsl_type *type) -{ - return type->is_image(); -} - -bool -glsl_sampler_type_is_shadow(const struct glsl_type *type) -{ - assert(glsl_type_is_sampler(type)); - return type->sampler_shadow; -} - -bool -glsl_sampler_type_is_array(const struct glsl_type *type) -{ - assert(glsl_type_is_sampler(type) || glsl_type_is_image(type)); - return type->sampler_array; -} - -const glsl_type * -glsl_void_type(void) -{ - return glsl_type::void_type; -} - -const glsl_type * -glsl_float_type(void) -{ - return glsl_type::float_type; -} - -const glsl_type * -glsl_vec_type(unsigned n) -{ - return glsl_type::vec(n); -} - -const glsl_type * -glsl_vec4_type(void) -{ - return glsl_type::vec4_type; -} - -const glsl_type * -glsl_int_type(void) -{ - return glsl_type::int_type; -} - -const glsl_type * -glsl_uint_type(void) -{ - return glsl_type::uint_type; -} - -const glsl_type * -glsl_bool_type(void) -{ - return glsl_type::bool_type; -} - -const glsl_type * -glsl_scalar_type(enum glsl_base_type base_type) -{ - return glsl_type::get_instance(base_type, 1, 1); -} - -const glsl_type * -glsl_vector_type(enum glsl_base_type base_type, unsigned components) -{ - assert(components > 1 && components <= 4); - return glsl_type::get_instance(base_type, components, 1); -} - -const glsl_type * -glsl_matrix_type(enum glsl_base_type base_type, unsigned rows, unsigned columns) -{ - assert(rows > 1 && rows <= 4 && columns >= 1 && columns <= 4); - return glsl_type::get_instance(base_type, rows, columns); -} - -const glsl_type * -glsl_array_type(const glsl_type *base, unsigned elements) -{ - return glsl_type::get_array_instance(base, elements); -} - -const glsl_type * -glsl_struct_type(const glsl_struct_field *fields, - unsigned num_fields, const char *name) -{ - return glsl_type::get_record_instance(fields, num_fields, name); -} - -const struct glsl_type * -glsl_sampler_type(enum glsl_sampler_dim dim, bool is_shadow, bool is_array, - enum glsl_base_type base_type) -{ - return glsl_type::get_sampler_instance(dim, is_shadow, is_array, base_type); -} - -const struct glsl_type * -glsl_image_type(enum glsl_sampler_dim dim, bool is_array, - enum glsl_base_type base_type) -{ - return glsl_type::get_image_instance(dim, is_array, base_type); -} - -const glsl_type * -glsl_function_type(const glsl_type *return_type, - const glsl_function_param *params, unsigned num_params) -{ - return glsl_type::get_function_instance(return_type, params, num_params); -} - -const glsl_type * -glsl_transposed_type(const struct glsl_type *type) -{ - return glsl_type::get_instance(type->base_type, type->matrix_columns, - type->vector_elements); -} diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h deleted file mode 100644 index 8cb7ec16ce3..00000000000 --- a/src/glsl/nir/nir_types.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright © 2014 Connor Abbott - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#pragma once - -#include <stdio.h> - -/* C wrapper around glsl_types.h */ - -#include "glsl_types.h" - -#ifdef __cplusplus -extern "C" { -#else -struct glsl_type; -#endif - -void glsl_print_type(const struct glsl_type *type, FILE *fp); -void glsl_print_struct(const struct glsl_type *type, FILE *fp); - -const struct glsl_type *glsl_get_struct_field(const struct glsl_type *type, - unsigned index); - -const struct glsl_type *glsl_get_array_element(const struct glsl_type *type); - -const struct glsl_type *glsl_get_column_type(const struct glsl_type *type); - -const struct glsl_type * -glsl_get_function_return_type(const struct glsl_type *type); - -const struct glsl_function_param * -glsl_get_function_param(const struct glsl_type *type, unsigned index); - -enum glsl_base_type glsl_get_base_type(const struct glsl_type *type); - -unsigned glsl_get_vector_elements(const struct glsl_type *type); - -unsigned glsl_get_components(const struct glsl_type *type); - -unsigned glsl_get_matrix_columns(const struct glsl_type *type); - -unsigned glsl_get_length(const struct glsl_type *type); - -unsigned glsl_get_aoa_size(const struct glsl_type *type); - -unsigned glsl_count_attribute_slots(const struct glsl_type *type, - bool vertex_input_slots); - -const char *glsl_get_struct_elem_name(const struct glsl_type *type, - unsigned index); - -enum glsl_sampler_dim glsl_get_sampler_dim(const struct glsl_type *type); -enum glsl_base_type glsl_get_sampler_result_type(const struct glsl_type *type); - -unsigned glsl_get_record_location_offset(const struct glsl_type *type, - unsigned length); - -bool glsl_type_is_void(const struct glsl_type *type); -bool glsl_type_is_error(const struct glsl_type *type); -bool glsl_type_is_vector(const struct glsl_type *type); -bool glsl_type_is_scalar(const struct glsl_type *type); -bool glsl_type_is_vector_or_scalar(const struct glsl_type *type); -bool glsl_type_is_matrix(const struct glsl_type *type); -bool glsl_type_is_array(const struct glsl_type *type); -bool glsl_type_is_struct(const struct glsl_type *type); -bool glsl_type_is_sampler(const struct glsl_type *type); -bool glsl_type_is_image(const struct glsl_type *type); -bool glsl_sampler_type_is_shadow(const struct glsl_type *type); -bool glsl_sampler_type_is_array(const struct glsl_type *type); - -const struct glsl_type *glsl_void_type(void); -const struct glsl_type *glsl_float_type(void); -const struct glsl_type *glsl_vec_type(unsigned n); -const struct glsl_type *glsl_vec4_type(void); -const struct glsl_type *glsl_int_type(void); -const struct glsl_type *glsl_uint_type(void); -const struct glsl_type *glsl_bool_type(void); - -const struct glsl_type *glsl_scalar_type(enum glsl_base_type base_type); -const struct glsl_type *glsl_vector_type(enum glsl_base_type base_type, - unsigned components); -const struct glsl_type *glsl_matrix_type(enum glsl_base_type base_type, - unsigned rows, unsigned columns); -const struct glsl_type *glsl_array_type(const struct glsl_type *base, - unsigned elements); -const struct glsl_type *glsl_struct_type(const struct glsl_struct_field *fields, - unsigned num_fields, const char *name); -const struct glsl_type *glsl_sampler_type(enum glsl_sampler_dim dim, - bool is_shadow, bool is_array, - enum glsl_base_type base_type); -const struct glsl_type *glsl_image_type(enum glsl_sampler_dim dim, - bool is_array, - enum glsl_base_type base_type); -const struct glsl_type * glsl_function_type(const struct glsl_type *return_type, - const struct glsl_function_param *params, - unsigned num_params); - -const struct glsl_type *glsl_transposed_type(const struct glsl_type *type); - -#ifdef __cplusplus -} -#endif diff --git a/src/glsl/nir/nir_validate.c b/src/glsl/nir/nir_validate.c deleted file mode 100644 index 1a943d76314..00000000000 --- a/src/glsl/nir/nir_validate.c +++ /dev/null @@ -1,1076 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Connor Abbott ([email protected]) - * - */ - -#include "nir.h" -#include <assert.h> - -/* - * This file checks for invalid IR indicating a bug somewhere in the compiler. - */ - -/* Since this file is just a pile of asserts, don't bother compiling it if - * we're not building a debug build. - */ -#ifdef DEBUG - -/* - * Per-register validation state. - */ - -typedef struct { - /* - * equivalent to the uses and defs in nir_register, but built up by the - * validator. At the end, we verify that the sets have the same entries. - */ - struct set *uses, *if_uses, *defs; - nir_function_impl *where_defined; /* NULL for global registers */ -} reg_validate_state; - -typedef struct { - /* - * equivalent to the uses in nir_ssa_def, but built up by the validator. - * At the end, we verify that the sets have the same entries. - */ - struct set *uses, *if_uses; - nir_function_impl *where_defined; -} ssa_def_validate_state; - -typedef struct { - /* map of register -> validation state (struct above) */ - struct hash_table *regs; - - /* the current shader being validated */ - nir_shader *shader; - - /* the current instruction being validated */ - nir_instr *instr; - - /* the current basic block being validated */ - nir_block *block; - - /* the current if statement being validated */ - nir_if *if_stmt; - - /* the current loop being visited */ - nir_loop *loop; - - /* the parent of the current cf node being visited */ - nir_cf_node *parent_node; - - /* the current function implementation being validated */ - nir_function_impl *impl; - - /* map of SSA value -> function implementation where it is defined */ - struct hash_table *ssa_defs; - - /* bitset of ssa definitions we have found; used to check uniqueness */ - BITSET_WORD *ssa_defs_found; - - /* bitset of registers we have currently found; used to check uniqueness */ - BITSET_WORD *regs_found; - - /* map of local variable -> function implementation where it is defined */ - struct hash_table *var_defs; -} validate_state; - -static void validate_src(nir_src *src, validate_state *state); - -static void -validate_reg_src(nir_src *src, validate_state *state) -{ - assert(src->reg.reg != NULL); - - struct hash_entry *entry; - entry = _mesa_hash_table_search(state->regs, src->reg.reg); - assert(entry); - - reg_validate_state *reg_state = (reg_validate_state *) entry->data; - - if (state->instr) { - _mesa_set_add(reg_state->uses, src); - } else { - assert(state->if_stmt); - _mesa_set_add(reg_state->if_uses, src); - } - - if (!src->reg.reg->is_global) { - assert(reg_state->where_defined == state->impl && - "using a register declared in a different function"); - } - - assert((src->reg.reg->num_array_elems == 0 || - src->reg.base_offset < src->reg.reg->num_array_elems) && - "definitely out-of-bounds array access"); - - if (src->reg.indirect) { - assert(src->reg.reg->num_array_elems != 0); - assert((src->reg.indirect->is_ssa || - src->reg.indirect->reg.indirect == NULL) && - "only one level of indirection allowed"); - validate_src(src->reg.indirect, state); - } -} - -static void -validate_ssa_src(nir_src *src, validate_state *state) -{ - assert(src->ssa != NULL); - - struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, src->ssa); - - assert(entry); - - ssa_def_validate_state *def_state = (ssa_def_validate_state *)entry->data; - - assert(def_state->where_defined == state->impl && - "using an SSA value defined in a different function"); - - if (state->instr) { - _mesa_set_add(def_state->uses, src); - } else { - assert(state->if_stmt); - _mesa_set_add(def_state->if_uses, src); - } - - /* TODO validate that the use is dominated by the definition */ -} - -static void -validate_src(nir_src *src, validate_state *state) -{ - if (state->instr) - assert(src->parent_instr == state->instr); - else - assert(src->parent_if == state->if_stmt); - - if (src->is_ssa) - validate_ssa_src(src, state); - else - validate_reg_src(src, state); -} - -static void -validate_alu_src(nir_alu_instr *instr, unsigned index, validate_state *state) -{ - nir_alu_src *src = &instr->src[index]; - - unsigned num_components; - if (src->src.is_ssa) - num_components = src->src.ssa->num_components; - else { - if (src->src.reg.reg->is_packed) - num_components = 4; /* can't check anything */ - else - num_components = src->src.reg.reg->num_components; - } - for (unsigned i = 0; i < 4; i++) { - assert(src->swizzle[i] < 4); - - if (nir_alu_instr_channel_used(instr, index, i)) - assert(src->swizzle[i] < num_components); - } - - validate_src(&src->src, state); -} - -static void -validate_reg_dest(nir_reg_dest *dest, validate_state *state) -{ - assert(dest->reg != NULL); - - assert(dest->parent_instr == state->instr); - - struct hash_entry *entry2; - entry2 = _mesa_hash_table_search(state->regs, dest->reg); - - assert(entry2); - - reg_validate_state *reg_state = (reg_validate_state *) entry2->data; - _mesa_set_add(reg_state->defs, dest); - - if (!dest->reg->is_global) { - assert(reg_state->where_defined == state->impl && - "writing to a register declared in a different function"); - } - - assert((dest->reg->num_array_elems == 0 || - dest->base_offset < dest->reg->num_array_elems) && - "definitely out-of-bounds array access"); - - if (dest->indirect) { - assert(dest->reg->num_array_elems != 0); - assert((dest->indirect->is_ssa || dest->indirect->reg.indirect == NULL) && - "only one level of indirection allowed"); - validate_src(dest->indirect, state); - } -} - -static void -validate_ssa_def(nir_ssa_def *def, validate_state *state) -{ - assert(def->index < state->impl->ssa_alloc); - assert(!BITSET_TEST(state->ssa_defs_found, def->index)); - BITSET_SET(state->ssa_defs_found, def->index); - - assert(def->parent_instr == state->instr); - - assert(def->num_components <= 4); - - list_validate(&def->uses); - list_validate(&def->if_uses); - - ssa_def_validate_state *def_state = ralloc(state->ssa_defs, - ssa_def_validate_state); - def_state->where_defined = state->impl; - def_state->uses = _mesa_set_create(def_state, _mesa_hash_pointer, - _mesa_key_pointer_equal); - def_state->if_uses = _mesa_set_create(def_state, _mesa_hash_pointer, - _mesa_key_pointer_equal); - _mesa_hash_table_insert(state->ssa_defs, def, def_state); -} - -static void -validate_dest(nir_dest *dest, validate_state *state) -{ - if (dest->is_ssa) - validate_ssa_def(&dest->ssa, state); - else - validate_reg_dest(&dest->reg, state); -} - -static void -validate_alu_dest(nir_alu_dest *dest, validate_state *state) -{ - unsigned dest_size = - dest->dest.is_ssa ? dest->dest.ssa.num_components - : dest->dest.reg.reg->num_components; - bool is_packed = !dest->dest.is_ssa && dest->dest.reg.reg->is_packed; - /* - * validate that the instruction doesn't write to components not in the - * register/SSA value - */ - assert(is_packed || !(dest->write_mask & ~((1 << dest_size) - 1))); - - /* validate that saturate is only ever used on instructions with - * destinations of type float - */ - nir_alu_instr *alu = nir_instr_as_alu(state->instr); - assert(nir_op_infos[alu->op].output_type == nir_type_float || - !dest->saturate); - - validate_dest(&dest->dest, state); -} - -static void -validate_alu_instr(nir_alu_instr *instr, validate_state *state) -{ - assert(instr->op < nir_num_opcodes); - - for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - validate_alu_src(instr, i, state); - } - - validate_alu_dest(&instr->dest, state); -} - -static void -validate_deref_chain(nir_deref *deref, validate_state *state) -{ - assert(deref->child == NULL || ralloc_parent(deref->child) == deref); - - nir_deref *parent = NULL; - while (deref != NULL) { - switch (deref->deref_type) { - case nir_deref_type_array: - assert(deref->type == glsl_get_array_element(parent->type)); - if (nir_deref_as_array(deref)->deref_array_type == - nir_deref_array_type_indirect) - validate_src(&nir_deref_as_array(deref)->indirect, state); - break; - - case nir_deref_type_struct: - assert(deref->type == - glsl_get_struct_field(parent->type, - nir_deref_as_struct(deref)->index)); - break; - - case nir_deref_type_var: - break; - - default: - assert(!"Invalid deref type"); - break; - } - - parent = deref; - deref = deref->child; - } -} - -static void -validate_var_use(nir_variable *var, validate_state *state) -{ - if (var->data.mode == nir_var_local) { - struct hash_entry *entry = _mesa_hash_table_search(state->var_defs, var); - - assert(entry); - assert((nir_function_impl *) entry->data == state->impl); - } -} - -static void -validate_deref_var(void *parent_mem_ctx, nir_deref_var *deref, validate_state *state) -{ - assert(deref != NULL); - assert(ralloc_parent(deref) == parent_mem_ctx); - assert(deref->deref.type == deref->var->type); - - validate_var_use(deref->var, state); - - validate_deref_chain(&deref->deref, state); -} - -static void -validate_intrinsic_instr(nir_intrinsic_instr *instr, validate_state *state) -{ - unsigned num_srcs = nir_intrinsic_infos[instr->intrinsic].num_srcs; - for (unsigned i = 0; i < num_srcs; i++) { - unsigned components_read = - nir_intrinsic_infos[instr->intrinsic].src_components[i]; - if (components_read == 0) - components_read = instr->num_components; - - assert(components_read > 0); - - if (instr->src[i].is_ssa) { - assert(components_read <= instr->src[i].ssa->num_components); - } else if (!instr->src[i].reg.reg->is_packed) { - assert(components_read <= instr->src[i].reg.reg->num_components); - } - - validate_src(&instr->src[i], state); - } - - unsigned num_vars = nir_intrinsic_infos[instr->intrinsic].num_variables; - for (unsigned i = 0; i < num_vars; i++) { - validate_deref_var(instr, instr->variables[i], state); - } - - if (nir_intrinsic_infos[instr->intrinsic].has_dest) { - unsigned components_written = - nir_intrinsic_infos[instr->intrinsic].dest_components; - if (components_written == 0) - components_written = instr->num_components; - - assert(components_written > 0); - - if (instr->dest.is_ssa) { - assert(components_written <= instr->dest.ssa.num_components); - } else if (!instr->dest.reg.reg->is_packed) { - assert(components_written <= instr->dest.reg.reg->num_components); - } - - validate_dest(&instr->dest, state); - } - - switch (instr->intrinsic) { - case nir_intrinsic_load_var: { - const struct glsl_type *type = - nir_deref_tail(&instr->variables[0]->deref)->type; - assert(glsl_type_is_vector_or_scalar(type) || - (instr->variables[0]->var->data.mode == nir_var_uniform && - glsl_get_base_type(type) == GLSL_TYPE_SUBROUTINE)); - assert(instr->num_components == glsl_get_vector_elements(type)); - break; - } - case nir_intrinsic_store_var: { - const struct glsl_type *type = - nir_deref_tail(&instr->variables[0]->deref)->type; - assert(glsl_type_is_vector_or_scalar(type) || - (instr->variables[0]->var->data.mode == nir_var_uniform && - glsl_get_base_type(type) == GLSL_TYPE_SUBROUTINE)); - assert(instr->num_components == glsl_get_vector_elements(type)); - assert(instr->variables[0]->var->data.mode != nir_var_shader_in && - instr->variables[0]->var->data.mode != nir_var_uniform && - instr->variables[0]->var->data.mode != nir_var_shader_storage); - assert((instr->const_index[0] & ~((1 << instr->num_components) - 1)) == 0); - break; - } - case nir_intrinsic_copy_var: - assert(nir_deref_tail(&instr->variables[0]->deref)->type == - nir_deref_tail(&instr->variables[1]->deref)->type); - assert(instr->variables[0]->var->data.mode != nir_var_shader_in && - instr->variables[0]->var->data.mode != nir_var_uniform && - instr->variables[0]->var->data.mode != nir_var_shader_storage); - break; - default: - break; - } -} - -static void -validate_tex_instr(nir_tex_instr *instr, validate_state *state) -{ - bool src_type_seen[nir_num_tex_src_types]; - for (unsigned i = 0; i < nir_num_tex_src_types; i++) - src_type_seen[i] = false; - - for (unsigned i = 0; i < instr->num_srcs; i++) { - assert(!src_type_seen[instr->src[i].src_type]); - src_type_seen[instr->src[i].src_type] = true; - validate_src(&instr->src[i].src, state); - } - - if (instr->sampler != NULL) - validate_deref_var(instr, instr->sampler, state); - - validate_dest(&instr->dest, state); -} - -static void -validate_call_instr(nir_call_instr *instr, validate_state *state) -{ - if (instr->return_deref == NULL) { - assert(glsl_type_is_void(instr->callee->return_type)); - } else { - assert(instr->return_deref->deref.type == instr->callee->return_type); - validate_deref_var(instr, instr->return_deref, state); - } - - assert(instr->num_params == instr->callee->num_params); - - for (unsigned i = 0; i < instr->num_params; i++) { - assert(instr->callee->params[i].type == instr->params[i]->deref.type); - validate_deref_var(instr, instr->params[i], state); - } -} - -static void -validate_load_const_instr(nir_load_const_instr *instr, validate_state *state) -{ - validate_ssa_def(&instr->def, state); -} - -static void -validate_ssa_undef_instr(nir_ssa_undef_instr *instr, validate_state *state) -{ - validate_ssa_def(&instr->def, state); -} - -static void -validate_phi_instr(nir_phi_instr *instr, validate_state *state) -{ - /* - * don't validate the sources until we get to them from their predecessor - * basic blocks, to avoid validating an SSA use before its definition. - */ - - validate_dest(&instr->dest, state); - - exec_list_validate(&instr->srcs); - assert(exec_list_length(&instr->srcs) == - state->block->predecessors->entries); -} - -static void -validate_instr(nir_instr *instr, validate_state *state) -{ - assert(instr->block == state->block); - - state->instr = instr; - - switch (instr->type) { - case nir_instr_type_alu: - validate_alu_instr(nir_instr_as_alu(instr), state); - break; - - case nir_instr_type_call: - validate_call_instr(nir_instr_as_call(instr), state); - break; - - case nir_instr_type_intrinsic: - validate_intrinsic_instr(nir_instr_as_intrinsic(instr), state); - break; - - case nir_instr_type_tex: - validate_tex_instr(nir_instr_as_tex(instr), state); - break; - - case nir_instr_type_load_const: - validate_load_const_instr(nir_instr_as_load_const(instr), state); - break; - - case nir_instr_type_phi: - validate_phi_instr(nir_instr_as_phi(instr), state); - break; - - case nir_instr_type_ssa_undef: - validate_ssa_undef_instr(nir_instr_as_ssa_undef(instr), state); - break; - - case nir_instr_type_jump: - break; - - default: - assert(!"Invalid ALU instruction type"); - break; - } - - state->instr = NULL; -} - -static void -validate_phi_src(nir_phi_instr *instr, nir_block *pred, validate_state *state) -{ - state->instr = &instr->instr; - - assert(instr->dest.is_ssa); - - exec_list_validate(&instr->srcs); - nir_foreach_phi_src(instr, src) { - if (src->pred == pred) { - assert(src->src.is_ssa); - assert(src->src.ssa->num_components == - instr->dest.ssa.num_components); - - validate_src(&src->src, state); - state->instr = NULL; - return; - } - } - - abort(); -} - -static void -validate_phi_srcs(nir_block *block, nir_block *succ, validate_state *state) -{ - nir_foreach_instr(succ, instr) { - if (instr->type != nir_instr_type_phi) - break; - - validate_phi_src(nir_instr_as_phi(instr), block, state); - } -} - -static void validate_cf_node(nir_cf_node *node, validate_state *state); - -static void -validate_block(nir_block *block, validate_state *state) -{ - assert(block->cf_node.parent == state->parent_node); - - state->block = block; - - exec_list_validate(&block->instr_list); - nir_foreach_instr(block, instr) { - if (instr->type == nir_instr_type_phi) { - assert(instr == nir_block_first_instr(block) || - nir_instr_prev(instr)->type == nir_instr_type_phi); - } - - if (instr->type == nir_instr_type_jump) { - assert(instr == nir_block_last_instr(block)); - } - - validate_instr(instr, state); - } - - assert(block->successors[0] != NULL); - assert(block->successors[0] != block->successors[1]); - - for (unsigned i = 0; i < 2; i++) { - if (block->successors[i] != NULL) { - struct set_entry *entry = - _mesa_set_search(block->successors[i]->predecessors, block); - assert(entry); - - validate_phi_srcs(block, block->successors[i], state); - } - } - - struct set_entry *entry; - set_foreach(block->predecessors, entry) { - const nir_block *pred = entry->key; - assert(pred->successors[0] == block || - pred->successors[1] == block); - } - - if (!exec_list_is_empty(&block->instr_list) && - nir_block_last_instr(block)->type == nir_instr_type_jump) { - assert(block->successors[1] == NULL); - nir_jump_instr *jump = nir_instr_as_jump(nir_block_last_instr(block)); - switch (jump->type) { - case nir_jump_break: { - nir_block *after = - nir_cf_node_as_block(nir_cf_node_next(&state->loop->cf_node)); - assert(block->successors[0] == after); - break; - } - - case nir_jump_continue: { - nir_block *first = - nir_cf_node_as_block(nir_loop_first_cf_node(state->loop)); - assert(block->successors[0] == first); - break; - } - - case nir_jump_return: - assert(block->successors[0] == state->impl->end_block); - break; - - default: - unreachable("bad jump type"); - } - } else { - nir_cf_node *next = nir_cf_node_next(&block->cf_node); - if (next == NULL) { - switch (state->parent_node->type) { - case nir_cf_node_loop: { - nir_block *first = - nir_cf_node_as_block(nir_loop_first_cf_node(state->loop)); - assert(block->successors[0] == first); - /* due to the hack for infinite loops, block->successors[1] may - * point to the block after the loop. - */ - break; - } - - case nir_cf_node_if: { - nir_block *after = - nir_cf_node_as_block(nir_cf_node_next(state->parent_node)); - assert(block->successors[0] == after); - assert(block->successors[1] == NULL); - break; - } - - case nir_cf_node_function: - assert(block->successors[0] == state->impl->end_block); - assert(block->successors[1] == NULL); - break; - - default: - unreachable("unknown control flow node type"); - } - } else { - if (next->type == nir_cf_node_if) { - nir_if *if_stmt = nir_cf_node_as_if(next); - assert(&block->successors[0]->cf_node == - nir_if_first_then_node(if_stmt)); - assert(&block->successors[1]->cf_node == - nir_if_first_else_node(if_stmt)); - } else { - assert(next->type == nir_cf_node_loop); - nir_loop *loop = nir_cf_node_as_loop(next); - assert(&block->successors[0]->cf_node == - nir_loop_first_cf_node(loop)); - assert(block->successors[1] == NULL); - } - } - } -} - -static void -validate_if(nir_if *if_stmt, validate_state *state) -{ - state->if_stmt = if_stmt; - - assert(!exec_node_is_head_sentinel(if_stmt->cf_node.node.prev)); - nir_cf_node *prev_node = nir_cf_node_prev(&if_stmt->cf_node); - assert(prev_node->type == nir_cf_node_block); - - assert(!exec_node_is_tail_sentinel(if_stmt->cf_node.node.next)); - nir_cf_node *next_node = nir_cf_node_next(&if_stmt->cf_node); - assert(next_node->type == nir_cf_node_block); - - validate_src(&if_stmt->condition, state); - - assert(!exec_list_is_empty(&if_stmt->then_list)); - assert(!exec_list_is_empty(&if_stmt->else_list)); - - nir_cf_node *old_parent = state->parent_node; - state->parent_node = &if_stmt->cf_node; - - exec_list_validate(&if_stmt->then_list); - foreach_list_typed(nir_cf_node, cf_node, node, &if_stmt->then_list) { - validate_cf_node(cf_node, state); - } - - exec_list_validate(&if_stmt->else_list); - foreach_list_typed(nir_cf_node, cf_node, node, &if_stmt->else_list) { - validate_cf_node(cf_node, state); - } - - state->parent_node = old_parent; - state->if_stmt = NULL; -} - -static void -validate_loop(nir_loop *loop, validate_state *state) -{ - assert(!exec_node_is_head_sentinel(loop->cf_node.node.prev)); - nir_cf_node *prev_node = nir_cf_node_prev(&loop->cf_node); - assert(prev_node->type == nir_cf_node_block); - - assert(!exec_node_is_tail_sentinel(loop->cf_node.node.next)); - nir_cf_node *next_node = nir_cf_node_next(&loop->cf_node); - assert(next_node->type == nir_cf_node_block); - - assert(!exec_list_is_empty(&loop->body)); - - nir_cf_node *old_parent = state->parent_node; - state->parent_node = &loop->cf_node; - nir_loop *old_loop = state->loop; - state->loop = loop; - - exec_list_validate(&loop->body); - foreach_list_typed(nir_cf_node, cf_node, node, &loop->body) { - validate_cf_node(cf_node, state); - } - - state->parent_node = old_parent; - state->loop = old_loop; -} - -static void -validate_cf_node(nir_cf_node *node, validate_state *state) -{ - assert(node->parent == state->parent_node); - - switch (node->type) { - case nir_cf_node_block: - validate_block(nir_cf_node_as_block(node), state); - break; - - case nir_cf_node_if: - validate_if(nir_cf_node_as_if(node), state); - break; - - case nir_cf_node_loop: - validate_loop(nir_cf_node_as_loop(node), state); - break; - - default: - unreachable("Invalid CF node type"); - } -} - -static void -prevalidate_reg_decl(nir_register *reg, bool is_global, validate_state *state) -{ - assert(reg->is_global == is_global); - - if (is_global) - assert(reg->index < state->shader->reg_alloc); - else - assert(reg->index < state->impl->reg_alloc); - assert(!BITSET_TEST(state->regs_found, reg->index)); - BITSET_SET(state->regs_found, reg->index); - - list_validate(®->uses); - list_validate(®->defs); - list_validate(®->if_uses); - - reg_validate_state *reg_state = ralloc(state->regs, reg_validate_state); - reg_state->uses = _mesa_set_create(reg_state, _mesa_hash_pointer, - _mesa_key_pointer_equal); - reg_state->if_uses = _mesa_set_create(reg_state, _mesa_hash_pointer, - _mesa_key_pointer_equal); - reg_state->defs = _mesa_set_create(reg_state, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - reg_state->where_defined = is_global ? NULL : state->impl; - - _mesa_hash_table_insert(state->regs, reg, reg_state); -} - -static void -postvalidate_reg_decl(nir_register *reg, validate_state *state) -{ - struct hash_entry *entry = _mesa_hash_table_search(state->regs, reg); - - reg_validate_state *reg_state = (reg_validate_state *) entry->data; - - nir_foreach_use(reg, src) { - struct set_entry *entry = _mesa_set_search(reg_state->uses, src); - assert(entry); - _mesa_set_remove(reg_state->uses, entry); - } - - if (reg_state->uses->entries != 0) { - printf("extra entries in register uses:\n"); - struct set_entry *entry; - set_foreach(reg_state->uses, entry) - printf("%p\n", entry->key); - - abort(); - } - - nir_foreach_if_use(reg, src) { - struct set_entry *entry = _mesa_set_search(reg_state->if_uses, src); - assert(entry); - _mesa_set_remove(reg_state->if_uses, entry); - } - - if (reg_state->if_uses->entries != 0) { - printf("extra entries in register if_uses:\n"); - struct set_entry *entry; - set_foreach(reg_state->if_uses, entry) - printf("%p\n", entry->key); - - abort(); - } - - nir_foreach_def(reg, src) { - struct set_entry *entry = _mesa_set_search(reg_state->defs, src); - assert(entry); - _mesa_set_remove(reg_state->defs, entry); - } - - if (reg_state->defs->entries != 0) { - printf("extra entries in register defs:\n"); - struct set_entry *entry; - set_foreach(reg_state->defs, entry) - printf("%p\n", entry->key); - - abort(); - } -} - -static void -validate_var_decl(nir_variable *var, bool is_global, validate_state *state) -{ - assert(is_global != (var->data.mode == nir_var_local)); - - /* - * TODO validate some things ir_validate.cpp does (requires more GLSL type - * support) - */ - - if (!is_global) { - _mesa_hash_table_insert(state->var_defs, var, state->impl); - } -} - -static bool -postvalidate_ssa_def(nir_ssa_def *def, void *void_state) -{ - validate_state *state = void_state; - - struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, def); - ssa_def_validate_state *def_state = (ssa_def_validate_state *)entry->data; - - nir_foreach_use(def, src) { - struct set_entry *entry = _mesa_set_search(def_state->uses, src); - assert(entry); - _mesa_set_remove(def_state->uses, entry); - } - - if (def_state->uses->entries != 0) { - printf("extra entries in register uses:\n"); - struct set_entry *entry; - set_foreach(def_state->uses, entry) - printf("%p\n", entry->key); - - abort(); - } - - nir_foreach_if_use(def, src) { - struct set_entry *entry = _mesa_set_search(def_state->if_uses, src); - assert(entry); - _mesa_set_remove(def_state->if_uses, entry); - } - - if (def_state->if_uses->entries != 0) { - printf("extra entries in register uses:\n"); - struct set_entry *entry; - set_foreach(def_state->if_uses, entry) - printf("%p\n", entry->key); - - abort(); - } - - return true; -} - -static bool -postvalidate_ssa_defs_block(nir_block *block, void *state) -{ - nir_foreach_instr(block, instr) - nir_foreach_ssa_def(instr, postvalidate_ssa_def, state); - - return true; -} - -static void -validate_function_impl(nir_function_impl *impl, validate_state *state) -{ - assert(impl->function->impl == impl); - assert(impl->cf_node.parent == NULL); - - assert(impl->num_params == impl->function->num_params); - for (unsigned i = 0; i < impl->num_params; i++) - assert(impl->params[i]->type == impl->function->params[i].type); - - if (glsl_type_is_void(impl->function->return_type)) - assert(impl->return_var == NULL); - else - assert(impl->return_var->type == impl->function->return_type); - - assert(exec_list_is_empty(&impl->end_block->instr_list)); - assert(impl->end_block->successors[0] == NULL); - assert(impl->end_block->successors[1] == NULL); - - state->impl = impl; - state->parent_node = &impl->cf_node; - - exec_list_validate(&impl->locals); - nir_foreach_variable(var, &impl->locals) { - validate_var_decl(var, false, state); - } - - state->regs_found = realloc(state->regs_found, - BITSET_WORDS(impl->reg_alloc) * - sizeof(BITSET_WORD)); - memset(state->regs_found, 0, BITSET_WORDS(impl->reg_alloc) * - sizeof(BITSET_WORD)); - exec_list_validate(&impl->registers); - foreach_list_typed(nir_register, reg, node, &impl->registers) { - prevalidate_reg_decl(reg, false, state); - } - - state->ssa_defs_found = realloc(state->ssa_defs_found, - BITSET_WORDS(impl->ssa_alloc) * - sizeof(BITSET_WORD)); - memset(state->ssa_defs_found, 0, BITSET_WORDS(impl->ssa_alloc) * - sizeof(BITSET_WORD)); - exec_list_validate(&impl->body); - foreach_list_typed(nir_cf_node, node, node, &impl->body) { - validate_cf_node(node, state); - } - - foreach_list_typed(nir_register, reg, node, &impl->registers) { - postvalidate_reg_decl(reg, state); - } - - nir_foreach_block(impl, postvalidate_ssa_defs_block, state); -} - -static void -validate_function(nir_function *func, validate_state *state) -{ - if (func->impl != NULL) { - assert(func->impl->function == func); - validate_function_impl(func->impl, state); - } -} - -static void -init_validate_state(validate_state *state) -{ - state->regs = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - state->ssa_defs = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - state->ssa_defs_found = NULL; - state->regs_found = NULL; - state->var_defs = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); - state->loop = NULL; -} - -static void -destroy_validate_state(validate_state *state) -{ - _mesa_hash_table_destroy(state->regs, NULL); - _mesa_hash_table_destroy(state->ssa_defs, NULL); - free(state->ssa_defs_found); - free(state->regs_found); - _mesa_hash_table_destroy(state->var_defs, NULL); -} - -void -nir_validate_shader(nir_shader *shader) -{ - validate_state state; - init_validate_state(&state); - - state.shader = shader; - - exec_list_validate(&shader->uniforms); - nir_foreach_variable(var, &shader->uniforms) { - validate_var_decl(var, true, &state); - } - - exec_list_validate(&shader->inputs); - nir_foreach_variable(var, &shader->inputs) { - validate_var_decl(var, true, &state); - } - - exec_list_validate(&shader->outputs); - nir_foreach_variable(var, &shader->outputs) { - validate_var_decl(var, true, &state); - } - - exec_list_validate(&shader->shared); - nir_foreach_variable(var, &shader->shared) { - validate_var_decl(var, true, &state); - } - - exec_list_validate(&shader->globals); - nir_foreach_variable(var, &shader->globals) { - validate_var_decl(var, true, &state); - } - - exec_list_validate(&shader->system_values); - nir_foreach_variable(var, &shader->system_values) { - validate_var_decl(var, true, &state); - } - - state.regs_found = realloc(state.regs_found, - BITSET_WORDS(shader->reg_alloc) * - sizeof(BITSET_WORD)); - memset(state.regs_found, 0, BITSET_WORDS(shader->reg_alloc) * - sizeof(BITSET_WORD)); - exec_list_validate(&shader->registers); - foreach_list_typed(nir_register, reg, node, &shader->registers) { - prevalidate_reg_decl(reg, true, &state); - } - - exec_list_validate(&shader->functions); - foreach_list_typed(nir_function, func, node, &shader->functions) { - validate_function(func, &state); - } - - foreach_list_typed(nir_register, reg, node, &shader->registers) { - postvalidate_reg_decl(reg, &state); - } - - destroy_validate_state(&state); -} - -#endif /* NDEBUG */ diff --git a/src/glsl/nir/nir_vla.h b/src/glsl/nir/nir_vla.h deleted file mode 100644 index 753783316a2..00000000000 --- a/src/glsl/nir/nir_vla.h +++ /dev/null @@ -1,54 +0,0 @@ -/************************************************************************** - * - * Copyright 2015 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - -#pragma once - - -#include "c99_alloca.h" - - -/* Declare a variable length array, with no initialization */ -#define NIR_VLA(_type, _name, _length) \ - _type *_name = alloca((_length) * sizeof *_name) - - -/* Declare a variable length array, and initialize it with the given byte. - * - * _length is evaluated twice, so expressions with side-effects must be - * avoided. - */ -#define NIR_VLA_FILL(_type, _name, _length, _byte) \ - _type *_name = memset(alloca((_length) * sizeof *_name), _byte, (_length) * sizeof *_name) - - -/* Declare a variable length array, and zero it. - * - * Just like NIR_VLA_FILL, _length is evaluated twice, so expressions with - * side-effects must be avoided. - */ -#define NIR_VLA_ZERO(_type, _name, _length) \ - NIR_VLA_FILL(_type, _name, _length, 0) diff --git a/src/glsl/nir/nir_worklist.c b/src/glsl/nir/nir_worklist.c deleted file mode 100644 index 3087a1d2354..00000000000 --- a/src/glsl/nir/nir_worklist.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir_worklist.h" - -void -nir_block_worklist_init(nir_block_worklist *w, unsigned num_blocks, - void *mem_ctx) -{ - w->size = num_blocks; - w->count = 0; - w->start = 0; - - w->blocks_present = rzalloc_array(mem_ctx, BITSET_WORD, - BITSET_WORDS(num_blocks)); - w->blocks = ralloc_array(mem_ctx, nir_block *, num_blocks); -} - -void -nir_block_worklist_fini(nir_block_worklist *w) -{ - ralloc_free(w->blocks_present); - ralloc_free(w->blocks); -} - -static bool -worklist_add_block(nir_block *block, void *w) -{ - nir_block_worklist_push_tail(w, block); - - return true; -} - -void -nir_block_worklist_add_all(nir_block_worklist *w, nir_function_impl *impl) -{ - nir_foreach_block(impl, worklist_add_block, w); -} - -void -nir_block_worklist_push_head(nir_block_worklist *w, nir_block *block) -{ - /* Pushing a block we already have is a no-op */ - if (BITSET_TEST(w->blocks_present, block->index)) - return; - - assert(w->count < w->size); - - if (w->start == 0) - w->start = w->size - 1; - else - w->start--; - - w->count++; - - w->blocks[w->start] = block; - BITSET_SET(w->blocks_present, block->index); -} - -nir_block * -nir_block_worklist_peek_head(const nir_block_worklist *w) -{ - assert(w->count > 0); - - return w->blocks[w->start]; -} - -nir_block * -nir_block_worklist_pop_head(nir_block_worklist *w) -{ - assert(w->count > 0); - - unsigned head = w->start; - - w->start = (w->start + 1) % w->size; - w->count--; - - BITSET_CLEAR(w->blocks_present, w->blocks[head]->index); - return w->blocks[head]; -} - -void -nir_block_worklist_push_tail(nir_block_worklist *w, nir_block *block) -{ - /* Pushing a block we already have is a no-op */ - if (BITSET_TEST(w->blocks_present, block->index)) - return; - - assert(w->count < w->size); - - w->count++; - - unsigned tail = (w->start + w->count - 1) % w->size; - - w->blocks[tail] = block; - BITSET_SET(w->blocks_present, block->index); -} - -nir_block * -nir_block_worklist_peek_tail(const nir_block_worklist *w) -{ - assert(w->count > 0); - - unsigned tail = (w->start + w->count - 1) % w->size; - - return w->blocks[tail]; -} - -nir_block * -nir_block_worklist_pop_tail(nir_block_worklist *w) -{ - assert(w->count > 0); - - unsigned tail = (w->start + w->count - 1) % w->size; - - w->count--; - - BITSET_CLEAR(w->blocks_present, w->blocks[tail]->index); - return w->blocks[tail]; -} diff --git a/src/glsl/nir/nir_worklist.h b/src/glsl/nir/nir_worklist.h deleted file mode 100644 index 829bff24a55..00000000000 --- a/src/glsl/nir/nir_worklist.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright © 2014 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#pragma once - -#ifndef _NIR_WORKLIST_ -#define _NIR_WORKLIST_ - -#include "nir.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Represents a double-ended queue of unique blocks - * - * The worklist datastructure guarantees that eacy block is in the queue at - * most once. Pushing a block onto either end of the queue is a no-op if - * the block is already in the queue. In order for this to work, the - * caller must ensure that the blocks are properly indexed. - */ -typedef struct { - /* The total size of the worklist */ - unsigned size; - - /* The number of blocks currently in the worklist */ - unsigned count; - - /* The offset in the array of blocks at which the list starts */ - unsigned start; - - /* A bitset of all of the blocks currently present in the worklist */ - BITSET_WORD *blocks_present; - - /* The actual worklist */ - nir_block **blocks; -} nir_block_worklist; - -void nir_block_worklist_init(nir_block_worklist *w, unsigned num_blocks, - void *mem_ctx); -void nir_block_worklist_fini(nir_block_worklist *w); - -void nir_block_worklist_add_all(nir_block_worklist *w, nir_function_impl *impl); - -static inline bool -nir_block_worklist_is_empty(const nir_block_worklist *w) -{ - return w->count == 0; -} - -void nir_block_worklist_push_head(nir_block_worklist *w, nir_block *block); - -nir_block *nir_block_worklist_peek_head(const nir_block_worklist *w); - -nir_block *nir_block_worklist_pop_head(nir_block_worklist *w); - -void nir_block_worklist_push_tail(nir_block_worklist *w, nir_block *block); - -nir_block *nir_block_worklist_peek_tail(const nir_block_worklist *w); - -nir_block *nir_block_worklist_pop_tail(nir_block_worklist *w); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* _NIR_WORKLIST_ */ diff --git a/src/glsl/nir/shader_enums.c b/src/glsl/nir/shader_enums.c deleted file mode 100644 index ff2f564dc98..00000000000 --- a/src/glsl/nir/shader_enums.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright © 2015 Red Hat - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Rob Clark <[email protected]> - */ - -#include "shader_enums.h" -#include "util/macros.h" -#include "mesa/main/config.h" - -#define ENUM(x) [x] = #x -#define NAME(val) ((((val) < ARRAY_SIZE(names)) && names[(val)]) ? names[(val)] : "UNKNOWN") - -const char * -gl_shader_stage_name(gl_shader_stage stage) -{ - static const char *names[] = { - ENUM(MESA_SHADER_VERTEX), - ENUM(MESA_SHADER_TESS_CTRL), - ENUM(MESA_SHADER_TESS_EVAL), - ENUM(MESA_SHADER_GEOMETRY), - ENUM(MESA_SHADER_FRAGMENT), - ENUM(MESA_SHADER_COMPUTE), - }; - STATIC_ASSERT(ARRAY_SIZE(names) == MESA_SHADER_STAGES); - return NAME(stage); -} - -/** - * Translate a gl_shader_stage to a short shader stage name for debug - * printouts and error messages. - */ -const char * -_mesa_shader_stage_to_string(unsigned stage) -{ - switch (stage) { - case MESA_SHADER_VERTEX: return "vertex"; - case MESA_SHADER_FRAGMENT: return "fragment"; - case MESA_SHADER_GEOMETRY: return "geometry"; - case MESA_SHADER_COMPUTE: return "compute"; - case MESA_SHADER_TESS_CTRL: return "tessellation control"; - case MESA_SHADER_TESS_EVAL: return "tessellation evaluation"; - } - - unreachable("Unknown shader stage."); -} - -/** - * Translate a gl_shader_stage to a shader stage abbreviation (VS, GS, FS) - * for debug printouts and error messages. - */ -const char * -_mesa_shader_stage_to_abbrev(unsigned stage) -{ - switch (stage) { - case MESA_SHADER_VERTEX: return "VS"; - case MESA_SHADER_FRAGMENT: return "FS"; - case MESA_SHADER_GEOMETRY: return "GS"; - case MESA_SHADER_COMPUTE: return "CS"; - case MESA_SHADER_TESS_CTRL: return "TCS"; - case MESA_SHADER_TESS_EVAL: return "TES"; - } - - unreachable("Unknown shader stage."); -} - -const char * -gl_vert_attrib_name(gl_vert_attrib attrib) -{ - static const char *names[] = { - ENUM(VERT_ATTRIB_POS), - ENUM(VERT_ATTRIB_WEIGHT), - ENUM(VERT_ATTRIB_NORMAL), - ENUM(VERT_ATTRIB_COLOR0), - ENUM(VERT_ATTRIB_COLOR1), - ENUM(VERT_ATTRIB_FOG), - ENUM(VERT_ATTRIB_COLOR_INDEX), - ENUM(VERT_ATTRIB_EDGEFLAG), - ENUM(VERT_ATTRIB_TEX0), - ENUM(VERT_ATTRIB_TEX1), - ENUM(VERT_ATTRIB_TEX2), - ENUM(VERT_ATTRIB_TEX3), - ENUM(VERT_ATTRIB_TEX4), - ENUM(VERT_ATTRIB_TEX5), - ENUM(VERT_ATTRIB_TEX6), - ENUM(VERT_ATTRIB_TEX7), - ENUM(VERT_ATTRIB_POINT_SIZE), - ENUM(VERT_ATTRIB_GENERIC0), - ENUM(VERT_ATTRIB_GENERIC1), - ENUM(VERT_ATTRIB_GENERIC2), - ENUM(VERT_ATTRIB_GENERIC3), - ENUM(VERT_ATTRIB_GENERIC4), - ENUM(VERT_ATTRIB_GENERIC5), - ENUM(VERT_ATTRIB_GENERIC6), - ENUM(VERT_ATTRIB_GENERIC7), - ENUM(VERT_ATTRIB_GENERIC8), - ENUM(VERT_ATTRIB_GENERIC9), - ENUM(VERT_ATTRIB_GENERIC10), - ENUM(VERT_ATTRIB_GENERIC11), - ENUM(VERT_ATTRIB_GENERIC12), - ENUM(VERT_ATTRIB_GENERIC13), - ENUM(VERT_ATTRIB_GENERIC14), - ENUM(VERT_ATTRIB_GENERIC15), - }; - STATIC_ASSERT(ARRAY_SIZE(names) == VERT_ATTRIB_MAX); - return NAME(attrib); -} - -const char * -gl_varying_slot_name(gl_varying_slot slot) -{ - static const char *names[] = { - ENUM(VARYING_SLOT_POS), - ENUM(VARYING_SLOT_COL0), - ENUM(VARYING_SLOT_COL1), - ENUM(VARYING_SLOT_FOGC), - ENUM(VARYING_SLOT_TEX0), - ENUM(VARYING_SLOT_TEX1), - ENUM(VARYING_SLOT_TEX2), - ENUM(VARYING_SLOT_TEX3), - ENUM(VARYING_SLOT_TEX4), - ENUM(VARYING_SLOT_TEX5), - ENUM(VARYING_SLOT_TEX6), - ENUM(VARYING_SLOT_TEX7), - ENUM(VARYING_SLOT_PSIZ), - ENUM(VARYING_SLOT_BFC0), - ENUM(VARYING_SLOT_BFC1), - ENUM(VARYING_SLOT_EDGE), - ENUM(VARYING_SLOT_CLIP_VERTEX), - ENUM(VARYING_SLOT_CLIP_DIST0), - ENUM(VARYING_SLOT_CLIP_DIST1), - ENUM(VARYING_SLOT_PRIMITIVE_ID), - ENUM(VARYING_SLOT_LAYER), - ENUM(VARYING_SLOT_VIEWPORT), - ENUM(VARYING_SLOT_FACE), - ENUM(VARYING_SLOT_PNTC), - ENUM(VARYING_SLOT_TESS_LEVEL_OUTER), - ENUM(VARYING_SLOT_TESS_LEVEL_INNER), - ENUM(VARYING_SLOT_VAR0), - ENUM(VARYING_SLOT_VAR1), - ENUM(VARYING_SLOT_VAR2), - ENUM(VARYING_SLOT_VAR3), - ENUM(VARYING_SLOT_VAR4), - ENUM(VARYING_SLOT_VAR5), - ENUM(VARYING_SLOT_VAR6), - ENUM(VARYING_SLOT_VAR7), - ENUM(VARYING_SLOT_VAR8), - ENUM(VARYING_SLOT_VAR9), - ENUM(VARYING_SLOT_VAR10), - ENUM(VARYING_SLOT_VAR11), - ENUM(VARYING_SLOT_VAR12), - ENUM(VARYING_SLOT_VAR13), - ENUM(VARYING_SLOT_VAR14), - ENUM(VARYING_SLOT_VAR15), - ENUM(VARYING_SLOT_VAR16), - ENUM(VARYING_SLOT_VAR17), - ENUM(VARYING_SLOT_VAR18), - ENUM(VARYING_SLOT_VAR19), - ENUM(VARYING_SLOT_VAR20), - ENUM(VARYING_SLOT_VAR21), - ENUM(VARYING_SLOT_VAR22), - ENUM(VARYING_SLOT_VAR23), - ENUM(VARYING_SLOT_VAR24), - ENUM(VARYING_SLOT_VAR25), - ENUM(VARYING_SLOT_VAR26), - ENUM(VARYING_SLOT_VAR27), - ENUM(VARYING_SLOT_VAR28), - ENUM(VARYING_SLOT_VAR29), - ENUM(VARYING_SLOT_VAR30), - ENUM(VARYING_SLOT_VAR31), - }; - STATIC_ASSERT(ARRAY_SIZE(names) == VARYING_SLOT_MAX); - return NAME(slot); -} - -const char * -gl_system_value_name(gl_system_value sysval) -{ - static const char *names[] = { - ENUM(SYSTEM_VALUE_VERTEX_ID), - ENUM(SYSTEM_VALUE_INSTANCE_ID), - ENUM(SYSTEM_VALUE_INSTANCE_INDEX), - ENUM(SYSTEM_VALUE_VERTEX_ID_ZERO_BASE), - ENUM(SYSTEM_VALUE_BASE_VERTEX), - ENUM(SYSTEM_VALUE_INVOCATION_ID), - ENUM(SYSTEM_VALUE_FRONT_FACE), - ENUM(SYSTEM_VALUE_SAMPLE_ID), - ENUM(SYSTEM_VALUE_SAMPLE_POS), - ENUM(SYSTEM_VALUE_SAMPLE_MASK_IN), - ENUM(SYSTEM_VALUE_TESS_COORD), - ENUM(SYSTEM_VALUE_VERTICES_IN), - ENUM(SYSTEM_VALUE_PRIMITIVE_ID), - ENUM(SYSTEM_VALUE_TESS_LEVEL_OUTER), - ENUM(SYSTEM_VALUE_TESS_LEVEL_INNER), - ENUM(SYSTEM_VALUE_LOCAL_INVOCATION_ID), - ENUM(SYSTEM_VALUE_LOCAL_INVOCATION_INDEX), - ENUM(SYSTEM_VALUE_GLOBAL_INVOCATION_ID), - ENUM(SYSTEM_VALUE_WORK_GROUP_ID), - ENUM(SYSTEM_VALUE_NUM_WORK_GROUPS), - ENUM(SYSTEM_VALUE_VERTEX_CNT), - }; - STATIC_ASSERT(ARRAY_SIZE(names) == SYSTEM_VALUE_MAX); - return NAME(sysval); -} - -const char * -glsl_interp_qualifier_name(enum glsl_interp_qualifier qual) -{ - static const char *names[] = { - ENUM(INTERP_QUALIFIER_NONE), - ENUM(INTERP_QUALIFIER_SMOOTH), - ENUM(INTERP_QUALIFIER_FLAT), - ENUM(INTERP_QUALIFIER_NOPERSPECTIVE), - }; - STATIC_ASSERT(ARRAY_SIZE(names) == INTERP_QUALIFIER_COUNT); - return NAME(qual); -} - -const char * -gl_frag_result_name(gl_frag_result result) -{ - static const char *names[] = { - ENUM(FRAG_RESULT_DEPTH), - ENUM(FRAG_RESULT_STENCIL), - ENUM(FRAG_RESULT_COLOR), - ENUM(FRAG_RESULT_SAMPLE_MASK), - ENUM(FRAG_RESULT_DATA0), - ENUM(FRAG_RESULT_DATA1), - ENUM(FRAG_RESULT_DATA2), - ENUM(FRAG_RESULT_DATA3), - ENUM(FRAG_RESULT_DATA4), - ENUM(FRAG_RESULT_DATA5), - ENUM(FRAG_RESULT_DATA6), - ENUM(FRAG_RESULT_DATA7), - }; - STATIC_ASSERT(ARRAY_SIZE(names) == FRAG_RESULT_MAX); - return NAME(result); -} diff --git a/src/glsl/nir/shader_enums.h b/src/glsl/nir/shader_enums.h deleted file mode 100644 index e3f46e3d739..00000000000 --- a/src/glsl/nir/shader_enums.h +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Mesa 3-D graphics library - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * Copyright (C) 2009 VMware, Inc. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SHADER_ENUMS_H -#define SHADER_ENUMS_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Shader stages. Note that these will become 5 with tessellation. - * - * The order must match how shaders are ordered in the pipeline. - * The GLSL linker assumes that if i<j, then the j-th shader is - * executed later than the i-th shader. - */ -typedef enum -{ - MESA_SHADER_VERTEX = 0, - MESA_SHADER_TESS_CTRL = 1, - MESA_SHADER_TESS_EVAL = 2, - MESA_SHADER_GEOMETRY = 3, - MESA_SHADER_FRAGMENT = 4, - MESA_SHADER_COMPUTE = 5, -} gl_shader_stage; - -const char *gl_shader_stage_name(gl_shader_stage stage); - -/** - * Translate a gl_shader_stage to a short shader stage name for debug - * printouts and error messages. - */ -const char *_mesa_shader_stage_to_string(unsigned stage); - -/** - * Translate a gl_shader_stage to a shader stage abbreviation (VS, GS, FS) - * for debug printouts and error messages. - */ -const char *_mesa_shader_stage_to_abbrev(unsigned stage); - -#define MESA_SHADER_STAGES (MESA_SHADER_COMPUTE + 1) - - -/** - * Indexes for vertex program attributes. - * GL_NV_vertex_program aliases generic attributes over the conventional - * attributes. In GL_ARB_vertex_program shader the aliasing is optional. - * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the - * generic attributes are distinct/separate). - */ -typedef enum -{ - VERT_ATTRIB_POS = 0, - VERT_ATTRIB_WEIGHT = 1, - VERT_ATTRIB_NORMAL = 2, - VERT_ATTRIB_COLOR0 = 3, - VERT_ATTRIB_COLOR1 = 4, - VERT_ATTRIB_FOG = 5, - VERT_ATTRIB_COLOR_INDEX = 6, - VERT_ATTRIB_EDGEFLAG = 7, - VERT_ATTRIB_TEX0 = 8, - VERT_ATTRIB_TEX1 = 9, - VERT_ATTRIB_TEX2 = 10, - VERT_ATTRIB_TEX3 = 11, - VERT_ATTRIB_TEX4 = 12, - VERT_ATTRIB_TEX5 = 13, - VERT_ATTRIB_TEX6 = 14, - VERT_ATTRIB_TEX7 = 15, - VERT_ATTRIB_POINT_SIZE = 16, - VERT_ATTRIB_GENERIC0 = 17, - VERT_ATTRIB_GENERIC1 = 18, - VERT_ATTRIB_GENERIC2 = 19, - VERT_ATTRIB_GENERIC3 = 20, - VERT_ATTRIB_GENERIC4 = 21, - VERT_ATTRIB_GENERIC5 = 22, - VERT_ATTRIB_GENERIC6 = 23, - VERT_ATTRIB_GENERIC7 = 24, - VERT_ATTRIB_GENERIC8 = 25, - VERT_ATTRIB_GENERIC9 = 26, - VERT_ATTRIB_GENERIC10 = 27, - VERT_ATTRIB_GENERIC11 = 28, - VERT_ATTRIB_GENERIC12 = 29, - VERT_ATTRIB_GENERIC13 = 30, - VERT_ATTRIB_GENERIC14 = 31, - VERT_ATTRIB_GENERIC15 = 32, - VERT_ATTRIB_MAX = 33 -} gl_vert_attrib; - -const char *gl_vert_attrib_name(gl_vert_attrib attrib); - -/** - * Symbolic constats to help iterating over - * specific blocks of vertex attributes. - * - * VERT_ATTRIB_FF - * includes all fixed function attributes as well as - * the aliased GL_NV_vertex_program shader attributes. - * VERT_ATTRIB_TEX - * include the classic texture coordinate attributes. - * Is a subset of VERT_ATTRIB_FF. - * VERT_ATTRIB_GENERIC - * include the OpenGL 2.0+ GLSL generic shader attributes. - * These alias the generic GL_ARB_vertex_shader attributes. - */ -#define VERT_ATTRIB_FF(i) (VERT_ATTRIB_POS + (i)) -#define VERT_ATTRIB_FF_MAX VERT_ATTRIB_GENERIC0 - -#define VERT_ATTRIB_TEX(i) (VERT_ATTRIB_TEX0 + (i)) -#define VERT_ATTRIB_TEX_MAX MAX_TEXTURE_COORD_UNITS - -#define VERT_ATTRIB_GENERIC(i) (VERT_ATTRIB_GENERIC0 + (i)) -#define VERT_ATTRIB_GENERIC_MAX MAX_VERTEX_GENERIC_ATTRIBS - -/** - * Bitflags for vertex attributes. - * These are used in bitfields in many places. - */ -/*@{*/ -#define VERT_BIT_POS BITFIELD64_BIT(VERT_ATTRIB_POS) -#define VERT_BIT_WEIGHT BITFIELD64_BIT(VERT_ATTRIB_WEIGHT) -#define VERT_BIT_NORMAL BITFIELD64_BIT(VERT_ATTRIB_NORMAL) -#define VERT_BIT_COLOR0 BITFIELD64_BIT(VERT_ATTRIB_COLOR0) -#define VERT_BIT_COLOR1 BITFIELD64_BIT(VERT_ATTRIB_COLOR1) -#define VERT_BIT_FOG BITFIELD64_BIT(VERT_ATTRIB_FOG) -#define VERT_BIT_COLOR_INDEX BITFIELD64_BIT(VERT_ATTRIB_COLOR_INDEX) -#define VERT_BIT_EDGEFLAG BITFIELD64_BIT(VERT_ATTRIB_EDGEFLAG) -#define VERT_BIT_TEX0 BITFIELD64_BIT(VERT_ATTRIB_TEX0) -#define VERT_BIT_TEX1 BITFIELD64_BIT(VERT_ATTRIB_TEX1) -#define VERT_BIT_TEX2 BITFIELD64_BIT(VERT_ATTRIB_TEX2) -#define VERT_BIT_TEX3 BITFIELD64_BIT(VERT_ATTRIB_TEX3) -#define VERT_BIT_TEX4 BITFIELD64_BIT(VERT_ATTRIB_TEX4) -#define VERT_BIT_TEX5 BITFIELD64_BIT(VERT_ATTRIB_TEX5) -#define VERT_BIT_TEX6 BITFIELD64_BIT(VERT_ATTRIB_TEX6) -#define VERT_BIT_TEX7 BITFIELD64_BIT(VERT_ATTRIB_TEX7) -#define VERT_BIT_POINT_SIZE BITFIELD64_BIT(VERT_ATTRIB_POINT_SIZE) -#define VERT_BIT_GENERIC0 BITFIELD64_BIT(VERT_ATTRIB_GENERIC0) - -#define VERT_BIT(i) BITFIELD64_BIT(i) -#define VERT_BIT_ALL BITFIELD64_RANGE(0, VERT_ATTRIB_MAX) - -#define VERT_BIT_FF(i) VERT_BIT(i) -#define VERT_BIT_FF_ALL BITFIELD64_RANGE(0, VERT_ATTRIB_FF_MAX) -#define VERT_BIT_TEX(i) VERT_BIT(VERT_ATTRIB_TEX(i)) -#define VERT_BIT_TEX_ALL \ - BITFIELD64_RANGE(VERT_ATTRIB_TEX(0), VERT_ATTRIB_TEX_MAX) - -#define VERT_BIT_GENERIC(i) VERT_BIT(VERT_ATTRIB_GENERIC(i)) -#define VERT_BIT_GENERIC_ALL \ - BITFIELD64_RANGE(VERT_ATTRIB_GENERIC(0), VERT_ATTRIB_GENERIC_MAX) -/*@}*/ - - -/** - * Indexes for vertex shader outputs, geometry shader inputs/outputs, and - * fragment shader inputs. - * - * Note that some of these values are not available to all pipeline stages. - * - * When this enum is updated, the following code must be updated too: - * - vertResults (in prog_print.c's arb_output_attrib_string()) - * - fragAttribs (in prog_print.c's arb_input_attrib_string()) - * - _mesa_varying_slot_in_fs() - */ -typedef enum -{ - VARYING_SLOT_POS, - VARYING_SLOT_COL0, /* COL0 and COL1 must be contiguous */ - VARYING_SLOT_COL1, - VARYING_SLOT_FOGC, - VARYING_SLOT_TEX0, /* TEX0-TEX7 must be contiguous */ - VARYING_SLOT_TEX1, - VARYING_SLOT_TEX2, - VARYING_SLOT_TEX3, - VARYING_SLOT_TEX4, - VARYING_SLOT_TEX5, - VARYING_SLOT_TEX6, - VARYING_SLOT_TEX7, - VARYING_SLOT_PSIZ, /* Does not appear in FS */ - VARYING_SLOT_BFC0, /* Does not appear in FS */ - VARYING_SLOT_BFC1, /* Does not appear in FS */ - VARYING_SLOT_EDGE, /* Does not appear in FS */ - VARYING_SLOT_CLIP_VERTEX, /* Does not appear in FS */ - VARYING_SLOT_CLIP_DIST0, - VARYING_SLOT_CLIP_DIST1, - VARYING_SLOT_PRIMITIVE_ID, /* Does not appear in VS */ - VARYING_SLOT_LAYER, /* Appears as VS or GS output */ - VARYING_SLOT_VIEWPORT, /* Appears as VS or GS output */ - VARYING_SLOT_FACE, /* FS only */ - VARYING_SLOT_PNTC, /* FS only */ - VARYING_SLOT_TESS_LEVEL_OUTER, /* Only appears as TCS output. */ - VARYING_SLOT_TESS_LEVEL_INNER, /* Only appears as TCS output. */ - VARYING_SLOT_VAR0, /* First generic varying slot */ - /* the remaining are simply for the benefit of gl_varying_slot_name() - * and not to be construed as an upper bound: - */ - VARYING_SLOT_VAR1, - VARYING_SLOT_VAR2, - VARYING_SLOT_VAR3, - VARYING_SLOT_VAR4, - VARYING_SLOT_VAR5, - VARYING_SLOT_VAR6, - VARYING_SLOT_VAR7, - VARYING_SLOT_VAR8, - VARYING_SLOT_VAR9, - VARYING_SLOT_VAR10, - VARYING_SLOT_VAR11, - VARYING_SLOT_VAR12, - VARYING_SLOT_VAR13, - VARYING_SLOT_VAR14, - VARYING_SLOT_VAR15, - VARYING_SLOT_VAR16, - VARYING_SLOT_VAR17, - VARYING_SLOT_VAR18, - VARYING_SLOT_VAR19, - VARYING_SLOT_VAR20, - VARYING_SLOT_VAR21, - VARYING_SLOT_VAR22, - VARYING_SLOT_VAR23, - VARYING_SLOT_VAR24, - VARYING_SLOT_VAR25, - VARYING_SLOT_VAR26, - VARYING_SLOT_VAR27, - VARYING_SLOT_VAR28, - VARYING_SLOT_VAR29, - VARYING_SLOT_VAR30, - VARYING_SLOT_VAR31, -} gl_varying_slot; - - -#define VARYING_SLOT_MAX (VARYING_SLOT_VAR0 + MAX_VARYING) -#define VARYING_SLOT_PATCH0 (VARYING_SLOT_MAX) -#define VARYING_SLOT_TESS_MAX (VARYING_SLOT_PATCH0 + MAX_VARYING) - -const char *gl_varying_slot_name(gl_varying_slot slot); - -/** - * Bitflags for varying slots. - */ -/*@{*/ -#define VARYING_BIT_POS BITFIELD64_BIT(VARYING_SLOT_POS) -#define VARYING_BIT_COL0 BITFIELD64_BIT(VARYING_SLOT_COL0) -#define VARYING_BIT_COL1 BITFIELD64_BIT(VARYING_SLOT_COL1) -#define VARYING_BIT_FOGC BITFIELD64_BIT(VARYING_SLOT_FOGC) -#define VARYING_BIT_TEX0 BITFIELD64_BIT(VARYING_SLOT_TEX0) -#define VARYING_BIT_TEX1 BITFIELD64_BIT(VARYING_SLOT_TEX1) -#define VARYING_BIT_TEX2 BITFIELD64_BIT(VARYING_SLOT_TEX2) -#define VARYING_BIT_TEX3 BITFIELD64_BIT(VARYING_SLOT_TEX3) -#define VARYING_BIT_TEX4 BITFIELD64_BIT(VARYING_SLOT_TEX4) -#define VARYING_BIT_TEX5 BITFIELD64_BIT(VARYING_SLOT_TEX5) -#define VARYING_BIT_TEX6 BITFIELD64_BIT(VARYING_SLOT_TEX6) -#define VARYING_BIT_TEX7 BITFIELD64_BIT(VARYING_SLOT_TEX7) -#define VARYING_BIT_TEX(U) BITFIELD64_BIT(VARYING_SLOT_TEX0 + (U)) -#define VARYING_BITS_TEX_ANY BITFIELD64_RANGE(VARYING_SLOT_TEX0, \ - MAX_TEXTURE_COORD_UNITS) -#define VARYING_BIT_PSIZ BITFIELD64_BIT(VARYING_SLOT_PSIZ) -#define VARYING_BIT_BFC0 BITFIELD64_BIT(VARYING_SLOT_BFC0) -#define VARYING_BIT_BFC1 BITFIELD64_BIT(VARYING_SLOT_BFC1) -#define VARYING_BIT_EDGE BITFIELD64_BIT(VARYING_SLOT_EDGE) -#define VARYING_BIT_CLIP_VERTEX BITFIELD64_BIT(VARYING_SLOT_CLIP_VERTEX) -#define VARYING_BIT_CLIP_DIST0 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0) -#define VARYING_BIT_CLIP_DIST1 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1) -#define VARYING_BIT_PRIMITIVE_ID BITFIELD64_BIT(VARYING_SLOT_PRIMITIVE_ID) -#define VARYING_BIT_LAYER BITFIELD64_BIT(VARYING_SLOT_LAYER) -#define VARYING_BIT_VIEWPORT BITFIELD64_BIT(VARYING_SLOT_VIEWPORT) -#define VARYING_BIT_FACE BITFIELD64_BIT(VARYING_SLOT_FACE) -#define VARYING_BIT_PNTC BITFIELD64_BIT(VARYING_SLOT_PNTC) -#define VARYING_BIT_TESS_LEVEL_OUTER BITFIELD64_BIT(VARYING_SLOT_TESS_LEVEL_OUTER) -#define VARYING_BIT_TESS_LEVEL_INNER BITFIELD64_BIT(VARYING_SLOT_TESS_LEVEL_INNER) -#define VARYING_BIT_VAR(V) BITFIELD64_BIT(VARYING_SLOT_VAR0 + (V)) -/*@}*/ - -/** - * Bitflags for system values. - */ -#define SYSTEM_BIT_SAMPLE_ID ((uint64_t)1 << SYSTEM_VALUE_SAMPLE_ID) -#define SYSTEM_BIT_SAMPLE_POS ((uint64_t)1 << SYSTEM_VALUE_SAMPLE_POS) -#define SYSTEM_BIT_SAMPLE_MASK_IN ((uint64_t)1 << SYSTEM_VALUE_SAMPLE_MASK_IN) -#define SYSTEM_BIT_LOCAL_INVOCATION_ID ((uint64_t)1 << SYSTEM_VALUE_LOCAL_INVOCATION_ID) - -/** - * If the gl_register_file is PROGRAM_SYSTEM_VALUE, the register index will be - * one of these values. If a NIR variable's mode is nir_var_system_value, it - * will be one of these values. - */ -typedef enum -{ - /** - * \name Vertex shader system values - */ - /*@{*/ - /** - * OpenGL-style vertex ID. - * - * Section 2.11.7 (Shader Execution), subsection Shader Inputs, of the - * OpenGL 3.3 core profile spec says: - * - * "gl_VertexID holds the integer index i implicitly passed by - * DrawArrays or one of the other drawing commands defined in section - * 2.8.3." - * - * Section 2.8.3 (Drawing Commands) of the same spec says: - * - * "The commands....are equivalent to the commands with the same base - * name (without the BaseVertex suffix), except that the ith element - * transferred by the corresponding draw call will be taken from - * element indices[i] + basevertex of each enabled array." - * - * Additionally, the overview in the GL_ARB_shader_draw_parameters spec - * says: - * - * "In unextended GL, vertex shaders have inputs named gl_VertexID and - * gl_InstanceID, which contain, respectively the index of the vertex - * and instance. The value of gl_VertexID is the implicitly passed - * index of the vertex being processed, which includes the value of - * baseVertex, for those commands that accept it." - * - * gl_VertexID gets basevertex added in. This differs from DirectX where - * SV_VertexID does \b not get basevertex added in. - * - * \note - * If all system values are available, \c SYSTEM_VALUE_VERTEX_ID will be - * equal to \c SYSTEM_VALUE_VERTEX_ID_ZERO_BASE plus - * \c SYSTEM_VALUE_BASE_VERTEX. - * - * \sa SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, SYSTEM_VALUE_BASE_VERTEX - */ - SYSTEM_VALUE_VERTEX_ID, - - /** - * Instanced ID as supplied to gl_InstanceID - * - * Values assigned to gl_InstanceID always begin with zero, regardless of - * the value of baseinstance. - * - * Section 11.1.3.9 (Shader Inputs) of the OpenGL 4.4 core profile spec - * says: - * - * "gl_InstanceID holds the integer instance number of the current - * primitive in an instanced draw call (see section 10.5)." - * - * Through a big chain of pseudocode, section 10.5 describes that - * baseinstance is not counted by gl_InstanceID. In that section, notice - * - * "If an enabled vertex attribute array is instanced (it has a - * non-zero divisor as specified by VertexAttribDivisor), the element - * index that is transferred to the GL, for all vertices, is given by - * - * floor(instance/divisor) + baseinstance - * - * If an array corresponding to an attribute required by a vertex - * shader is not enabled, then the corresponding element is taken from - * the current attribute state (see section 10.2)." - * - * Note that baseinstance is \b not included in the value of instance. - */ - SYSTEM_VALUE_INSTANCE_ID, - - /** - * Vulkan InstanceIndex. - * - * InstanceIndex = gl_InstanceID + gl_BaseInstance - */ - SYSTEM_VALUE_INSTANCE_INDEX, - - /** - * DirectX-style vertex ID. - * - * Unlike \c SYSTEM_VALUE_VERTEX_ID, this system value does \b not include - * the value of basevertex. - * - * \sa SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_BASE_VERTEX - */ - SYSTEM_VALUE_VERTEX_ID_ZERO_BASE, - - /** - * Value of \c basevertex passed to \c glDrawElementsBaseVertex and similar - * functions. - * - * \sa SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_VERTEX_ID_ZERO_BASE - */ - SYSTEM_VALUE_BASE_VERTEX, - - /** - * Value of \c baseinstance passed to instanced draw entry points - * - * \sa SYSTEM_VALUE_INSTANCE_ID - */ - SYSTEM_VALUE_BASE_INSTANCE, - - /** - * From _ARB_shader_draw_parameters: - * - * "Additionally, this extension adds a further built-in variable, - * gl_DrawID to the shading language. This variable contains the index - * of the draw currently being processed by a Multi* variant of a - * drawing command (such as MultiDrawElements or - * MultiDrawArraysIndirect)." - * - * If GL_ARB_multi_draw_indirect is not supported, this is always 0. - */ - SYSTEM_VALUE_DRAW_ID, - /*@}*/ - - /** - * \name Geometry shader system values - */ - /*@{*/ - SYSTEM_VALUE_INVOCATION_ID, /**< (Also in Tessellation Control shader) */ - /*@}*/ - - /** - * \name Fragment shader system values - */ - /*@{*/ - SYSTEM_VALUE_FRAG_COORD, - SYSTEM_VALUE_FRONT_FACE, - SYSTEM_VALUE_SAMPLE_ID, - SYSTEM_VALUE_SAMPLE_POS, - SYSTEM_VALUE_SAMPLE_MASK_IN, - SYSTEM_VALUE_HELPER_INVOCATION, - /*@}*/ - - /** - * \name Tessellation Evaluation shader system values - */ - /*@{*/ - SYSTEM_VALUE_TESS_COORD, - SYSTEM_VALUE_VERTICES_IN, /**< Tessellation vertices in input patch */ - SYSTEM_VALUE_PRIMITIVE_ID, - SYSTEM_VALUE_TESS_LEVEL_OUTER, /**< TES input */ - SYSTEM_VALUE_TESS_LEVEL_INNER, /**< TES input */ - /*@}*/ - - /** - * \name Compute shader system values - */ - /*@{*/ - SYSTEM_VALUE_LOCAL_INVOCATION_ID, - SYSTEM_VALUE_LOCAL_INVOCATION_INDEX, - SYSTEM_VALUE_GLOBAL_INVOCATION_ID, - SYSTEM_VALUE_WORK_GROUP_ID, - SYSTEM_VALUE_NUM_WORK_GROUPS, - /*@}*/ - - /** - * Driver internal vertex-count, used (for example) for drivers to - * calculate stride for stream-out outputs. Not externally visible. - */ - SYSTEM_VALUE_VERTEX_CNT, - - SYSTEM_VALUE_MAX /**< Number of values */ -} gl_system_value; - -const char *gl_system_value_name(gl_system_value sysval); - -/** - * The possible interpolation qualifiers that can be applied to a fragment - * shader input in GLSL. - * - * Note: INTERP_QUALIFIER_NONE must be 0 so that memsetting the - * gl_fragment_program data structure to 0 causes the default behavior. - */ -enum glsl_interp_qualifier -{ - INTERP_QUALIFIER_NONE = 0, - INTERP_QUALIFIER_SMOOTH, - INTERP_QUALIFIER_FLAT, - INTERP_QUALIFIER_NOPERSPECTIVE, - INTERP_QUALIFIER_COUNT /**< Number of interpolation qualifiers */ -}; - -const char *glsl_interp_qualifier_name(enum glsl_interp_qualifier qual); - -/** - * Fragment program results - */ -typedef enum -{ - FRAG_RESULT_DEPTH = 0, - FRAG_RESULT_STENCIL = 1, - /* If a single color should be written to all render targets, this - * register is written. No FRAG_RESULT_DATAn will be written. - */ - FRAG_RESULT_COLOR = 2, - FRAG_RESULT_SAMPLE_MASK = 3, - - /* FRAG_RESULT_DATAn are the per-render-target (GLSL gl_FragData[n] - * or ARB_fragment_program fragment.color[n]) color results. If - * any are written, FRAG_RESULT_COLOR will not be written. - * FRAG_RESULT_DATA1 and up are simply for the benefit of - * gl_frag_result_name() and not to be construed as an upper bound - */ - FRAG_RESULT_DATA0 = 4, - FRAG_RESULT_DATA1, - FRAG_RESULT_DATA2, - FRAG_RESULT_DATA3, - FRAG_RESULT_DATA4, - FRAG_RESULT_DATA5, - FRAG_RESULT_DATA6, - FRAG_RESULT_DATA7, -} gl_frag_result; - -const char *gl_frag_result_name(gl_frag_result result); - -#define FRAG_RESULT_MAX (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS) - -/** - * \brief Layout qualifiers for gl_FragDepth. - * - * Extension AMD_conservative_depth allows gl_FragDepth to be redeclared with - * a layout qualifier. - * - * \see enum ir_depth_layout - */ -enum gl_frag_depth_layout -{ - FRAG_DEPTH_LAYOUT_NONE, /**< No layout is specified. */ - FRAG_DEPTH_LAYOUT_ANY, - FRAG_DEPTH_LAYOUT_GREATER, - FRAG_DEPTH_LAYOUT_LESS, - FRAG_DEPTH_LAYOUT_UNCHANGED -}; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* SHADER_ENUMS_H */ diff --git a/src/glsl/nir/spirv/GLSL.std.450.h b/src/glsl/nir/spirv/GLSL.std.450.h deleted file mode 100644 index d1c9b5c1d44..00000000000 --- a/src/glsl/nir/spirv/GLSL.std.450.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -** Copyright (c) 2014-2015 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and/or associated documentation files (the "Materials"), -** to deal in the Materials without restriction, including without limitation -** the rights to use, copy, modify, merge, publish, distribute, sublicense, -** and/or sell copies of the Materials, and to permit persons to whom the -** Materials are furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Materials. -** -** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS -** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS -** IN THE MATERIALS. -*/ - -#ifndef GLSLstd450_H -#define GLSLstd450_H - -const int GLSLstd450Version = 99; -const int GLSLstd450Revision = 3; - -enum GLSLstd450 { - GLSLstd450Bad = 0, // Don't use - - GLSLstd450Round = 1, - GLSLstd450RoundEven = 2, - GLSLstd450Trunc = 3, - GLSLstd450FAbs = 4, - GLSLstd450SAbs = 5, - GLSLstd450FSign = 6, - GLSLstd450SSign = 7, - GLSLstd450Floor = 8, - GLSLstd450Ceil = 9, - GLSLstd450Fract = 10, - - GLSLstd450Radians = 11, - GLSLstd450Degrees = 12, - GLSLstd450Sin = 13, - GLSLstd450Cos = 14, - GLSLstd450Tan = 15, - GLSLstd450Asin = 16, - GLSLstd450Acos = 17, - GLSLstd450Atan = 18, - GLSLstd450Sinh = 19, - GLSLstd450Cosh = 20, - GLSLstd450Tanh = 21, - GLSLstd450Asinh = 22, - GLSLstd450Acosh = 23, - GLSLstd450Atanh = 24, - GLSLstd450Atan2 = 25, - - GLSLstd450Pow = 26, - GLSLstd450Exp = 27, - GLSLstd450Log = 28, - GLSLstd450Exp2 = 29, - GLSLstd450Log2 = 30, - GLSLstd450Sqrt = 31, - GLSLstd450InverseSqrt = 32, - - GLSLstd450Determinant = 33, - GLSLstd450MatrixInverse = 34, - - GLSLstd450Modf = 35, // second operand needs an OpVariable to write to - GLSLstd450ModfStruct = 36, // no OpVariable operand - GLSLstd450FMin = 37, - GLSLstd450UMin = 38, - GLSLstd450SMin = 39, - GLSLstd450FMax = 40, - GLSLstd450UMax = 41, - GLSLstd450SMax = 42, - GLSLstd450FClamp = 43, - GLSLstd450UClamp = 44, - GLSLstd450SClamp = 45, - GLSLstd450FMix = 46, - GLSLstd450IMix = 47, - GLSLstd450Step = 48, - GLSLstd450SmoothStep = 49, - - GLSLstd450Fma = 50, - GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to - GLSLstd450FrexpStruct = 52, // no OpVariable operand - GLSLstd450Ldexp = 53, - - GLSLstd450PackSnorm4x8 = 54, - GLSLstd450PackUnorm4x8 = 55, - GLSLstd450PackSnorm2x16 = 56, - GLSLstd450PackUnorm2x16 = 57, - GLSLstd450PackHalf2x16 = 58, - GLSLstd450PackDouble2x32 = 59, - GLSLstd450UnpackSnorm2x16 = 60, - GLSLstd450UnpackUnorm2x16 = 61, - GLSLstd450UnpackHalf2x16 = 62, - GLSLstd450UnpackSnorm4x8 = 63, - GLSLstd450UnpackUnorm4x8 = 64, - GLSLstd450UnpackDouble2x32 = 65, - - GLSLstd450Length = 66, - GLSLstd450Distance = 67, - GLSLstd450Cross = 68, - GLSLstd450Normalize = 69, - GLSLstd450FaceForward = 70, - GLSLstd450Reflect = 71, - GLSLstd450Refract = 72, - - GLSLstd450FindILsb = 73, - GLSLstd450FindSMsb = 74, - GLSLstd450FindUMsb = 75, - - GLSLstd450InterpolateAtCentroid = 76, - GLSLstd450InterpolateAtSample = 77, - GLSLstd450InterpolateAtOffset = 78, - - GLSLstd450Count -}; - -#endif // #ifndef GLSLstd450_H diff --git a/src/glsl/nir/spirv/nir_spirv.h b/src/glsl/nir/spirv/nir_spirv.h deleted file mode 100644 index 9c9c93d36c2..00000000000 --- a/src/glsl/nir/spirv/nir_spirv.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#pragma once - -#ifndef _NIR_SPIRV_H_ -#define _NIR_SPIRV_H_ - -#include "nir.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct nir_spirv_specialization { - uint32_t id; - uint32_t data; -}; - -nir_function *spirv_to_nir(const uint32_t *words, size_t word_count, - struct nir_spirv_specialization *specializations, - unsigned num_specializations, - gl_shader_stage stage, const char *entry_point_name, - const nir_shader_compiler_options *options); - -#ifdef __cplusplus -} -#endif - -#endif /* _NIR_SPIRV_H_ */ diff --git a/src/glsl/nir/spirv/spirv.h b/src/glsl/nir/spirv/spirv.h deleted file mode 100644 index 63bcb2f88dd..00000000000 --- a/src/glsl/nir/spirv/spirv.h +++ /dev/null @@ -1,870 +0,0 @@ -/* -** Copyright (c) 2014-2015 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and/or associated documentation files (the "Materials"), -** to deal in the Materials without restriction, including without limitation -** the rights to use, copy, modify, merge, publish, distribute, sublicense, -** and/or sell copies of the Materials, and to permit persons to whom the -** Materials are furnished to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in -** all copies or substantial portions of the Materials. -** -** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS -** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS -** IN THE MATERIALS. -*/ - -/* -** This header is automatically generated by the same tool that creates -** the Binary Section of the SPIR-V specification. -*/ - -/* -** Enumeration tokens for SPIR-V, in various styles: -** C, C++, C++11, JSON, Lua, Python -** -** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] -** -** Some tokens act like mask values, which can be OR'd together, -** while others are mutually exclusive. The mask-like ones have -** "Mask" in their name, and a parallel enum that has the shift -** amount (1 << x) for each corresponding enumerant. -*/ - -#ifndef spirv_H -#define spirv_H - -typedef unsigned int SpvId; - -#define SPV_VERSION 0x10000 -#define SPV_REVISION 2 - -static const unsigned int SpvMagicNumber = 0x07230203; -static const unsigned int SpvVersion = 0x00010000; -static const unsigned int SpvRevision = 2; -static const unsigned int SpvOpCodeMask = 0xffff; -static const unsigned int SpvWordCountShift = 16; - -typedef enum SpvSourceLanguage_ { - SpvSourceLanguageUnknown = 0, - SpvSourceLanguageESSL = 1, - SpvSourceLanguageGLSL = 2, - SpvSourceLanguageOpenCL_C = 3, - SpvSourceLanguageOpenCL_CPP = 4, -} SpvSourceLanguage; - -typedef enum SpvExecutionModel_ { - SpvExecutionModelVertex = 0, - SpvExecutionModelTessellationControl = 1, - SpvExecutionModelTessellationEvaluation = 2, - SpvExecutionModelGeometry = 3, - SpvExecutionModelFragment = 4, - SpvExecutionModelGLCompute = 5, - SpvExecutionModelKernel = 6, -} SpvExecutionModel; - -typedef enum SpvAddressingModel_ { - SpvAddressingModelLogical = 0, - SpvAddressingModelPhysical32 = 1, - SpvAddressingModelPhysical64 = 2, -} SpvAddressingModel; - -typedef enum SpvMemoryModel_ { - SpvMemoryModelSimple = 0, - SpvMemoryModelGLSL450 = 1, - SpvMemoryModelOpenCL = 2, -} SpvMemoryModel; - -typedef enum SpvExecutionMode_ { - SpvExecutionModeInvocations = 0, - SpvExecutionModeSpacingEqual = 1, - SpvExecutionModeSpacingFractionalEven = 2, - SpvExecutionModeSpacingFractionalOdd = 3, - SpvExecutionModeVertexOrderCw = 4, - SpvExecutionModeVertexOrderCcw = 5, - SpvExecutionModePixelCenterInteger = 6, - SpvExecutionModeOriginUpperLeft = 7, - SpvExecutionModeOriginLowerLeft = 8, - SpvExecutionModeEarlyFragmentTests = 9, - SpvExecutionModePointMode = 10, - SpvExecutionModeXfb = 11, - SpvExecutionModeDepthReplacing = 12, - SpvExecutionModeDepthGreater = 14, - SpvExecutionModeDepthLess = 15, - SpvExecutionModeDepthUnchanged = 16, - SpvExecutionModeLocalSize = 17, - SpvExecutionModeLocalSizeHint = 18, - SpvExecutionModeInputPoints = 19, - SpvExecutionModeInputLines = 20, - SpvExecutionModeInputLinesAdjacency = 21, - SpvExecutionModeTriangles = 22, - SpvExecutionModeInputTrianglesAdjacency = 23, - SpvExecutionModeQuads = 24, - SpvExecutionModeIsolines = 25, - SpvExecutionModeOutputVertices = 26, - SpvExecutionModeOutputPoints = 27, - SpvExecutionModeOutputLineStrip = 28, - SpvExecutionModeOutputTriangleStrip = 29, - SpvExecutionModeVecTypeHint = 30, - SpvExecutionModeContractionOff = 31, -} SpvExecutionMode; - -typedef enum SpvStorageClass_ { - SpvStorageClassUniformConstant = 0, - SpvStorageClassInput = 1, - SpvStorageClassUniform = 2, - SpvStorageClassOutput = 3, - SpvStorageClassWorkgroup = 4, - SpvStorageClassCrossWorkgroup = 5, - SpvStorageClassPrivate = 6, - SpvStorageClassFunction = 7, - SpvStorageClassGeneric = 8, - SpvStorageClassPushConstant = 9, - SpvStorageClassAtomicCounter = 10, - SpvStorageClassImage = 11, -} SpvStorageClass; - -typedef enum SpvDim_ { - SpvDim1D = 0, - SpvDim2D = 1, - SpvDim3D = 2, - SpvDimCube = 3, - SpvDimRect = 4, - SpvDimBuffer = 5, - SpvDimSubpassData = 6, -} SpvDim; - -typedef enum SpvSamplerAddressingMode_ { - SpvSamplerAddressingModeNone = 0, - SpvSamplerAddressingModeClampToEdge = 1, - SpvSamplerAddressingModeClamp = 2, - SpvSamplerAddressingModeRepeat = 3, - SpvSamplerAddressingModeRepeatMirrored = 4, -} SpvSamplerAddressingMode; - -typedef enum SpvSamplerFilterMode_ { - SpvSamplerFilterModeNearest = 0, - SpvSamplerFilterModeLinear = 1, -} SpvSamplerFilterMode; - -typedef enum SpvImageFormat_ { - SpvImageFormatUnknown = 0, - SpvImageFormatRgba32f = 1, - SpvImageFormatRgba16f = 2, - SpvImageFormatR32f = 3, - SpvImageFormatRgba8 = 4, - SpvImageFormatRgba8Snorm = 5, - SpvImageFormatRg32f = 6, - SpvImageFormatRg16f = 7, - SpvImageFormatR11fG11fB10f = 8, - SpvImageFormatR16f = 9, - SpvImageFormatRgba16 = 10, - SpvImageFormatRgb10A2 = 11, - SpvImageFormatRg16 = 12, - SpvImageFormatRg8 = 13, - SpvImageFormatR16 = 14, - SpvImageFormatR8 = 15, - SpvImageFormatRgba16Snorm = 16, - SpvImageFormatRg16Snorm = 17, - SpvImageFormatRg8Snorm = 18, - SpvImageFormatR16Snorm = 19, - SpvImageFormatR8Snorm = 20, - SpvImageFormatRgba32i = 21, - SpvImageFormatRgba16i = 22, - SpvImageFormatRgba8i = 23, - SpvImageFormatR32i = 24, - SpvImageFormatRg32i = 25, - SpvImageFormatRg16i = 26, - SpvImageFormatRg8i = 27, - SpvImageFormatR16i = 28, - SpvImageFormatR8i = 29, - SpvImageFormatRgba32ui = 30, - SpvImageFormatRgba16ui = 31, - SpvImageFormatRgba8ui = 32, - SpvImageFormatR32ui = 33, - SpvImageFormatRgb10a2ui = 34, - SpvImageFormatRg32ui = 35, - SpvImageFormatRg16ui = 36, - SpvImageFormatRg8ui = 37, - SpvImageFormatR16ui = 38, - SpvImageFormatR8ui = 39, -} SpvImageFormat; - -typedef enum SpvImageChannelOrder_ { - SpvImageChannelOrderR = 0, - SpvImageChannelOrderA = 1, - SpvImageChannelOrderRG = 2, - SpvImageChannelOrderRA = 3, - SpvImageChannelOrderRGB = 4, - SpvImageChannelOrderRGBA = 5, - SpvImageChannelOrderBGRA = 6, - SpvImageChannelOrderARGB = 7, - SpvImageChannelOrderIntensity = 8, - SpvImageChannelOrderLuminance = 9, - SpvImageChannelOrderRx = 10, - SpvImageChannelOrderRGx = 11, - SpvImageChannelOrderRGBx = 12, - SpvImageChannelOrderDepth = 13, - SpvImageChannelOrderDepthStencil = 14, - SpvImageChannelOrdersRGB = 15, - SpvImageChannelOrdersRGBx = 16, - SpvImageChannelOrdersRGBA = 17, - SpvImageChannelOrdersBGRA = 18, -} SpvImageChannelOrder; - -typedef enum SpvImageChannelDataType_ { - SpvImageChannelDataTypeSnormInt8 = 0, - SpvImageChannelDataTypeSnormInt16 = 1, - SpvImageChannelDataTypeUnormInt8 = 2, - SpvImageChannelDataTypeUnormInt16 = 3, - SpvImageChannelDataTypeUnormShort565 = 4, - SpvImageChannelDataTypeUnormShort555 = 5, - SpvImageChannelDataTypeUnormInt101010 = 6, - SpvImageChannelDataTypeSignedInt8 = 7, - SpvImageChannelDataTypeSignedInt16 = 8, - SpvImageChannelDataTypeSignedInt32 = 9, - SpvImageChannelDataTypeUnsignedInt8 = 10, - SpvImageChannelDataTypeUnsignedInt16 = 11, - SpvImageChannelDataTypeUnsignedInt32 = 12, - SpvImageChannelDataTypeHalfFloat = 13, - SpvImageChannelDataTypeFloat = 14, - SpvImageChannelDataTypeUnormInt24 = 15, - SpvImageChannelDataTypeUnormInt101010_2 = 16, -} SpvImageChannelDataType; - -typedef enum SpvImageOperandsShift_ { - SpvImageOperandsBiasShift = 0, - SpvImageOperandsLodShift = 1, - SpvImageOperandsGradShift = 2, - SpvImageOperandsConstOffsetShift = 3, - SpvImageOperandsOffsetShift = 4, - SpvImageOperandsConstOffsetsShift = 5, - SpvImageOperandsSampleShift = 6, - SpvImageOperandsMinLodShift = 7, -} SpvImageOperandsShift; - -typedef enum SpvImageOperandsMask_ { - SpvImageOperandsMaskNone = 0, - SpvImageOperandsBiasMask = 0x00000001, - SpvImageOperandsLodMask = 0x00000002, - SpvImageOperandsGradMask = 0x00000004, - SpvImageOperandsConstOffsetMask = 0x00000008, - SpvImageOperandsOffsetMask = 0x00000010, - SpvImageOperandsConstOffsetsMask = 0x00000020, - SpvImageOperandsSampleMask = 0x00000040, - SpvImageOperandsMinLodMask = 0x00000080, -} SpvImageOperandsMask; - -typedef enum SpvFPFastMathModeShift_ { - SpvFPFastMathModeNotNaNShift = 0, - SpvFPFastMathModeNotInfShift = 1, - SpvFPFastMathModeNSZShift = 2, - SpvFPFastMathModeAllowRecipShift = 3, - SpvFPFastMathModeFastShift = 4, -} SpvFPFastMathModeShift; - -typedef enum SpvFPFastMathModeMask_ { - SpvFPFastMathModeMaskNone = 0, - SpvFPFastMathModeNotNaNMask = 0x00000001, - SpvFPFastMathModeNotInfMask = 0x00000002, - SpvFPFastMathModeNSZMask = 0x00000004, - SpvFPFastMathModeAllowRecipMask = 0x00000008, - SpvFPFastMathModeFastMask = 0x00000010, -} SpvFPFastMathModeMask; - -typedef enum SpvFPRoundingMode_ { - SpvFPRoundingModeRTE = 0, - SpvFPRoundingModeRTZ = 1, - SpvFPRoundingModeRTP = 2, - SpvFPRoundingModeRTN = 3, -} SpvFPRoundingMode; - -typedef enum SpvLinkageType_ { - SpvLinkageTypeExport = 0, - SpvLinkageTypeImport = 1, -} SpvLinkageType; - -typedef enum SpvAccessQualifier_ { - SpvAccessQualifierReadOnly = 0, - SpvAccessQualifierWriteOnly = 1, - SpvAccessQualifierReadWrite = 2, -} SpvAccessQualifier; - -typedef enum SpvFunctionParameterAttribute_ { - SpvFunctionParameterAttributeZext = 0, - SpvFunctionParameterAttributeSext = 1, - SpvFunctionParameterAttributeByVal = 2, - SpvFunctionParameterAttributeSret = 3, - SpvFunctionParameterAttributeNoAlias = 4, - SpvFunctionParameterAttributeNoCapture = 5, - SpvFunctionParameterAttributeNoWrite = 6, - SpvFunctionParameterAttributeNoReadWrite = 7, -} SpvFunctionParameterAttribute; - -typedef enum SpvDecoration_ { - SpvDecorationRelaxedPrecision = 0, - SpvDecorationSpecId = 1, - SpvDecorationBlock = 2, - SpvDecorationBufferBlock = 3, - SpvDecorationRowMajor = 4, - SpvDecorationColMajor = 5, - SpvDecorationArrayStride = 6, - SpvDecorationMatrixStride = 7, - SpvDecorationGLSLShared = 8, - SpvDecorationGLSLPacked = 9, - SpvDecorationCPacked = 10, - SpvDecorationBuiltIn = 11, - SpvDecorationNoPerspective = 13, - SpvDecorationFlat = 14, - SpvDecorationPatch = 15, - SpvDecorationCentroid = 16, - SpvDecorationSample = 17, - SpvDecorationInvariant = 18, - SpvDecorationRestrict = 19, - SpvDecorationAliased = 20, - SpvDecorationVolatile = 21, - SpvDecorationConstant = 22, - SpvDecorationCoherent = 23, - SpvDecorationNonWritable = 24, - SpvDecorationNonReadable = 25, - SpvDecorationUniform = 26, - SpvDecorationSaturatedConversion = 28, - SpvDecorationStream = 29, - SpvDecorationLocation = 30, - SpvDecorationComponent = 31, - SpvDecorationIndex = 32, - SpvDecorationBinding = 33, - SpvDecorationDescriptorSet = 34, - SpvDecorationOffset = 35, - SpvDecorationXfbBuffer = 36, - SpvDecorationXfbStride = 37, - SpvDecorationFuncParamAttr = 38, - SpvDecorationFPRoundingMode = 39, - SpvDecorationFPFastMathMode = 40, - SpvDecorationLinkageAttributes = 41, - SpvDecorationNoContraction = 42, - SpvDecorationInputAttachmentIndex = 43, - SpvDecorationAlignment = 44, -} SpvDecoration; - -typedef enum SpvBuiltIn_ { - SpvBuiltInPosition = 0, - SpvBuiltInPointSize = 1, - SpvBuiltInClipDistance = 3, - SpvBuiltInCullDistance = 4, - SpvBuiltInVertexId = 5, - SpvBuiltInInstanceId = 6, - SpvBuiltInPrimitiveId = 7, - SpvBuiltInInvocationId = 8, - SpvBuiltInLayer = 9, - SpvBuiltInViewportIndex = 10, - SpvBuiltInTessLevelOuter = 11, - SpvBuiltInTessLevelInner = 12, - SpvBuiltInTessCoord = 13, - SpvBuiltInPatchVertices = 14, - SpvBuiltInFragCoord = 15, - SpvBuiltInPointCoord = 16, - SpvBuiltInFrontFacing = 17, - SpvBuiltInSampleId = 18, - SpvBuiltInSamplePosition = 19, - SpvBuiltInSampleMask = 20, - SpvBuiltInFragDepth = 22, - SpvBuiltInHelperInvocation = 23, - SpvBuiltInNumWorkgroups = 24, - SpvBuiltInWorkgroupSize = 25, - SpvBuiltInWorkgroupId = 26, - SpvBuiltInLocalInvocationId = 27, - SpvBuiltInGlobalInvocationId = 28, - SpvBuiltInLocalInvocationIndex = 29, - SpvBuiltInWorkDim = 30, - SpvBuiltInGlobalSize = 31, - SpvBuiltInEnqueuedWorkgroupSize = 32, - SpvBuiltInGlobalOffset = 33, - SpvBuiltInGlobalLinearId = 34, - SpvBuiltInSubgroupSize = 36, - SpvBuiltInSubgroupMaxSize = 37, - SpvBuiltInNumSubgroups = 38, - SpvBuiltInNumEnqueuedSubgroups = 39, - SpvBuiltInSubgroupId = 40, - SpvBuiltInSubgroupLocalInvocationId = 41, - SpvBuiltInVertexIndex = 42, - SpvBuiltInInstanceIndex = 43, -} SpvBuiltIn; - -typedef enum SpvSelectionControlShift_ { - SpvSelectionControlFlattenShift = 0, - SpvSelectionControlDontFlattenShift = 1, -} SpvSelectionControlShift; - -typedef enum SpvSelectionControlMask_ { - SpvSelectionControlMaskNone = 0, - SpvSelectionControlFlattenMask = 0x00000001, - SpvSelectionControlDontFlattenMask = 0x00000002, -} SpvSelectionControlMask; - -typedef enum SpvLoopControlShift_ { - SpvLoopControlUnrollShift = 0, - SpvLoopControlDontUnrollShift = 1, -} SpvLoopControlShift; - -typedef enum SpvLoopControlMask_ { - SpvLoopControlMaskNone = 0, - SpvLoopControlUnrollMask = 0x00000001, - SpvLoopControlDontUnrollMask = 0x00000002, -} SpvLoopControlMask; - -typedef enum SpvFunctionControlShift_ { - SpvFunctionControlInlineShift = 0, - SpvFunctionControlDontInlineShift = 1, - SpvFunctionControlPureShift = 2, - SpvFunctionControlConstShift = 3, -} SpvFunctionControlShift; - -typedef enum SpvFunctionControlMask_ { - SpvFunctionControlMaskNone = 0, - SpvFunctionControlInlineMask = 0x00000001, - SpvFunctionControlDontInlineMask = 0x00000002, - SpvFunctionControlPureMask = 0x00000004, - SpvFunctionControlConstMask = 0x00000008, -} SpvFunctionControlMask; - -typedef enum SpvMemorySemanticsShift_ { - SpvMemorySemanticsAcquireShift = 1, - SpvMemorySemanticsReleaseShift = 2, - SpvMemorySemanticsAcquireReleaseShift = 3, - SpvMemorySemanticsSequentiallyConsistentShift = 4, - SpvMemorySemanticsUniformMemoryShift = 6, - SpvMemorySemanticsSubgroupMemoryShift = 7, - SpvMemorySemanticsWorkgroupMemoryShift = 8, - SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, - SpvMemorySemanticsAtomicCounterMemoryShift = 10, - SpvMemorySemanticsImageMemoryShift = 11, -} SpvMemorySemanticsShift; - -typedef enum SpvMemorySemanticsMask_ { - SpvMemorySemanticsMaskNone = 0, - SpvMemorySemanticsAcquireMask = 0x00000002, - SpvMemorySemanticsReleaseMask = 0x00000004, - SpvMemorySemanticsAcquireReleaseMask = 0x00000008, - SpvMemorySemanticsSequentiallyConsistentMask = 0x00000010, - SpvMemorySemanticsUniformMemoryMask = 0x00000040, - SpvMemorySemanticsSubgroupMemoryMask = 0x00000080, - SpvMemorySemanticsWorkgroupMemoryMask = 0x00000100, - SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, - SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, - SpvMemorySemanticsImageMemoryMask = 0x00000800, -} SpvMemorySemanticsMask; - -typedef enum SpvMemoryAccessShift_ { - SpvMemoryAccessVolatileShift = 0, - SpvMemoryAccessAlignedShift = 1, - SpvMemoryAccessNontemporalShift = 2, -} SpvMemoryAccessShift; - -typedef enum SpvMemoryAccessMask_ { - SpvMemoryAccessMaskNone = 0, - SpvMemoryAccessVolatileMask = 0x00000001, - SpvMemoryAccessAlignedMask = 0x00000002, - SpvMemoryAccessNontemporalMask = 0x00000004, -} SpvMemoryAccessMask; - -typedef enum SpvScope_ { - SpvScopeCrossDevice = 0, - SpvScopeDevice = 1, - SpvScopeWorkgroup = 2, - SpvScopeSubgroup = 3, - SpvScopeInvocation = 4, -} SpvScope; - -typedef enum SpvGroupOperation_ { - SpvGroupOperationReduce = 0, - SpvGroupOperationInclusiveScan = 1, - SpvGroupOperationExclusiveScan = 2, -} SpvGroupOperation; - -typedef enum SpvKernelEnqueueFlags_ { - SpvKernelEnqueueFlagsNoWait = 0, - SpvKernelEnqueueFlagsWaitKernel = 1, - SpvKernelEnqueueFlagsWaitWorkGroup = 2, -} SpvKernelEnqueueFlags; - -typedef enum SpvKernelProfilingInfoShift_ { - SpvKernelProfilingInfoCmdExecTimeShift = 0, -} SpvKernelProfilingInfoShift; - -typedef enum SpvKernelProfilingInfoMask_ { - SpvKernelProfilingInfoMaskNone = 0, - SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001, -} SpvKernelProfilingInfoMask; - -typedef enum SpvCapability_ { - SpvCapabilityMatrix = 0, - SpvCapabilityShader = 1, - SpvCapabilityGeometry = 2, - SpvCapabilityTessellation = 3, - SpvCapabilityAddresses = 4, - SpvCapabilityLinkage = 5, - SpvCapabilityKernel = 6, - SpvCapabilityVector16 = 7, - SpvCapabilityFloat16Buffer = 8, - SpvCapabilityFloat16 = 9, - SpvCapabilityFloat64 = 10, - SpvCapabilityInt64 = 11, - SpvCapabilityInt64Atomics = 12, - SpvCapabilityImageBasic = 13, - SpvCapabilityImageReadWrite = 14, - SpvCapabilityImageMipmap = 15, - SpvCapabilityPipes = 17, - SpvCapabilityGroups = 18, - SpvCapabilityDeviceEnqueue = 19, - SpvCapabilityLiteralSampler = 20, - SpvCapabilityAtomicStorage = 21, - SpvCapabilityInt16 = 22, - SpvCapabilityTessellationPointSize = 23, - SpvCapabilityGeometryPointSize = 24, - SpvCapabilityImageGatherExtended = 25, - SpvCapabilityStorageImageMultisample = 27, - SpvCapabilityUniformBufferArrayDynamicIndexing = 28, - SpvCapabilitySampledImageArrayDynamicIndexing = 29, - SpvCapabilityStorageBufferArrayDynamicIndexing = 30, - SpvCapabilityStorageImageArrayDynamicIndexing = 31, - SpvCapabilityClipDistance = 32, - SpvCapabilityCullDistance = 33, - SpvCapabilityImageCubeArray = 34, - SpvCapabilitySampleRateShading = 35, - SpvCapabilityImageRect = 36, - SpvCapabilitySampledRect = 37, - SpvCapabilityGenericPointer = 38, - SpvCapabilityInt8 = 39, - SpvCapabilityInputAttachment = 40, - SpvCapabilitySparseResidency = 41, - SpvCapabilityMinLod = 42, - SpvCapabilitySampled1D = 43, - SpvCapabilityImage1D = 44, - SpvCapabilitySampledCubeArray = 45, - SpvCapabilitySampledBuffer = 46, - SpvCapabilityImageBuffer = 47, - SpvCapabilityImageMSArray = 48, - SpvCapabilityStorageImageExtendedFormats = 49, - SpvCapabilityImageQuery = 50, - SpvCapabilityDerivativeControl = 51, - SpvCapabilityInterpolationFunction = 52, - SpvCapabilityTransformFeedback = 53, - SpvCapabilityGeometryStreams = 54, - SpvCapabilityStorageImageReadWithoutFormat = 55, - SpvCapabilityStorageImageWriteWithoutFormat = 56, - SpvCapabilityMultiViewport = 57, -} SpvCapability; - -typedef enum SpvOp_ { - SpvOpNop = 0, - SpvOpUndef = 1, - SpvOpSourceContinued = 2, - SpvOpSource = 3, - SpvOpSourceExtension = 4, - SpvOpName = 5, - SpvOpMemberName = 6, - SpvOpString = 7, - SpvOpLine = 8, - SpvOpExtension = 10, - SpvOpExtInstImport = 11, - SpvOpExtInst = 12, - SpvOpMemoryModel = 14, - SpvOpEntryPoint = 15, - SpvOpExecutionMode = 16, - SpvOpCapability = 17, - SpvOpTypeVoid = 19, - SpvOpTypeBool = 20, - SpvOpTypeInt = 21, - SpvOpTypeFloat = 22, - SpvOpTypeVector = 23, - SpvOpTypeMatrix = 24, - SpvOpTypeImage = 25, - SpvOpTypeSampler = 26, - SpvOpTypeSampledImage = 27, - SpvOpTypeArray = 28, - SpvOpTypeRuntimeArray = 29, - SpvOpTypeStruct = 30, - SpvOpTypeOpaque = 31, - SpvOpTypePointer = 32, - SpvOpTypeFunction = 33, - SpvOpTypeEvent = 34, - SpvOpTypeDeviceEvent = 35, - SpvOpTypeReserveId = 36, - SpvOpTypeQueue = 37, - SpvOpTypePipe = 38, - SpvOpTypeForwardPointer = 39, - SpvOpConstantTrue = 41, - SpvOpConstantFalse = 42, - SpvOpConstant = 43, - SpvOpConstantComposite = 44, - SpvOpConstantSampler = 45, - SpvOpConstantNull = 46, - SpvOpSpecConstantTrue = 48, - SpvOpSpecConstantFalse = 49, - SpvOpSpecConstant = 50, - SpvOpSpecConstantComposite = 51, - SpvOpSpecConstantOp = 52, - SpvOpFunction = 54, - SpvOpFunctionParameter = 55, - SpvOpFunctionEnd = 56, - SpvOpFunctionCall = 57, - SpvOpVariable = 59, - SpvOpImageTexelPointer = 60, - SpvOpLoad = 61, - SpvOpStore = 62, - SpvOpCopyMemory = 63, - SpvOpCopyMemorySized = 64, - SpvOpAccessChain = 65, - SpvOpInBoundsAccessChain = 66, - SpvOpPtrAccessChain = 67, - SpvOpArrayLength = 68, - SpvOpGenericPtrMemSemantics = 69, - SpvOpInBoundsPtrAccessChain = 70, - SpvOpDecorate = 71, - SpvOpMemberDecorate = 72, - SpvOpDecorationGroup = 73, - SpvOpGroupDecorate = 74, - SpvOpGroupMemberDecorate = 75, - SpvOpVectorExtractDynamic = 77, - SpvOpVectorInsertDynamic = 78, - SpvOpVectorShuffle = 79, - SpvOpCompositeConstruct = 80, - SpvOpCompositeExtract = 81, - SpvOpCompositeInsert = 82, - SpvOpCopyObject = 83, - SpvOpTranspose = 84, - SpvOpSampledImage = 86, - SpvOpImageSampleImplicitLod = 87, - SpvOpImageSampleExplicitLod = 88, - SpvOpImageSampleDrefImplicitLod = 89, - SpvOpImageSampleDrefExplicitLod = 90, - SpvOpImageSampleProjImplicitLod = 91, - SpvOpImageSampleProjExplicitLod = 92, - SpvOpImageSampleProjDrefImplicitLod = 93, - SpvOpImageSampleProjDrefExplicitLod = 94, - SpvOpImageFetch = 95, - SpvOpImageGather = 96, - SpvOpImageDrefGather = 97, - SpvOpImageRead = 98, - SpvOpImageWrite = 99, - SpvOpImage = 100, - SpvOpImageQueryFormat = 101, - SpvOpImageQueryOrder = 102, - SpvOpImageQuerySizeLod = 103, - SpvOpImageQuerySize = 104, - SpvOpImageQueryLod = 105, - SpvOpImageQueryLevels = 106, - SpvOpImageQuerySamples = 107, - SpvOpConvertFToU = 109, - SpvOpConvertFToS = 110, - SpvOpConvertSToF = 111, - SpvOpConvertUToF = 112, - SpvOpUConvert = 113, - SpvOpSConvert = 114, - SpvOpFConvert = 115, - SpvOpQuantizeToF16 = 116, - SpvOpConvertPtrToU = 117, - SpvOpSatConvertSToU = 118, - SpvOpSatConvertUToS = 119, - SpvOpConvertUToPtr = 120, - SpvOpPtrCastToGeneric = 121, - SpvOpGenericCastToPtr = 122, - SpvOpGenericCastToPtrExplicit = 123, - SpvOpBitcast = 124, - SpvOpSNegate = 126, - SpvOpFNegate = 127, - SpvOpIAdd = 128, - SpvOpFAdd = 129, - SpvOpISub = 130, - SpvOpFSub = 131, - SpvOpIMul = 132, - SpvOpFMul = 133, - SpvOpUDiv = 134, - SpvOpSDiv = 135, - SpvOpFDiv = 136, - SpvOpUMod = 137, - SpvOpSRem = 138, - SpvOpSMod = 139, - SpvOpFRem = 140, - SpvOpFMod = 141, - SpvOpVectorTimesScalar = 142, - SpvOpMatrixTimesScalar = 143, - SpvOpVectorTimesMatrix = 144, - SpvOpMatrixTimesVector = 145, - SpvOpMatrixTimesMatrix = 146, - SpvOpOuterProduct = 147, - SpvOpDot = 148, - SpvOpIAddCarry = 149, - SpvOpISubBorrow = 150, - SpvOpUMulExtended = 151, - SpvOpSMulExtended = 152, - SpvOpAny = 154, - SpvOpAll = 155, - SpvOpIsNan = 156, - SpvOpIsInf = 157, - SpvOpIsFinite = 158, - SpvOpIsNormal = 159, - SpvOpSignBitSet = 160, - SpvOpLessOrGreater = 161, - SpvOpOrdered = 162, - SpvOpUnordered = 163, - SpvOpLogicalEqual = 164, - SpvOpLogicalNotEqual = 165, - SpvOpLogicalOr = 166, - SpvOpLogicalAnd = 167, - SpvOpLogicalNot = 168, - SpvOpSelect = 169, - SpvOpIEqual = 170, - SpvOpINotEqual = 171, - SpvOpUGreaterThan = 172, - SpvOpSGreaterThan = 173, - SpvOpUGreaterThanEqual = 174, - SpvOpSGreaterThanEqual = 175, - SpvOpULessThan = 176, - SpvOpSLessThan = 177, - SpvOpULessThanEqual = 178, - SpvOpSLessThanEqual = 179, - SpvOpFOrdEqual = 180, - SpvOpFUnordEqual = 181, - SpvOpFOrdNotEqual = 182, - SpvOpFUnordNotEqual = 183, - SpvOpFOrdLessThan = 184, - SpvOpFUnordLessThan = 185, - SpvOpFOrdGreaterThan = 186, - SpvOpFUnordGreaterThan = 187, - SpvOpFOrdLessThanEqual = 188, - SpvOpFUnordLessThanEqual = 189, - SpvOpFOrdGreaterThanEqual = 190, - SpvOpFUnordGreaterThanEqual = 191, - SpvOpShiftRightLogical = 194, - SpvOpShiftRightArithmetic = 195, - SpvOpShiftLeftLogical = 196, - SpvOpBitwiseOr = 197, - SpvOpBitwiseXor = 198, - SpvOpBitwiseAnd = 199, - SpvOpNot = 200, - SpvOpBitFieldInsert = 201, - SpvOpBitFieldSExtract = 202, - SpvOpBitFieldUExtract = 203, - SpvOpBitReverse = 204, - SpvOpBitCount = 205, - SpvOpDPdx = 207, - SpvOpDPdy = 208, - SpvOpFwidth = 209, - SpvOpDPdxFine = 210, - SpvOpDPdyFine = 211, - SpvOpFwidthFine = 212, - SpvOpDPdxCoarse = 213, - SpvOpDPdyCoarse = 214, - SpvOpFwidthCoarse = 215, - SpvOpEmitVertex = 218, - SpvOpEndPrimitive = 219, - SpvOpEmitStreamVertex = 220, - SpvOpEndStreamPrimitive = 221, - SpvOpControlBarrier = 224, - SpvOpMemoryBarrier = 225, - SpvOpAtomicLoad = 227, - SpvOpAtomicStore = 228, - SpvOpAtomicExchange = 229, - SpvOpAtomicCompareExchange = 230, - SpvOpAtomicCompareExchangeWeak = 231, - SpvOpAtomicIIncrement = 232, - SpvOpAtomicIDecrement = 233, - SpvOpAtomicIAdd = 234, - SpvOpAtomicISub = 235, - SpvOpAtomicSMin = 236, - SpvOpAtomicUMin = 237, - SpvOpAtomicSMax = 238, - SpvOpAtomicUMax = 239, - SpvOpAtomicAnd = 240, - SpvOpAtomicOr = 241, - SpvOpAtomicXor = 242, - SpvOpPhi = 245, - SpvOpLoopMerge = 246, - SpvOpSelectionMerge = 247, - SpvOpLabel = 248, - SpvOpBranch = 249, - SpvOpBranchConditional = 250, - SpvOpSwitch = 251, - SpvOpKill = 252, - SpvOpReturn = 253, - SpvOpReturnValue = 254, - SpvOpUnreachable = 255, - SpvOpLifetimeStart = 256, - SpvOpLifetimeStop = 257, - SpvOpGroupAsyncCopy = 259, - SpvOpGroupWaitEvents = 260, - SpvOpGroupAll = 261, - SpvOpGroupAny = 262, - SpvOpGroupBroadcast = 263, - SpvOpGroupIAdd = 264, - SpvOpGroupFAdd = 265, - SpvOpGroupFMin = 266, - SpvOpGroupUMin = 267, - SpvOpGroupSMin = 268, - SpvOpGroupFMax = 269, - SpvOpGroupUMax = 270, - SpvOpGroupSMax = 271, - SpvOpReadPipe = 274, - SpvOpWritePipe = 275, - SpvOpReservedReadPipe = 276, - SpvOpReservedWritePipe = 277, - SpvOpReserveReadPipePackets = 278, - SpvOpReserveWritePipePackets = 279, - SpvOpCommitReadPipe = 280, - SpvOpCommitWritePipe = 281, - SpvOpIsValidReserveId = 282, - SpvOpGetNumPipePackets = 283, - SpvOpGetMaxPipePackets = 284, - SpvOpGroupReserveReadPipePackets = 285, - SpvOpGroupReserveWritePipePackets = 286, - SpvOpGroupCommitReadPipe = 287, - SpvOpGroupCommitWritePipe = 288, - SpvOpEnqueueMarker = 291, - SpvOpEnqueueKernel = 292, - SpvOpGetKernelNDrangeSubGroupCount = 293, - SpvOpGetKernelNDrangeMaxSubGroupSize = 294, - SpvOpGetKernelWorkGroupSize = 295, - SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296, - SpvOpRetainEvent = 297, - SpvOpReleaseEvent = 298, - SpvOpCreateUserEvent = 299, - SpvOpIsValidEvent = 300, - SpvOpSetUserEventStatus = 301, - SpvOpCaptureEventProfilingInfo = 302, - SpvOpGetDefaultQueue = 303, - SpvOpBuildNDRange = 304, - SpvOpImageSparseSampleImplicitLod = 305, - SpvOpImageSparseSampleExplicitLod = 306, - SpvOpImageSparseSampleDrefImplicitLod = 307, - SpvOpImageSparseSampleDrefExplicitLod = 308, - SpvOpImageSparseSampleProjImplicitLod = 309, - SpvOpImageSparseSampleProjExplicitLod = 310, - SpvOpImageSparseSampleProjDrefImplicitLod = 311, - SpvOpImageSparseSampleProjDrefExplicitLod = 312, - SpvOpImageSparseFetch = 313, - SpvOpImageSparseGather = 314, - SpvOpImageSparseDrefGather = 315, - SpvOpImageSparseTexelsResident = 316, - SpvOpNoLine = 317, - SpvOpAtomicFlagTestAndSet = 318, - SpvOpAtomicFlagClear = 319, -} SpvOp; - -#endif // #ifndef spirv_H - diff --git a/src/glsl/nir/spirv/spirv_to_nir.c b/src/glsl/nir/spirv/spirv_to_nir.c deleted file mode 100644 index c002457ce12..00000000000 --- a/src/glsl/nir/spirv/spirv_to_nir.c +++ /dev/null @@ -1,2654 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "vtn_private.h" -#include "nir/nir_vla.h" -#include "nir/nir_control_flow.h" -#include "nir/nir_constant_expressions.h" - -static struct vtn_ssa_value * -vtn_undef_ssa_value(struct vtn_builder *b, const struct glsl_type *type) -{ - struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value); - val->type = type; - - if (glsl_type_is_vector_or_scalar(type)) { - unsigned num_components = glsl_get_vector_elements(val->type); - nir_ssa_undef_instr *undef = - nir_ssa_undef_instr_create(b->shader, num_components); - - nir_instr_insert_before_cf_list(&b->impl->body, &undef->instr); - val->def = &undef->def; - } else { - unsigned elems = glsl_get_length(val->type); - val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); - if (glsl_type_is_matrix(type)) { - const struct glsl_type *elem_type = - glsl_vector_type(glsl_get_base_type(type), - glsl_get_vector_elements(type)); - - for (unsigned i = 0; i < elems; i++) - val->elems[i] = vtn_undef_ssa_value(b, elem_type); - } else if (glsl_type_is_array(type)) { - const struct glsl_type *elem_type = glsl_get_array_element(type); - for (unsigned i = 0; i < elems; i++) - val->elems[i] = vtn_undef_ssa_value(b, elem_type); - } else { - for (unsigned i = 0; i < elems; i++) { - const struct glsl_type *elem_type = glsl_get_struct_field(type, i); - val->elems[i] = vtn_undef_ssa_value(b, elem_type); - } - } - } - - return val; -} - -static struct vtn_ssa_value * -vtn_const_ssa_value(struct vtn_builder *b, nir_constant *constant, - const struct glsl_type *type) -{ - struct hash_entry *entry = _mesa_hash_table_search(b->const_table, constant); - - if (entry) - return entry->data; - - struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value); - val->type = type; - - switch (glsl_get_base_type(type)) { - case GLSL_TYPE_INT: - case GLSL_TYPE_UINT: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - if (glsl_type_is_vector_or_scalar(type)) { - unsigned num_components = glsl_get_vector_elements(val->type); - nir_load_const_instr *load = - nir_load_const_instr_create(b->shader, num_components); - - for (unsigned i = 0; i < num_components; i++) - load->value.u[i] = constant->value.u[i]; - - nir_instr_insert_before_cf_list(&b->impl->body, &load->instr); - val->def = &load->def; - } else { - assert(glsl_type_is_matrix(type)); - unsigned rows = glsl_get_vector_elements(val->type); - unsigned columns = glsl_get_matrix_columns(val->type); - val->elems = ralloc_array(b, struct vtn_ssa_value *, columns); - - for (unsigned i = 0; i < columns; i++) { - struct vtn_ssa_value *col_val = rzalloc(b, struct vtn_ssa_value); - col_val->type = glsl_get_column_type(val->type); - nir_load_const_instr *load = - nir_load_const_instr_create(b->shader, rows); - - for (unsigned j = 0; j < rows; j++) - load->value.u[j] = constant->value.u[rows * i + j]; - - nir_instr_insert_before_cf_list(&b->impl->body, &load->instr); - col_val->def = &load->def; - - val->elems[i] = col_val; - } - } - break; - - case GLSL_TYPE_ARRAY: { - unsigned elems = glsl_get_length(val->type); - val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); - const struct glsl_type *elem_type = glsl_get_array_element(val->type); - for (unsigned i = 0; i < elems; i++) - val->elems[i] = vtn_const_ssa_value(b, constant->elements[i], - elem_type); - break; - } - - case GLSL_TYPE_STRUCT: { - unsigned elems = glsl_get_length(val->type); - val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); - for (unsigned i = 0; i < elems; i++) { - const struct glsl_type *elem_type = - glsl_get_struct_field(val->type, i); - val->elems[i] = vtn_const_ssa_value(b, constant->elements[i], - elem_type); - } - break; - } - - default: - unreachable("bad constant type"); - } - - return val; -} - -struct vtn_ssa_value * -vtn_ssa_value(struct vtn_builder *b, uint32_t value_id) -{ - struct vtn_value *val = vtn_untyped_value(b, value_id); - switch (val->value_type) { - case vtn_value_type_undef: - return vtn_undef_ssa_value(b, val->type->type); - - case vtn_value_type_constant: - return vtn_const_ssa_value(b, val->constant, val->const_type); - - case vtn_value_type_ssa: - return val->ssa; - - case vtn_value_type_access_chain: - /* This is needed for function parameters */ - return vtn_variable_load(b, val->access_chain); - - default: - unreachable("Invalid type for an SSA value"); - } -} - -static char * -vtn_string_literal(struct vtn_builder *b, const uint32_t *words, - unsigned word_count, unsigned *words_used) -{ - char *dup = ralloc_strndup(b, (char *)words, word_count * sizeof(*words)); - if (words_used) { - /* Ammount of space taken by the string (including the null) */ - unsigned len = strlen(dup) + 1; - *words_used = DIV_ROUND_UP(len, sizeof(*words)); - } - return dup; -} - -const uint32_t * -vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start, - const uint32_t *end, vtn_instruction_handler handler) -{ - b->file = NULL; - b->line = -1; - b->col = -1; - - const uint32_t *w = start; - while (w < end) { - SpvOp opcode = w[0] & SpvOpCodeMask; - unsigned count = w[0] >> SpvWordCountShift; - assert(count >= 1 && w + count <= end); - - switch (opcode) { - case SpvOpNop: - break; /* Do nothing */ - - case SpvOpLine: - b->file = vtn_value(b, w[1], vtn_value_type_string)->str; - b->line = w[2]; - b->col = w[3]; - break; - - case SpvOpNoLine: - b->file = NULL; - b->line = -1; - b->col = -1; - break; - - default: - if (!handler(b, opcode, w, count)) - return w; - break; - } - - w += count; - } - assert(w == end); - return w; -} - -static void -vtn_handle_extension(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - switch (opcode) { - case SpvOpExtInstImport: { - struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_extension); - if (strcmp((const char *)&w[2], "GLSL.std.450") == 0) { - val->ext_handler = vtn_handle_glsl450_instruction; - } else { - assert(!"Unsupported extension"); - } - break; - } - - case SpvOpExtInst: { - struct vtn_value *val = vtn_value(b, w[3], vtn_value_type_extension); - bool handled = val->ext_handler(b, w[4], w, count); - (void)handled; - assert(handled); - break; - } - - default: - unreachable("Unhandled opcode"); - } -} - -static void -_foreach_decoration_helper(struct vtn_builder *b, - struct vtn_value *base_value, - int parent_member, - struct vtn_value *value, - vtn_decoration_foreach_cb cb, void *data) -{ - for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) { - int member; - if (dec->scope == VTN_DEC_DECORATION) { - member = parent_member; - } else if (dec->scope >= VTN_DEC_STRUCT_MEMBER0) { - assert(parent_member == -1); - member = dec->scope - VTN_DEC_STRUCT_MEMBER0; - } else { - /* Not a decoration */ - continue; - } - - if (dec->group) { - assert(dec->group->value_type == vtn_value_type_decoration_group); - _foreach_decoration_helper(b, base_value, member, dec->group, - cb, data); - } else { - cb(b, base_value, member, dec, data); - } - } -} - -/** Iterates (recursively if needed) over all of the decorations on a value - * - * This function iterates over all of the decorations applied to a given - * value. If it encounters a decoration group, it recurses into the group - * and iterates over all of those decorations as well. - */ -void -vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, - vtn_decoration_foreach_cb cb, void *data) -{ - _foreach_decoration_helper(b, value, -1, value, cb, data); -} - -void -vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value, - vtn_execution_mode_foreach_cb cb, void *data) -{ - for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) { - if (dec->scope != VTN_DEC_EXECUTION_MODE) - continue; - - assert(dec->group == NULL); - cb(b, value, dec, data); - } -} - -static void -vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - const uint32_t *w_end = w + count; - const uint32_t target = w[1]; - w += 2; - - switch (opcode) { - case SpvOpDecorationGroup: - vtn_push_value(b, target, vtn_value_type_decoration_group); - break; - - case SpvOpDecorate: - case SpvOpMemberDecorate: - case SpvOpExecutionMode: { - struct vtn_value *val = &b->values[target]; - - struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration); - switch (opcode) { - case SpvOpDecorate: - dec->scope = VTN_DEC_DECORATION; - break; - case SpvOpMemberDecorate: - dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++); - break; - case SpvOpExecutionMode: - dec->scope = VTN_DEC_EXECUTION_MODE; - break; - default: - unreachable("Invalid decoration opcode"); - } - dec->decoration = *(w++); - dec->literals = w; - - /* Link into the list */ - dec->next = val->decoration; - val->decoration = dec; - break; - } - - case SpvOpGroupMemberDecorate: - case SpvOpGroupDecorate: { - struct vtn_value *group = - vtn_value(b, target, vtn_value_type_decoration_group); - - for (; w < w_end; w++) { - struct vtn_value *val = vtn_untyped_value(b, *w); - struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration); - - dec->group = group; - if (opcode == SpvOpGroupDecorate) { - dec->scope = VTN_DEC_DECORATION; - } else { - dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++); - } - - /* Link into the list */ - dec->next = val->decoration; - val->decoration = dec; - } - break; - } - - default: - unreachable("Unhandled opcode"); - } -} - -struct member_decoration_ctx { - struct glsl_struct_field *fields; - struct vtn_type *type; -}; - -/* does a shallow copy of a vtn_type */ - -static struct vtn_type * -vtn_type_copy(struct vtn_builder *b, struct vtn_type *src) -{ - struct vtn_type *dest = ralloc(b, struct vtn_type); - dest->type = src->type; - dest->is_builtin = src->is_builtin; - if (src->is_builtin) - dest->builtin = src->builtin; - - if (!glsl_type_is_scalar(src->type)) { - switch (glsl_get_base_type(src->type)) { - case GLSL_TYPE_INT: - case GLSL_TYPE_UINT: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - case GLSL_TYPE_ARRAY: - dest->row_major = src->row_major; - dest->stride = src->stride; - dest->array_element = src->array_element; - break; - - case GLSL_TYPE_STRUCT: { - unsigned elems = glsl_get_length(src->type); - - dest->members = ralloc_array(b, struct vtn_type *, elems); - memcpy(dest->members, src->members, elems * sizeof(struct vtn_type *)); - - dest->offsets = ralloc_array(b, unsigned, elems); - memcpy(dest->offsets, src->offsets, elems * sizeof(unsigned)); - break; - } - - default: - unreachable("unhandled type"); - } - } - - return dest; -} - -static struct vtn_type * -mutable_matrix_member(struct vtn_builder *b, struct vtn_type *type, int member) -{ - type->members[member] = vtn_type_copy(b, type->members[member]); - type = type->members[member]; - - /* We may have an array of matrices.... Oh, joy! */ - while (glsl_type_is_array(type->type)) { - type->array_element = vtn_type_copy(b, type->array_element); - type = type->array_element; - } - - assert(glsl_type_is_matrix(type->type)); - - return type; -} - -static void -struct_member_decoration_cb(struct vtn_builder *b, - struct vtn_value *val, int member, - const struct vtn_decoration *dec, void *void_ctx) -{ - struct member_decoration_ctx *ctx = void_ctx; - - if (member < 0) - return; - - switch (dec->decoration) { - case SpvDecorationRelaxedPrecision: - break; /* FIXME: Do nothing with this for now. */ - case SpvDecorationNoPerspective: - ctx->fields[member].interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; - break; - case SpvDecorationFlat: - ctx->fields[member].interpolation = INTERP_QUALIFIER_FLAT; - break; - case SpvDecorationCentroid: - ctx->fields[member].centroid = true; - break; - case SpvDecorationSample: - ctx->fields[member].sample = true; - break; - case SpvDecorationLocation: - ctx->fields[member].location = dec->literals[0]; - break; - case SpvDecorationBuiltIn: - ctx->type->members[member] = vtn_type_copy(b, ctx->type->members[member]); - ctx->type->members[member]->is_builtin = true; - ctx->type->members[member]->builtin = dec->literals[0]; - ctx->type->builtin_block = true; - break; - case SpvDecorationOffset: - ctx->type->offsets[member] = dec->literals[0]; - break; - case SpvDecorationMatrixStride: - mutable_matrix_member(b, ctx->type, member)->stride = dec->literals[0]; - break; - case SpvDecorationColMajor: - break; /* Nothing to do here. Column-major is the default. */ - case SpvDecorationRowMajor: - mutable_matrix_member(b, ctx->type, member)->row_major = true; - break; - default: - unreachable("Unhandled member decoration"); - } -} - -static void -type_decoration_cb(struct vtn_builder *b, - struct vtn_value *val, int member, - const struct vtn_decoration *dec, void *ctx) -{ - struct vtn_type *type = val->type; - - if (member != -1) - return; - - switch (dec->decoration) { - case SpvDecorationArrayStride: - type->stride = dec->literals[0]; - break; - case SpvDecorationBlock: - type->block = true; - break; - case SpvDecorationBufferBlock: - type->buffer_block = true; - break; - case SpvDecorationGLSLShared: - case SpvDecorationGLSLPacked: - /* Ignore these, since we get explicit offsets anyways */ - break; - - case SpvDecorationStream: - assert(dec->literals[0] == 0); - break; - - default: - unreachable("Unhandled type decoration"); - } -} - -static unsigned -translate_image_format(SpvImageFormat format) -{ - switch (format) { - case SpvImageFormatUnknown: return 0; /* GL_NONE */ - case SpvImageFormatRgba32f: return 0x8814; /* GL_RGBA32F */ - case SpvImageFormatRgba16f: return 0x881A; /* GL_RGBA16F */ - case SpvImageFormatR32f: return 0x822E; /* GL_R32F */ - case SpvImageFormatRgba8: return 0x8058; /* GL_RGBA8 */ - case SpvImageFormatRgba8Snorm: return 0x8F97; /* GL_RGBA8_SNORM */ - case SpvImageFormatRg32f: return 0x8230; /* GL_RG32F */ - case SpvImageFormatRg16f: return 0x822F; /* GL_RG16F */ - case SpvImageFormatR11fG11fB10f: return 0x8C3A; /* GL_R11F_G11F_B10F */ - case SpvImageFormatR16f: return 0x822D; /* GL_R16F */ - case SpvImageFormatRgba16: return 0x805B; /* GL_RGBA16 */ - case SpvImageFormatRgb10A2: return 0x8059; /* GL_RGB10_A2 */ - case SpvImageFormatRg16: return 0x822C; /* GL_RG16 */ - case SpvImageFormatRg8: return 0x822B; /* GL_RG8 */ - case SpvImageFormatR16: return 0x822A; /* GL_R16 */ - case SpvImageFormatR8: return 0x8229; /* GL_R8 */ - case SpvImageFormatRgba16Snorm: return 0x8F9B; /* GL_RGBA16_SNORM */ - case SpvImageFormatRg16Snorm: return 0x8F99; /* GL_RG16_SNORM */ - case SpvImageFormatRg8Snorm: return 0x8F95; /* GL_RG8_SNORM */ - case SpvImageFormatR16Snorm: return 0x8F98; /* GL_R16_SNORM */ - case SpvImageFormatR8Snorm: return 0x8F94; /* GL_R8_SNORM */ - case SpvImageFormatRgba32i: return 0x8D82; /* GL_RGBA32I */ - case SpvImageFormatRgba16i: return 0x8D88; /* GL_RGBA16I */ - case SpvImageFormatRgba8i: return 0x8D8E; /* GL_RGBA8I */ - case SpvImageFormatR32i: return 0x8235; /* GL_R32I */ - case SpvImageFormatRg32i: return 0x823B; /* GL_RG32I */ - case SpvImageFormatRg16i: return 0x8239; /* GL_RG16I */ - case SpvImageFormatRg8i: return 0x8237; /* GL_RG8I */ - case SpvImageFormatR16i: return 0x8233; /* GL_R16I */ - case SpvImageFormatR8i: return 0x8231; /* GL_R8I */ - case SpvImageFormatRgba32ui: return 0x8D70; /* GL_RGBA32UI */ - case SpvImageFormatRgba16ui: return 0x8D76; /* GL_RGBA16UI */ - case SpvImageFormatRgba8ui: return 0x8D7C; /* GL_RGBA8UI */ - case SpvImageFormatR32ui: return 0x8236; /* GL_R32UI */ - case SpvImageFormatRgb10a2ui: return 0x906F; /* GL_RGB10_A2UI */ - case SpvImageFormatRg32ui: return 0x823C; /* GL_RG32UI */ - case SpvImageFormatRg16ui: return 0x823A; /* GL_RG16UI */ - case SpvImageFormatRg8ui: return 0x8238; /* GL_RG8UI */ - case SpvImageFormatR16ui: return 0x823A; /* GL_RG16UI */ - case SpvImageFormatR8ui: return 0x8232; /* GL_R8UI */ - default: - assert(!"Invalid image format"); - return 0; - } -} - -static void -vtn_handle_type(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_type); - - val->type = rzalloc(b, struct vtn_type); - val->type->is_builtin = false; - val->type->val = val; - - switch (opcode) { - case SpvOpTypeVoid: - val->type->type = glsl_void_type(); - break; - case SpvOpTypeBool: - val->type->type = glsl_bool_type(); - break; - case SpvOpTypeInt: - val->type->type = glsl_int_type(); - break; - case SpvOpTypeFloat: - val->type->type = glsl_float_type(); - break; - - case SpvOpTypeVector: { - struct vtn_type *base = vtn_value(b, w[2], vtn_value_type_type)->type; - unsigned elems = w[3]; - - assert(glsl_type_is_scalar(base->type)); - val->type->type = glsl_vector_type(glsl_get_base_type(base->type), elems); - - /* Vectors implicitly have sizeof(base_type) stride. For now, this - * is always 4 bytes. This will have to change if we want to start - * supporting doubles or half-floats. - */ - val->type->stride = 4; - val->type->array_element = base; - break; - } - - case SpvOpTypeMatrix: { - struct vtn_type *base = vtn_value(b, w[2], vtn_value_type_type)->type; - unsigned columns = w[3]; - - assert(glsl_type_is_vector(base->type)); - val->type->type = glsl_matrix_type(glsl_get_base_type(base->type), - glsl_get_vector_elements(base->type), - columns); - assert(!glsl_type_is_error(val->type->type)); - val->type->array_element = base; - val->type->row_major = false; - val->type->stride = 0; - break; - } - - case SpvOpTypeRuntimeArray: - case SpvOpTypeArray: { - struct vtn_type *array_element = - vtn_value(b, w[2], vtn_value_type_type)->type; - - unsigned length; - if (opcode == SpvOpTypeRuntimeArray) { - /* A length of 0 is used to denote unsized arrays */ - length = 0; - } else { - length = - vtn_value(b, w[3], vtn_value_type_constant)->constant->value.u[0]; - } - - val->type->type = glsl_array_type(array_element->type, length); - val->type->array_element = array_element; - val->type->stride = 0; - break; - } - - case SpvOpTypeStruct: { - unsigned num_fields = count - 2; - val->type->members = ralloc_array(b, struct vtn_type *, num_fields); - val->type->offsets = ralloc_array(b, unsigned, num_fields); - - NIR_VLA(struct glsl_struct_field, fields, count); - for (unsigned i = 0; i < num_fields; i++) { - val->type->members[i] = - vtn_value(b, w[i + 2], vtn_value_type_type)->type; - fields[i] = (struct glsl_struct_field) { - .type = val->type->members[i]->type, - .name = ralloc_asprintf(b, "field%d", i), - .location = -1, - }; - } - - struct member_decoration_ctx ctx = { - .fields = fields, - .type = val->type - }; - - vtn_foreach_decoration(b, val, struct_member_decoration_cb, &ctx); - - const char *name = val->name ? val->name : "struct"; - - val->type->type = glsl_struct_type(fields, num_fields, name); - break; - } - - case SpvOpTypeFunction: { - const struct glsl_type *return_type = - vtn_value(b, w[2], vtn_value_type_type)->type->type; - NIR_VLA(struct glsl_function_param, params, count - 3); - for (unsigned i = 0; i < count - 3; i++) { - params[i].type = vtn_value(b, w[i + 3], vtn_value_type_type)->type->type; - - /* FIXME: */ - params[i].in = true; - params[i].out = true; - } - val->type->type = glsl_function_type(return_type, params, count - 3); - break; - } - - case SpvOpTypePointer: - /* FIXME: For now, we'll just do the really lame thing and return - * the same type. The validator should ensure that the proper number - * of dereferences happen - */ - val->type = vtn_value(b, w[3], vtn_value_type_type)->type; - break; - - case SpvOpTypeImage: { - const struct glsl_type *sampled_type = - vtn_value(b, w[2], vtn_value_type_type)->type->type; - - assert(glsl_type_is_vector_or_scalar(sampled_type)); - - enum glsl_sampler_dim dim; - switch ((SpvDim)w[3]) { - case SpvDim1D: dim = GLSL_SAMPLER_DIM_1D; break; - case SpvDim2D: dim = GLSL_SAMPLER_DIM_2D; break; - case SpvDim3D: dim = GLSL_SAMPLER_DIM_3D; break; - case SpvDimCube: dim = GLSL_SAMPLER_DIM_CUBE; break; - case SpvDimRect: dim = GLSL_SAMPLER_DIM_RECT; break; - case SpvDimBuffer: dim = GLSL_SAMPLER_DIM_BUF; break; - default: - unreachable("Invalid SPIR-V Sampler dimension"); - } - - bool is_shadow = w[4]; - bool is_array = w[5]; - bool multisampled = w[6]; - unsigned sampled = w[7]; - SpvImageFormat format = w[8]; - - if (count > 9) - val->type->access_qualifier = w[9]; - else - val->type->access_qualifier = SpvAccessQualifierReadWrite; - - assert(!multisampled && "FIXME: Handl multi-sampled textures"); - - val->type->image_format = translate_image_format(format); - - if (sampled == 1) { - val->type->type = glsl_sampler_type(dim, is_shadow, is_array, - glsl_get_base_type(sampled_type)); - } else if (sampled == 2) { - assert(format); - assert(!is_shadow); - val->type->type = glsl_image_type(dim, is_array, - glsl_get_base_type(sampled_type)); - } else { - assert(!"We need to know if the image will be sampled"); - } - break; - } - - case SpvOpTypeSampledImage: - val->type = vtn_value(b, w[2], vtn_value_type_type)->type; - break; - - case SpvOpTypeSampler: - /* The actual sampler type here doesn't really matter. It gets - * thrown away the moment you combine it with an image. What really - * matters is that it's a sampler type as opposed to an integer type - * so the backend knows what to do. - * - * TODO: Eventually we should consider adding a "bare sampler" type - * to glsl_types. - */ - val->type->type = glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, - GLSL_TYPE_FLOAT); - break; - - case SpvOpTypeOpaque: - case SpvOpTypeEvent: - case SpvOpTypeDeviceEvent: - case SpvOpTypeReserveId: - case SpvOpTypeQueue: - case SpvOpTypePipe: - default: - unreachable("Unhandled opcode"); - } - - vtn_foreach_decoration(b, val, type_decoration_cb, NULL); -} - -static nir_constant * -vtn_null_constant(struct vtn_builder *b, const struct glsl_type *type) -{ - nir_constant *c = rzalloc(b, nir_constant); - - switch (glsl_get_base_type(type)) { - case GLSL_TYPE_INT: - case GLSL_TYPE_UINT: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - /* Nothing to do here. It's already initialized to zero */ - break; - - case GLSL_TYPE_ARRAY: - assert(glsl_get_length(type) > 0); - c->num_elements = glsl_get_length(type); - c->elements = ralloc_array(b, nir_constant *, c->num_elements); - - c->elements[0] = vtn_null_constant(b, glsl_get_array_element(type)); - for (unsigned i = 1; i < c->num_elements; i++) - c->elements[i] = c->elements[0]; - break; - - case GLSL_TYPE_STRUCT: - c->num_elements = glsl_get_length(type); - c->elements = ralloc_array(b, nir_constant *, c->num_elements); - - for (unsigned i = 0; i < c->num_elements; i++) { - c->elements[i] = vtn_null_constant(b, glsl_get_struct_field(type, i)); - } - break; - - default: - unreachable("Invalid type for null constant"); - } - - return c; -} - -static void -spec_constant_deocoration_cb(struct vtn_builder *b, struct vtn_value *v, - int member, const struct vtn_decoration *dec, - void *data) -{ - assert(member == -1); - if (dec->decoration != SpvDecorationSpecId) - return; - - uint32_t *const_value = data; - - for (unsigned i = 0; i < b->num_specializations; i++) { - if (b->specializations[i].id == dec->literals[0]) { - *const_value = b->specializations[i].data; - return; - } - } -} - -static uint32_t -get_specialization(struct vtn_builder *b, struct vtn_value *val, - uint32_t const_value) -{ - vtn_foreach_decoration(b, val, spec_constant_deocoration_cb, &const_value); - return const_value; -} - -static void -vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant); - val->const_type = vtn_value(b, w[1], vtn_value_type_type)->type->type; - val->constant = rzalloc(b, nir_constant); - switch (opcode) { - case SpvOpConstantTrue: - assert(val->const_type == glsl_bool_type()); - val->constant->value.u[0] = NIR_TRUE; - break; - case SpvOpConstantFalse: - assert(val->const_type == glsl_bool_type()); - val->constant->value.u[0] = NIR_FALSE; - break; - - case SpvOpSpecConstantTrue: - case SpvOpSpecConstantFalse: { - assert(val->const_type == glsl_bool_type()); - uint32_t int_val = - get_specialization(b, val, (opcode == SpvOpSpecConstantTrue)); - val->constant->value.u[0] = int_val ? NIR_TRUE : NIR_FALSE; - break; - } - - case SpvOpConstant: - assert(glsl_type_is_scalar(val->const_type)); - val->constant->value.u[0] = w[3]; - break; - case SpvOpSpecConstant: - assert(glsl_type_is_scalar(val->const_type)); - val->constant->value.u[0] = get_specialization(b, val, w[3]); - break; - case SpvOpSpecConstantComposite: - case SpvOpConstantComposite: { - unsigned elem_count = count - 3; - nir_constant **elems = ralloc_array(b, nir_constant *, elem_count); - for (unsigned i = 0; i < elem_count; i++) - elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant; - - switch (glsl_get_base_type(val->const_type)) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - if (glsl_type_is_matrix(val->const_type)) { - unsigned rows = glsl_get_vector_elements(val->const_type); - assert(glsl_get_matrix_columns(val->const_type) == elem_count); - for (unsigned i = 0; i < elem_count; i++) - for (unsigned j = 0; j < rows; j++) - val->constant->value.u[rows * i + j] = elems[i]->value.u[j]; - } else { - assert(glsl_type_is_vector(val->const_type)); - assert(glsl_get_vector_elements(val->const_type) == elem_count); - for (unsigned i = 0; i < elem_count; i++) - val->constant->value.u[i] = elems[i]->value.u[0]; - } - ralloc_free(elems); - break; - - case GLSL_TYPE_STRUCT: - case GLSL_TYPE_ARRAY: - ralloc_steal(val->constant, elems); - val->constant->num_elements = elem_count; - val->constant->elements = elems; - break; - - default: - unreachable("Unsupported type for constants"); - } - break; - } - - case SpvOpSpecConstantOp: { - SpvOp opcode = get_specialization(b, val, w[3]); - switch (opcode) { - case SpvOpVectorShuffle: { - struct vtn_value *v0 = vtn_value(b, w[4], vtn_value_type_constant); - struct vtn_value *v1 = vtn_value(b, w[5], vtn_value_type_constant); - unsigned len0 = glsl_get_vector_elements(v0->const_type); - unsigned len1 = glsl_get_vector_elements(v1->const_type); - - uint32_t u[8]; - for (unsigned i = 0; i < len0; i++) - u[i] = v0->constant->value.u[i]; - for (unsigned i = 0; i < len1; i++) - u[len0 + i] = v1->constant->value.u[i]; - - for (unsigned i = 0; i < count - 6; i++) { - uint32_t comp = w[i + 6]; - if (comp == (uint32_t)-1) { - val->constant->value.u[i] = 0xdeadbeef; - } else { - val->constant->value.u[i] = u[comp]; - } - } - return; - } - - case SpvOpCompositeExtract: - case SpvOpCompositeInsert: { - struct vtn_value *comp; - unsigned deref_start; - struct nir_constant **c; - if (opcode == SpvOpCompositeExtract) { - comp = vtn_value(b, w[4], vtn_value_type_constant); - deref_start = 5; - c = &comp->constant; - } else { - comp = vtn_value(b, w[5], vtn_value_type_constant); - deref_start = 6; - val->constant = nir_constant_clone(comp->constant, - (nir_variable *)b); - c = &val->constant; - } - - int elem = -1; - const struct glsl_type *type = comp->const_type; - for (unsigned i = deref_start; i < count; i++) { - switch (glsl_get_base_type(type)) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - /* If we hit this granularity, we're picking off an element */ - if (elem < 0) - elem = 0; - - if (glsl_type_is_matrix(type)) { - elem += w[i] * glsl_get_vector_elements(type); - type = glsl_get_column_type(type); - } else { - assert(glsl_type_is_vector(type)); - elem += w[i]; - type = glsl_scalar_type(glsl_get_base_type(type)); - } - continue; - - case GLSL_TYPE_ARRAY: - c = &(*c)->elements[w[i]]; - type = glsl_get_array_element(type); - continue; - - case GLSL_TYPE_STRUCT: - c = &(*c)->elements[w[i]]; - type = glsl_get_struct_field(type, w[i]); - continue; - - default: - unreachable("Invalid constant type"); - } - } - - if (opcode == SpvOpCompositeExtract) { - if (elem == -1) { - val->constant = *c; - } else { - unsigned num_components = glsl_get_vector_elements(type); - for (unsigned i = 0; i < num_components; i++) - val->constant->value.u[i] = (*c)->value.u[elem + i]; - } - } else { - struct vtn_value *insert = - vtn_value(b, w[4], vtn_value_type_constant); - assert(insert->const_type == type); - if (elem == -1) { - *c = insert->constant; - } else { - unsigned num_components = glsl_get_vector_elements(type); - for (unsigned i = 0; i < num_components; i++) - (*c)->value.u[elem + i] = insert->constant->value.u[i]; - } - } - return; - } - - default: { - bool swap; - nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap); - - unsigned num_components = glsl_get_vector_elements(val->const_type); - - nir_const_value src[3]; - assert(count <= 7); - for (unsigned i = 0; i < count - 4; i++) { - nir_constant *c = - vtn_value(b, w[4 + i], vtn_value_type_constant)->constant; - - unsigned j = swap ? 1 - i : i; - for (unsigned k = 0; k < num_components; k++) - src[j].u[k] = c->value.u[k]; - } - - nir_const_value res = nir_eval_const_opcode(op, num_components, src); - - for (unsigned k = 0; k < num_components; k++) - val->constant->value.u[k] = res.u[k]; - - return; - } /* default */ - } - } - - case SpvOpConstantNull: - val->constant = vtn_null_constant(b, val->const_type); - break; - - case SpvOpConstantSampler: - assert(!"OpConstantSampler requires Kernel Capability"); - break; - - default: - unreachable("Unhandled opcode"); - } -} - -static void -vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - struct nir_function *callee = - vtn_value(b, w[3], vtn_value_type_function)->func->impl->function; - - nir_call_instr *call = nir_call_instr_create(b->nb.shader, callee); - for (unsigned i = 0; i < call->num_params; i++) { - unsigned arg_id = w[4 + i]; - struct vtn_value *arg = vtn_untyped_value(b, arg_id); - if (arg->value_type == vtn_value_type_access_chain) { - nir_deref_var *d = vtn_access_chain_to_deref(b, arg->access_chain); - call->params[i] = nir_deref_as_var(nir_copy_deref(call, &d->deref)); - } else { - struct vtn_ssa_value *arg_ssa = vtn_ssa_value(b, arg_id); - - /* Make a temporary to store the argument in */ - nir_variable *tmp = - nir_local_variable_create(b->impl, arg_ssa->type, "arg_tmp"); - call->params[i] = nir_deref_var_create(call, tmp); - - vtn_local_store(b, arg_ssa, call->params[i]); - } - } - - nir_variable *out_tmp = NULL; - if (!glsl_type_is_void(callee->return_type)) { - out_tmp = nir_local_variable_create(b->impl, callee->return_type, - "out_tmp"); - call->return_deref = nir_deref_var_create(call, out_tmp); - } - - nir_builder_instr_insert(&b->nb, &call->instr); - - if (glsl_type_is_void(callee->return_type)) { - vtn_push_value(b, w[2], vtn_value_type_undef); - } else { - struct vtn_value *retval = vtn_push_value(b, w[2], vtn_value_type_ssa); - retval->ssa = vtn_local_load(b, call->return_deref); - } -} - -struct vtn_ssa_value * -vtn_create_ssa_value(struct vtn_builder *b, const struct glsl_type *type) -{ - struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value); - val->type = type; - - if (!glsl_type_is_vector_or_scalar(type)) { - unsigned elems = glsl_get_length(type); - val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); - for (unsigned i = 0; i < elems; i++) { - const struct glsl_type *child_type; - - switch (glsl_get_base_type(type)) { - case GLSL_TYPE_INT: - case GLSL_TYPE_UINT: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - child_type = glsl_get_column_type(type); - break; - case GLSL_TYPE_ARRAY: - child_type = glsl_get_array_element(type); - break; - case GLSL_TYPE_STRUCT: - child_type = glsl_get_struct_field(type, i); - break; - default: - unreachable("unkown base type"); - } - - val->elems[i] = vtn_create_ssa_value(b, child_type); - } - } - - return val; -} - -static nir_tex_src -vtn_tex_src(struct vtn_builder *b, unsigned index, nir_tex_src_type type) -{ - nir_tex_src src; - src.src = nir_src_for_ssa(vtn_ssa_value(b, index)->def); - src.src_type = type; - return src; -} - -static void -vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - if (opcode == SpvOpSampledImage) { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_sampled_image); - val->sampled_image = ralloc(b, struct vtn_sampled_image); - val->sampled_image->image = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - val->sampled_image->sampler = - vtn_value(b, w[4], vtn_value_type_access_chain)->access_chain; - return; - } else if (opcode == SpvOpImage) { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_access_chain); - struct vtn_value *src_val = vtn_untyped_value(b, w[3]); - if (src_val->value_type == vtn_value_type_sampled_image) { - val->access_chain = src_val->sampled_image->image; - } else { - assert(src_val->value_type == vtn_value_type_access_chain); - val->access_chain = src_val->access_chain; - } - return; - } - - struct vtn_type *ret_type = vtn_value(b, w[1], vtn_value_type_type)->type; - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - - struct vtn_sampled_image sampled; - struct vtn_value *sampled_val = vtn_untyped_value(b, w[3]); - if (sampled_val->value_type == vtn_value_type_sampled_image) { - sampled = *sampled_val->sampled_image; - } else { - assert(sampled_val->value_type == vtn_value_type_access_chain); - sampled.image = NULL; - sampled.sampler = sampled_val->access_chain; - } - - nir_tex_src srcs[8]; /* 8 should be enough */ - nir_tex_src *p = srcs; - - unsigned idx = 4; - - bool has_coord = false; - switch (opcode) { - case SpvOpImageSampleImplicitLod: - case SpvOpImageSampleExplicitLod: - case SpvOpImageSampleDrefImplicitLod: - case SpvOpImageSampleDrefExplicitLod: - case SpvOpImageSampleProjImplicitLod: - case SpvOpImageSampleProjExplicitLod: - case SpvOpImageSampleProjDrefImplicitLod: - case SpvOpImageSampleProjDrefExplicitLod: - case SpvOpImageFetch: - case SpvOpImageGather: - case SpvOpImageDrefGather: - case SpvOpImageQueryLod: { - /* All these types have the coordinate as their first real argument */ - struct vtn_ssa_value *coord = vtn_ssa_value(b, w[idx++]); - has_coord = true; - p->src = nir_src_for_ssa(coord->def); - p->src_type = nir_tex_src_coord; - p++; - break; - } - - default: - break; - } - - /* These all have an explicit depth value as their next source */ - switch (opcode) { - case SpvOpImageSampleDrefImplicitLod: - case SpvOpImageSampleDrefExplicitLod: - case SpvOpImageSampleProjDrefImplicitLod: - case SpvOpImageSampleProjDrefExplicitLod: - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_comparitor); - break; - default: - break; - } - - /* For OpImageQuerySizeLod, we always have an LOD */ - if (opcode == SpvOpImageQuerySizeLod) - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_lod); - - /* Figure out the base texture operation */ - nir_texop texop; - switch (opcode) { - case SpvOpImageSampleImplicitLod: - case SpvOpImageSampleDrefImplicitLod: - case SpvOpImageSampleProjImplicitLod: - case SpvOpImageSampleProjDrefImplicitLod: - texop = nir_texop_tex; - break; - - case SpvOpImageSampleExplicitLod: - case SpvOpImageSampleDrefExplicitLod: - case SpvOpImageSampleProjExplicitLod: - case SpvOpImageSampleProjDrefExplicitLod: - texop = nir_texop_txl; - break; - - case SpvOpImageFetch: - texop = nir_texop_txf; - break; - - case SpvOpImageGather: - case SpvOpImageDrefGather: - texop = nir_texop_tg4; - break; - - case SpvOpImageQuerySizeLod: - case SpvOpImageQuerySize: - texop = nir_texop_txs; - break; - - case SpvOpImageQueryLod: - texop = nir_texop_lod; - break; - - case SpvOpImageQueryLevels: - texop = nir_texop_query_levels; - break; - - case SpvOpImageQuerySamples: - default: - unreachable("Unhandled opcode"); - } - - /* Now we need to handle some number of optional arguments */ - if (idx < count) { - uint32_t operands = w[idx++]; - - if (operands & SpvImageOperandsBiasMask) { - assert(texop == nir_texop_tex); - texop = nir_texop_txb; - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_bias); - } - - if (operands & SpvImageOperandsLodMask) { - assert(texop == nir_texop_txl || texop == nir_texop_txf || - texop == nir_texop_txs); - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_lod); - } - - if (operands & SpvImageOperandsGradMask) { - assert(texop == nir_texop_tex); - texop = nir_texop_txd; - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_ddx); - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_ddy); - } - - if (operands & SpvImageOperandsOffsetMask || - operands & SpvImageOperandsConstOffsetMask) - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_offset); - - if (operands & SpvImageOperandsConstOffsetsMask) - assert(!"Constant offsets to texture gather not yet implemented"); - - if (operands & SpvImageOperandsSampleMask) { - assert(texop == nir_texop_txf); - texop = nir_texop_txf_ms; - (*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_ms_index); - } - } - /* We should have now consumed exactly all of the arguments */ - assert(idx == count); - - nir_tex_instr *instr = nir_tex_instr_create(b->shader, p - srcs); - instr->op = texop; - - memcpy(instr->src, srcs, instr->num_srcs * sizeof(*instr->src)); - - const struct glsl_type *image_type; - if (sampled.image) { - image_type = sampled.image->var->var->interface_type; - } else { - image_type = sampled.sampler->var->var->interface_type; - } - - instr->sampler_dim = glsl_get_sampler_dim(image_type); - instr->is_array = glsl_sampler_type_is_array(image_type); - instr->is_shadow = glsl_sampler_type_is_shadow(image_type); - instr->is_new_style_shadow = instr->is_shadow; - - if (has_coord) { - switch (instr->sampler_dim) { - case GLSL_SAMPLER_DIM_1D: - case GLSL_SAMPLER_DIM_BUF: - instr->coord_components = 1; - break; - case GLSL_SAMPLER_DIM_2D: - case GLSL_SAMPLER_DIM_RECT: - instr->coord_components = 2; - break; - case GLSL_SAMPLER_DIM_3D: - case GLSL_SAMPLER_DIM_CUBE: - case GLSL_SAMPLER_DIM_MS: - instr->coord_components = 3; - break; - default: - assert("Invalid sampler type"); - } - - if (instr->is_array) - instr->coord_components++; - } else { - instr->coord_components = 0; - } - - switch (glsl_get_sampler_result_type(image_type)) { - case GLSL_TYPE_FLOAT: instr->dest_type = nir_type_float; break; - case GLSL_TYPE_INT: instr->dest_type = nir_type_int; break; - case GLSL_TYPE_UINT: instr->dest_type = nir_type_uint; break; - case GLSL_TYPE_BOOL: instr->dest_type = nir_type_bool; break; - default: - unreachable("Invalid base type for sampler result"); - } - - nir_deref_var *sampler = vtn_access_chain_to_deref(b, sampled.sampler); - instr->sampler = nir_deref_as_var(nir_copy_deref(instr, &sampler->deref)); - if (sampled.image) { - nir_deref_var *image = vtn_access_chain_to_deref(b, sampled.image); - instr->texture = nir_deref_as_var(nir_copy_deref(instr, &image->deref)); - } else { - instr->texture = NULL; - } - - nir_ssa_dest_init(&instr->instr, &instr->dest, - nir_tex_instr_dest_size(instr), NULL); - - assert(glsl_get_vector_elements(ret_type->type) == - nir_tex_instr_dest_size(instr)); - - val->ssa = vtn_create_ssa_value(b, ret_type->type); - val->ssa->def = &instr->dest.ssa; - - nir_builder_instr_insert(&b->nb, &instr->instr); -} - -static nir_ssa_def * -get_image_coord(struct vtn_builder *b, uint32_t value) -{ - struct vtn_ssa_value *coord = vtn_ssa_value(b, value); - - /* The image_load_store intrinsics assume a 4-dim coordinate */ - unsigned dim = glsl_get_vector_elements(coord->type); - unsigned swizzle[4]; - for (unsigned i = 0; i < 4; i++) - swizzle[i] = MIN2(i, dim - 1); - - return nir_swizzle(&b->nb, coord->def, swizzle, 4, false); -} - -static void -vtn_handle_image(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - /* Just get this one out of the way */ - if (opcode == SpvOpImageTexelPointer) { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_image_pointer); - val->image = ralloc(b, struct vtn_image_pointer); - - val->image->image = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - val->image->coord = get_image_coord(b, w[4]); - val->image->sample = vtn_ssa_value(b, w[5])->def; - return; - } - - struct vtn_image_pointer image; - - switch (opcode) { - case SpvOpAtomicExchange: - case SpvOpAtomicCompareExchange: - case SpvOpAtomicCompareExchangeWeak: - case SpvOpAtomicIIncrement: - case SpvOpAtomicIDecrement: - case SpvOpAtomicIAdd: - case SpvOpAtomicISub: - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: - image = *vtn_value(b, w[3], vtn_value_type_image_pointer)->image; - break; - - case SpvOpImageQuerySize: - image.image = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - image.coord = NULL; - image.sample = NULL; - break; - - case SpvOpImageRead: - image.image = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - image.coord = get_image_coord(b, w[4]); - - if (count > 5 && (w[5] & SpvImageOperandsSampleMask)) { - assert(w[5] == SpvImageOperandsSampleMask); - image.sample = vtn_ssa_value(b, w[6])->def; - } else { - image.sample = nir_ssa_undef(&b->nb, 1); - } - break; - - case SpvOpImageWrite: - image.image = - vtn_value(b, w[1], vtn_value_type_access_chain)->access_chain; - image.coord = get_image_coord(b, w[2]); - - /* texel = w[3] */ - - if (count > 4 && (w[4] & SpvImageOperandsSampleMask)) { - assert(w[4] == SpvImageOperandsSampleMask); - image.sample = vtn_ssa_value(b, w[5])->def; - } else { - image.sample = nir_ssa_undef(&b->nb, 1); - } - break; - - default: - unreachable("Invalid image opcode"); - } - - nir_intrinsic_op op; - switch (opcode) { -#define OP(S, N) case SpvOp##S: op = nir_intrinsic_image_##N; break; - OP(ImageQuerySize, size) - OP(ImageRead, load) - OP(ImageWrite, store) - OP(AtomicExchange, atomic_exchange) - OP(AtomicCompareExchange, atomic_comp_swap) - OP(AtomicIIncrement, atomic_add) - OP(AtomicIDecrement, atomic_add) - OP(AtomicIAdd, atomic_add) - OP(AtomicISub, atomic_add) - OP(AtomicSMin, atomic_min) - OP(AtomicUMin, atomic_min) - OP(AtomicSMax, atomic_max) - OP(AtomicUMax, atomic_max) - OP(AtomicAnd, atomic_and) - OP(AtomicOr, atomic_or) - OP(AtomicXor, atomic_xor) -#undef OP - default: - unreachable("Invalid image opcode"); - } - - nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b->shader, op); - - nir_deref_var *image_deref = vtn_access_chain_to_deref(b, image.image); - intrin->variables[0] = - nir_deref_as_var(nir_copy_deref(&intrin->instr, &image_deref->deref)); - - /* ImageQuerySize doesn't take any extra parameters */ - if (opcode != SpvOpImageQuerySize) { - /* The image coordinate is always 4 components but we may not have that - * many. Swizzle to compensate. - */ - unsigned swiz[4]; - for (unsigned i = 0; i < 4; i++) - swiz[i] = i < image.coord->num_components ? i : 0; - intrin->src[0] = nir_src_for_ssa(nir_swizzle(&b->nb, image.coord, - swiz, 4, false)); - intrin->src[1] = nir_src_for_ssa(image.sample); - } - - switch (opcode) { - case SpvOpImageQuerySize: - case SpvOpImageRead: - break; - case SpvOpImageWrite: - intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[3])->def); - break; - case SpvOpAtomicIIncrement: - intrin->src[2] = nir_src_for_ssa(nir_imm_int(&b->nb, 1)); - break; - case SpvOpAtomicIDecrement: - intrin->src[2] = nir_src_for_ssa(nir_imm_int(&b->nb, -1)); - break; - - case SpvOpAtomicExchange: - case SpvOpAtomicIAdd: - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: - intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[6])->def); - break; - - case SpvOpAtomicCompareExchange: - intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[7])->def); - intrin->src[3] = nir_src_for_ssa(vtn_ssa_value(b, w[6])->def); - break; - - case SpvOpAtomicISub: - intrin->src[2] = nir_src_for_ssa(nir_ineg(&b->nb, vtn_ssa_value(b, w[6])->def)); - break; - - default: - unreachable("Invalid image opcode"); - } - - if (opcode != SpvOpImageWrite) { - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; - nir_ssa_dest_init(&intrin->instr, &intrin->dest, 4, NULL); - - nir_builder_instr_insert(&b->nb, &intrin->instr); - - /* The image intrinsics always return 4 channels but we may not want - * that many. Emit a mov to trim it down. - */ - unsigned swiz[4] = {0, 1, 2, 3}; - val->ssa = vtn_create_ssa_value(b, type->type); - val->ssa->def = nir_swizzle(&b->nb, &intrin->dest.ssa, swiz, - glsl_get_vector_elements(type->type), false); - } else { - nir_builder_instr_insert(&b->nb, &intrin->instr); - } -} - -static nir_intrinsic_op -get_ssbo_nir_atomic_op(SpvOp opcode) -{ - switch (opcode) { -#define OP(S, N) case SpvOp##S: return nir_intrinsic_ssbo_##N; - OP(AtomicExchange, atomic_exchange) - OP(AtomicCompareExchange, atomic_comp_swap) - OP(AtomicIIncrement, atomic_add) - OP(AtomicIDecrement, atomic_add) - OP(AtomicIAdd, atomic_add) - OP(AtomicISub, atomic_add) - OP(AtomicSMin, atomic_imin) - OP(AtomicUMin, atomic_umin) - OP(AtomicSMax, atomic_imax) - OP(AtomicUMax, atomic_umax) - OP(AtomicAnd, atomic_and) - OP(AtomicOr, atomic_or) - OP(AtomicXor, atomic_xor) -#undef OP - default: - unreachable("Invalid SSBO atomic"); - } -} - -static nir_intrinsic_op -get_shared_nir_atomic_op(SpvOp opcode) -{ - switch (opcode) { -#define OP(S, N) case SpvOp##S: return nir_intrinsic_var_##N; - OP(AtomicExchange, atomic_exchange) - OP(AtomicCompareExchange, atomic_comp_swap) - OP(AtomicIIncrement, atomic_add) - OP(AtomicIDecrement, atomic_add) - OP(AtomicIAdd, atomic_add) - OP(AtomicISub, atomic_add) - OP(AtomicSMin, atomic_imin) - OP(AtomicUMin, atomic_umin) - OP(AtomicSMax, atomic_imax) - OP(AtomicUMax, atomic_umax) - OP(AtomicAnd, atomic_and) - OP(AtomicOr, atomic_or) - OP(AtomicXor, atomic_xor) -#undef OP - default: - unreachable("Invalid shared atomic"); - } -} - -static void -fill_common_atomic_sources(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, nir_src *src) -{ - switch (opcode) { - case SpvOpAtomicIIncrement: - src[0] = nir_src_for_ssa(nir_imm_int(&b->nb, 1)); - break; - - case SpvOpAtomicIDecrement: - src[0] = nir_src_for_ssa(nir_imm_int(&b->nb, -1)); - break; - - case SpvOpAtomicISub: - src[0] = - nir_src_for_ssa(nir_ineg(&b->nb, vtn_ssa_value(b, w[6])->def)); - break; - - case SpvOpAtomicCompareExchange: - src[0] = nir_src_for_ssa(vtn_ssa_value(b, w[7])->def); - src[1] = nir_src_for_ssa(vtn_ssa_value(b, w[8])->def); - break; - /* Fall through */ - - case SpvOpAtomicExchange: - case SpvOpAtomicIAdd: - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: - src[0] = nir_src_for_ssa(vtn_ssa_value(b, w[6])->def); - break; - - default: - unreachable("Invalid SPIR-V atomic"); - } -} - -static void -vtn_handle_ssbo_or_shared_atomic(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - struct vtn_access_chain *chain = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - nir_intrinsic_instr *atomic; - - /* - SpvScope scope = w[4]; - SpvMemorySemanticsMask semantics = w[5]; - */ - - if (chain->var->mode == vtn_variable_mode_workgroup) { - nir_deref *deref = &vtn_access_chain_to_deref(b, chain)->deref; - nir_intrinsic_op op = get_shared_nir_atomic_op(opcode); - atomic = nir_intrinsic_instr_create(b->nb.shader, op); - atomic->variables[0] = nir_deref_as_var(nir_copy_deref(atomic, deref)); - fill_common_atomic_sources(b, opcode, w, &atomic->src[0]); - } else { - assert(chain->var->mode == vtn_variable_mode_ssbo); - struct vtn_type *type; - nir_ssa_def *offset, *index; - offset = vtn_access_chain_to_offset(b, chain, &index, &type, NULL, false); - - nir_intrinsic_op op = get_ssbo_nir_atomic_op(opcode); - - atomic = nir_intrinsic_instr_create(b->nb.shader, op); - atomic->src[0] = nir_src_for_ssa(index); - atomic->src[1] = nir_src_for_ssa(offset); - fill_common_atomic_sources(b, opcode, w, &atomic->src[2]); - } - - nir_ssa_dest_init(&atomic->instr, &atomic->dest, 1, NULL); - - struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->ssa = rzalloc(b, struct vtn_ssa_value); - val->ssa->def = &atomic->dest.ssa; - val->ssa->type = type->type; - - nir_builder_instr_insert(&b->nb, &atomic->instr); -} - -static nir_alu_instr * -create_vec(nir_shader *shader, unsigned num_components) -{ - nir_op op; - switch (num_components) { - case 1: op = nir_op_fmov; break; - case 2: op = nir_op_vec2; break; - case 3: op = nir_op_vec3; break; - case 4: op = nir_op_vec4; break; - default: unreachable("bad vector size"); - } - - nir_alu_instr *vec = nir_alu_instr_create(shader, op); - nir_ssa_dest_init(&vec->instr, &vec->dest.dest, num_components, NULL); - vec->dest.write_mask = (1 << num_components) - 1; - - return vec; -} - -struct vtn_ssa_value * -vtn_ssa_transpose(struct vtn_builder *b, struct vtn_ssa_value *src) -{ - if (src->transposed) - return src->transposed; - - struct vtn_ssa_value *dest = - vtn_create_ssa_value(b, glsl_transposed_type(src->type)); - - for (unsigned i = 0; i < glsl_get_matrix_columns(dest->type); i++) { - nir_alu_instr *vec = create_vec(b->shader, - glsl_get_matrix_columns(src->type)); - if (glsl_type_is_vector_or_scalar(src->type)) { - vec->src[0].src = nir_src_for_ssa(src->def); - vec->src[0].swizzle[0] = i; - } else { - for (unsigned j = 0; j < glsl_get_matrix_columns(src->type); j++) { - vec->src[j].src = nir_src_for_ssa(src->elems[j]->def); - vec->src[j].swizzle[0] = i; - } - } - nir_builder_instr_insert(&b->nb, &vec->instr); - dest->elems[i]->def = &vec->dest.dest.ssa; - } - - dest->transposed = src; - - return dest; -} - -nir_ssa_def * -vtn_vector_extract(struct vtn_builder *b, nir_ssa_def *src, unsigned index) -{ - unsigned swiz[4] = { index }; - return nir_swizzle(&b->nb, src, swiz, 1, true); -} - -nir_ssa_def * -vtn_vector_insert(struct vtn_builder *b, nir_ssa_def *src, nir_ssa_def *insert, - unsigned index) -{ - nir_alu_instr *vec = create_vec(b->shader, src->num_components); - - for (unsigned i = 0; i < src->num_components; i++) { - if (i == index) { - vec->src[i].src = nir_src_for_ssa(insert); - } else { - vec->src[i].src = nir_src_for_ssa(src); - vec->src[i].swizzle[0] = i; - } - } - - nir_builder_instr_insert(&b->nb, &vec->instr); - - return &vec->dest.dest.ssa; -} - -nir_ssa_def * -vtn_vector_extract_dynamic(struct vtn_builder *b, nir_ssa_def *src, - nir_ssa_def *index) -{ - nir_ssa_def *dest = vtn_vector_extract(b, src, 0); - for (unsigned i = 1; i < src->num_components; i++) - dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)), - vtn_vector_extract(b, src, i), dest); - - return dest; -} - -nir_ssa_def * -vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src, - nir_ssa_def *insert, nir_ssa_def *index) -{ - nir_ssa_def *dest = vtn_vector_insert(b, src, insert, 0); - for (unsigned i = 1; i < src->num_components; i++) - dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)), - vtn_vector_insert(b, src, insert, i), dest); - - return dest; -} - -static nir_ssa_def * -vtn_vector_shuffle(struct vtn_builder *b, unsigned num_components, - nir_ssa_def *src0, nir_ssa_def *src1, - const uint32_t *indices) -{ - nir_alu_instr *vec = create_vec(b->shader, num_components); - - nir_ssa_undef_instr *undef = nir_ssa_undef_instr_create(b->shader, 1); - nir_builder_instr_insert(&b->nb, &undef->instr); - - for (unsigned i = 0; i < num_components; i++) { - uint32_t index = indices[i]; - if (index == 0xffffffff) { - vec->src[i].src = nir_src_for_ssa(&undef->def); - } else if (index < src0->num_components) { - vec->src[i].src = nir_src_for_ssa(src0); - vec->src[i].swizzle[0] = index; - } else { - vec->src[i].src = nir_src_for_ssa(src1); - vec->src[i].swizzle[0] = index - src0->num_components; - } - } - - nir_builder_instr_insert(&b->nb, &vec->instr); - - return &vec->dest.dest.ssa; -} - -/* - * Concatentates a number of vectors/scalars together to produce a vector - */ -static nir_ssa_def * -vtn_vector_construct(struct vtn_builder *b, unsigned num_components, - unsigned num_srcs, nir_ssa_def **srcs) -{ - nir_alu_instr *vec = create_vec(b->shader, num_components); - - unsigned dest_idx = 0; - for (unsigned i = 0; i < num_srcs; i++) { - nir_ssa_def *src = srcs[i]; - for (unsigned j = 0; j < src->num_components; j++) { - vec->src[dest_idx].src = nir_src_for_ssa(src); - vec->src[dest_idx].swizzle[0] = j; - dest_idx++; - } - } - - nir_builder_instr_insert(&b->nb, &vec->instr); - - return &vec->dest.dest.ssa; -} - -static struct vtn_ssa_value * -vtn_composite_copy(void *mem_ctx, struct vtn_ssa_value *src) -{ - struct vtn_ssa_value *dest = rzalloc(mem_ctx, struct vtn_ssa_value); - dest->type = src->type; - - if (glsl_type_is_vector_or_scalar(src->type)) { - dest->def = src->def; - } else { - unsigned elems = glsl_get_length(src->type); - - dest->elems = ralloc_array(mem_ctx, struct vtn_ssa_value *, elems); - for (unsigned i = 0; i < elems; i++) - dest->elems[i] = vtn_composite_copy(mem_ctx, src->elems[i]); - } - - return dest; -} - -static struct vtn_ssa_value * -vtn_composite_insert(struct vtn_builder *b, struct vtn_ssa_value *src, - struct vtn_ssa_value *insert, const uint32_t *indices, - unsigned num_indices) -{ - struct vtn_ssa_value *dest = vtn_composite_copy(b, src); - - struct vtn_ssa_value *cur = dest; - unsigned i; - for (i = 0; i < num_indices - 1; i++) { - cur = cur->elems[indices[i]]; - } - - if (glsl_type_is_vector_or_scalar(cur->type)) { - /* According to the SPIR-V spec, OpCompositeInsert may work down to - * the component granularity. In that case, the last index will be - * the index to insert the scalar into the vector. - */ - - cur->def = vtn_vector_insert(b, cur->def, insert->def, indices[i]); - } else { - cur->elems[indices[i]] = insert; - } - - return dest; -} - -static struct vtn_ssa_value * -vtn_composite_extract(struct vtn_builder *b, struct vtn_ssa_value *src, - const uint32_t *indices, unsigned num_indices) -{ - struct vtn_ssa_value *cur = src; - for (unsigned i = 0; i < num_indices; i++) { - if (glsl_type_is_vector_or_scalar(cur->type)) { - assert(i == num_indices - 1); - /* According to the SPIR-V spec, OpCompositeExtract may work down to - * the component granularity. The last index will be the index of the - * vector to extract. - */ - - struct vtn_ssa_value *ret = rzalloc(b, struct vtn_ssa_value); - ret->type = glsl_scalar_type(glsl_get_base_type(cur->type)); - ret->def = vtn_vector_extract(b, cur->def, indices[i]); - return ret; - } else { - cur = cur->elems[indices[i]]; - } - } - - return cur; -} - -static void -vtn_handle_composite(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - const struct glsl_type *type = - vtn_value(b, w[1], vtn_value_type_type)->type->type; - val->ssa = vtn_create_ssa_value(b, type); - - switch (opcode) { - case SpvOpVectorExtractDynamic: - val->ssa->def = vtn_vector_extract_dynamic(b, vtn_ssa_value(b, w[3])->def, - vtn_ssa_value(b, w[4])->def); - break; - - case SpvOpVectorInsertDynamic: - val->ssa->def = vtn_vector_insert_dynamic(b, vtn_ssa_value(b, w[3])->def, - vtn_ssa_value(b, w[4])->def, - vtn_ssa_value(b, w[5])->def); - break; - - case SpvOpVectorShuffle: - val->ssa->def = vtn_vector_shuffle(b, glsl_get_vector_elements(type), - vtn_ssa_value(b, w[3])->def, - vtn_ssa_value(b, w[4])->def, - w + 5); - break; - - case SpvOpCompositeConstruct: { - unsigned elems = count - 3; - if (glsl_type_is_vector_or_scalar(type)) { - nir_ssa_def *srcs[4]; - for (unsigned i = 0; i < elems; i++) - srcs[i] = vtn_ssa_value(b, w[3 + i])->def; - val->ssa->def = - vtn_vector_construct(b, glsl_get_vector_elements(type), - elems, srcs); - } else { - val->ssa->elems = ralloc_array(b, struct vtn_ssa_value *, elems); - for (unsigned i = 0; i < elems; i++) - val->ssa->elems[i] = vtn_ssa_value(b, w[3 + i]); - } - break; - } - case SpvOpCompositeExtract: - val->ssa = vtn_composite_extract(b, vtn_ssa_value(b, w[3]), - w + 4, count - 4); - break; - - case SpvOpCompositeInsert: - val->ssa = vtn_composite_insert(b, vtn_ssa_value(b, w[4]), - vtn_ssa_value(b, w[3]), - w + 5, count - 5); - break; - - case SpvOpCopyObject: - val->ssa = vtn_composite_copy(b, vtn_ssa_value(b, w[3])); - break; - - default: - unreachable("unknown composite operation"); - } -} - -static void -vtn_handle_barrier(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - nir_intrinsic_op intrinsic_op; - switch (opcode) { - case SpvOpEmitVertex: - case SpvOpEmitStreamVertex: - intrinsic_op = nir_intrinsic_emit_vertex; - break; - case SpvOpEndPrimitive: - case SpvOpEndStreamPrimitive: - intrinsic_op = nir_intrinsic_end_primitive; - break; - case SpvOpMemoryBarrier: - intrinsic_op = nir_intrinsic_memory_barrier; - break; - case SpvOpControlBarrier: - intrinsic_op = nir_intrinsic_barrier; - break; - default: - unreachable("unknown barrier instruction"); - } - - nir_intrinsic_instr *intrin = - nir_intrinsic_instr_create(b->shader, intrinsic_op); - - if (opcode == SpvOpEmitStreamVertex || opcode == SpvOpEndStreamPrimitive) - intrin->const_index[0] = w[1]; - - nir_builder_instr_insert(&b->nb, &intrin->instr); -} - -static unsigned -gl_primitive_from_spv_execution_mode(SpvExecutionMode mode) -{ - switch (mode) { - case SpvExecutionModeInputPoints: - case SpvExecutionModeOutputPoints: - return 0; /* GL_POINTS */ - case SpvExecutionModeInputLines: - return 1; /* GL_LINES */ - case SpvExecutionModeInputLinesAdjacency: - return 0x000A; /* GL_LINE_STRIP_ADJACENCY_ARB */ - case SpvExecutionModeTriangles: - return 4; /* GL_TRIANGLES */ - case SpvExecutionModeInputTrianglesAdjacency: - return 0x000C; /* GL_TRIANGLES_ADJACENCY_ARB */ - case SpvExecutionModeQuads: - return 7; /* GL_QUADS */ - case SpvExecutionModeIsolines: - return 0x8E7A; /* GL_ISOLINES */ - case SpvExecutionModeOutputLineStrip: - return 3; /* GL_LINE_STRIP */ - case SpvExecutionModeOutputTriangleStrip: - return 5; /* GL_TRIANGLE_STRIP */ - default: - assert(!"Invalid primitive type"); - return 4; - } -} - -static unsigned -vertices_in_from_spv_execution_mode(SpvExecutionMode mode) -{ - switch (mode) { - case SpvExecutionModeInputPoints: - return 1; - case SpvExecutionModeInputLines: - return 2; - case SpvExecutionModeInputLinesAdjacency: - return 4; - case SpvExecutionModeTriangles: - return 3; - case SpvExecutionModeInputTrianglesAdjacency: - return 6; - default: - assert(!"Invalid GS input mode"); - return 0; - } -} - -static gl_shader_stage -stage_for_execution_model(SpvExecutionModel model) -{ - switch (model) { - case SpvExecutionModelVertex: - return MESA_SHADER_VERTEX; - case SpvExecutionModelTessellationControl: - return MESA_SHADER_TESS_CTRL; - case SpvExecutionModelTessellationEvaluation: - return MESA_SHADER_TESS_EVAL; - case SpvExecutionModelGeometry: - return MESA_SHADER_GEOMETRY; - case SpvExecutionModelFragment: - return MESA_SHADER_FRAGMENT; - case SpvExecutionModelGLCompute: - return MESA_SHADER_COMPUTE; - default: - unreachable("Unsupported execution model"); - } -} - -static bool -vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - switch (opcode) { - case SpvOpSource: - case SpvOpSourceExtension: - case SpvOpSourceContinued: - case SpvOpExtension: - /* Unhandled, but these are for debug so that's ok. */ - break; - - case SpvOpCapability: - switch ((SpvCapability)w[1]) { - case SpvCapabilityMatrix: - case SpvCapabilityShader: - case SpvCapabilityGeometry: - break; - default: - assert(!"Unsupported capability"); - } - break; - - case SpvOpExtInstImport: - vtn_handle_extension(b, opcode, w, count); - break; - - case SpvOpMemoryModel: - assert(w[1] == SpvAddressingModelLogical); - assert(w[2] == SpvMemoryModelGLSL450); - break; - - case SpvOpEntryPoint: { - struct vtn_value *entry_point = &b->values[w[2]]; - /* Let this be a name label regardless */ - unsigned name_words; - entry_point->name = vtn_string_literal(b, &w[3], count - 3, &name_words); - - if (strcmp(entry_point->name, b->entry_point_name) != 0 || - stage_for_execution_model(w[1]) != b->entry_point_stage) - break; - - assert(b->entry_point == NULL); - b->entry_point = entry_point; - break; - } - - case SpvOpString: - vtn_push_value(b, w[1], vtn_value_type_string)->str = - vtn_string_literal(b, &w[2], count - 2, NULL); - break; - - case SpvOpName: - b->values[w[1]].name = vtn_string_literal(b, &w[2], count - 2, NULL); - break; - - case SpvOpMemberName: - /* TODO */ - break; - - case SpvOpExecutionMode: - case SpvOpDecorationGroup: - case SpvOpDecorate: - case SpvOpMemberDecorate: - case SpvOpGroupDecorate: - case SpvOpGroupMemberDecorate: - vtn_handle_decoration(b, opcode, w, count); - break; - - default: - return false; /* End of preamble */ - } - - return true; -} - -static void -vtn_handle_execution_mode(struct vtn_builder *b, struct vtn_value *entry_point, - const struct vtn_decoration *mode, void *data) -{ - assert(b->entry_point == entry_point); - - switch(mode->exec_mode) { - case SpvExecutionModeOriginUpperLeft: - case SpvExecutionModeOriginLowerLeft: - b->origin_upper_left = - (mode->exec_mode == SpvExecutionModeOriginUpperLeft); - break; - - case SpvExecutionModeEarlyFragmentTests: - assert(b->shader->stage == MESA_SHADER_FRAGMENT); - b->shader->info.fs.early_fragment_tests = true; - break; - - case SpvExecutionModeInvocations: - assert(b->shader->stage == MESA_SHADER_GEOMETRY); - b->shader->info.gs.invocations = MAX2(1, mode->literals[0]); - break; - - case SpvExecutionModeDepthReplacing: - assert(b->shader->stage == MESA_SHADER_FRAGMENT); - b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_ANY; - break; - case SpvExecutionModeDepthGreater: - assert(b->shader->stage == MESA_SHADER_FRAGMENT); - b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_GREATER; - break; - case SpvExecutionModeDepthLess: - assert(b->shader->stage == MESA_SHADER_FRAGMENT); - b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_LESS; - break; - case SpvExecutionModeDepthUnchanged: - assert(b->shader->stage == MESA_SHADER_FRAGMENT); - b->shader->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_UNCHANGED; - break; - - case SpvExecutionModeLocalSize: - assert(b->shader->stage == MESA_SHADER_COMPUTE); - b->shader->info.cs.local_size[0] = mode->literals[0]; - b->shader->info.cs.local_size[1] = mode->literals[1]; - b->shader->info.cs.local_size[2] = mode->literals[2]; - break; - case SpvExecutionModeLocalSizeHint: - break; /* Nothing do do with this */ - - case SpvExecutionModeOutputVertices: - assert(b->shader->stage == MESA_SHADER_GEOMETRY); - b->shader->info.gs.vertices_out = mode->literals[0]; - break; - - case SpvExecutionModeInputPoints: - case SpvExecutionModeInputLines: - case SpvExecutionModeInputLinesAdjacency: - case SpvExecutionModeTriangles: - case SpvExecutionModeInputTrianglesAdjacency: - case SpvExecutionModeQuads: - case SpvExecutionModeIsolines: - if (b->shader->stage == MESA_SHADER_GEOMETRY) { - b->shader->info.gs.vertices_in = - vertices_in_from_spv_execution_mode(mode->exec_mode); - } else { - assert(!"Tesselation shaders not yet supported"); - } - break; - - case SpvExecutionModeOutputPoints: - case SpvExecutionModeOutputLineStrip: - case SpvExecutionModeOutputTriangleStrip: - assert(b->shader->stage == MESA_SHADER_GEOMETRY); - b->shader->info.gs.output_primitive = - gl_primitive_from_spv_execution_mode(mode->exec_mode); - break; - - case SpvExecutionModeSpacingEqual: - case SpvExecutionModeSpacingFractionalEven: - case SpvExecutionModeSpacingFractionalOdd: - case SpvExecutionModeVertexOrderCw: - case SpvExecutionModeVertexOrderCcw: - case SpvExecutionModePointMode: - assert(!"TODO: Add tessellation metadata"); - break; - - case SpvExecutionModePixelCenterInteger: - case SpvExecutionModeXfb: - assert(!"Unhandled execution mode"); - break; - - case SpvExecutionModeVecTypeHint: - case SpvExecutionModeContractionOff: - break; /* OpenCL */ - } -} - -static bool -vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - switch (opcode) { - case SpvOpSource: - case SpvOpSourceContinued: - case SpvOpSourceExtension: - case SpvOpExtension: - case SpvOpCapability: - case SpvOpExtInstImport: - case SpvOpMemoryModel: - case SpvOpEntryPoint: - case SpvOpExecutionMode: - case SpvOpString: - case SpvOpName: - case SpvOpMemberName: - case SpvOpDecorationGroup: - case SpvOpDecorate: - case SpvOpMemberDecorate: - case SpvOpGroupDecorate: - case SpvOpGroupMemberDecorate: - assert(!"Invalid opcode types and variables section"); - break; - - case SpvOpTypeVoid: - case SpvOpTypeBool: - case SpvOpTypeInt: - case SpvOpTypeFloat: - case SpvOpTypeVector: - case SpvOpTypeMatrix: - case SpvOpTypeImage: - case SpvOpTypeSampler: - case SpvOpTypeSampledImage: - case SpvOpTypeArray: - case SpvOpTypeRuntimeArray: - case SpvOpTypeStruct: - case SpvOpTypeOpaque: - case SpvOpTypePointer: - case SpvOpTypeFunction: - case SpvOpTypeEvent: - case SpvOpTypeDeviceEvent: - case SpvOpTypeReserveId: - case SpvOpTypeQueue: - case SpvOpTypePipe: - vtn_handle_type(b, opcode, w, count); - break; - - case SpvOpConstantTrue: - case SpvOpConstantFalse: - case SpvOpConstant: - case SpvOpConstantComposite: - case SpvOpConstantSampler: - case SpvOpConstantNull: - case SpvOpSpecConstantTrue: - case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: - case SpvOpSpecConstantComposite: - case SpvOpSpecConstantOp: - vtn_handle_constant(b, opcode, w, count); - break; - - case SpvOpVariable: - vtn_handle_variables(b, opcode, w, count); - break; - - default: - return false; /* End of preamble */ - } - - return true; -} - -static bool -vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - switch (opcode) { - case SpvOpLabel: - break; - - case SpvOpLoopMerge: - case SpvOpSelectionMerge: - /* This is handled by cfg pre-pass and walk_blocks */ - break; - - case SpvOpUndef: { - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_undef); - val->type = vtn_value(b, w[1], vtn_value_type_type)->type; - break; - } - - case SpvOpExtInst: - vtn_handle_extension(b, opcode, w, count); - break; - - case SpvOpVariable: - case SpvOpLoad: - case SpvOpStore: - case SpvOpCopyMemory: - case SpvOpCopyMemorySized: - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - case SpvOpArrayLength: - vtn_handle_variables(b, opcode, w, count); - break; - - case SpvOpFunctionCall: - vtn_handle_function_call(b, opcode, w, count); - break; - - case SpvOpSampledImage: - case SpvOpImage: - case SpvOpImageSampleImplicitLod: - case SpvOpImageSampleExplicitLod: - case SpvOpImageSampleDrefImplicitLod: - case SpvOpImageSampleDrefExplicitLod: - case SpvOpImageSampleProjImplicitLod: - case SpvOpImageSampleProjExplicitLod: - case SpvOpImageSampleProjDrefImplicitLod: - case SpvOpImageSampleProjDrefExplicitLod: - case SpvOpImageFetch: - case SpvOpImageGather: - case SpvOpImageDrefGather: - case SpvOpImageQuerySizeLod: - case SpvOpImageQueryLod: - case SpvOpImageQueryLevels: - case SpvOpImageQuerySamples: - vtn_handle_texture(b, opcode, w, count); - break; - - case SpvOpImageRead: - case SpvOpImageWrite: - case SpvOpImageTexelPointer: - vtn_handle_image(b, opcode, w, count); - break; - - case SpvOpImageQuerySize: { - struct vtn_access_chain *image = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - if (glsl_type_is_image(image->var->var->interface_type)) { - vtn_handle_image(b, opcode, w, count); - } else { - vtn_handle_texture(b, opcode, w, count); - } - break; - } - - case SpvOpAtomicExchange: - case SpvOpAtomicCompareExchange: - case SpvOpAtomicCompareExchangeWeak: - case SpvOpAtomicIIncrement: - case SpvOpAtomicIDecrement: - case SpvOpAtomicIAdd: - case SpvOpAtomicISub: - case SpvOpAtomicSMin: - case SpvOpAtomicUMin: - case SpvOpAtomicSMax: - case SpvOpAtomicUMax: - case SpvOpAtomicAnd: - case SpvOpAtomicOr: - case SpvOpAtomicXor: { - struct vtn_value *pointer = vtn_untyped_value(b, w[3]); - if (pointer->value_type == vtn_value_type_image_pointer) { - vtn_handle_image(b, opcode, w, count); - } else { - assert(pointer->value_type == vtn_value_type_access_chain); - vtn_handle_ssbo_or_shared_atomic(b, opcode, w, count); - } - break; - } - - case SpvOpSNegate: - case SpvOpFNegate: - case SpvOpNot: - case SpvOpAny: - case SpvOpAll: - case SpvOpConvertFToU: - case SpvOpConvertFToS: - case SpvOpConvertSToF: - case SpvOpConvertUToF: - case SpvOpUConvert: - case SpvOpSConvert: - case SpvOpFConvert: - case SpvOpQuantizeToF16: - case SpvOpConvertPtrToU: - case SpvOpConvertUToPtr: - case SpvOpPtrCastToGeneric: - case SpvOpGenericCastToPtr: - case SpvOpBitcast: - case SpvOpIsNan: - case SpvOpIsInf: - case SpvOpIsFinite: - case SpvOpIsNormal: - case SpvOpSignBitSet: - case SpvOpLessOrGreater: - case SpvOpOrdered: - case SpvOpUnordered: - case SpvOpIAdd: - case SpvOpFAdd: - case SpvOpISub: - case SpvOpFSub: - case SpvOpIMul: - case SpvOpFMul: - case SpvOpUDiv: - case SpvOpSDiv: - case SpvOpFDiv: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpVectorTimesScalar: - case SpvOpDot: - case SpvOpIAddCarry: - case SpvOpISubBorrow: - case SpvOpUMulExtended: - case SpvOpSMulExtended: - case SpvOpShiftRightLogical: - case SpvOpShiftRightArithmetic: - case SpvOpShiftLeftLogical: - case SpvOpLogicalEqual: - case SpvOpLogicalNotEqual: - case SpvOpLogicalOr: - case SpvOpLogicalAnd: - case SpvOpLogicalNot: - case SpvOpBitwiseOr: - case SpvOpBitwiseXor: - case SpvOpBitwiseAnd: - case SpvOpSelect: - case SpvOpIEqual: - case SpvOpFOrdEqual: - case SpvOpFUnordEqual: - case SpvOpINotEqual: - case SpvOpFOrdNotEqual: - case SpvOpFUnordNotEqual: - case SpvOpULessThan: - case SpvOpSLessThan: - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - case SpvOpUGreaterThan: - case SpvOpSGreaterThan: - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - case SpvOpULessThanEqual: - case SpvOpSLessThanEqual: - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - case SpvOpUGreaterThanEqual: - case SpvOpSGreaterThanEqual: - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: - case SpvOpDPdx: - case SpvOpDPdy: - case SpvOpFwidth: - case SpvOpDPdxFine: - case SpvOpDPdyFine: - case SpvOpFwidthFine: - case SpvOpDPdxCoarse: - case SpvOpDPdyCoarse: - case SpvOpFwidthCoarse: - case SpvOpBitFieldInsert: - case SpvOpBitFieldSExtract: - case SpvOpBitFieldUExtract: - case SpvOpBitReverse: - case SpvOpBitCount: - case SpvOpTranspose: - case SpvOpOuterProduct: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - vtn_handle_alu(b, opcode, w, count); - break; - - case SpvOpVectorExtractDynamic: - case SpvOpVectorInsertDynamic: - case SpvOpVectorShuffle: - case SpvOpCompositeConstruct: - case SpvOpCompositeExtract: - case SpvOpCompositeInsert: - case SpvOpCopyObject: - vtn_handle_composite(b, opcode, w, count); - break; - - case SpvOpEmitVertex: - case SpvOpEndPrimitive: - case SpvOpEmitStreamVertex: - case SpvOpEndStreamPrimitive: - case SpvOpControlBarrier: - case SpvOpMemoryBarrier: - vtn_handle_barrier(b, opcode, w, count); - break; - - default: - unreachable("Unhandled opcode"); - } - - return true; -} - -nir_function * -spirv_to_nir(const uint32_t *words, size_t word_count, - struct nir_spirv_specialization *spec, unsigned num_spec, - gl_shader_stage stage, const char *entry_point_name, - const nir_shader_compiler_options *options) -{ - const uint32_t *word_end = words + word_count; - - /* Handle the SPIR-V header (first 4 dwords) */ - assert(word_count > 5); - - assert(words[0] == SpvMagicNumber); - assert(words[1] >= 0x10000); - /* words[2] == generator magic */ - unsigned value_id_bound = words[3]; - assert(words[4] == 0); - - words+= 5; - - /* Initialize the stn_builder object */ - struct vtn_builder *b = rzalloc(NULL, struct vtn_builder); - b->value_id_bound = value_id_bound; - b->values = rzalloc_array(b, struct vtn_value, value_id_bound); - exec_list_make_empty(&b->functions); - b->entry_point_stage = stage; - b->entry_point_name = entry_point_name; - - /* Handle all the preamble instructions */ - words = vtn_foreach_instruction(b, words, word_end, - vtn_handle_preamble_instruction); - - if (b->entry_point == NULL) { - assert(!"Entry point not found"); - ralloc_free(b); - return NULL; - } - - b->shader = nir_shader_create(NULL, stage, options); - - /* Parse execution modes */ - vtn_foreach_execution_mode(b, b->entry_point, - vtn_handle_execution_mode, NULL); - - b->specializations = spec; - b->num_specializations = num_spec; - - /* Handle all variable, type, and constant instructions */ - words = vtn_foreach_instruction(b, words, word_end, - vtn_handle_variable_or_type_instruction); - - vtn_build_cfg(b, words, word_end); - - foreach_list_typed(struct vtn_function, func, node, &b->functions) { - b->impl = func->impl; - b->const_table = _mesa_hash_table_create(b, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - vtn_function_emit(b, func, vtn_handle_body_instruction); - } - - assert(b->entry_point->value_type == vtn_value_type_function); - nir_function *entry_point = b->entry_point->func->impl->function; - assert(entry_point); - - ralloc_free(b); - - return entry_point; -} diff --git a/src/glsl/nir/spirv/vtn_alu.c b/src/glsl/nir/spirv/vtn_alu.c deleted file mode 100644 index d866da7445e..00000000000 --- a/src/glsl/nir/spirv/vtn_alu.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright © 2016 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "vtn_private.h" - -/* - * Normally, column vectors in SPIR-V correspond to a single NIR SSA - * definition. But for matrix multiplies, we want to do one routine for - * multiplying a matrix by a matrix and then pretend that vectors are matrices - * with one column. So we "wrap" these things, and unwrap the result before we - * send it off. - */ - -static struct vtn_ssa_value * -wrap_matrix(struct vtn_builder *b, struct vtn_ssa_value *val) -{ - if (val == NULL) - return NULL; - - if (glsl_type_is_matrix(val->type)) - return val; - - struct vtn_ssa_value *dest = rzalloc(b, struct vtn_ssa_value); - dest->type = val->type; - dest->elems = ralloc_array(b, struct vtn_ssa_value *, 1); - dest->elems[0] = val; - - return dest; -} - -static struct vtn_ssa_value * -unwrap_matrix(struct vtn_ssa_value *val) -{ - if (glsl_type_is_matrix(val->type)) - return val; - - return val->elems[0]; -} - -static struct vtn_ssa_value * -matrix_multiply(struct vtn_builder *b, - struct vtn_ssa_value *_src0, struct vtn_ssa_value *_src1) -{ - - struct vtn_ssa_value *src0 = wrap_matrix(b, _src0); - struct vtn_ssa_value *src1 = wrap_matrix(b, _src1); - struct vtn_ssa_value *src0_transpose = wrap_matrix(b, _src0->transposed); - struct vtn_ssa_value *src1_transpose = wrap_matrix(b, _src1->transposed); - - unsigned src0_rows = glsl_get_vector_elements(src0->type); - unsigned src0_columns = glsl_get_matrix_columns(src0->type); - unsigned src1_columns = glsl_get_matrix_columns(src1->type); - - const struct glsl_type *dest_type; - if (src1_columns > 1) { - dest_type = glsl_matrix_type(glsl_get_base_type(src0->type), - src0_rows, src1_columns); - } else { - dest_type = glsl_vector_type(glsl_get_base_type(src0->type), src0_rows); - } - struct vtn_ssa_value *dest = vtn_create_ssa_value(b, dest_type); - - dest = wrap_matrix(b, dest); - - bool transpose_result = false; - if (src0_transpose && src1_transpose) { - /* transpose(A) * transpose(B) = transpose(B * A) */ - src1 = src0_transpose; - src0 = src1_transpose; - src0_transpose = NULL; - src1_transpose = NULL; - transpose_result = true; - } - - if (src0_transpose && !src1_transpose && - glsl_get_base_type(src0->type) == GLSL_TYPE_FLOAT) { - /* We already have the rows of src0 and the columns of src1 available, - * so we can just take the dot product of each row with each column to - * get the result. - */ - - for (unsigned i = 0; i < src1_columns; i++) { - nir_ssa_def *vec_src[4]; - for (unsigned j = 0; j < src0_rows; j++) { - vec_src[j] = nir_fdot(&b->nb, src0_transpose->elems[j]->def, - src1->elems[i]->def); - } - dest->elems[i]->def = nir_vec(&b->nb, vec_src, src0_rows); - } - } else { - /* We don't handle the case where src1 is transposed but not src0, since - * the general case only uses individual components of src1 so the - * optimizer should chew through the transpose we emitted for src1. - */ - - for (unsigned i = 0; i < src1_columns; i++) { - /* dest[i] = sum(src0[j] * src1[i][j] for all j) */ - dest->elems[i]->def = - nir_fmul(&b->nb, src0->elems[0]->def, - nir_channel(&b->nb, src1->elems[i]->def, 0)); - for (unsigned j = 1; j < src0_columns; j++) { - dest->elems[i]->def = - nir_fadd(&b->nb, dest->elems[i]->def, - nir_fmul(&b->nb, src0->elems[j]->def, - nir_channel(&b->nb, src1->elems[i]->def, j))); - } - } - } - - dest = unwrap_matrix(dest); - - if (transpose_result) - dest = vtn_ssa_transpose(b, dest); - - return dest; -} - -static struct vtn_ssa_value * -mat_times_scalar(struct vtn_builder *b, - struct vtn_ssa_value *mat, - nir_ssa_def *scalar) -{ - struct vtn_ssa_value *dest = vtn_create_ssa_value(b, mat->type); - for (unsigned i = 0; i < glsl_get_matrix_columns(mat->type); i++) { - if (glsl_get_base_type(mat->type) == GLSL_TYPE_FLOAT) - dest->elems[i]->def = nir_fmul(&b->nb, mat->elems[i]->def, scalar); - else - dest->elems[i]->def = nir_imul(&b->nb, mat->elems[i]->def, scalar); - } - - return dest; -} - -static void -vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode, - struct vtn_value *dest, - struct vtn_ssa_value *src0, struct vtn_ssa_value *src1) -{ - switch (opcode) { - case SpvOpFNegate: { - dest->ssa = vtn_create_ssa_value(b, src0->type); - unsigned cols = glsl_get_matrix_columns(src0->type); - for (unsigned i = 0; i < cols; i++) - dest->ssa->elems[i]->def = nir_fneg(&b->nb, src0->elems[i]->def); - break; - } - - case SpvOpFAdd: { - dest->ssa = vtn_create_ssa_value(b, src0->type); - unsigned cols = glsl_get_matrix_columns(src0->type); - for (unsigned i = 0; i < cols; i++) - dest->ssa->elems[i]->def = - nir_fadd(&b->nb, src0->elems[i]->def, src1->elems[i]->def); - break; - } - - case SpvOpFSub: { - dest->ssa = vtn_create_ssa_value(b, src0->type); - unsigned cols = glsl_get_matrix_columns(src0->type); - for (unsigned i = 0; i < cols; i++) - dest->ssa->elems[i]->def = - nir_fsub(&b->nb, src0->elems[i]->def, src1->elems[i]->def); - break; - } - - case SpvOpTranspose: - dest->ssa = vtn_ssa_transpose(b, src0); - break; - - case SpvOpMatrixTimesScalar: - if (src0->transposed) { - dest->ssa = vtn_ssa_transpose(b, mat_times_scalar(b, src0->transposed, - src1->def)); - } else { - dest->ssa = mat_times_scalar(b, src0, src1->def); - } - break; - - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - if (opcode == SpvOpVectorTimesMatrix) { - dest->ssa = matrix_multiply(b, vtn_ssa_transpose(b, src1), src0); - } else { - dest->ssa = matrix_multiply(b, src0, src1); - } - break; - - default: unreachable("unknown matrix opcode"); - } -} - -nir_op -vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap) -{ - /* Indicates that the first two arguments should be swapped. This is - * used for implementing greater-than and less-than-or-equal. - */ - *swap = false; - - switch (opcode) { - case SpvOpSNegate: return nir_op_ineg; - case SpvOpFNegate: return nir_op_fneg; - case SpvOpNot: return nir_op_inot; - case SpvOpIAdd: return nir_op_iadd; - case SpvOpFAdd: return nir_op_fadd; - case SpvOpISub: return nir_op_isub; - case SpvOpFSub: return nir_op_fsub; - case SpvOpIMul: return nir_op_imul; - case SpvOpFMul: return nir_op_fmul; - case SpvOpUDiv: return nir_op_udiv; - case SpvOpSDiv: return nir_op_idiv; - case SpvOpFDiv: return nir_op_fdiv; - case SpvOpUMod: return nir_op_umod; - case SpvOpSMod: return nir_op_imod; - case SpvOpFMod: return nir_op_fmod; - case SpvOpSRem: return nir_op_irem; - case SpvOpFRem: return nir_op_frem; - - case SpvOpShiftRightLogical: return nir_op_ushr; - case SpvOpShiftRightArithmetic: return nir_op_ishr; - case SpvOpShiftLeftLogical: return nir_op_ishl; - case SpvOpLogicalOr: return nir_op_ior; - case SpvOpLogicalEqual: return nir_op_ieq; - case SpvOpLogicalNotEqual: return nir_op_ine; - case SpvOpLogicalAnd: return nir_op_iand; - case SpvOpLogicalNot: return nir_op_inot; - case SpvOpBitwiseOr: return nir_op_ior; - case SpvOpBitwiseXor: return nir_op_ixor; - case SpvOpBitwiseAnd: return nir_op_iand; - case SpvOpSelect: return nir_op_bcsel; - case SpvOpIEqual: return nir_op_ieq; - - case SpvOpBitFieldInsert: return nir_op_bitfield_insert; - case SpvOpBitFieldSExtract: return nir_op_ibitfield_extract; - case SpvOpBitFieldUExtract: return nir_op_ubitfield_extract; - case SpvOpBitReverse: return nir_op_bitfield_reverse; - case SpvOpBitCount: return nir_op_bit_count; - - /* Comparisons: (TODO: How do we want to handled ordered/unordered?) */ - case SpvOpFOrdEqual: return nir_op_feq; - case SpvOpFUnordEqual: return nir_op_feq; - case SpvOpINotEqual: return nir_op_ine; - case SpvOpFOrdNotEqual: return nir_op_fne; - case SpvOpFUnordNotEqual: return nir_op_fne; - case SpvOpULessThan: return nir_op_ult; - case SpvOpSLessThan: return nir_op_ilt; - case SpvOpFOrdLessThan: return nir_op_flt; - case SpvOpFUnordLessThan: return nir_op_flt; - case SpvOpUGreaterThan: *swap = true; return nir_op_ult; - case SpvOpSGreaterThan: *swap = true; return nir_op_ilt; - case SpvOpFOrdGreaterThan: *swap = true; return nir_op_flt; - case SpvOpFUnordGreaterThan: *swap = true; return nir_op_flt; - case SpvOpULessThanEqual: *swap = true; return nir_op_uge; - case SpvOpSLessThanEqual: *swap = true; return nir_op_ige; - case SpvOpFOrdLessThanEqual: *swap = true; return nir_op_fge; - case SpvOpFUnordLessThanEqual: *swap = true; return nir_op_fge; - case SpvOpUGreaterThanEqual: return nir_op_uge; - case SpvOpSGreaterThanEqual: return nir_op_ige; - case SpvOpFOrdGreaterThanEqual: return nir_op_fge; - case SpvOpFUnordGreaterThanEqual: return nir_op_fge; - - /* Conversions: */ - case SpvOpConvertFToU: return nir_op_f2u; - case SpvOpConvertFToS: return nir_op_f2i; - case SpvOpConvertSToF: return nir_op_i2f; - case SpvOpConvertUToF: return nir_op_u2f; - case SpvOpBitcast: return nir_op_imov; - case SpvOpUConvert: - case SpvOpQuantizeToF16: return nir_op_fquantize2f16; - /* TODO: NIR is 32-bit only; these are no-ops. */ - case SpvOpSConvert: return nir_op_imov; - case SpvOpFConvert: return nir_op_fmov; - - /* Derivatives: */ - case SpvOpDPdx: return nir_op_fddx; - case SpvOpDPdy: return nir_op_fddy; - case SpvOpDPdxFine: return nir_op_fddx_fine; - case SpvOpDPdyFine: return nir_op_fddy_fine; - case SpvOpDPdxCoarse: return nir_op_fddx_coarse; - case SpvOpDPdyCoarse: return nir_op_fddy_coarse; - - default: - unreachable("No NIR equivalent"); - } -} - -void -vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - const struct glsl_type *type = - vtn_value(b, w[1], vtn_value_type_type)->type->type; - - /* Collect the various SSA sources */ - const unsigned num_inputs = count - 3; - struct vtn_ssa_value *vtn_src[4] = { NULL, }; - for (unsigned i = 0; i < num_inputs; i++) - vtn_src[i] = vtn_ssa_value(b, w[i + 3]); - - if (glsl_type_is_matrix(vtn_src[0]->type) || - (num_inputs >= 2 && glsl_type_is_matrix(vtn_src[1]->type))) { - vtn_handle_matrix_alu(b, opcode, val, vtn_src[0], vtn_src[1]); - return; - } - - val->ssa = vtn_create_ssa_value(b, type); - nir_ssa_def *src[4] = { NULL, }; - for (unsigned i = 0; i < num_inputs; i++) { - assert(glsl_type_is_vector_or_scalar(vtn_src[i]->type)); - src[i] = vtn_src[i]->def; - } - - switch (opcode) { - case SpvOpAny: - if (src[0]->num_components == 1) { - val->ssa->def = nir_imov(&b->nb, src[0]); - } else { - nir_op op; - switch (src[0]->num_components) { - case 2: op = nir_op_bany_inequal2; break; - case 3: op = nir_op_bany_inequal3; break; - case 4: op = nir_op_bany_inequal4; break; - } - val->ssa->def = nir_build_alu(&b->nb, op, src[0], - nir_imm_int(&b->nb, NIR_FALSE), - NULL, NULL); - } - return; - - case SpvOpAll: - if (src[0]->num_components == 1) { - val->ssa->def = nir_imov(&b->nb, src[0]); - } else { - nir_op op; - switch (src[0]->num_components) { - case 2: op = nir_op_ball_iequal2; break; - case 3: op = nir_op_ball_iequal3; break; - case 4: op = nir_op_ball_iequal4; break; - } - val->ssa->def = nir_build_alu(&b->nb, op, src[0], - nir_imm_int(&b->nb, NIR_TRUE), - NULL, NULL); - } - return; - - case SpvOpOuterProduct: { - for (unsigned i = 0; i < src[1]->num_components; i++) { - val->ssa->elems[i]->def = - nir_fmul(&b->nb, src[0], nir_channel(&b->nb, src[1], i)); - } - return; - } - - case SpvOpDot: - val->ssa->def = nir_fdot(&b->nb, src[0], src[1]); - return; - - case SpvOpIAddCarry: - assert(glsl_type_is_struct(val->ssa->type)); - val->ssa->elems[0]->def = nir_iadd(&b->nb, src[0], src[1]); - val->ssa->elems[1]->def = nir_uadd_carry(&b->nb, src[0], src[1]); - return; - - case SpvOpISubBorrow: - assert(glsl_type_is_struct(val->ssa->type)); - val->ssa->elems[0]->def = nir_isub(&b->nb, src[0], src[1]); - val->ssa->elems[1]->def = nir_usub_borrow(&b->nb, src[0], src[1]); - return; - - case SpvOpUMulExtended: - assert(glsl_type_is_struct(val->ssa->type)); - val->ssa->elems[0]->def = nir_imul(&b->nb, src[0], src[1]); - val->ssa->elems[1]->def = nir_umul_high(&b->nb, src[0], src[1]); - return; - - case SpvOpSMulExtended: - assert(glsl_type_is_struct(val->ssa->type)); - val->ssa->elems[0]->def = nir_imul(&b->nb, src[0], src[1]); - val->ssa->elems[1]->def = nir_imul_high(&b->nb, src[0], src[1]); - return; - - case SpvOpFwidth: - val->ssa->def = nir_fadd(&b->nb, - nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])), - nir_fabs(&b->nb, nir_fddx(&b->nb, src[1]))); - return; - case SpvOpFwidthFine: - val->ssa->def = nir_fadd(&b->nb, - nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])), - nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1]))); - return; - case SpvOpFwidthCoarse: - val->ssa->def = nir_fadd(&b->nb, - nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])), - nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1]))); - return; - - case SpvOpVectorTimesScalar: - /* The builder will take care of splatting for us. */ - val->ssa->def = nir_fmul(&b->nb, src[0], src[1]); - return; - - case SpvOpIsNan: - val->ssa->def = nir_fne(&b->nb, src[0], src[0]); - return; - - case SpvOpIsInf: - val->ssa->def = nir_feq(&b->nb, nir_fabs(&b->nb, src[0]), - nir_imm_float(&b->nb, INFINITY)); - return; - - default: { - bool swap; - nir_op op = vtn_nir_alu_op_for_spirv_opcode(opcode, &swap); - - if (swap) { - nir_ssa_def *tmp = src[0]; - src[0] = src[1]; - src[1] = tmp; - } - - val->ssa->def = nir_build_alu(&b->nb, op, src[0], src[1], src[2], src[3]); - return; - } /* default */ - } -} diff --git a/src/glsl/nir/spirv/vtn_cfg.c b/src/glsl/nir/spirv/vtn_cfg.c deleted file mode 100644 index 041408b1cfb..00000000000 --- a/src/glsl/nir/spirv/vtn_cfg.c +++ /dev/null @@ -1,768 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "vtn_private.h" -#include "nir/nir_vla.h" - -static bool -vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - switch (opcode) { - case SpvOpFunction: { - assert(b->func == NULL); - b->func = rzalloc(b, struct vtn_function); - - list_inithead(&b->func->body); - b->func->control = w[3]; - - const struct glsl_type *result_type = - vtn_value(b, w[1], vtn_value_type_type)->type->type; - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function); - val->func = b->func; - - const struct glsl_type *func_type = - vtn_value(b, w[4], vtn_value_type_type)->type->type; - - assert(glsl_get_function_return_type(func_type) == result_type); - - nir_function *func = - nir_function_create(b->shader, ralloc_strdup(b->shader, val->name)); - - func->num_params = glsl_get_length(func_type); - func->params = ralloc_array(b->shader, nir_parameter, func->num_params); - for (unsigned i = 0; i < func->num_params; i++) { - const struct glsl_function_param *param = - glsl_get_function_param(func_type, i); - func->params[i].type = param->type; - if (param->in) { - if (param->out) { - func->params[i].param_type = nir_parameter_inout; - } else { - func->params[i].param_type = nir_parameter_in; - } - } else { - if (param->out) { - func->params[i].param_type = nir_parameter_out; - } else { - assert(!"Parameter is neither in nor out"); - } - } - } - - func->return_type = glsl_get_function_return_type(func_type); - - b->func->impl = nir_function_impl_create(func); - if (!glsl_type_is_void(func->return_type)) { - b->func->impl->return_var = - nir_local_variable_create(b->func->impl, func->return_type, "ret"); - } - - b->func_param_idx = 0; - break; - } - - case SpvOpFunctionEnd: - b->func->end = w; - b->func = NULL; - break; - - case SpvOpFunctionParameter: { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_access_chain); - - assert(b->func_param_idx < b->func->impl->num_params); - unsigned idx = b->func_param_idx++; - - nir_variable *param = - nir_local_variable_create(b->func->impl, - b->func->impl->function->params[idx].type, - val->name); - b->func->impl->params[idx] = param; - - struct vtn_variable *vtn_var = rzalloc(b, struct vtn_variable); - vtn_var->mode = vtn_variable_mode_param; - vtn_var->type = vtn_value(b, w[1], vtn_value_type_type)->type; - vtn_var->var = param; - vtn_var->chain.var = vtn_var; - vtn_var->chain.length = 0; - - val->access_chain = &vtn_var->chain; - break; - } - - case SpvOpLabel: { - assert(b->block == NULL); - b->block = rzalloc(b, struct vtn_block); - b->block->node.type = vtn_cf_node_type_block; - b->block->label = w; - vtn_push_value(b, w[1], vtn_value_type_block)->block = b->block; - - if (b->func->start_block == NULL) { - /* This is the first block encountered for this function. In this - * case, we set the start block and add it to the list of - * implemented functions that we'll walk later. - */ - b->func->start_block = b->block; - exec_list_push_tail(&b->functions, &b->func->node); - } - break; - } - - case SpvOpSelectionMerge: - case SpvOpLoopMerge: - assert(b->block && b->block->merge == NULL); - b->block->merge = w; - break; - - case SpvOpBranch: - case SpvOpBranchConditional: - case SpvOpSwitch: - case SpvOpKill: - case SpvOpReturn: - case SpvOpReturnValue: - case SpvOpUnreachable: - assert(b->block && b->block->branch == NULL); - b->block->branch = w; - b->block = NULL; - break; - - default: - /* Continue on as per normal */ - return true; - } - - return true; -} - -static void -vtn_add_case(struct vtn_builder *b, struct vtn_switch *swtch, - struct vtn_block *break_block, - uint32_t block_id, uint32_t val, bool is_default) -{ - struct vtn_block *case_block = - vtn_value(b, block_id, vtn_value_type_block)->block; - - /* Don't create dummy cases that just break */ - if (case_block == break_block) - return; - - if (case_block->switch_case == NULL) { - struct vtn_case *c = ralloc(b, struct vtn_case); - - list_inithead(&c->body); - c->start_block = case_block; - c->fallthrough = NULL; - nir_array_init(&c->values, b); - c->is_default = false; - c->visited = false; - - list_addtail(&c->link, &swtch->cases); - - case_block->switch_case = c; - } - - if (is_default) { - case_block->switch_case->is_default = true; - } else { - nir_array_add(&case_block->switch_case->values, uint32_t, val); - } -} - -/* This function performs a depth-first search of the cases and puts them - * in fall-through order. - */ -static void -vtn_order_case(struct vtn_switch *swtch, struct vtn_case *cse) -{ - if (cse->visited) - return; - - cse->visited = true; - - list_del(&cse->link); - - if (cse->fallthrough) { - vtn_order_case(swtch, cse->fallthrough); - - /* If we have a fall-through, place this case right before the case it - * falls through to. This ensures that fallthroughs come one after - * the other. These two can never get separated because that would - * imply something else falling through to the same case. Also, this - * can't break ordering because the DFS ensures that this case is - * visited before anything that falls through to it. - */ - list_addtail(&cse->link, &cse->fallthrough->link); - } else { - list_add(&cse->link, &swtch->cases); - } -} - -static enum vtn_branch_type -vtn_get_branch_type(struct vtn_block *block, - struct vtn_case *swcase, struct vtn_block *switch_break, - struct vtn_block *loop_break, struct vtn_block *loop_cont) -{ - if (block->switch_case) { - /* This branch is actually a fallthrough */ - assert(swcase->fallthrough == NULL || - swcase->fallthrough == block->switch_case); - swcase->fallthrough = block->switch_case; - return vtn_branch_type_switch_fallthrough; - } else if (block == switch_break) { - return vtn_branch_type_switch_break; - } else if (block == loop_break) { - return vtn_branch_type_loop_break; - } else if (block == loop_cont) { - return vtn_branch_type_loop_continue; - } else { - return vtn_branch_type_none; - } -} - -static void -vtn_cfg_walk_blocks(struct vtn_builder *b, struct list_head *cf_list, - struct vtn_block *start, struct vtn_case *switch_case, - struct vtn_block *switch_break, - struct vtn_block *loop_break, struct vtn_block *loop_cont, - struct vtn_block *end) -{ - struct vtn_block *block = start; - while (block != end) { - if (block->merge && (*block->merge & SpvOpCodeMask) == SpvOpLoopMerge && - !block->loop) { - struct vtn_loop *loop = ralloc(b, struct vtn_loop); - - loop->node.type = vtn_cf_node_type_loop; - list_inithead(&loop->body); - list_inithead(&loop->cont_body); - loop->control = block->merge[3]; - - list_addtail(&loop->node.link, cf_list); - block->loop = loop; - - struct vtn_block *new_loop_break = - vtn_value(b, block->merge[1], vtn_value_type_block)->block; - struct vtn_block *new_loop_cont = - vtn_value(b, block->merge[2], vtn_value_type_block)->block; - - /* Note: This recursive call will start with the current block as - * its start block. If we weren't careful, we would get here - * again and end up in infinite recursion. This is why we set - * block->loop above and check for it before creating one. This - * way, we only create the loop once and the second call that - * tries to handle this loop goes to the cases below and gets - * handled as a regular block. - * - * Note: When we make the recursive walk calls, we pass NULL for - * the switch break since you have to break out of the loop first. - * We do, however, still pass the current switch case because it's - * possible that the merge block for the loop is the start of - * another case. - */ - vtn_cfg_walk_blocks(b, &loop->body, block, switch_case, NULL, - new_loop_break, new_loop_cont, NULL ); - vtn_cfg_walk_blocks(b, &loop->cont_body, new_loop_cont, NULL, NULL, - new_loop_break, NULL, block); - - block = new_loop_break; - continue; - } - - assert(block->node.link.next == NULL); - list_addtail(&block->node.link, cf_list); - - switch (*block->branch & SpvOpCodeMask) { - case SpvOpBranch: { - struct vtn_block *branch_block = - vtn_value(b, block->branch[1], vtn_value_type_block)->block; - - block->branch_type = vtn_get_branch_type(branch_block, - switch_case, switch_break, - loop_break, loop_cont); - - if (block->branch_type != vtn_branch_type_none) - return; - - block = branch_block; - continue; - } - - case SpvOpReturn: - case SpvOpReturnValue: - block->branch_type = vtn_branch_type_return; - return; - - case SpvOpKill: - block->branch_type = vtn_branch_type_discard; - return; - - case SpvOpBranchConditional: { - struct vtn_block *then_block = - vtn_value(b, block->branch[2], vtn_value_type_block)->block; - struct vtn_block *else_block = - vtn_value(b, block->branch[3], vtn_value_type_block)->block; - - struct vtn_if *if_stmt = ralloc(b, struct vtn_if); - - if_stmt->node.type = vtn_cf_node_type_if; - if_stmt->condition = block->branch[1]; - list_inithead(&if_stmt->then_body); - list_inithead(&if_stmt->else_body); - - list_addtail(&if_stmt->node.link, cf_list); - - if (block->merge && - (*block->merge & SpvOpCodeMask) == SpvOpSelectionMerge) { - if_stmt->control = block->merge[2]; - } - - if_stmt->then_type = vtn_get_branch_type(then_block, - switch_case, switch_break, - loop_break, loop_cont); - if_stmt->else_type = vtn_get_branch_type(else_block, - switch_case, switch_break, - loop_break, loop_cont); - - if (if_stmt->then_type == vtn_branch_type_none && - if_stmt->else_type == vtn_branch_type_none) { - /* Neither side of the if is something we can short-circuit. */ - assert((*block->merge & SpvOpCodeMask) == SpvOpSelectionMerge); - struct vtn_block *merge_block = - vtn_value(b, block->merge[1], vtn_value_type_block)->block; - - vtn_cfg_walk_blocks(b, &if_stmt->then_body, then_block, - switch_case, switch_break, - loop_break, loop_cont, merge_block); - vtn_cfg_walk_blocks(b, &if_stmt->else_body, else_block, - switch_case, switch_break, - loop_break, loop_cont, merge_block); - - enum vtn_branch_type merge_type = - vtn_get_branch_type(merge_block, switch_case, switch_break, - loop_break, loop_cont); - if (merge_type == vtn_branch_type_none) { - block = merge_block; - continue; - } else { - return; - } - } else if (if_stmt->then_type != vtn_branch_type_none && - if_stmt->else_type != vtn_branch_type_none) { - /* Both sides were short-circuited. We're done here. */ - return; - } else { - /* Exeactly one side of the branch could be short-circuited. - * We set the branch up as a predicated break/continue and we - * continue on with the other side as if it were what comes - * after the if. - */ - if (if_stmt->then_type == vtn_branch_type_none) { - block = then_block; - } else { - block = else_block; - } - continue; - } - unreachable("Should have returned or continued"); - } - - case SpvOpSwitch: { - assert((*block->merge & SpvOpCodeMask) == SpvOpSelectionMerge); - struct vtn_block *break_block = - vtn_value(b, block->merge[1], vtn_value_type_block)->block; - - struct vtn_switch *swtch = ralloc(b, struct vtn_switch); - - swtch->node.type = vtn_cf_node_type_switch; - swtch->selector = block->branch[1]; - list_inithead(&swtch->cases); - - list_addtail(&swtch->node.link, cf_list); - - /* First, we go through and record all of the cases. */ - const uint32_t *branch_end = - block->branch + (block->branch[0] >> SpvWordCountShift); - - vtn_add_case(b, swtch, break_block, block->branch[2], 0, true); - for (const uint32_t *w = block->branch + 3; w < branch_end; w += 2) - vtn_add_case(b, swtch, break_block, w[1], w[0], false); - - /* Now, we go through and walk the blocks. While we walk through - * the blocks, we also gather the much-needed fall-through - * information. - */ - list_for_each_entry(struct vtn_case, cse, &swtch->cases, link) { - assert(cse->start_block != break_block); - vtn_cfg_walk_blocks(b, &cse->body, cse->start_block, cse, - break_block, NULL, loop_cont, NULL); - } - - /* Finally, we walk over all of the cases one more time and put - * them in fall-through order. - */ - for (const uint32_t *w = block->branch + 2; w < branch_end; w += 2) { - struct vtn_block *case_block = - vtn_value(b, *w, vtn_value_type_block)->block; - - if (case_block == break_block) - continue; - - assert(case_block->switch_case); - - vtn_order_case(swtch, case_block->switch_case); - } - - block = break_block; - continue; - } - - case SpvOpUnreachable: - return; - - default: - unreachable("Unhandled opcode"); - } - } -} - -void -vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, const uint32_t *end) -{ - vtn_foreach_instruction(b, words, end, - vtn_cfg_handle_prepass_instruction); - - foreach_list_typed(struct vtn_function, func, node, &b->functions) { - vtn_cfg_walk_blocks(b, &func->body, func->start_block, - NULL, NULL, NULL, NULL, NULL); - } -} - -static bool -vtn_handle_phis_first_pass(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - if (opcode == SpvOpLabel) - return true; /* Nothing to do */ - - /* If this isn't a phi node, stop. */ - if (opcode != SpvOpPhi) - return false; - - /* For handling phi nodes, we do a poor-man's out-of-ssa on the spot. - * For each phi, we create a variable with the appropreate type and - * do a load from that variable. Then, in a second pass, we add - * stores to that variable to each of the predecessor blocks. - * - * We could do something more intelligent here. However, in order to - * handle loops and things properly, we really need dominance - * information. It would end up basically being the into-SSA - * algorithm all over again. It's easier if we just let - * lower_vars_to_ssa do that for us instead of repeating it here. - */ - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - - struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; - nir_variable *phi_var = - nir_local_variable_create(b->nb.impl, type->type, "phi"); - _mesa_hash_table_insert(b->phi_table, w, phi_var); - - val->ssa = vtn_local_load(b, nir_deref_var_create(b, phi_var)); - - return true; -} - -static bool -vtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - if (opcode != SpvOpPhi) - return true; - - struct hash_entry *phi_entry = _mesa_hash_table_search(b->phi_table, w); - assert(phi_entry); - nir_variable *phi_var = phi_entry->data; - - for (unsigned i = 3; i < count; i += 2) { - struct vtn_ssa_value *src = vtn_ssa_value(b, w[i]); - struct vtn_block *pred = - vtn_value(b, w[i + 1], vtn_value_type_block)->block; - - b->nb.cursor = nir_after_block_before_jump(pred->end_block); - - vtn_local_store(b, src, nir_deref_var_create(b, phi_var)); - } - - return true; -} - -static void -vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type, - nir_variable *switch_fall_var, bool *has_switch_break) -{ - switch (branch_type) { - case vtn_branch_type_switch_break: - nir_store_var(&b->nb, switch_fall_var, nir_imm_int(&b->nb, NIR_FALSE), 1); - *has_switch_break = true; - break; - case vtn_branch_type_switch_fallthrough: - break; /* Nothing to do */ - case vtn_branch_type_loop_break: - nir_jump(&b->nb, nir_jump_break); - break; - case vtn_branch_type_loop_continue: - nir_jump(&b->nb, nir_jump_continue); - break; - case vtn_branch_type_return: - nir_jump(&b->nb, nir_jump_return); - break; - case vtn_branch_type_discard: { - nir_intrinsic_instr *discard = - nir_intrinsic_instr_create(b->nb.shader, nir_intrinsic_discard); - nir_builder_instr_insert(&b->nb, &discard->instr); - break; - } - default: - unreachable("Invalid branch type"); - } -} - -static void -vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list, - nir_variable *switch_fall_var, bool *has_switch_break, - vtn_instruction_handler handler) -{ - list_for_each_entry(struct vtn_cf_node, node, cf_list, link) { - switch (node->type) { - case vtn_cf_node_type_block: { - struct vtn_block *block = (struct vtn_block *)node; - - const uint32_t *block_start = block->label; - const uint32_t *block_end = block->merge ? block->merge : - block->branch; - - block_start = vtn_foreach_instruction(b, block_start, block_end, - vtn_handle_phis_first_pass); - - vtn_foreach_instruction(b, block_start, block_end, handler); - - block->end_block = nir_cursor_current_block(b->nb.cursor); - - if ((*block->branch & SpvOpCodeMask) == SpvOpReturnValue) { - struct vtn_ssa_value *src = vtn_ssa_value(b, block->branch[1]); - vtn_local_store(b, src, - nir_deref_var_create(b, b->impl->return_var)); - } - - if (block->branch_type != vtn_branch_type_none) { - vtn_emit_branch(b, block->branch_type, - switch_fall_var, has_switch_break); - } - - break; - } - - case vtn_cf_node_type_if: { - struct vtn_if *vtn_if = (struct vtn_if *)node; - - nir_if *if_stmt = nir_if_create(b->shader); - if_stmt->condition = - nir_src_for_ssa(vtn_ssa_value(b, vtn_if->condition)->def); - nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node); - - bool sw_break = false; - - b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); - if (vtn_if->then_type == vtn_branch_type_none) { - vtn_emit_cf_list(b, &vtn_if->then_body, - switch_fall_var, &sw_break, handler); - } else { - vtn_emit_branch(b, vtn_if->then_type, switch_fall_var, &sw_break); - } - - b->nb.cursor = nir_after_cf_list(&if_stmt->else_list); - if (vtn_if->else_type == vtn_branch_type_none) { - vtn_emit_cf_list(b, &vtn_if->else_body, - switch_fall_var, &sw_break, handler); - } else { - vtn_emit_branch(b, vtn_if->else_type, switch_fall_var, &sw_break); - } - - b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node); - - /* If we encountered a switch break somewhere inside of the if, - * then it would have been handled correctly by calling - * emit_cf_list or emit_branch for the interrior. However, we - * need to predicate everything following on wether or not we're - * still going. - */ - if (sw_break) { - *has_switch_break = true; - - nir_if *switch_if = nir_if_create(b->shader); - switch_if->condition = - nir_src_for_ssa(nir_load_var(&b->nb, switch_fall_var)); - nir_cf_node_insert(b->nb.cursor, &switch_if->cf_node); - - b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); - } - break; - } - - case vtn_cf_node_type_loop: { - struct vtn_loop *vtn_loop = (struct vtn_loop *)node; - - nir_loop *loop = nir_loop_create(b->shader); - nir_cf_node_insert(b->nb.cursor, &loop->cf_node); - - b->nb.cursor = nir_after_cf_list(&loop->body); - vtn_emit_cf_list(b, &vtn_loop->body, NULL, NULL, handler); - - if (!list_empty(&vtn_loop->cont_body)) { - /* If we have a non-trivial continue body then we need to put - * it at the beginning of the loop with a flag to ensure that - * it doesn't get executed in the first iteration. - */ - nir_variable *do_cont = - nir_local_variable_create(b->nb.impl, glsl_bool_type(), "cont"); - - b->nb.cursor = nir_before_cf_node(&loop->cf_node); - nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_FALSE), 1); - - b->nb.cursor = nir_before_cf_list(&loop->body); - nir_if *cont_if = nir_if_create(b->shader); - cont_if->condition = nir_src_for_ssa(nir_load_var(&b->nb, do_cont)); - nir_cf_node_insert(b->nb.cursor, &cont_if->cf_node); - - b->nb.cursor = nir_after_cf_list(&cont_if->then_list); - vtn_emit_cf_list(b, &vtn_loop->cont_body, NULL, NULL, handler); - - b->nb.cursor = nir_after_cf_node(&cont_if->cf_node); - nir_store_var(&b->nb, do_cont, nir_imm_int(&b->nb, NIR_TRUE), 1); - - b->has_loop_continue = true; - } - - b->nb.cursor = nir_after_cf_node(&loop->cf_node); - break; - } - - case vtn_cf_node_type_switch: { - struct vtn_switch *vtn_switch = (struct vtn_switch *)node; - - /* First, we create a variable to keep track of whether or not the - * switch is still going at any given point. Any switch breaks - * will set this variable to false. - */ - nir_variable *fall_var = - nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall"); - nir_store_var(&b->nb, fall_var, nir_imm_int(&b->nb, NIR_FALSE), 1); - - /* Next, we gather up all of the conditions. We have to do this - * up-front because we also need to build an "any" condition so - * that we can use !any for default. - */ - const int num_cases = list_length(&vtn_switch->cases); - NIR_VLA(nir_ssa_def *, conditions, num_cases); - - nir_ssa_def *sel = vtn_ssa_value(b, vtn_switch->selector)->def; - /* An accumulation of all conditions. Used for the default */ - nir_ssa_def *any = NULL; - - int i = 0; - list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) { - if (cse->is_default) { - conditions[i++] = NULL; - continue; - } - - nir_ssa_def *cond = NULL; - nir_array_foreach(&cse->values, uint32_t, val) { - nir_ssa_def *is_val = - nir_ieq(&b->nb, sel, nir_imm_int(&b->nb, *val)); - - cond = cond ? nir_ior(&b->nb, cond, is_val) : is_val; - } - - any = any ? nir_ior(&b->nb, any, cond) : cond; - conditions[i++] = cond; - } - assert(i == num_cases); - - /* Now we can walk the list of cases and actually emit code */ - i = 0; - list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) { - /* Figure out the condition */ - nir_ssa_def *cond = conditions[i++]; - if (cse->is_default) { - assert(cond == NULL); - cond = nir_inot(&b->nb, any); - } - /* Take fallthrough into account */ - cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var)); - - nir_if *case_if = nir_if_create(b->nb.shader); - case_if->condition = nir_src_for_ssa(cond); - nir_cf_node_insert(b->nb.cursor, &case_if->cf_node); - - bool has_break = false; - b->nb.cursor = nir_after_cf_list(&case_if->then_list); - nir_store_var(&b->nb, fall_var, nir_imm_int(&b->nb, NIR_TRUE), 1); - vtn_emit_cf_list(b, &cse->body, fall_var, &has_break, handler); - (void)has_break; /* We don't care */ - - b->nb.cursor = nir_after_cf_node(&case_if->cf_node); - } - assert(i == num_cases); - - break; - } - - default: - unreachable("Invalid CF node type"); - } - } -} - -void -vtn_function_emit(struct vtn_builder *b, struct vtn_function *func, - vtn_instruction_handler instruction_handler) -{ - nir_builder_init(&b->nb, func->impl); - b->nb.cursor = nir_after_cf_list(&func->impl->body); - b->has_loop_continue = false; - b->phi_table = _mesa_hash_table_create(b, _mesa_hash_pointer, - _mesa_key_pointer_equal); - - vtn_emit_cf_list(b, &func->body, NULL, NULL, instruction_handler); - - vtn_foreach_instruction(b, func->start_block->label, func->end, - vtn_handle_phi_second_pass); - - /* Continue blocks for loops get inserted before the body of the loop - * but instructions in the continue may use SSA defs in the loop body. - * Therefore, we need to repair SSA to insert the needed phi nodes. - */ - if (b->has_loop_continue) - nir_repair_ssa_impl(func->impl); -} diff --git a/src/glsl/nir/spirv/vtn_glsl450.c b/src/glsl/nir/spirv/vtn_glsl450.c deleted file mode 100644 index bc38aa4b1be..00000000000 --- a/src/glsl/nir/spirv/vtn_glsl450.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "vtn_private.h" -#include "GLSL.std.450.h" - -#define M_PIf ((float) M_PI) -#define M_PI_2f ((float) M_PI_2) -#define M_PI_4f ((float) M_PI_4) - -static nir_ssa_def * -build_mat2_det(nir_builder *b, nir_ssa_def *col[2]) -{ - unsigned swiz[4] = {1, 0, 0, 0}; - nir_ssa_def *p = nir_fmul(b, col[0], nir_swizzle(b, col[1], swiz, 2, true)); - return nir_fsub(b, nir_channel(b, p, 0), nir_channel(b, p, 1)); -} - -static nir_ssa_def * -build_mat3_det(nir_builder *b, nir_ssa_def *col[3]) -{ - unsigned yzx[4] = {1, 2, 0, 0}; - unsigned zxy[4] = {2, 0, 1, 0}; - - nir_ssa_def *prod0 = - nir_fmul(b, col[0], - nir_fmul(b, nir_swizzle(b, col[1], yzx, 3, true), - nir_swizzle(b, col[2], zxy, 3, true))); - nir_ssa_def *prod1 = - nir_fmul(b, col[0], - nir_fmul(b, nir_swizzle(b, col[1], zxy, 3, true), - nir_swizzle(b, col[2], yzx, 3, true))); - - nir_ssa_def *diff = nir_fsub(b, prod0, prod1); - - return nir_fadd(b, nir_channel(b, diff, 0), - nir_fadd(b, nir_channel(b, diff, 1), - nir_channel(b, diff, 2))); -} - -static nir_ssa_def * -build_mat4_det(nir_builder *b, nir_ssa_def **col) -{ - nir_ssa_def *subdet[4]; - for (unsigned i = 0; i < 4; i++) { - unsigned swiz[3]; - for (unsigned j = 0, k = 0; j < 3; j++, k++) { - if (k == i) - k++; /* skip column */ - swiz[j] = k; - } - - nir_ssa_def *subcol[3]; - subcol[0] = nir_swizzle(b, col[1], swiz, 3, true); - subcol[1] = nir_swizzle(b, col[2], swiz, 3, true); - subcol[2] = nir_swizzle(b, col[3], swiz, 3, true); - - subdet[i] = build_mat3_det(b, subcol); - } - - nir_ssa_def *prod = nir_fmul(b, col[0], nir_vec(b, subdet, 4)); - - return nir_fadd(b, nir_fsub(b, nir_channel(b, prod, 0), - nir_channel(b, prod, 1)), - nir_fsub(b, nir_channel(b, prod, 2), - nir_channel(b, prod, 3))); -} - -static nir_ssa_def * -build_mat_det(struct vtn_builder *b, struct vtn_ssa_value *src) -{ - unsigned size = glsl_get_vector_elements(src->type); - - nir_ssa_def *cols[4]; - for (unsigned i = 0; i < size; i++) - cols[i] = src->elems[i]->def; - - switch(size) { - case 2: return build_mat2_det(&b->nb, cols); - case 3: return build_mat3_det(&b->nb, cols); - case 4: return build_mat4_det(&b->nb, cols); - default: - unreachable("Invalid matrix size"); - } -} - -/* Computes the determinate of the submatrix given by taking src and - * removing the specified row and column. - */ -static nir_ssa_def * -build_mat_subdet(struct nir_builder *b, struct vtn_ssa_value *src, - unsigned size, unsigned row, unsigned col) -{ - assert(row < size && col < size); - if (size == 2) { - return nir_channel(b, src->elems[1 - col]->def, 1 - row); - } else { - /* Swizzle to get all but the specified row */ - unsigned swiz[3]; - for (unsigned j = 0; j < 4; j++) - swiz[j - (j > row)] = j; - - /* Grab all but the specified column */ - nir_ssa_def *subcol[3]; - for (unsigned j = 0; j < size; j++) { - if (j != col) { - subcol[j - (j > col)] = nir_swizzle(b, src->elems[j]->def, - swiz, size - 1, true); - } - } - - if (size == 3) { - return build_mat2_det(b, subcol); - } else { - assert(size == 4); - return build_mat3_det(b, subcol); - } - } -} - -static struct vtn_ssa_value * -matrix_inverse(struct vtn_builder *b, struct vtn_ssa_value *src) -{ - nir_ssa_def *adj_col[4]; - unsigned size = glsl_get_vector_elements(src->type); - - /* Build up an adjugate matrix */ - for (unsigned c = 0; c < size; c++) { - nir_ssa_def *elem[4]; - for (unsigned r = 0; r < size; r++) { - elem[r] = build_mat_subdet(&b->nb, src, size, c, r); - - if ((r + c) % 2) - elem[r] = nir_fneg(&b->nb, elem[r]); - } - - adj_col[c] = nir_vec(&b->nb, elem, size); - } - - nir_ssa_def *det_inv = nir_frcp(&b->nb, build_mat_det(b, src)); - - struct vtn_ssa_value *val = vtn_create_ssa_value(b, src->type); - for (unsigned i = 0; i < size; i++) - val->elems[i]->def = nir_fmul(&b->nb, adj_col[i], det_inv); - - return val; -} - -static nir_ssa_def* -build_length(nir_builder *b, nir_ssa_def *vec) -{ - switch (vec->num_components) { - case 1: return nir_fsqrt(b, nir_fmul(b, vec, vec)); - case 2: return nir_fsqrt(b, nir_fdot2(b, vec, vec)); - case 3: return nir_fsqrt(b, nir_fdot3(b, vec, vec)); - case 4: return nir_fsqrt(b, nir_fdot4(b, vec, vec)); - default: - unreachable("Invalid number of components"); - } -} - -static inline nir_ssa_def * -build_fclamp(nir_builder *b, - nir_ssa_def *x, nir_ssa_def *min_val, nir_ssa_def *max_val) -{ - return nir_fmin(b, nir_fmax(b, x, min_val), max_val); -} - -/** - * Return e^x. - */ -static nir_ssa_def * -build_exp(nir_builder *b, nir_ssa_def *x) -{ - return nir_fexp2(b, nir_fmul(b, x, nir_imm_float(b, M_LOG2E))); -} - -/** - * Return ln(x) - the natural logarithm of x. - */ -static nir_ssa_def * -build_log(nir_builder *b, nir_ssa_def *x) -{ - return nir_fmul(b, nir_flog2(b, x), nir_imm_float(b, 1.0 / M_LOG2E)); -} - -static nir_ssa_def * -build_asin(nir_builder *b, nir_ssa_def *x) -{ - /* - * asin(x) = sign(x) * (pi/2 - sqrt(1 - |x|) * (pi / 4 - 1 + |x| * (0.086566724 + |x| * -0.03102955))) - */ - nir_ssa_def *abs_x = nir_fabs(b, x); - return nir_fmul(b, nir_fsign(b, x), - nir_fsub(b, nir_imm_float(b, M_PI_2f), - nir_fmul(b, nir_fsqrt(b, nir_fsub(b, nir_imm_float(b, 1.0f), abs_x)), - nir_fadd(b, nir_imm_float(b, M_PI_2f), - nir_fmul(b, abs_x, - nir_fadd(b, nir_imm_float(b, M_PI_4f - 1.0f), - nir_fmul(b, abs_x, - nir_fadd(b, nir_imm_float(b, 0.086566724f), - nir_fmul(b, abs_x, - nir_imm_float(b, -0.03102955f)))))))))); -} - -static nir_ssa_def * -build_acos(nir_builder *b, nir_ssa_def *x) -{ - /* - * poly(x) = sign(x) * sqrt(1 - |x|) * (pi / 2 + |x| * (pi / 4 - 1 + |x| * (0.08132463 + |x| * -0.02363318))) - */ - nir_ssa_def *abs_x = nir_fabs(b, x); - nir_ssa_def *poly = nir_fmul(b, nir_fsqrt(b, nir_fsub(b, nir_imm_float(b, 1.0f), abs_x)), - nir_fadd(b, nir_imm_float(b, M_PI_2f), - nir_fmul(b, abs_x, - nir_fadd(b, nir_imm_float(b, M_PI_4f - 1.0f), - nir_fmul(b, abs_x, - nir_fadd(b, nir_imm_float(b, 0.08132463f), - nir_fmul(b, abs_x, - nir_imm_float(b, -0.02363318f)))))))); - return nir_bcsel(b, nir_flt(b, x, nir_imm_float(b, 0)), - nir_fsub(b, nir_imm_float(b, M_PI), poly), - poly); -} - -/** - * Compute xs[0] + xs[1] + xs[2] + ... using fadd. - */ -static nir_ssa_def * -build_fsum(nir_builder *b, nir_ssa_def **xs, int terms) -{ - nir_ssa_def *accum = xs[0]; - - for (int i = 1; i < terms; i++) - accum = nir_fadd(b, accum, xs[i]); - - return accum; -} - -static nir_ssa_def * -build_atan(nir_builder *b, nir_ssa_def *y_over_x) -{ - nir_ssa_def *abs_y_over_x = nir_fabs(b, y_over_x); - nir_ssa_def *one = nir_imm_float(b, 1.0f); - - /* - * range-reduction, first step: - * - * / y_over_x if |y_over_x| <= 1.0; - * x = < - * \ 1.0 / y_over_x otherwise - */ - nir_ssa_def *x = nir_fdiv(b, nir_fmin(b, abs_y_over_x, one), - nir_fmax(b, abs_y_over_x, one)); - - /* - * approximate atan by evaluating polynomial: - * - * x * 0.9999793128310355 - x^3 * 0.3326756418091246 + - * x^5 * 0.1938924977115610 - x^7 * 0.1173503194786851 + - * x^9 * 0.0536813784310406 - x^11 * 0.0121323213173444 - */ - nir_ssa_def *x_2 = nir_fmul(b, x, x); - nir_ssa_def *x_3 = nir_fmul(b, x_2, x); - nir_ssa_def *x_5 = nir_fmul(b, x_3, x_2); - nir_ssa_def *x_7 = nir_fmul(b, x_5, x_2); - nir_ssa_def *x_9 = nir_fmul(b, x_7, x_2); - nir_ssa_def *x_11 = nir_fmul(b, x_9, x_2); - - nir_ssa_def *polynomial_terms[] = { - nir_fmul(b, x, nir_imm_float(b, 0.9999793128310355f)), - nir_fmul(b, x_3, nir_imm_float(b, -0.3326756418091246f)), - nir_fmul(b, x_5, nir_imm_float(b, 0.1938924977115610f)), - nir_fmul(b, x_7, nir_imm_float(b, -0.1173503194786851f)), - nir_fmul(b, x_9, nir_imm_float(b, 0.0536813784310406f)), - nir_fmul(b, x_11, nir_imm_float(b, -0.0121323213173444f)), - }; - - nir_ssa_def *tmp = - build_fsum(b, polynomial_terms, ARRAY_SIZE(polynomial_terms)); - - /* range-reduction fixup */ - tmp = nir_fadd(b, tmp, - nir_fmul(b, - nir_b2f(b, nir_flt(b, one, abs_y_over_x)), - nir_fadd(b, nir_fmul(b, tmp, - nir_imm_float(b, -2.0f)), - nir_imm_float(b, M_PI_2f)))); - - /* sign fixup */ - return nir_fmul(b, tmp, nir_fsign(b, y_over_x)); -} - -static nir_ssa_def * -build_atan2(nir_builder *b, nir_ssa_def *y, nir_ssa_def *x) -{ - nir_ssa_def *zero = nir_imm_float(b, 0.0f); - - /* If |x| >= 1.0e-8 * |y|: */ - nir_ssa_def *condition = - nir_fge(b, nir_fabs(b, x), - nir_fmul(b, nir_imm_float(b, 1.0e-8f), nir_fabs(b, y))); - - /* Then...call atan(y/x) and fix it up: */ - nir_ssa_def *atan1 = build_atan(b, nir_fdiv(b, y, x)); - nir_ssa_def *r_then = - nir_bcsel(b, nir_flt(b, x, zero), - nir_fadd(b, atan1, - nir_bcsel(b, nir_fge(b, y, zero), - nir_imm_float(b, M_PIf), - nir_imm_float(b, -M_PIf))), - atan1); - - /* Else... */ - nir_ssa_def *r_else = - nir_fmul(b, nir_fsign(b, y), nir_imm_float(b, M_PI_2f)); - - return nir_bcsel(b, condition, r_then, r_else); -} - -static nir_ssa_def * -build_frexp(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent) -{ - nir_ssa_def *abs_x = nir_fabs(b, x); - nir_ssa_def *zero = nir_imm_float(b, 0.0f); - - /* Single-precision floating-point values are stored as - * 1 sign bit; - * 8 exponent bits; - * 23 mantissa bits. - * - * An exponent shift of 23 will shift the mantissa out, leaving only the - * exponent and sign bit (which itself may be zero, if the absolute value - * was taken before the bitcast and shift. - */ - nir_ssa_def *exponent_shift = nir_imm_int(b, 23); - nir_ssa_def *exponent_bias = nir_imm_int(b, -126); - - nir_ssa_def *sign_mantissa_mask = nir_imm_int(b, 0x807fffffu); - - /* Exponent of floating-point values in the range [0.5, 1.0). */ - nir_ssa_def *exponent_value = nir_imm_int(b, 0x3f000000u); - - nir_ssa_def *is_not_zero = nir_fne(b, abs_x, zero); - - *exponent = - nir_iadd(b, nir_ushr(b, abs_x, exponent_shift), - nir_bcsel(b, is_not_zero, exponent_bias, zero)); - - return nir_ior(b, nir_iand(b, x, sign_mantissa_mask), - nir_bcsel(b, is_not_zero, exponent_value, zero)); -} - -static void -handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint, - const uint32_t *w, unsigned count) -{ - struct nir_builder *nb = &b->nb; - const struct glsl_type *dest_type = - vtn_value(b, w[1], vtn_value_type_type)->type->type; - - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->ssa = vtn_create_ssa_value(b, dest_type); - - /* Collect the various SSA sources */ - unsigned num_inputs = count - 5; - nir_ssa_def *src[3]; - for (unsigned i = 0; i < num_inputs; i++) - src[i] = vtn_ssa_value(b, w[i + 5])->def; - - nir_op op; - switch (entrypoint) { - case GLSLstd450Round: op = nir_op_fround_even; break; /* TODO */ - case GLSLstd450RoundEven: op = nir_op_fround_even; break; - case GLSLstd450Trunc: op = nir_op_ftrunc; break; - case GLSLstd450FAbs: op = nir_op_fabs; break; - case GLSLstd450SAbs: op = nir_op_iabs; break; - case GLSLstd450FSign: op = nir_op_fsign; break; - case GLSLstd450SSign: op = nir_op_isign; break; - case GLSLstd450Floor: op = nir_op_ffloor; break; - case GLSLstd450Ceil: op = nir_op_fceil; break; - case GLSLstd450Fract: op = nir_op_ffract; break; - case GLSLstd450Radians: - val->ssa->def = nir_fmul(nb, src[0], nir_imm_float(nb, 0.01745329251)); - return; - case GLSLstd450Degrees: - val->ssa->def = nir_fmul(nb, src[0], nir_imm_float(nb, 57.2957795131)); - return; - case GLSLstd450Sin: op = nir_op_fsin; break; - case GLSLstd450Cos: op = nir_op_fcos; break; - case GLSLstd450Tan: - val->ssa->def = nir_fdiv(nb, nir_fsin(nb, src[0]), - nir_fcos(nb, src[0])); - return; - case GLSLstd450Pow: op = nir_op_fpow; break; - case GLSLstd450Exp2: op = nir_op_fexp2; break; - case GLSLstd450Log2: op = nir_op_flog2; break; - case GLSLstd450Sqrt: op = nir_op_fsqrt; break; - case GLSLstd450InverseSqrt: op = nir_op_frsq; break; - - case GLSLstd450Modf: { - nir_ssa_def *sign = nir_fsign(nb, src[0]); - nir_ssa_def *abs = nir_fabs(nb, src[0]); - val->ssa->def = nir_fmul(nb, sign, nir_ffract(nb, abs)); - nir_store_deref_var(nb, vtn_nir_deref(b, w[6]), - nir_fmul(nb, sign, nir_ffloor(nb, abs)), 0xf); - return; - } - - case GLSLstd450ModfStruct: { - nir_ssa_def *sign = nir_fsign(nb, src[0]); - nir_ssa_def *abs = nir_fabs(nb, src[0]); - assert(glsl_type_is_struct(val->ssa->type)); - val->ssa->elems[0]->def = nir_fmul(nb, sign, nir_ffract(nb, abs)); - val->ssa->elems[1]->def = nir_fmul(nb, sign, nir_ffloor(nb, abs)); - return; - } - - case GLSLstd450FMin: op = nir_op_fmin; break; - case GLSLstd450UMin: op = nir_op_umin; break; - case GLSLstd450SMin: op = nir_op_imin; break; - case GLSLstd450FMax: op = nir_op_fmax; break; - case GLSLstd450UMax: op = nir_op_umax; break; - case GLSLstd450SMax: op = nir_op_imax; break; - case GLSLstd450FMix: op = nir_op_flrp; break; - case GLSLstd450Step: - val->ssa->def = nir_sge(nb, src[1], src[0]); - return; - - case GLSLstd450Fma: op = nir_op_ffma; break; - case GLSLstd450Ldexp: op = nir_op_ldexp; break; - - /* Packing/Unpacking functions */ - case GLSLstd450PackSnorm4x8: op = nir_op_pack_snorm_4x8; break; - case GLSLstd450PackUnorm4x8: op = nir_op_pack_unorm_4x8; break; - case GLSLstd450PackSnorm2x16: op = nir_op_pack_snorm_2x16; break; - case GLSLstd450PackUnorm2x16: op = nir_op_pack_unorm_2x16; break; - case GLSLstd450PackHalf2x16: op = nir_op_pack_half_2x16; break; - case GLSLstd450UnpackSnorm4x8: op = nir_op_unpack_snorm_4x8; break; - case GLSLstd450UnpackUnorm4x8: op = nir_op_unpack_unorm_4x8; break; - case GLSLstd450UnpackSnorm2x16: op = nir_op_unpack_snorm_2x16; break; - case GLSLstd450UnpackUnorm2x16: op = nir_op_unpack_unorm_2x16; break; - case GLSLstd450UnpackHalf2x16: op = nir_op_unpack_half_2x16; break; - - case GLSLstd450Length: - val->ssa->def = build_length(nb, src[0]); - return; - case GLSLstd450Distance: - val->ssa->def = build_length(nb, nir_fsub(nb, src[0], src[1])); - return; - case GLSLstd450Normalize: - val->ssa->def = nir_fdiv(nb, src[0], build_length(nb, src[0])); - return; - - case GLSLstd450Exp: - val->ssa->def = build_exp(nb, src[0]); - return; - - case GLSLstd450Log: - val->ssa->def = build_log(nb, src[0]); - return; - - case GLSLstd450FClamp: - val->ssa->def = build_fclamp(nb, src[0], src[1], src[2]); - return; - case GLSLstd450UClamp: - val->ssa->def = nir_umin(nb, nir_umax(nb, src[0], src[1]), src[2]); - return; - case GLSLstd450SClamp: - val->ssa->def = nir_imin(nb, nir_imax(nb, src[0], src[1]), src[2]); - return; - - case GLSLstd450Cross: { - unsigned yzx[4] = { 1, 2, 0, 0 }; - unsigned zxy[4] = { 2, 0, 1, 0 }; - val->ssa->def = - nir_fsub(nb, nir_fmul(nb, nir_swizzle(nb, src[0], yzx, 3, true), - nir_swizzle(nb, src[1], zxy, 3, true)), - nir_fmul(nb, nir_swizzle(nb, src[0], zxy, 3, true), - nir_swizzle(nb, src[1], yzx, 3, true))); - return; - } - - case GLSLstd450SmoothStep: { - /* t = clamp((x - edge0) / (edge1 - edge0), 0, 1) */ - nir_ssa_def *t = - build_fclamp(nb, nir_fdiv(nb, nir_fsub(nb, src[2], src[0]), - nir_fsub(nb, src[1], src[0])), - nir_imm_float(nb, 0.0), nir_imm_float(nb, 1.0)); - /* result = t * t * (3 - 2 * t) */ - val->ssa->def = - nir_fmul(nb, t, nir_fmul(nb, t, - nir_fsub(nb, nir_imm_float(nb, 3.0), - nir_fmul(nb, nir_imm_float(nb, 2.0), t)))); - return; - } - - case GLSLstd450FaceForward: - val->ssa->def = - nir_bcsel(nb, nir_flt(nb, nir_fdot(nb, src[2], src[1]), - nir_imm_float(nb, 0.0)), - src[0], nir_fneg(nb, src[0])); - return; - - case GLSLstd450Reflect: - /* I - 2 * dot(N, I) * N */ - val->ssa->def = - nir_fsub(nb, src[0], nir_fmul(nb, nir_imm_float(nb, 2.0), - nir_fmul(nb, nir_fdot(nb, src[0], src[1]), - src[1]))); - return; - - case GLSLstd450Refract: { - nir_ssa_def *I = src[0]; - nir_ssa_def *N = src[1]; - nir_ssa_def *eta = src[2]; - nir_ssa_def *n_dot_i = nir_fdot(nb, N, I); - nir_ssa_def *one = nir_imm_float(nb, 1.0); - nir_ssa_def *zero = nir_imm_float(nb, 0.0); - /* k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I)) */ - nir_ssa_def *k = - nir_fsub(nb, one, nir_fmul(nb, eta, nir_fmul(nb, eta, - nir_fsub(nb, one, nir_fmul(nb, n_dot_i, n_dot_i))))); - nir_ssa_def *result = - nir_fsub(nb, nir_fmul(nb, eta, I), - nir_fmul(nb, nir_fadd(nb, nir_fmul(nb, eta, n_dot_i), - nir_fsqrt(nb, k)), N)); - /* XXX: bcsel, or if statement? */ - val->ssa->def = nir_bcsel(nb, nir_flt(nb, k, zero), zero, result); - return; - } - - case GLSLstd450Sinh: - /* 0.5 * (e^x - e^(-x)) */ - val->ssa->def = - nir_fmul(nb, nir_imm_float(nb, 0.5f), - nir_fsub(nb, build_exp(nb, src[0]), - build_exp(nb, nir_fneg(nb, src[0])))); - return; - - case GLSLstd450Cosh: - /* 0.5 * (e^x + e^(-x)) */ - val->ssa->def = - nir_fmul(nb, nir_imm_float(nb, 0.5f), - nir_fadd(nb, build_exp(nb, src[0]), - build_exp(nb, nir_fneg(nb, src[0])))); - return; - - case GLSLstd450Tanh: - /* (0.5 * (e^x - e^(-x))) / (0.5 * (e^x + e^(-x))) */ - val->ssa->def = - nir_fdiv(nb, nir_fmul(nb, nir_imm_float(nb, 0.5f), - nir_fsub(nb, build_exp(nb, src[0]), - build_exp(nb, nir_fneg(nb, src[0])))), - nir_fmul(nb, nir_imm_float(nb, 0.5f), - nir_fadd(nb, build_exp(nb, src[0]), - build_exp(nb, nir_fneg(nb, src[0]))))); - return; - - case GLSLstd450Asinh: - val->ssa->def = nir_fmul(nb, nir_fsign(nb, src[0]), - build_log(nb, nir_fadd(nb, nir_fabs(nb, src[0]), - nir_fsqrt(nb, nir_fadd(nb, nir_fmul(nb, src[0], src[0]), - nir_imm_float(nb, 1.0f)))))); - return; - case GLSLstd450Acosh: - val->ssa->def = build_log(nb, nir_fadd(nb, src[0], - nir_fsqrt(nb, nir_fsub(nb, nir_fmul(nb, src[0], src[0]), - nir_imm_float(nb, 1.0f))))); - return; - case GLSLstd450Atanh: { - nir_ssa_def *one = nir_imm_float(nb, 1.0); - val->ssa->def = nir_fmul(nb, nir_imm_float(nb, 0.5f), - build_log(nb, nir_fdiv(nb, nir_fadd(nb, one, src[0]), - nir_fsub(nb, one, src[0])))); - return; - } - - case GLSLstd450FindILsb: op = nir_op_find_lsb; break; - case GLSLstd450FindSMsb: op = nir_op_ifind_msb; break; - case GLSLstd450FindUMsb: op = nir_op_ufind_msb; break; - - case GLSLstd450Asin: - val->ssa->def = build_asin(nb, src[0]); - return; - - case GLSLstd450Acos: - val->ssa->def = build_acos(nb, src[0]); - return; - - case GLSLstd450Atan: - val->ssa->def = build_atan(nb, src[0]); - return; - - case GLSLstd450Atan2: - val->ssa->def = build_atan2(nb, src[0], src[1]); - return; - - case GLSLstd450Frexp: { - nir_ssa_def *exponent; - val->ssa->def = build_frexp(nb, src[0], &exponent); - nir_store_deref_var(nb, vtn_nir_deref(b, w[6]), exponent, 0xf); - return; - } - - case GLSLstd450FrexpStruct: { - assert(glsl_type_is_struct(val->ssa->type)); - val->ssa->elems[0]->def = build_frexp(nb, src[0], - &val->ssa->elems[1]->def); - return; - } - - case GLSLstd450PackDouble2x32: - case GLSLstd450UnpackDouble2x32: - default: - unreachable("Unhandled opcode"); - } - - nir_alu_instr *instr = nir_alu_instr_create(b->shader, op); - nir_ssa_dest_init(&instr->instr, &instr->dest.dest, - glsl_get_vector_elements(val->ssa->type), val->name); - instr->dest.write_mask = (1 << instr->dest.dest.ssa.num_components) - 1; - val->ssa->def = &instr->dest.dest.ssa; - - for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) - instr->src[i].src = nir_src_for_ssa(src[i]); - - nir_builder_instr_insert(nb, &instr->instr); -} - -bool -vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode, - const uint32_t *w, unsigned count) -{ - switch ((enum GLSLstd450)ext_opcode) { - case GLSLstd450Determinant: { - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->ssa = rzalloc(b, struct vtn_ssa_value); - val->ssa->type = vtn_value(b, w[1], vtn_value_type_type)->type->type; - val->ssa->def = build_mat_det(b, vtn_ssa_value(b, w[5])); - break; - } - - case GLSLstd450MatrixInverse: { - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->ssa = matrix_inverse(b, vtn_ssa_value(b, w[5])); - break; - } - - case GLSLstd450InterpolateAtCentroid: - case GLSLstd450InterpolateAtSample: - case GLSLstd450InterpolateAtOffset: - unreachable("Unhandled opcode"); - - default: - handle_glsl450_alu(b, (enum GLSLstd450)ext_opcode, w, count); - } - - return true; -} diff --git a/src/glsl/nir/spirv/vtn_private.h b/src/glsl/nir/spirv/vtn_private.h deleted file mode 100644 index 3840d8c4b65..00000000000 --- a/src/glsl/nir/spirv/vtn_private.h +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "nir/nir.h" -#include "nir/nir_builder.h" -#include "nir/nir_array.h" -#include "nir_spirv.h" -#include "spirv.h" - -struct vtn_builder; -struct vtn_decoration; - -enum vtn_value_type { - vtn_value_type_invalid = 0, - vtn_value_type_undef, - vtn_value_type_string, - vtn_value_type_decoration_group, - vtn_value_type_type, - vtn_value_type_constant, - vtn_value_type_access_chain, - vtn_value_type_function, - vtn_value_type_block, - vtn_value_type_ssa, - vtn_value_type_extension, - vtn_value_type_image_pointer, - vtn_value_type_sampled_image, -}; - -enum vtn_branch_type { - vtn_branch_type_none, - vtn_branch_type_switch_break, - vtn_branch_type_switch_fallthrough, - vtn_branch_type_loop_break, - vtn_branch_type_loop_continue, - vtn_branch_type_discard, - vtn_branch_type_return, -}; - -enum vtn_cf_node_type { - vtn_cf_node_type_block, - vtn_cf_node_type_if, - vtn_cf_node_type_loop, - vtn_cf_node_type_switch, -}; - -struct vtn_cf_node { - struct list_head link; - enum vtn_cf_node_type type; -}; - -struct vtn_loop { - struct vtn_cf_node node; - - /* The main body of the loop */ - struct list_head body; - - /* The "continue" part of the loop. This gets executed after the body - * and is where you go when you hit a continue. - */ - struct list_head cont_body; - - SpvLoopControlMask control; -}; - -struct vtn_if { - struct vtn_cf_node node; - - uint32_t condition; - - enum vtn_branch_type then_type; - struct list_head then_body; - - enum vtn_branch_type else_type; - struct list_head else_body; - - SpvSelectionControlMask control; -}; - -struct vtn_case { - struct list_head link; - - struct list_head body; - - /* The block that starts this case */ - struct vtn_block *start_block; - - /* The fallthrough case, if any */ - struct vtn_case *fallthrough; - - /* The uint32_t values that map to this case */ - nir_array values; - - /* True if this is the default case */ - bool is_default; - - /* Initialized to false; used when sorting the list of cases */ - bool visited; -}; - -struct vtn_switch { - struct vtn_cf_node node; - - uint32_t selector; - - struct list_head cases; -}; - -struct vtn_block { - struct vtn_cf_node node; - - /** A pointer to the label instruction */ - const uint32_t *label; - - /** A pointer to the merge instruction (or NULL if non exists) */ - const uint32_t *merge; - - /** A pointer to the branch instruction that ends this block */ - const uint32_t *branch; - - enum vtn_branch_type branch_type; - - /** Points to the loop that this block starts (if it starts a loop) */ - struct vtn_loop *loop; - - /** Points to the switch case started by this block (if any) */ - struct vtn_case *switch_case; - - /** The last block in this SPIR-V block. */ - nir_block *end_block; -}; - -struct vtn_function { - struct exec_node node; - - nir_function_impl *impl; - struct vtn_block *start_block; - - struct list_head body; - - const uint32_t *end; - - SpvFunctionControlMask control; -}; - -typedef bool (*vtn_instruction_handler)(struct vtn_builder *, uint32_t, - const uint32_t *, unsigned); - -void vtn_build_cfg(struct vtn_builder *b, const uint32_t *words, - const uint32_t *end); -void vtn_function_emit(struct vtn_builder *b, struct vtn_function *func, - vtn_instruction_handler instruction_handler); - -const uint32_t * -vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start, - const uint32_t *end, vtn_instruction_handler handler); - -struct vtn_ssa_value { - union { - nir_ssa_def *def; - struct vtn_ssa_value **elems; - }; - - /* For matrices, if this is non-NULL, then this value is actually the - * transpose of some other value. The value that `transposed` points to - * always dominates this value. - */ - struct vtn_ssa_value *transposed; - - const struct glsl_type *type; -}; - -struct vtn_type { - const struct glsl_type *type; - - /* The value that declares this type. Used for finding decorations */ - struct vtn_value *val; - - /* for matrices, whether the matrix is stored row-major */ - bool row_major; - - /* for structs, the offset of each member */ - unsigned *offsets; - - /* for structs, whether it was decorated as a "non-SSBO-like" block */ - bool block; - - /* for structs, whether it was decorated as an "SSBO-like" block */ - bool buffer_block; - - /* for structs with block == true, whether this is a builtin block (i.e. a - * block that contains only builtins). - */ - bool builtin_block; - - /* Image format for image_load_store type images */ - unsigned image_format; - - /* Access qualifier for storage images */ - SpvAccessQualifier access_qualifier; - - /* for arrays and matrices, the array stride */ - unsigned stride; - - /* for arrays, the vtn_type for the elements of the array */ - struct vtn_type *array_element; - - /* for structures, the vtn_type for each member */ - struct vtn_type **members; - - /* Whether this type, or a parent type, has been decorated as a builtin */ - bool is_builtin; - - SpvBuiltIn builtin; -}; - -struct vtn_variable; - -enum vtn_access_mode { - vtn_access_mode_id, - vtn_access_mode_literal, -}; - -struct vtn_access_link { - enum vtn_access_mode mode; - uint32_t id; -}; - -struct vtn_access_chain { - struct vtn_variable *var; - - uint32_t length; - - /* Struct elements and array offsets */ - struct vtn_access_link link[0]; -}; - -enum vtn_variable_mode { - vtn_variable_mode_local, - vtn_variable_mode_global, - vtn_variable_mode_param, - vtn_variable_mode_ubo, - vtn_variable_mode_ssbo, - vtn_variable_mode_push_constant, - vtn_variable_mode_image, - vtn_variable_mode_sampler, - vtn_variable_mode_workgroup, - vtn_variable_mode_input, - vtn_variable_mode_output, -}; - -struct vtn_variable { - enum vtn_variable_mode mode; - - struct vtn_type *type; - - unsigned descriptor_set; - unsigned binding; - - nir_variable *var; - nir_variable **members; - - struct vtn_access_chain chain; -}; - -struct vtn_image_pointer { - struct vtn_access_chain *image; - nir_ssa_def *coord; - nir_ssa_def *sample; -}; - -struct vtn_sampled_image { - struct vtn_access_chain *image; /* Image or array of images */ - struct vtn_access_chain *sampler; /* Sampler */ -}; - -struct vtn_value { - enum vtn_value_type value_type; - const char *name; - struct vtn_decoration *decoration; - union { - void *ptr; - char *str; - struct vtn_type *type; - struct { - nir_constant *constant; - const struct glsl_type *const_type; - }; - struct vtn_access_chain *access_chain; - struct vtn_image_pointer *image; - struct vtn_sampled_image *sampled_image; - struct vtn_function *func; - struct vtn_block *block; - struct vtn_ssa_value *ssa; - vtn_instruction_handler ext_handler; - }; -}; - -#define VTN_DEC_DECORATION -1 -#define VTN_DEC_EXECUTION_MODE -2 -#define VTN_DEC_STRUCT_MEMBER0 0 - -struct vtn_decoration { - struct vtn_decoration *next; - - /* Specifies how to apply this decoration. Negative values represent a - * decoration or execution mode. (See the VTN_DEC_ #defines above.) - * Non-negative values specify that it applies to a structure member. - */ - int scope; - - const uint32_t *literals; - struct vtn_value *group; - - union { - SpvDecoration decoration; - SpvExecutionMode exec_mode; - }; -}; - -struct vtn_builder { - nir_builder nb; - - nir_shader *shader; - nir_function_impl *impl; - struct vtn_block *block; - - /* Current file, line, and column. Useful for debugging. Set - * automatically by vtn_foreach_instruction. - */ - char *file; - int line, col; - - /* - * In SPIR-V, constants are global, whereas in NIR, the load_const - * instruction we use is per-function. So while we parse each function, we - * keep a hash table of constants we've resolved to nir_ssa_value's so - * far, and we lazily resolve them when we see them used in a function. - */ - struct hash_table *const_table; - - /* - * Map from phi instructions (pointer to the start of the instruction) - * to the variable corresponding to it. - */ - struct hash_table *phi_table; - - unsigned num_specializations; - struct nir_spirv_specialization *specializations; - - unsigned value_id_bound; - struct vtn_value *values; - - gl_shader_stage entry_point_stage; - const char *entry_point_name; - struct vtn_value *entry_point; - bool origin_upper_left; - - struct vtn_function *func; - struct exec_list functions; - - /* Current function parameter index */ - unsigned func_param_idx; - - bool has_loop_continue; -}; - -static inline struct vtn_value * -vtn_push_value(struct vtn_builder *b, uint32_t value_id, - enum vtn_value_type value_type) -{ - assert(value_id < b->value_id_bound); - assert(b->values[value_id].value_type == vtn_value_type_invalid); - - b->values[value_id].value_type = value_type; - - return &b->values[value_id]; -} - -static inline struct vtn_value * -vtn_untyped_value(struct vtn_builder *b, uint32_t value_id) -{ - assert(value_id < b->value_id_bound); - return &b->values[value_id]; -} - -static inline struct vtn_value * -vtn_value(struct vtn_builder *b, uint32_t value_id, - enum vtn_value_type value_type) -{ - struct vtn_value *val = vtn_untyped_value(b, value_id); - assert(val->value_type == value_type); - return val; -} - -struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id); - -struct vtn_ssa_value *vtn_create_ssa_value(struct vtn_builder *b, - const struct glsl_type *type); - -struct vtn_ssa_value *vtn_ssa_transpose(struct vtn_builder *b, - struct vtn_ssa_value *src); - -nir_ssa_def *vtn_vector_extract(struct vtn_builder *b, nir_ssa_def *src, - unsigned index); -nir_ssa_def *vtn_vector_extract_dynamic(struct vtn_builder *b, nir_ssa_def *src, - nir_ssa_def *index); -nir_ssa_def *vtn_vector_insert(struct vtn_builder *b, nir_ssa_def *src, - nir_ssa_def *insert, unsigned index); -nir_ssa_def *vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src, - nir_ssa_def *insert, nir_ssa_def *index); - -nir_deref_var *vtn_nir_deref(struct vtn_builder *b, uint32_t id); - -nir_deref_var *vtn_access_chain_to_deref(struct vtn_builder *b, - struct vtn_access_chain *chain); -nir_ssa_def * -vtn_access_chain_to_offset(struct vtn_builder *b, - struct vtn_access_chain *chain, - nir_ssa_def **index_out, struct vtn_type **type_out, - unsigned *end_idx_out, bool stop_at_matrix); - -struct vtn_ssa_value *vtn_local_load(struct vtn_builder *b, nir_deref_var *src); - -void vtn_local_store(struct vtn_builder *b, struct vtn_ssa_value *src, - nir_deref_var *dest); - -struct vtn_ssa_value * -vtn_variable_load(struct vtn_builder *b, struct vtn_access_chain *src); - -void vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src, - struct vtn_access_chain *dest); - -void vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count); - - -typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *, - struct vtn_value *, - int member, - const struct vtn_decoration *, - void *); - -void vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, - vtn_decoration_foreach_cb cb, void *data); - -typedef void (*vtn_execution_mode_foreach_cb)(struct vtn_builder *, - struct vtn_value *, - const struct vtn_decoration *, - void *); - -void vtn_foreach_execution_mode(struct vtn_builder *b, struct vtn_value *value, - vtn_execution_mode_foreach_cb cb, void *data); - -nir_op vtn_nir_alu_op_for_spirv_opcode(SpvOp opcode, bool *swap); - -void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count); - -bool vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode, - const uint32_t *words, unsigned count); diff --git a/src/glsl/nir/spirv/vtn_variables.c b/src/glsl/nir/spirv/vtn_variables.c deleted file mode 100644 index 3ad98aa5310..00000000000 --- a/src/glsl/nir/spirv/vtn_variables.c +++ /dev/null @@ -1,1412 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -#include "vtn_private.h" - -static struct vtn_access_chain * -vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old, - unsigned new_ids) -{ - struct vtn_access_chain *chain; - - unsigned new_len = old->length + new_ids; - chain = ralloc_size(b, sizeof(*chain) + new_len * sizeof(chain->link[0])); - - chain->var = old->var; - chain->length = new_len; - - for (unsigned i = 0; i < old->length; i++) - chain->link[i] = old->link[i]; - - return chain; -} - -static nir_ssa_def * -vtn_access_link_as_ssa(struct vtn_builder *b, struct vtn_access_link link, - unsigned stride) -{ - assert(stride > 0); - if (link.mode == vtn_access_mode_literal) { - return nir_imm_int(&b->nb, link.id * stride); - } else if (stride == 1) { - return vtn_ssa_value(b, link.id)->def; - } else { - return nir_imul(&b->nb, vtn_ssa_value(b, link.id)->def, - nir_imm_int(&b->nb, stride)); - } -} - -static struct vtn_type * -vtn_access_chain_tail_type(struct vtn_builder *b, - struct vtn_access_chain *chain) -{ - struct vtn_type *type = chain->var->type; - for (unsigned i = 0; i < chain->length; i++) { - if (glsl_type_is_struct(type->type)) { - assert(chain->link[i].mode == vtn_access_mode_literal); - type = type->members[chain->link[i].id]; - } else { - type = type->array_element; - } - } - return type; -} - -/* Crawls a chain of array derefs and rewrites the types so that the - * lengths stay the same but the terminal type is the one given by - * tail_type. This is useful for split structures. - */ -static void -rewrite_deref_types(nir_deref *deref, const struct glsl_type *type) -{ - deref->type = type; - if (deref->child) { - assert(deref->child->deref_type == nir_deref_type_array); - assert(glsl_type_is_array(deref->type)); - rewrite_deref_types(deref->child, glsl_get_array_element(type)); - } -} - -nir_deref_var * -vtn_access_chain_to_deref(struct vtn_builder *b, struct vtn_access_chain *chain) -{ - nir_deref_var *deref_var; - if (chain->var->var) { - deref_var = nir_deref_var_create(b, chain->var->var); - } else { - assert(chain->var->members); - /* Create the deref_var manually. It will get filled out later. */ - deref_var = rzalloc(b, nir_deref_var); - deref_var->deref.deref_type = nir_deref_type_var; - } - - struct vtn_type *deref_type = chain->var->type; - nir_deref *tail = &deref_var->deref; - nir_variable **members = chain->var->members; - - for (unsigned i = 0; i < chain->length; i++) { - enum glsl_base_type base_type = glsl_get_base_type(deref_type->type); - switch (base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_ARRAY: { - deref_type = deref_type->array_element; - - nir_deref_array *deref_arr = nir_deref_array_create(b); - deref_arr->deref.type = deref_type->type; - - if (chain->link[i].mode == vtn_access_mode_literal) { - deref_arr->deref_array_type = nir_deref_array_type_direct; - deref_arr->base_offset = chain->link[i].id; - } else { - assert(chain->link[i].mode == vtn_access_mode_id); - deref_arr->deref_array_type = nir_deref_array_type_indirect; - deref_arr->base_offset = 0; - deref_arr->indirect = - nir_src_for_ssa(vtn_ssa_value(b, chain->link[i].id)->def); - } - tail->child = &deref_arr->deref; - tail = tail->child; - break; - } - - case GLSL_TYPE_STRUCT: { - assert(chain->link[i].mode == vtn_access_mode_literal); - unsigned idx = chain->link[i].id; - deref_type = deref_type->members[idx]; - if (members) { - /* This is a pre-split structure. */ - deref_var->var = members[idx]; - rewrite_deref_types(&deref_var->deref, members[idx]->type); - assert(tail->type == deref_type->type); - members = NULL; - } else { - nir_deref_struct *deref_struct = nir_deref_struct_create(b, idx); - deref_struct->deref.type = deref_type->type; - tail->child = &deref_struct->deref; - tail = tail->child; - } - break; - } - default: - unreachable("Invalid type for deref"); - } - } - - assert(members == NULL); - return deref_var; -} - -static void -_vtn_local_load_store(struct vtn_builder *b, bool load, nir_deref_var *deref, - nir_deref *tail, struct vtn_ssa_value *inout) -{ - /* The deref tail may contain a deref to select a component of a vector (in - * other words, it might not be an actual tail) so we have to save it away - * here since we overwrite it later. - */ - nir_deref *old_child = tail->child; - - if (glsl_type_is_vector_or_scalar(tail->type)) { - /* Terminate the deref chain in case there is one more link to pick - * off a component of the vector. - */ - tail->child = NULL; - - nir_intrinsic_op op = load ? nir_intrinsic_load_var : - nir_intrinsic_store_var; - - nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b->shader, op); - intrin->variables[0] = - nir_deref_as_var(nir_copy_deref(intrin, &deref->deref)); - intrin->num_components = glsl_get_vector_elements(tail->type); - - if (load) { - nir_ssa_dest_init(&intrin->instr, &intrin->dest, - intrin->num_components, NULL); - inout->def = &intrin->dest.ssa; - } else { - intrin->const_index[0] = (1 << intrin->num_components) - 1; - intrin->src[0] = nir_src_for_ssa(inout->def); - } - - nir_builder_instr_insert(&b->nb, &intrin->instr); - } else if (glsl_get_base_type(tail->type) == GLSL_TYPE_ARRAY || - glsl_type_is_matrix(tail->type)) { - unsigned elems = glsl_get_length(tail->type); - nir_deref_array *deref_arr = nir_deref_array_create(b); - deref_arr->deref_array_type = nir_deref_array_type_direct; - deref_arr->deref.type = glsl_get_array_element(tail->type); - tail->child = &deref_arr->deref; - for (unsigned i = 0; i < elems; i++) { - deref_arr->base_offset = i; - _vtn_local_load_store(b, load, deref, tail->child, inout->elems[i]); - } - } else { - assert(glsl_get_base_type(tail->type) == GLSL_TYPE_STRUCT); - unsigned elems = glsl_get_length(tail->type); - nir_deref_struct *deref_struct = nir_deref_struct_create(b, 0); - tail->child = &deref_struct->deref; - for (unsigned i = 0; i < elems; i++) { - deref_struct->index = i; - deref_struct->deref.type = glsl_get_struct_field(tail->type, i); - _vtn_local_load_store(b, load, deref, tail->child, inout->elems[i]); - } - } - - tail->child = old_child; -} - -nir_deref_var * -vtn_nir_deref(struct vtn_builder *b, uint32_t id) -{ - struct vtn_access_chain *chain = - vtn_value(b, id, vtn_value_type_access_chain)->access_chain; - - return vtn_access_chain_to_deref(b, chain); -} - -/* - * Gets the NIR-level deref tail, which may have as a child an array deref - * selecting which component due to OpAccessChain supporting per-component - * indexing in SPIR-V. - */ -static nir_deref * -get_deref_tail(nir_deref_var *deref) -{ - nir_deref *cur = &deref->deref; - while (!glsl_type_is_vector_or_scalar(cur->type) && cur->child) - cur = cur->child; - - return cur; -} - -struct vtn_ssa_value * -vtn_local_load(struct vtn_builder *b, nir_deref_var *src) -{ - nir_deref *src_tail = get_deref_tail(src); - struct vtn_ssa_value *val = vtn_create_ssa_value(b, src_tail->type); - _vtn_local_load_store(b, true, src, src_tail, val); - - if (src_tail->child) { - nir_deref_array *vec_deref = nir_deref_as_array(src_tail->child); - assert(vec_deref->deref.child == NULL); - val->type = vec_deref->deref.type; - if (vec_deref->deref_array_type == nir_deref_array_type_direct) - val->def = vtn_vector_extract(b, val->def, vec_deref->base_offset); - else - val->def = vtn_vector_extract_dynamic(b, val->def, - vec_deref->indirect.ssa); - } - - return val; -} - -void -vtn_local_store(struct vtn_builder *b, struct vtn_ssa_value *src, - nir_deref_var *dest) -{ - nir_deref *dest_tail = get_deref_tail(dest); - - if (dest_tail->child) { - struct vtn_ssa_value *val = vtn_create_ssa_value(b, dest_tail->type); - _vtn_local_load_store(b, true, dest, dest_tail, val); - nir_deref_array *deref = nir_deref_as_array(dest_tail->child); - assert(deref->deref.child == NULL); - if (deref->deref_array_type == nir_deref_array_type_direct) - val->def = vtn_vector_insert(b, val->def, src->def, - deref->base_offset); - else - val->def = vtn_vector_insert_dynamic(b, val->def, src->def, - deref->indirect.ssa); - _vtn_local_load_store(b, false, dest, dest_tail, val); - } else { - _vtn_local_load_store(b, false, dest, dest_tail, src); - } -} - -static nir_ssa_def * -get_vulkan_resource_index(struct vtn_builder *b, struct vtn_access_chain *chain, - struct vtn_type **type, unsigned *chain_idx) -{ - /* Push constants have no explicit binding */ - if (chain->var->mode == vtn_variable_mode_push_constant) { - *chain_idx = 0; - *type = chain->var->type; - return NULL; - } - - nir_ssa_def *array_index; - if (glsl_type_is_array(chain->var->type->type)) { - assert(chain->length > 0); - array_index = vtn_access_link_as_ssa(b, chain->link[0], 1); - *chain_idx = 1; - *type = chain->var->type->array_element; - } else { - array_index = nir_imm_int(&b->nb, 0); - *chain_idx = 0; - *type = chain->var->type; - } - - nir_intrinsic_instr *instr = - nir_intrinsic_instr_create(b->nb.shader, - nir_intrinsic_vulkan_resource_index); - instr->src[0] = nir_src_for_ssa(array_index); - instr->const_index[0] = chain->var->descriptor_set; - instr->const_index[1] = chain->var->binding; - - nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL); - nir_builder_instr_insert(&b->nb, &instr->instr); - - return &instr->dest.ssa; -} - -nir_ssa_def * -vtn_access_chain_to_offset(struct vtn_builder *b, - struct vtn_access_chain *chain, - nir_ssa_def **index_out, struct vtn_type **type_out, - unsigned *end_idx_out, bool stop_at_matrix) -{ - unsigned idx = 0; - struct vtn_type *type; - *index_out = get_vulkan_resource_index(b, chain, &type, &idx); - - nir_ssa_def *offset = nir_imm_int(&b->nb, 0); - for (; idx < chain->length; idx++) { - enum glsl_base_type base_type = glsl_get_base_type(type->type); - switch (base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_DOUBLE: - case GLSL_TYPE_BOOL: - /* Some users may not want matrix or vector derefs */ - if (stop_at_matrix) - goto end; - /* Fall through */ - - case GLSL_TYPE_ARRAY: - offset = nir_iadd(&b->nb, offset, - vtn_access_link_as_ssa(b, chain->link[idx], - type->stride)); - - type = type->array_element; - break; - - case GLSL_TYPE_STRUCT: { - assert(chain->link[idx].mode == vtn_access_mode_literal); - unsigned member = chain->link[idx].id; - offset = nir_iadd(&b->nb, offset, - nir_imm_int(&b->nb, type->offsets[member])); - type = type->members[member]; - break; - } - - default: - unreachable("Invalid type for deref"); - } - } - -end: - *type_out = type; - if (end_idx_out) - *end_idx_out = idx; - - return offset; -} - -static void -_vtn_load_store_tail(struct vtn_builder *b, nir_intrinsic_op op, bool load, - nir_ssa_def *index, nir_ssa_def *offset, - struct vtn_ssa_value **inout, const struct glsl_type *type) -{ - nir_intrinsic_instr *instr = nir_intrinsic_instr_create(b->nb.shader, op); - instr->num_components = glsl_get_vector_elements(type); - - int src = 0; - if (!load) { - instr->const_index[0] = (1 << instr->num_components) - 1; /* write mask */ - instr->src[src++] = nir_src_for_ssa((*inout)->def); - } - - /* We set the base and size for push constant load to the entire push - * constant block for now. - */ - if (op == nir_intrinsic_load_push_constant) { - instr->const_index[0] = 0; - instr->const_index[1] = 128; - } - - if (index) - instr->src[src++] = nir_src_for_ssa(index); - - instr->src[src++] = nir_src_for_ssa(offset); - - if (load) { - nir_ssa_dest_init(&instr->instr, &instr->dest, - instr->num_components, NULL); - (*inout)->def = &instr->dest.ssa; - } - - nir_builder_instr_insert(&b->nb, &instr->instr); - - if (load && glsl_get_base_type(type) == GLSL_TYPE_BOOL) - (*inout)->def = nir_ine(&b->nb, (*inout)->def, nir_imm_int(&b->nb, 0)); -} - -static void -_vtn_block_load_store(struct vtn_builder *b, nir_intrinsic_op op, bool load, - nir_ssa_def *index, nir_ssa_def *offset, - struct vtn_access_chain *chain, unsigned chain_idx, - struct vtn_type *type, struct vtn_ssa_value **inout) -{ - if (chain && chain_idx >= chain->length) - chain = NULL; - - if (load && chain == NULL && *inout == NULL) - *inout = vtn_create_ssa_value(b, type->type); - - enum glsl_base_type base_type = glsl_get_base_type(type->type); - switch (base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - /* This is where things get interesting. At this point, we've hit - * a vector, a scalar, or a matrix. - */ - if (glsl_type_is_matrix(type->type)) { - if (chain == NULL) { - /* Loading the whole matrix */ - struct vtn_ssa_value *transpose; - unsigned num_ops, vec_width; - if (type->row_major) { - num_ops = glsl_get_vector_elements(type->type); - vec_width = glsl_get_matrix_columns(type->type); - if (load) { - const struct glsl_type *transpose_type = - glsl_matrix_type(base_type, vec_width, num_ops); - *inout = vtn_create_ssa_value(b, transpose_type); - } else { - transpose = vtn_ssa_transpose(b, *inout); - inout = &transpose; - } - } else { - num_ops = glsl_get_matrix_columns(type->type); - vec_width = glsl_get_vector_elements(type->type); - } - - for (unsigned i = 0; i < num_ops; i++) { - nir_ssa_def *elem_offset = - nir_iadd(&b->nb, offset, - nir_imm_int(&b->nb, i * type->stride)); - _vtn_load_store_tail(b, op, load, index, elem_offset, - &(*inout)->elems[i], - glsl_vector_type(base_type, vec_width)); - } - - if (load && type->row_major) - *inout = vtn_ssa_transpose(b, *inout); - } else if (type->row_major) { - /* Row-major but with an access chiain. */ - nir_ssa_def *col_offset = - vtn_access_link_as_ssa(b, chain->link[chain_idx], - type->array_element->stride); - offset = nir_iadd(&b->nb, offset, col_offset); - - if (chain_idx + 1 < chain->length) { - /* Picking off a single element */ - nir_ssa_def *row_offset = - vtn_access_link_as_ssa(b, chain->link[chain_idx + 1], - type->stride); - offset = nir_iadd(&b->nb, offset, row_offset); - if (load) - *inout = vtn_create_ssa_value(b, glsl_scalar_type(base_type)); - _vtn_load_store_tail(b, op, load, index, offset, inout, - glsl_scalar_type(base_type)); - } else { - /* Grabbing a column; picking one element off each row */ - unsigned num_comps = glsl_get_vector_elements(type->type); - const struct glsl_type *column_type = - glsl_get_column_type(type->type); - - nir_ssa_def *comps[4]; - for (unsigned i = 0; i < num_comps; i++) { - nir_ssa_def *elem_offset = - nir_iadd(&b->nb, offset, - nir_imm_int(&b->nb, i * type->stride)); - - struct vtn_ssa_value *comp, temp_val; - if (!load) { - temp_val.def = nir_channel(&b->nb, (*inout)->def, i); - temp_val.type = glsl_scalar_type(base_type); - } - comp = &temp_val; - _vtn_load_store_tail(b, op, load, index, elem_offset, - &comp, glsl_scalar_type(base_type)); - comps[i] = comp->def; - } - - if (load) { - if (*inout == NULL) - *inout = vtn_create_ssa_value(b, column_type); - - (*inout)->def = nir_vec(&b->nb, comps, num_comps); - } - } - } else { - /* Column-major with a deref. Fall through to array case. */ - nir_ssa_def *col_offset = - vtn_access_link_as_ssa(b, chain->link[chain_idx], type->stride); - offset = nir_iadd(&b->nb, offset, col_offset); - - _vtn_block_load_store(b, op, load, index, offset, - chain, chain_idx + 1, - type->array_element, inout); - } - } else if (chain == NULL) { - /* Single whole vector */ - assert(glsl_type_is_vector_or_scalar(type->type)); - _vtn_load_store_tail(b, op, load, index, offset, inout, type->type); - } else { - /* Single component of a vector. Fall through to array case. */ - nir_ssa_def *elem_offset = - vtn_access_link_as_ssa(b, chain->link[chain_idx], type->stride); - offset = nir_iadd(&b->nb, offset, elem_offset); - - _vtn_block_load_store(b, op, load, index, offset, NULL, 0, - type->array_element, inout); - } - return; - - case GLSL_TYPE_ARRAY: { - unsigned elems = glsl_get_length(type->type); - for (unsigned i = 0; i < elems; i++) { - nir_ssa_def *elem_off = - nir_iadd(&b->nb, offset, nir_imm_int(&b->nb, i * type->stride)); - _vtn_block_load_store(b, op, load, index, elem_off, NULL, 0, - type->array_element, &(*inout)->elems[i]); - } - return; - } - - case GLSL_TYPE_STRUCT: { - unsigned elems = glsl_get_length(type->type); - for (unsigned i = 0; i < elems; i++) { - nir_ssa_def *elem_off = - nir_iadd(&b->nb, offset, nir_imm_int(&b->nb, type->offsets[i])); - _vtn_block_load_store(b, op, load, index, elem_off, NULL, 0, - type->members[i], &(*inout)->elems[i]); - } - return; - } - - default: - unreachable("Invalid block member type"); - } -} - -static struct vtn_ssa_value * -vtn_block_load(struct vtn_builder *b, struct vtn_access_chain *src) -{ - nir_intrinsic_op op; - switch (src->var->mode) { - case vtn_variable_mode_ubo: - op = nir_intrinsic_load_ubo; - break; - case vtn_variable_mode_ssbo: - op = nir_intrinsic_load_ssbo; - break; - case vtn_variable_mode_push_constant: - op = nir_intrinsic_load_push_constant; - break; - default: - assert(!"Invalid block variable mode"); - } - - nir_ssa_def *offset, *index = NULL; - struct vtn_type *type; - unsigned chain_idx; - offset = vtn_access_chain_to_offset(b, src, &index, &type, &chain_idx, true); - - struct vtn_ssa_value *value = NULL; - _vtn_block_load_store(b, op, true, index, offset, - src, chain_idx, type, &value); - return value; -} - -static void -vtn_block_store(struct vtn_builder *b, struct vtn_ssa_value *src, - struct vtn_access_chain *dst) -{ - nir_ssa_def *offset, *index = NULL; - struct vtn_type *type; - unsigned chain_idx; - offset = vtn_access_chain_to_offset(b, dst, &index, &type, &chain_idx, true); - - _vtn_block_load_store(b, nir_intrinsic_store_ssbo, false, index, offset, - dst, chain_idx, type, &src); -} - -static bool -vtn_variable_is_external_block(struct vtn_variable *var) -{ - return var->mode == vtn_variable_mode_ssbo || - var->mode == vtn_variable_mode_ubo || - var->mode == vtn_variable_mode_push_constant; -} - -static void -_vtn_variable_load_store(struct vtn_builder *b, bool load, - struct vtn_access_chain *chain, - struct vtn_type *tail_type, - struct vtn_ssa_value **inout) -{ - enum glsl_base_type base_type = glsl_get_base_type(tail_type->type); - switch (base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - /* At this point, we have a scalar, vector, or matrix so we know that - * there cannot be any structure splitting still in the way. By - * stopping at the matrix level rather than the vector level, we - * ensure that matrices get loaded in the optimal way even if they - * are storred row-major in a UBO. - */ - if (load) { - *inout = vtn_local_load(b, vtn_access_chain_to_deref(b, chain)); - } else { - vtn_local_store(b, *inout, vtn_access_chain_to_deref(b, chain)); - } - return; - - case GLSL_TYPE_ARRAY: - case GLSL_TYPE_STRUCT: { - struct vtn_access_chain *new_chain = - vtn_access_chain_extend(b, chain, 1); - new_chain->link[chain->length].mode = vtn_access_mode_literal; - unsigned elems = glsl_get_length(tail_type->type); - if (load) { - assert(*inout == NULL); - *inout = rzalloc(b, struct vtn_ssa_value); - (*inout)->type = tail_type->type; - (*inout)->elems = rzalloc_array(b, struct vtn_ssa_value *, elems); - } - for (unsigned i = 0; i < elems; i++) { - new_chain->link[chain->length].id = i; - struct vtn_type *elem_type = base_type == GLSL_TYPE_ARRAY ? - tail_type->array_element : tail_type->members[i]; - _vtn_variable_load_store(b, load, new_chain, elem_type, - &(*inout)->elems[i]); - } - return; - } - - default: - unreachable("Invalid access chain type"); - } -} - -struct vtn_ssa_value * -vtn_variable_load(struct vtn_builder *b, struct vtn_access_chain *src) -{ - if (vtn_variable_is_external_block(src->var)) { - return vtn_block_load(b, src); - } else { - struct vtn_type *tail_type = vtn_access_chain_tail_type(b, src); - struct vtn_ssa_value *val = NULL; - _vtn_variable_load_store(b, true, src, tail_type, &val); - return val; - } -} - -void -vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src, - struct vtn_access_chain *dest) -{ - if (vtn_variable_is_external_block(dest->var)) { - assert(dest->var->mode == vtn_variable_mode_ssbo); - vtn_block_store(b, src, dest); - } else { - struct vtn_type *tail_type = vtn_access_chain_tail_type(b, dest); - _vtn_variable_load_store(b, false, dest, tail_type, &src); - } -} - -static void -_vtn_variable_copy(struct vtn_builder *b, struct vtn_access_chain *dest, - struct vtn_access_chain *src, struct vtn_type *tail_type) -{ - enum glsl_base_type base_type = glsl_get_base_type(tail_type->type); - switch (base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - /* At this point, we have a scalar, vector, or matrix so we know that - * there cannot be any structure splitting still in the way. By - * stopping at the matrix level rather than the vector level, we - * ensure that matrices get loaded in the optimal way even if they - * are storred row-major in a UBO. - */ - vtn_variable_store(b, vtn_variable_load(b, src), dest); - return; - - case GLSL_TYPE_ARRAY: - case GLSL_TYPE_STRUCT: { - struct vtn_access_chain *new_src, *new_dest; - new_src = vtn_access_chain_extend(b, src, 1); - new_dest = vtn_access_chain_extend(b, dest, 1); - new_src->link[src->length].mode = vtn_access_mode_literal; - new_dest->link[dest->length].mode = vtn_access_mode_literal; - unsigned elems = glsl_get_length(tail_type->type); - for (unsigned i = 0; i < elems; i++) { - new_src->link[src->length].id = i; - new_dest->link[dest->length].id = i; - struct vtn_type *elem_type = base_type == GLSL_TYPE_ARRAY ? - tail_type->array_element : tail_type->members[i]; - _vtn_variable_copy(b, new_dest, new_src, elem_type); - } - return; - } - - default: - unreachable("Invalid access chain type"); - } -} - -static void -vtn_variable_copy(struct vtn_builder *b, struct vtn_access_chain *dest, - struct vtn_access_chain *src) -{ - struct vtn_type *tail_type = vtn_access_chain_tail_type(b, src); - assert(vtn_access_chain_tail_type(b, dest)->type == tail_type->type); - - /* TODO: At some point, we should add a special-case for when we can - * just emit a copy_var intrinsic. - */ - _vtn_variable_copy(b, dest, src, tail_type); -} - -static void -set_mode_system_value(nir_variable_mode *mode) -{ - assert(*mode == nir_var_system_value || *mode == nir_var_shader_in); - *mode = nir_var_system_value; -} - -static void -vtn_get_builtin_location(struct vtn_builder *b, - SpvBuiltIn builtin, int *location, - nir_variable_mode *mode) -{ - switch (builtin) { - case SpvBuiltInPosition: - *location = VARYING_SLOT_POS; - break; - case SpvBuiltInPointSize: - *location = VARYING_SLOT_PSIZ; - break; - case SpvBuiltInClipDistance: - *location = VARYING_SLOT_CLIP_DIST0; /* XXX CLIP_DIST1? */ - break; - case SpvBuiltInCullDistance: - /* XXX figure this out */ - break; - case SpvBuiltInVertexIndex: - *location = SYSTEM_VALUE_VERTEX_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInVertexId: - /* Vulkan defines VertexID to be zero-based and reserves the new - * builtin keyword VertexIndex to indicate the non-zero-based value. - */ - *location = SYSTEM_VALUE_VERTEX_ID_ZERO_BASE; - set_mode_system_value(mode); - break; - case SpvBuiltInInstanceIndex: - *location = SYSTEM_VALUE_INSTANCE_INDEX; - set_mode_system_value(mode); - break; - case SpvBuiltInInstanceId: - *location = SYSTEM_VALUE_INSTANCE_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInPrimitiveId: - *location = VARYING_SLOT_PRIMITIVE_ID; - *mode = nir_var_shader_out; - break; - case SpvBuiltInInvocationId: - *location = SYSTEM_VALUE_INVOCATION_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInLayer: - *location = VARYING_SLOT_LAYER; - *mode = nir_var_shader_out; - break; - case SpvBuiltInViewportIndex: - *location = VARYING_SLOT_VIEWPORT; - if (b->shader->stage == MESA_SHADER_GEOMETRY) - *mode = nir_var_shader_out; - else if (b->shader->stage == MESA_SHADER_FRAGMENT) - *mode = nir_var_shader_in; - else - unreachable("invalid stage for SpvBuiltInViewportIndex"); - break; - case SpvBuiltInTessLevelOuter: - case SpvBuiltInTessLevelInner: - case SpvBuiltInTessCoord: - case SpvBuiltInPatchVertices: - unreachable("no tessellation support"); - case SpvBuiltInFragCoord: - *location = VARYING_SLOT_POS; - assert(*mode == nir_var_shader_in); - break; - case SpvBuiltInPointCoord: - *location = VARYING_SLOT_PNTC; - assert(*mode == nir_var_shader_in); - break; - case SpvBuiltInFrontFacing: - *location = VARYING_SLOT_FACE; - assert(*mode == nir_var_shader_in); - break; - case SpvBuiltInSampleId: - *location = SYSTEM_VALUE_SAMPLE_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInSamplePosition: - *location = SYSTEM_VALUE_SAMPLE_POS; - set_mode_system_value(mode); - break; - case SpvBuiltInSampleMask: - *location = SYSTEM_VALUE_SAMPLE_MASK_IN; /* XXX out? */ - set_mode_system_value(mode); - break; - case SpvBuiltInFragDepth: - *location = FRAG_RESULT_DEPTH; - assert(*mode == nir_var_shader_out); - break; - case SpvBuiltInNumWorkgroups: - *location = SYSTEM_VALUE_NUM_WORK_GROUPS; - set_mode_system_value(mode); - break; - case SpvBuiltInWorkgroupSize: - /* This should already be handled */ - unreachable("unsupported builtin"); - break; - case SpvBuiltInWorkgroupId: - *location = SYSTEM_VALUE_WORK_GROUP_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInLocalInvocationId: - *location = SYSTEM_VALUE_LOCAL_INVOCATION_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInLocalInvocationIndex: - *location = SYSTEM_VALUE_LOCAL_INVOCATION_INDEX; - set_mode_system_value(mode); - break; - case SpvBuiltInGlobalInvocationId: - *location = SYSTEM_VALUE_GLOBAL_INVOCATION_ID; - set_mode_system_value(mode); - break; - case SpvBuiltInHelperInvocation: - default: - unreachable("unsupported builtin"); - } -} - -static void -var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member, - const struct vtn_decoration *dec, void *void_var) -{ - struct vtn_variable *vtn_var = void_var; - - /* Handle decorations that apply to a vtn_variable as a whole */ - switch (dec->decoration) { - case SpvDecorationBinding: - vtn_var->binding = dec->literals[0]; - return; - case SpvDecorationDescriptorSet: - vtn_var->descriptor_set = dec->literals[0]; - return; - - case SpvDecorationLocation: { - unsigned location = dec->literals[0]; - bool is_vertex_input; - if (b->shader->stage == MESA_SHADER_FRAGMENT && - vtn_var->mode == vtn_variable_mode_output) { - is_vertex_input = false; - location += FRAG_RESULT_DATA0; - } else if (b->shader->stage == MESA_SHADER_VERTEX && - vtn_var->mode == vtn_variable_mode_input) { - is_vertex_input = true; - location += VERT_ATTRIB_GENERIC0; - } else if (vtn_var->mode == vtn_variable_mode_input || - vtn_var->mode == vtn_variable_mode_output) { - is_vertex_input = false; - location += VARYING_SLOT_VAR0; - } else { - assert(!"Location must be on input or output variable"); - } - - if (vtn_var->var) { - vtn_var->var->data.location = location; - vtn_var->var->data.explicit_location = true; - } else { - assert(vtn_var->members); - unsigned length = glsl_get_length(vtn_var->type->type); - for (unsigned i = 0; i < length; i++) { - vtn_var->members[i]->data.location = location; - vtn_var->members[i]->data.explicit_location = true; - location += - glsl_count_attribute_slots(vtn_var->members[i]->interface_type, - is_vertex_input); - } - } - return; - } - - default: - break; - } - - /* Now we handle decorations that apply to a particular nir_variable */ - nir_variable *nir_var = vtn_var->var; - if (val->value_type == vtn_value_type_access_chain) { - assert(val->access_chain->length == 0); - assert(val->access_chain->var == void_var); - assert(member == -1); - } else { - assert(val->value_type == vtn_value_type_type); - if (member != -1) - nir_var = vtn_var->members[member]; - } - - if (nir_var == NULL) - return; - - switch (dec->decoration) { - case SpvDecorationRelaxedPrecision: - break; /* FIXME: Do nothing with this for now. */ - case SpvDecorationNoPerspective: - nir_var->data.interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; - break; - case SpvDecorationFlat: - nir_var->data.interpolation = INTERP_QUALIFIER_FLAT; - break; - case SpvDecorationCentroid: - nir_var->data.centroid = true; - break; - case SpvDecorationSample: - nir_var->data.sample = true; - break; - case SpvDecorationInvariant: - nir_var->data.invariant = true; - break; - case SpvDecorationConstant: - assert(nir_var->constant_initializer != NULL); - nir_var->data.read_only = true; - break; - case SpvDecorationNonWritable: - nir_var->data.read_only = true; - break; - case SpvDecorationComponent: - nir_var->data.location_frac = dec->literals[0]; - break; - case SpvDecorationIndex: - nir_var->data.explicit_index = true; - nir_var->data.index = dec->literals[0]; - break; - case SpvDecorationBuiltIn: { - SpvBuiltIn builtin = dec->literals[0]; - - if (builtin == SpvBuiltInWorkgroupSize) { - /* This shouldn't be a builtin. It's actually a constant. */ - nir_var->data.mode = nir_var_global; - nir_var->data.read_only = true; - - nir_constant *c = rzalloc(nir_var, nir_constant); - c->value.u[0] = b->shader->info.cs.local_size[0]; - c->value.u[1] = b->shader->info.cs.local_size[1]; - c->value.u[2] = b->shader->info.cs.local_size[2]; - nir_var->constant_initializer = c; - break; - } - - nir_variable_mode mode = nir_var->data.mode; - vtn_get_builtin_location(b, builtin, &nir_var->data.location, &mode); - nir_var->data.explicit_location = true; - nir_var->data.mode = mode; - - if (builtin == SpvBuiltInFragCoord || builtin == SpvBuiltInSamplePosition) - nir_var->data.origin_upper_left = b->origin_upper_left; - break; - } - case SpvDecorationRowMajor: - case SpvDecorationColMajor: - case SpvDecorationGLSLShared: - case SpvDecorationPatch: - case SpvDecorationRestrict: - case SpvDecorationAliased: - case SpvDecorationVolatile: - case SpvDecorationCoherent: - case SpvDecorationNonReadable: - case SpvDecorationUniform: - /* This is really nice but we have no use for it right now. */ - case SpvDecorationCPacked: - case SpvDecorationSaturatedConversion: - case SpvDecorationStream: - case SpvDecorationOffset: - case SpvDecorationXfbBuffer: - case SpvDecorationFuncParamAttr: - case SpvDecorationFPRoundingMode: - case SpvDecorationFPFastMathMode: - case SpvDecorationLinkageAttributes: - case SpvDecorationSpecId: - break; - default: - unreachable("Unhandled variable decoration"); - } -} - -/* Tries to compute the size of an interface block based on the strides and - * offsets that are provided to us in the SPIR-V source. - */ -static unsigned -vtn_type_block_size(struct vtn_type *type) -{ - enum glsl_base_type base_type = glsl_get_base_type(type->type); - switch (base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - case GLSL_TYPE_DOUBLE: { - unsigned cols = type->row_major ? glsl_get_vector_elements(type->type) : - glsl_get_matrix_columns(type->type); - if (cols > 1) { - assert(type->stride > 0); - return type->stride * cols; - } else if (base_type == GLSL_TYPE_DOUBLE) { - return glsl_get_vector_elements(type->type) * 8; - } else { - return glsl_get_vector_elements(type->type) * 4; - } - } - - case GLSL_TYPE_STRUCT: - case GLSL_TYPE_INTERFACE: { - unsigned size = 0; - unsigned num_fields = glsl_get_length(type->type); - for (unsigned f = 0; f < num_fields; f++) { - unsigned field_end = type->offsets[f] + - vtn_type_block_size(type->members[f]); - size = MAX2(size, field_end); - } - return size; - } - - case GLSL_TYPE_ARRAY: - assert(type->stride > 0); - assert(glsl_get_length(type->type) > 0); - return type->stride * glsl_get_length(type->type); - - default: - assert(!"Invalid block type"); - return 0; - } -} - -void -vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) -{ - switch (opcode) { - case SpvOpVariable: { - struct vtn_variable *var = rzalloc(b, struct vtn_variable); - var->type = vtn_value(b, w[1], vtn_value_type_type)->type; - - var->chain.var = var; - var->chain.length = 0; - - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_access_chain); - val->access_chain = &var->chain; - - struct vtn_type *without_array = var->type; - while(glsl_type_is_array(without_array->type)) - without_array = without_array->array_element; - - nir_variable_mode nir_mode; - switch ((SpvStorageClass)w[3]) { - case SpvStorageClassUniform: - case SpvStorageClassUniformConstant: - if (without_array->block) { - var->mode = vtn_variable_mode_ubo; - b->shader->info.num_ubos++; - } else if (without_array->buffer_block) { - var->mode = vtn_variable_mode_ssbo; - b->shader->info.num_ssbos++; - } else if (glsl_type_is_image(without_array->type)) { - var->mode = vtn_variable_mode_image; - nir_mode = nir_var_uniform; - b->shader->info.num_images++; - } else if (glsl_type_is_sampler(without_array->type)) { - var->mode = vtn_variable_mode_sampler; - nir_mode = nir_var_uniform; - b->shader->info.num_textures++; - } else { - assert(!"Invalid uniform variable type"); - } - break; - case SpvStorageClassPushConstant: - var->mode = vtn_variable_mode_push_constant; - assert(b->shader->num_uniforms == 0); - b->shader->num_uniforms = vtn_type_block_size(var->type) * 4; - break; - case SpvStorageClassInput: - var->mode = vtn_variable_mode_input; - nir_mode = nir_var_shader_in; - break; - case SpvStorageClassOutput: - var->mode = vtn_variable_mode_output; - nir_mode = nir_var_shader_out; - break; - case SpvStorageClassPrivate: - var->mode = vtn_variable_mode_global; - nir_mode = nir_var_global; - break; - case SpvStorageClassFunction: - var->mode = vtn_variable_mode_local; - nir_mode = nir_var_local; - break; - case SpvStorageClassWorkgroup: - var->mode = vtn_variable_mode_workgroup; - nir_mode = nir_var_shared; - break; - case SpvStorageClassCrossWorkgroup: - case SpvStorageClassGeneric: - case SpvStorageClassAtomicCounter: - default: - unreachable("Unhandled variable storage class"); - } - - switch (var->mode) { - case vtn_variable_mode_local: - case vtn_variable_mode_global: - case vtn_variable_mode_image: - case vtn_variable_mode_sampler: - case vtn_variable_mode_workgroup: - /* For these, we create the variable normally */ - var->var = rzalloc(b->shader, nir_variable); - var->var->name = ralloc_strdup(var->var, val->name); - var->var->type = var->type->type; - var->var->data.mode = nir_mode; - - switch (var->mode) { - case vtn_variable_mode_image: - case vtn_variable_mode_sampler: - var->var->interface_type = without_array->type; - break; - default: - var->var->interface_type = NULL; - break; - } - break; - - case vtn_variable_mode_input: - case vtn_variable_mode_output: { - /* For inputs and outputs, we immediately split structures. This - * is for a couple of reasons. For one, builtins may all come in - * a struct and we really want those split out into separate - * variables. For another, interpolation qualifiers can be - * applied to members of the top-level struct ane we need to be - * able to preserve that information. - */ - - int array_length = -1; - struct vtn_type *interface_type = var->type; - if (b->shader->stage == MESA_SHADER_GEOMETRY && - glsl_type_is_array(var->type->type)) { - /* In Geometry shaders (and some tessellation), inputs come - * in per-vertex arrays. However, some builtins come in - * non-per-vertex, hence the need for the is_array check. In - * any case, there are no non-builtin arrays allowed so this - * check should be sufficient. - */ - interface_type = var->type->array_element; - array_length = glsl_get_length(var->type->type); - } - - if (glsl_type_is_struct(interface_type->type)) { - /* It's a struct. Split it. */ - unsigned num_members = glsl_get_length(interface_type->type); - var->members = ralloc_array(b, nir_variable *, num_members); - - for (unsigned i = 0; i < num_members; i++) { - const struct glsl_type *mtype = interface_type->members[i]->type; - if (array_length >= 0) - mtype = glsl_array_type(mtype, array_length); - - var->members[i] = rzalloc(b->shader, nir_variable); - var->members[i]->name = - ralloc_asprintf(var->members[i], "%s.%d", val->name, i); - var->members[i]->type = mtype; - var->members[i]->interface_type = - interface_type->members[i]->type; - var->members[i]->data.mode = nir_mode; - } - } else { - var->var = rzalloc(b->shader, nir_variable); - var->var->name = ralloc_strdup(var->var, val->name); - var->var->type = var->type->type; - var->var->interface_type = interface_type->type; - var->var->data.mode = nir_mode; - } - - /* For inputs and outputs, we need to grab locations and builtin - * information from the interface type. - */ - vtn_foreach_decoration(b, interface_type->val, var_decoration_cb, var); - break; - - case vtn_variable_mode_param: - unreachable("Not created through OpVariable"); - } - - case vtn_variable_mode_ubo: - case vtn_variable_mode_ssbo: - case vtn_variable_mode_push_constant: - /* These don't need actual variables. */ - break; - } - - if (count > 4) { - assert(count == 5); - nir_constant *constant = - vtn_value(b, w[4], vtn_value_type_constant)->constant; - var->var->constant_initializer = - nir_constant_clone(constant, var->var); - } - - vtn_foreach_decoration(b, val, var_decoration_cb, var); - - if (var->mode == vtn_variable_mode_image || - var->mode == vtn_variable_mode_sampler) { - /* XXX: We still need the binding information in the nir_variable - * for these. We should fix that. - */ - var->var->data.binding = var->binding; - var->var->data.descriptor_set = var->descriptor_set; - - if (var->mode == vtn_variable_mode_image) - var->var->data.image.format = without_array->image_format; - } - - if (var->mode == vtn_variable_mode_local) { - assert(var->members == NULL && var->var != NULL); - nir_function_impl_add_variable(b->impl, var->var); - } else if (var->var) { - nir_shader_add_variable(b->shader, var->var); - } else if (var->members) { - unsigned count = glsl_get_length(without_array->type); - for (unsigned i = 0; i < count; i++) { - assert(var->members[i]->data.mode != nir_var_local); - nir_shader_add_variable(b->shader, var->members[i]); - } - } else { - assert(var->mode == vtn_variable_mode_ubo || - var->mode == vtn_variable_mode_ssbo || - var->mode == vtn_variable_mode_push_constant); - } - break; - } - - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: { - struct vtn_access_chain *base, *chain; - struct vtn_value *base_val = vtn_untyped_value(b, w[3]); - if (base_val->value_type == vtn_value_type_sampled_image) { - /* This is rather insane. SPIR-V allows you to use OpSampledImage - * to combine an array of images with a single sampler to get an - * array of sampled images that all share the same sampler. - * Fortunately, this means that we can more-or-less ignore the - * sampler when crawling the access chain, but it does leave us - * with this rather awkward little special-case. - */ - base = base_val->sampled_image->image; - } else { - assert(base_val->value_type == vtn_value_type_access_chain); - base = base_val->access_chain; - } - - chain = vtn_access_chain_extend(b, base, count - 4); - - unsigned idx = base->length; - for (int i = 4; i < count; i++) { - struct vtn_value *link_val = vtn_untyped_value(b, w[i]); - if (link_val->value_type == vtn_value_type_constant) { - chain->link[idx].mode = vtn_access_mode_literal; - chain->link[idx].id = link_val->constant->value.u[0]; - } else { - chain->link[idx].mode = vtn_access_mode_id; - chain->link[idx].id = w[i]; - } - idx++; - } - - if (base_val->value_type == vtn_value_type_sampled_image) { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_sampled_image); - val->sampled_image = ralloc(b, struct vtn_sampled_image); - val->sampled_image->image = chain; - val->sampled_image->sampler = base_val->sampled_image->sampler; - } else { - struct vtn_value *val = - vtn_push_value(b, w[2], vtn_value_type_access_chain); - val->access_chain = chain; - } - break; - } - - case SpvOpCopyMemory: { - struct vtn_value *dest = vtn_value(b, w[1], vtn_value_type_access_chain); - struct vtn_value *src = vtn_value(b, w[2], vtn_value_type_access_chain); - - vtn_variable_copy(b, dest->access_chain, src->access_chain); - break; - } - - case SpvOpLoad: { - struct vtn_access_chain *src = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - - if (src->var->mode == vtn_variable_mode_image || - src->var->mode == vtn_variable_mode_sampler) { - vtn_push_value(b, w[2], vtn_value_type_access_chain)->access_chain = src; - return; - } - - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->ssa = vtn_variable_load(b, src); - break; - } - - case SpvOpStore: { - struct vtn_access_chain *dest = - vtn_value(b, w[1], vtn_value_type_access_chain)->access_chain; - struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]); - vtn_variable_store(b, src, dest); - break; - } - - case SpvOpArrayLength: { - struct vtn_access_chain *chain = - vtn_value(b, w[3], vtn_value_type_access_chain)->access_chain; - - const uint32_t offset = chain->var->type->offsets[w[4]]; - const uint32_t stride = chain->var->type->members[w[4]]->stride; - - unsigned chain_idx; - struct vtn_type *type; - nir_ssa_def *index = - get_vulkan_resource_index(b, chain, &type, &chain_idx); - - nir_intrinsic_instr *instr = - nir_intrinsic_instr_create(b->nb.shader, - nir_intrinsic_get_buffer_size); - instr->src[0] = nir_src_for_ssa(index); - nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL); - nir_builder_instr_insert(&b->nb, &instr->instr); - nir_ssa_def *buf_size = &instr->dest.ssa; - - /* array_length = max(buffer_size - offset, 0) / stride */ - nir_ssa_def *array_length = - nir_idiv(&b->nb, - nir_imax(&b->nb, - nir_isub(&b->nb, - buf_size, - nir_imm_int(&b->nb, offset)), - nir_imm_int(&b->nb, 0u)), - nir_imm_int(&b->nb, stride)); - - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->ssa = vtn_create_ssa_value(b, glsl_uint_type()); - val->ssa->def = array_length; - break; - } - - case SpvOpCopyMemorySized: - default: - unreachable("Unhandled opcode"); - } -} diff --git a/src/glsl/nir/spirv2nir.c b/src/glsl/nir/spirv2nir.c deleted file mode 100644 index c837186bdfc..00000000000 --- a/src/glsl/nir/spirv2nir.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * Authors: - * Jason Ekstrand ([email protected]) - * - */ - -/* - * A simple executable that opens a SPIR-V shader, converts it to NIR, and - * dumps out the result. This should be useful for testing the - * spirv_to_nir code. - */ - -#include "spirv/nir_spirv.h" - -#include <sys/mman.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> - -int main(int argc, char **argv) -{ - int fd = open(argv[1], O_RDONLY); - off_t len = lseek(fd, 0, SEEK_END); - - assert(len % 4 == 0); - size_t word_count = len / 4; - - const void *map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); - assert(map != NULL); - - nir_function *func = spirv_to_nir(map, word_count, NULL, 0, - MESA_SHADER_FRAGMENT, "main", NULL); - nir_print_shader(func->shader, stderr); -} diff --git a/src/glsl/nir/tests/control_flow_tests.cpp b/src/glsl/nir/tests/control_flow_tests.cpp deleted file mode 100644 index b9379ef3b06..00000000000 --- a/src/glsl/nir/tests/control_flow_tests.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright © 2015 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include <gtest/gtest.h> -#include "nir.h" -#include "nir_builder.h" - -class nir_cf_test : public ::testing::Test { -protected: - nir_cf_test(); - ~nir_cf_test(); - - nir_builder b; -}; - -nir_cf_test::nir_cf_test() -{ - static const nir_shader_compiler_options options = { }; - nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, &options); -} - -nir_cf_test::~nir_cf_test() -{ - ralloc_free(b.shader); -} - -TEST_F(nir_cf_test, delete_break_in_loop) -{ - /* Create IR: - * - * while (...) { break; } - */ - nir_loop *loop = nir_loop_create(b.shader); - nir_cf_node_insert(nir_after_cf_list(&b.impl->body), &loop->cf_node); - - b.cursor = nir_after_cf_list(&loop->body); - - nir_jump_instr *jump = nir_jump_instr_create(b.shader, nir_jump_break); - nir_builder_instr_insert(&b, &jump->instr); - - /* At this point, we should have: - * - * impl main { - * block block_0: - * // preds: - * // succs: block_1 - * loop { - * block block_1: - * // preds: block_0 - * break - * // succs: block_2 - * } - * block block_2: - * // preds: block_1 - * // succs: block_3 - * block block_3: - * } - */ - nir_block *block_0 = nir_start_block(b.impl); - nir_block *block_1 = nir_cf_node_as_block(nir_loop_first_cf_node(loop)); - nir_block *block_2 = nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node)); - nir_block *block_3 = b.impl->end_block; - ASSERT_EQ(nir_cf_node_block, block_0->cf_node.type); - ASSERT_EQ(nir_cf_node_block, block_1->cf_node.type); - ASSERT_EQ(nir_cf_node_block, block_2->cf_node.type); - ASSERT_EQ(nir_cf_node_block, block_3->cf_node.type); - - /* Verify the successors and predecessors. */ - EXPECT_EQ(block_1, block_0->successors[0]); - EXPECT_EQ(NULL, block_0->successors[1]); - EXPECT_EQ(block_2, block_1->successors[0]); - EXPECT_EQ(NULL, block_1->successors[1]); - EXPECT_EQ(block_3, block_2->successors[0]); - EXPECT_EQ(NULL, block_2->successors[1]); - EXPECT_EQ(NULL, block_3->successors[0]); - EXPECT_EQ(NULL, block_3->successors[1]); - EXPECT_EQ(0, block_0->predecessors->entries); - EXPECT_EQ(1, block_1->predecessors->entries); - EXPECT_EQ(1, block_2->predecessors->entries); - EXPECT_EQ(1, block_3->predecessors->entries); - EXPECT_TRUE(_mesa_set_search(block_1->predecessors, block_0)); - EXPECT_TRUE(_mesa_set_search(block_2->predecessors, block_1)); - EXPECT_TRUE(_mesa_set_search(block_3->predecessors, block_2)); - - nir_print_shader(b.shader, stderr); - - /* Now remove the break. */ - nir_instr_remove(&jump->instr); - - nir_print_shader(b.shader, stderr); - - /* At this point, we should have: - * - * impl main { - * block block_0: - * // preds: - * // succs: block_1 - * loop { - * block block_1: - * // preds: block_0 block_1 - * // succs: block_1 - * } - * block block_2: - * // preds: block_1 - * // succs: block_3 - * block block_3: - * } - * - * Re-verify the predecessors and successors. - */ - EXPECT_EQ(block_1, block_0->successors[0]); - EXPECT_EQ(NULL, block_0->successors[1]); - EXPECT_EQ(block_1, block_1->successors[0]); /* back to itself */ - EXPECT_EQ(block_2, block_1->successors[1]); /* fake successor */ - EXPECT_EQ(block_3, block_2->successors[0]); - EXPECT_EQ(NULL, block_2->successors[1]); - EXPECT_EQ(NULL, block_3->successors[0]); - EXPECT_EQ(NULL, block_3->successors[1]); - EXPECT_EQ(0, block_0->predecessors->entries); - EXPECT_EQ(2, block_1->predecessors->entries); - EXPECT_EQ(1, block_2->predecessors->entries); - EXPECT_EQ(1, block_3->predecessors->entries); - EXPECT_TRUE(_mesa_set_search(block_1->predecessors, block_0)); - EXPECT_TRUE(_mesa_set_search(block_1->predecessors, block_1)); - EXPECT_TRUE(_mesa_set_search(block_2->predecessors, block_1)); - EXPECT_TRUE(_mesa_set_search(block_3->predecessors, block_2)); - - nir_metadata_require(b.impl, nir_metadata_dominance); -} |