1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2014 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Connor Abbott (cwabbott0@gmail.com)
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "compiler/nir/nir.h"
29bf215546Sopenharmony_ci#include "compiler/nir/nir_builder.h"
30bf215546Sopenharmony_ci#include "gl_nir.h"
31bf215546Sopenharmony_ci#include "ir_uniform.h"
32bf215546Sopenharmony_ci#include "main/config.h"
33bf215546Sopenharmony_ci#include "main/shader_types.h"
34bf215546Sopenharmony_ci#include <assert.h>
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci/*
37bf215546Sopenharmony_ci * replace atomic counter intrinsics that use a variable with intrinsics
38bf215546Sopenharmony_ci * that directly store the buffer index and byte offset
39bf215546Sopenharmony_ci */
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_cistatic bool
42bf215546Sopenharmony_cilower_deref_instr(nir_builder *b, nir_intrinsic_instr *instr,
43bf215546Sopenharmony_ci                  const struct gl_shader_program *shader_program,
44bf215546Sopenharmony_ci                  nir_shader *shader, bool use_binding_as_idx)
45bf215546Sopenharmony_ci{
46bf215546Sopenharmony_ci   nir_intrinsic_op op;
47bf215546Sopenharmony_ci   switch (instr->intrinsic) {
48bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_read_deref:
49bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_read;
50bf215546Sopenharmony_ci      break;
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_inc_deref:
53bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_inc;
54bf215546Sopenharmony_ci      break;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_pre_dec_deref:
57bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_pre_dec;
58bf215546Sopenharmony_ci      break;
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_post_dec_deref:
61bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_post_dec;
62bf215546Sopenharmony_ci      break;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_add_deref:
65bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_add;
66bf215546Sopenharmony_ci      break;
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_min_deref:
69bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_min;
70bf215546Sopenharmony_ci      break;
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_max_deref:
73bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_max;
74bf215546Sopenharmony_ci      break;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_and_deref:
77bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_and;
78bf215546Sopenharmony_ci      break;
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_or_deref:
81bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_or;
82bf215546Sopenharmony_ci      break;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_xor_deref:
85bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_xor;
86bf215546Sopenharmony_ci      break;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_exchange_deref:
89bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_exchange;
90bf215546Sopenharmony_ci      break;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   case nir_intrinsic_atomic_counter_comp_swap_deref:
93bf215546Sopenharmony_ci      op = nir_intrinsic_atomic_counter_comp_swap;
94bf215546Sopenharmony_ci      break;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   default:
97bf215546Sopenharmony_ci      return false;
98bf215546Sopenharmony_ci   }
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   nir_deref_instr *deref = nir_src_as_deref(instr->src[0]);
101bf215546Sopenharmony_ci   nir_variable *var = nir_deref_instr_get_variable(deref);
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   if (var->data.mode != nir_var_uniform &&
104bf215546Sopenharmony_ci       var->data.mode != nir_var_mem_ssbo &&
105bf215546Sopenharmony_ci       var->data.mode != nir_var_mem_shared)
106bf215546Sopenharmony_ci      return false; /* atomics passed as function arguments can't be lowered */
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   const unsigned uniform_loc = var->data.location;
109bf215546Sopenharmony_ci   const unsigned idx = use_binding_as_idx ? var->data.binding :
110bf215546Sopenharmony_ci      shader_program->data->UniformStorage[uniform_loc].opaque[shader->info.stage].index;
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   b->cursor = nir_before_instr(&instr->instr);
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   nir_ssa_def *offset = nir_imm_int(b, var->data.offset);
115bf215546Sopenharmony_ci   for (nir_deref_instr *d = deref; d->deref_type != nir_deref_type_var;
116bf215546Sopenharmony_ci        d = nir_deref_instr_parent(d)) {
117bf215546Sopenharmony_ci      assert(d->deref_type == nir_deref_type_array);
118bf215546Sopenharmony_ci      assert(d->arr.index.is_ssa);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci      unsigned array_stride = ATOMIC_COUNTER_SIZE;
121bf215546Sopenharmony_ci      if (glsl_type_is_array(d->type))
122bf215546Sopenharmony_ci         array_stride *= glsl_get_aoa_size(d->type);
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci      offset = nir_iadd(b, offset, nir_imul(b, d->arr.index.ssa,
125bf215546Sopenharmony_ci                                            nir_imm_int(b, array_stride)));
126bf215546Sopenharmony_ci   }
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   /* Since the first source is a deref and the first source in the lowered
129bf215546Sopenharmony_ci    * instruction is the offset, we can just swap it out and change the
130bf215546Sopenharmony_ci    * opcode.
131bf215546Sopenharmony_ci    */
132bf215546Sopenharmony_ci   instr->intrinsic = op;
133bf215546Sopenharmony_ci   nir_instr_rewrite_src(&instr->instr, &instr->src[0],
134bf215546Sopenharmony_ci                         nir_src_for_ssa(offset));
135bf215546Sopenharmony_ci   nir_intrinsic_set_base(instr, idx);
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   nir_deref_instr_remove_if_unused(deref);
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   return true;
140bf215546Sopenharmony_ci}
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_cibool
143bf215546Sopenharmony_cigl_nir_lower_atomics(nir_shader *shader,
144bf215546Sopenharmony_ci                     const struct gl_shader_program *shader_program,
145bf215546Sopenharmony_ci                     bool use_binding_as_idx)
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   bool progress = false;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   nir_foreach_function(function, shader) {
150bf215546Sopenharmony_ci      if (!function->impl)
151bf215546Sopenharmony_ci         continue;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci      bool impl_progress = false;
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci      nir_builder build;
156bf215546Sopenharmony_ci      nir_builder_init(&build, function->impl);
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci      nir_foreach_block(block, function->impl) {
159bf215546Sopenharmony_ci         nir_foreach_instr_safe(instr, block) {
160bf215546Sopenharmony_ci            if (instr->type != nir_instr_type_intrinsic)
161bf215546Sopenharmony_ci               continue;
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci            impl_progress |= lower_deref_instr(&build,
164bf215546Sopenharmony_ci                                               nir_instr_as_intrinsic(instr),
165bf215546Sopenharmony_ci                                               shader_program, shader,
166bf215546Sopenharmony_ci                                               use_binding_as_idx);
167bf215546Sopenharmony_ci         }
168bf215546Sopenharmony_ci      }
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci      if (impl_progress) {
171bf215546Sopenharmony_ci         nir_metadata_preserve(function->impl, nir_metadata_block_index |
172bf215546Sopenharmony_ci                                               nir_metadata_dominance);
173bf215546Sopenharmony_ci         progress = true;
174bf215546Sopenharmony_ci      }
175bf215546Sopenharmony_ci   }
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   return progress;
178bf215546Sopenharmony_ci}
179