1/* 2 * Copyright © 2020 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "nir_builder.h" 25 26static bool 27lower_vec3_to_vec4_impl(nir_function_impl *impl, nir_variable_mode modes) 28{ 29 bool progress = false; 30 31 if (modes & nir_var_function_temp) { 32 nir_foreach_function_temp_variable(var, impl) { 33 const struct glsl_type *vec4_type = 34 glsl_type_replace_vec3_with_vec4(var->type); 35 if (var->type != vec4_type) { 36 var->type = vec4_type; 37 progress = true; 38 } 39 } 40 } 41 42 nir_builder b; 43 nir_builder_init(&b, impl); 44 45 nir_foreach_block(block, impl) { 46 nir_foreach_instr_safe(instr, block) { 47 switch (instr->type) { 48 case nir_instr_type_deref: { 49 nir_deref_instr *deref = nir_instr_as_deref(instr); 50 if (!nir_deref_mode_is_in_set(deref, modes)) 51 continue; 52 53 const struct glsl_type *vec4_type = 54 glsl_type_replace_vec3_with_vec4(deref->type); 55 if (deref->type != vec4_type) { 56 deref->type = vec4_type; 57 progress = true; 58 } 59 break; 60 } 61 62 case nir_instr_type_intrinsic: { 63 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); 64 switch (intrin->intrinsic) { 65 case nir_intrinsic_load_deref: { 66 if (intrin->num_components != 3) 67 break; 68 69 nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); 70 if (!nir_deref_mode_is_in_set(deref, modes)) 71 break; 72 73 assert(intrin->dest.is_ssa); 74 intrin->num_components = 4; 75 intrin->dest.ssa.num_components = 4; 76 77 b.cursor = nir_after_instr(&intrin->instr); 78 nir_ssa_def *vec3 = nir_channels(&b, &intrin->dest.ssa, 0x7); 79 nir_ssa_def_rewrite_uses_after(&intrin->dest.ssa, 80 vec3, 81 vec3->parent_instr); 82 progress = true; 83 break; 84 } 85 86 case nir_intrinsic_store_deref: { 87 if (intrin->num_components != 3) 88 break; 89 90 nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); 91 if (!nir_deref_mode_is_in_set(deref, modes)) 92 break; 93 94 assert(intrin->src[1].is_ssa); 95 nir_ssa_def *data = intrin->src[1].ssa; 96 97 b.cursor = nir_before_instr(&intrin->instr); 98 unsigned swiz[] = { 0, 1, 2, 2 }; 99 data = nir_swizzle(&b, data, swiz, 4); 100 101 intrin->num_components = 4; 102 nir_instr_rewrite_src(&intrin->instr, &intrin->src[1], 103 nir_src_for_ssa(data)); 104 progress = true; 105 break; 106 } 107 108 case nir_intrinsic_copy_deref: { 109 nir_deref_instr *dst = nir_src_as_deref(intrin->src[0]); 110 nir_deref_instr *src = nir_src_as_deref(intrin->src[0]); 111 /* If we convert once side of a copy and not the other, that 112 * would be very bad. 113 */ 114 if (nir_deref_mode_may_be(dst, modes) || 115 nir_deref_mode_may_be(src, modes)) { 116 assert(nir_deref_mode_must_be(dst, modes)); 117 assert(nir_deref_mode_must_be(src, modes)); 118 } 119 break; 120 } 121 122 default: 123 break; 124 } 125 break; 126 } 127 128 default: 129 break; 130 } 131 } 132 } 133 134 if (progress) { 135 nir_metadata_preserve(impl, nir_metadata_block_index | 136 nir_metadata_dominance); 137 } else { 138 nir_metadata_preserve(impl, nir_metadata_all); 139 } 140 141 return progress; 142} 143 144bool 145nir_lower_vec3_to_vec4(nir_shader *shader, nir_variable_mode modes) 146{ 147 bool progress = false; 148 149 if (modes & ~nir_var_function_temp) { 150 nir_foreach_variable_in_shader(var, shader) { 151 if (!(var->data.mode & modes)) 152 continue; 153 154 const struct glsl_type *vec4_type = 155 glsl_type_replace_vec3_with_vec4(var->type); 156 if (var->type != vec4_type) { 157 var->type = vec4_type; 158 progress = true; 159 } 160 } 161 } 162 163 nir_foreach_function(function, shader) { 164 if (function->impl && lower_vec3_to_vec4_impl(function->impl, modes)) 165 progress = true; 166 } 167 168 return progress; 169} 170