1 /* -*- mesa-c++  -*-
2  *
3  * Copyright (c) 2021 Collabora LTD
4  *
5  * Author: Gert Wollny <gert.wollny@collabora.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * on the rights to use, copy, modify, merge, publish, distribute, sub
11  * license, and/or sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 
28 #include "sfn_nir.h"
29 
30 #include "nir.h"
31 #include "nir_builder.h"
32 
33 
34 static nir_ssa_def *
r600_legalize_image_load_store_impl(nir_builder * b,nir_instr * instr,void * _options)35 r600_legalize_image_load_store_impl(nir_builder *b, nir_instr *instr, void *_options)
36 {
37    b->cursor = nir_before_instr(instr);
38    auto ir = nir_instr_as_intrinsic(instr);
39 
40    nir_ssa_def *default_value = nir_imm_vec4(b, 0.0, 0.0, 0.0, 0.0);
41 
42    nir_ssa_def *result = NIR_LOWER_INSTR_PROGRESS_REPLACE;
43 
44    bool load_value = ir->intrinsic != nir_intrinsic_image_store;
45 
46    if (load_value)
47       default_value = nir_imm_zero(b, nir_dest_num_components(ir->dest),
48                                    nir_dest_bit_size(ir->dest));
49 
50    auto image_exists = nir_ult(b, ir->src[0].ssa, nir_imm_int(b, b->shader->info.num_images));
51 
52    nir_if *if_exists = nir_push_if(b, image_exists);
53 
54    nir_if *load_if = nullptr;
55 
56    if (ir->intrinsic != nir_intrinsic_image_size) {
57 
58       /*  Image exists start */
59       auto new_index = nir_umin(b, ir->src[0].ssa,
60             nir_imm_int(b, b->shader->info.num_images - 1));
61       nir_instr_rewrite_src_ssa(instr, &ir->src[0], new_index);
62 
63       enum glsl_sampler_dim dim = nir_intrinsic_image_dim(ir);
64 
65       unsigned num_components = 2;
66       switch (dim) {
67       case GLSL_SAMPLER_DIM_BUF:
68       case GLSL_SAMPLER_DIM_1D:
69          num_components = 1; break;
70       case GLSL_SAMPLER_DIM_2D:
71       case GLSL_SAMPLER_DIM_RECT:
72       case GLSL_SAMPLER_DIM_CUBE:
73          num_components = 2; break;
74       case GLSL_SAMPLER_DIM_3D:
75          num_components = 3; break;
76       default:
77          unreachable("Unexpected image size");
78       }
79 
80       if (num_components < 3 && nir_intrinsic_image_array(ir))
81          num_components++;
82 
83       auto img_size = nir_image_size(b, num_components, 32, ir->src[0].ssa, nir_imm_int(b, 0),
84             dim, nir_intrinsic_image_array(ir),
85             nir_intrinsic_format(ir),
86             nir_intrinsic_access(ir));
87 
88       unsigned mask = (1 << num_components) - 1;
89       unsigned num_src1_comp = MIN2(ir->src[1].ssa->num_components, num_components);
90       unsigned src1_mask = (1 << num_src1_comp) - 1;
91 
92       auto in_range = nir_ult(b,
93                               nir_channels(b, ir->src[1].ssa, src1_mask),
94                               nir_channels(b, img_size, mask));
95 
96       switch (num_components) {
97       case 2: in_range = nir_iand(b, nir_channel(b, in_range, 0),  nir_channel(b, in_range, 1)); break;
98       case 3: {
99          auto tmp = nir_iand(b, nir_channel(b, in_range, 0),  nir_channel(b, in_range, 1));
100          in_range = nir_iand(b, tmp,  nir_channel(b, in_range, 2));
101          break;
102       }
103       }
104 
105       /*  Access is in range start */
106       load_if = nir_push_if(b, in_range);
107    }
108 
109    auto new_load = nir_instr_clone(b->shader, instr);
110    auto new_load_ir = nir_instr_as_intrinsic(new_load);
111 
112    nir_builder_instr_insert(b, new_load);
113 
114    if (load_value)
115       result = &new_load_ir->dest.ssa;
116 
117    if (ir->intrinsic != nir_intrinsic_image_size) {
118       /*  Access is out of range start */
119       nir_if *load_else = nir_push_else(b, load_if);
120 
121       nir_pop_if(b, load_else);
122       /* End range check */
123 
124       if (load_value)
125          result = nir_if_phi(b, result, default_value);
126    }
127 
128    /* Start image doesn't exists */
129    nir_if *else_exists = nir_push_else(b, if_exists);
130 
131    /* Nothing to do, default is already set */
132    nir_pop_if(b, else_exists);
133 
134    if (load_value)
135       result = nir_if_phi(b, result, default_value);
136 
137    if (load_value)
138       b->cursor = nir_after_instr(result->parent_instr);
139    else
140       b->cursor = nir_after_cf_node(&else_exists->cf_node);
141 
142    return result;
143 }
144 
145 static bool
r600_legalize_image_load_store_filter(const nir_instr * instr,const void * _options)146 r600_legalize_image_load_store_filter(const nir_instr *instr, const void *_options)
147 {
148    if (instr->type != nir_instr_type_intrinsic)
149       return false;
150 
151    auto ir = nir_instr_as_intrinsic(instr);
152    switch (ir->intrinsic) {
153    case nir_intrinsic_image_store:
154    case nir_intrinsic_image_load:
155    case nir_intrinsic_image_atomic_add:
156    case nir_intrinsic_image_atomic_and:
157    case nir_intrinsic_image_atomic_or:
158    case nir_intrinsic_image_atomic_xor:
159    case nir_intrinsic_image_atomic_exchange:
160    case nir_intrinsic_image_atomic_comp_swap:
161    case nir_intrinsic_image_atomic_umin:
162    case nir_intrinsic_image_atomic_umax:
163    case nir_intrinsic_image_atomic_imin:
164    case nir_intrinsic_image_atomic_imax:
165    case nir_intrinsic_image_size:
166       return true;
167    default:
168       return false;
169    }
170 }
171 
172 /* This pass makes sure only existing images are accessd and
173  * the access is withing range, if not zero is returned by all
174  * image ops that return a value.
175  */
176 bool
r600_legalize_image_load_store(nir_shader * shader)177 r600_legalize_image_load_store(nir_shader *shader)
178 {
179    return nir_shader_lower_instructions(shader,
180                                         r600_legalize_image_load_store_filter,
181                                         r600_legalize_image_load_store_impl,
182                                         nullptr);
183 };
184