mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-04-23 07:20:37 +02:00
This is so that passes and backends can tell if a coherent load/store is atomic or not, instead of having to assume it could be either. Signed-off-by: Rhys Perry <pendingchaos02@gmail.com> Reviewed-by: Daniel Schürmann <daniel@schuermann.dev> Reviewed-by: Georg Lehmann <dadschoorse@gmail.com> Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36602>
162 lines
6 KiB
C
162 lines
6 KiB
C
/*
|
|
* Copyright © 2024 Igalia
|
|
*
|
|
* 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_builder_opcodes.h"
|
|
#include "nir_intrinsics.h"
|
|
|
|
/*
|
|
* Convert atomic arithmetic to regular arithmetic along with cmpxchg
|
|
* by repeating the operation until the result is expected.
|
|
*
|
|
* eg:
|
|
* atomicAdd(a[0], 1) ->
|
|
*
|
|
* uint expected = atomicLoad(a[0]);
|
|
* while (true) {
|
|
* uint before = expected;
|
|
* expected += 1;
|
|
* uint original = atomicCompareExchange(a[0], before, expected);
|
|
* if (original == before) {break;}
|
|
* expected = original;
|
|
* }
|
|
*/
|
|
|
|
static nir_def *
|
|
build_atomic(nir_builder *b, nir_intrinsic_instr *intr)
|
|
{
|
|
nir_def *load;
|
|
switch (intr->intrinsic) {
|
|
case nir_intrinsic_ssbo_atomic:
|
|
load = nir_load_ssbo(b, 1, intr->def.bit_size, intr->src[0].ssa,
|
|
intr->src[1].ssa,
|
|
.align_mul = intr->def.bit_size / 8,
|
|
.align_offset = 0,
|
|
.offset_shift = nir_intrinsic_offset_shift(intr),
|
|
.access = ACCESS_ATOMIC | ACCESS_COHERENT);
|
|
break;
|
|
case nir_intrinsic_shared_atomic:
|
|
load = nir_load_shared(b, 1, intr->def.bit_size,
|
|
intr->src[0].ssa,
|
|
.align_mul = intr->def.bit_size / 8,
|
|
.align_offset = 0,
|
|
.access = ACCESS_ATOMIC);
|
|
break;
|
|
case nir_intrinsic_global_atomic:
|
|
load = nir_build_load_global(b, 1, intr->def.bit_size, intr->src[0].ssa,
|
|
.access = ACCESS_ATOMIC | ACCESS_COHERENT);
|
|
break;
|
|
default:
|
|
UNREACHABLE("unsupported atomic type");
|
|
}
|
|
|
|
nir_def *data = intr->intrinsic == nir_intrinsic_ssbo_atomic ? intr->src[2].ssa : intr->src[1].ssa;
|
|
nir_loop *loop = nir_push_loop(b);
|
|
nir_def *xchg;
|
|
{
|
|
nir_phi_instr *phi = nir_phi_instr_create(b->shader);
|
|
nir_def_init(&phi->instr, &phi->def, 1, intr->def.bit_size);
|
|
nir_phi_instr_add_src(phi, nir_def_block(load), load);
|
|
nir_def *before = &phi->def;
|
|
nir_def *expected = nir_build_alu2(
|
|
b, nir_atomic_op_to_alu(nir_intrinsic_atomic_op(intr)), before, data);
|
|
nir_alu_instr *op = nir_def_as_alu(expected);
|
|
op->exact = true;
|
|
op->fp_fast_math = 0;
|
|
switch (intr->intrinsic) {
|
|
case nir_intrinsic_ssbo_atomic:
|
|
xchg = nir_ssbo_atomic_swap(b, intr->def.bit_size,
|
|
intr->src[0].ssa,
|
|
intr->src[1].ssa,
|
|
before, expected,
|
|
.atomic_op = nir_atomic_op_cmpxchg,
|
|
.offset_shift = nir_intrinsic_offset_shift(intr));
|
|
break;
|
|
case nir_intrinsic_shared_atomic:
|
|
xchg = nir_shared_atomic_swap(b, intr->def.bit_size,
|
|
intr->src[0].ssa,
|
|
before, expected,
|
|
.atomic_op = nir_atomic_op_cmpxchg);
|
|
break;
|
|
case nir_intrinsic_global_atomic:
|
|
xchg = nir_global_atomic_swap(b, intr->def.bit_size,
|
|
intr->src[0].ssa,
|
|
before, expected,
|
|
.atomic_op = nir_atomic_op_cmpxchg);
|
|
break;
|
|
default:
|
|
UNREACHABLE("unsupported atomic type");
|
|
}
|
|
nir_break_if(b, nir_ieq(b, xchg, before));
|
|
nir_phi_instr_add_src(phi, nir_loop_last_block(loop), xchg);
|
|
b->cursor = nir_before_block(nir_loop_first_block(loop));
|
|
nir_builder_instr_insert(b, &phi->instr);
|
|
}
|
|
nir_pop_loop(b, loop);
|
|
return xchg;
|
|
}
|
|
|
|
static bool
|
|
lower_atomics(struct nir_builder *b, nir_intrinsic_instr *intr,
|
|
void *supported)
|
|
{
|
|
nir_instr_filter_cb supported_cb = supported;
|
|
|
|
if (intr->intrinsic != nir_intrinsic_ssbo_atomic &&
|
|
intr->intrinsic != nir_intrinsic_shared_atomic &&
|
|
intr->intrinsic != nir_intrinsic_global_atomic)
|
|
return false;
|
|
if (supported_cb(&intr->instr, NULL))
|
|
return false;
|
|
b->cursor = nir_before_instr(&intr->instr);
|
|
switch (nir_intrinsic_atomic_op(intr)) {
|
|
case nir_atomic_op_imin:
|
|
case nir_atomic_op_umin:
|
|
case nir_atomic_op_imax:
|
|
case nir_atomic_op_umax:
|
|
case nir_atomic_op_iand:
|
|
case nir_atomic_op_ior:
|
|
case nir_atomic_op_ixor:
|
|
case nir_atomic_op_fadd:
|
|
case nir_atomic_op_fmin:
|
|
case nir_atomic_op_fmax:
|
|
case nir_atomic_op_iadd: {
|
|
nir_def_replace(&intr->def, build_atomic(b, intr));
|
|
return true;
|
|
}
|
|
case nir_atomic_op_cmpxchg:
|
|
case nir_atomic_op_xchg:
|
|
return false;
|
|
case nir_atomic_op_fcmpxchg: /* unimplemented */
|
|
default:
|
|
UNREACHABLE("Invalid nir_atomic_op");
|
|
}
|
|
}
|
|
|
|
bool
|
|
nir_lower_atomics(nir_shader *shader, nir_instr_filter_cb supported)
|
|
{
|
|
return nir_shader_intrinsics_pass(shader, lower_atomics,
|
|
nir_metadata_none, supported);
|
|
}
|