summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBas Nieuwenhuizen <[email protected]>2016-03-29 13:20:26 +0200
committerBas Nieuwenhuizen <[email protected]>2016-04-19 18:10:31 +0200
commitb082147b788ee45862f8d1b0e1b47478d6b99447 (patch)
tree670887a06d53257f8eb400eef1de3f5b95a07610
parent8acf3e501b40aa30371105c18187441085369dfe (diff)
radeonsi: implement shared atomics
v2: - Use single region - Use get_memory_ptr Signed-off-by: Bas Nieuwenhuizen <[email protected]> Reviewed-by: Marek Olšák <[email protected]> Reviewed-by: Nicolai Hähnle <[email protected]> Reviewed-by: Edward O'Callaghan <[email protected]>
-rw-r--r--src/gallium/drivers/radeonsi/si_shader.c77
1 files changed, 76 insertions, 1 deletions
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index ff19746fb30..f63ad2b32e0 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -3452,7 +3452,7 @@ static void atomic_fetch_args(
buffer_append_args(ctx, emit_data, rsrc, bld_base->uint_bld.zero,
offset, true);
- } else {
+ } else if (inst->Src[0].Register.File == TGSI_FILE_IMAGE) {
unsigned target = inst->Memory.Texture;
LLVMValueRef coords;
@@ -3473,17 +3473,92 @@ static void atomic_fetch_args(
}
}
+static void atomic_emit_memory(struct si_shader_context *ctx,
+ struct lp_build_emit_data *emit_data) {
+ struct gallivm_state *gallivm = &ctx->radeon_bld.gallivm;
+ LLVMBuilderRef builder = gallivm->builder;
+ const struct tgsi_full_instruction * inst = emit_data->inst;
+ LLVMValueRef ptr, result, arg;
+
+ ptr = get_memory_ptr(ctx, inst, ctx->i32, 1);
+
+ arg = lp_build_emit_fetch(&ctx->radeon_bld.soa.bld_base, inst, 2, 0);
+ arg = LLVMBuildBitCast(builder, arg, ctx->i32, "");
+
+ if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS) {
+ LLVMValueRef new_data;
+ new_data = lp_build_emit_fetch(&ctx->radeon_bld.soa.bld_base,
+ inst, 3, 0);
+
+ new_data = LLVMBuildBitCast(builder, new_data, ctx->i32, "");
+
+#if HAVE_LLVM >= 0x309
+ result = LLVMBuildAtomicCmpXchg(builder, ptr, arg, new_data,
+ LLVMAtomicOrderingSequentiallyConsistent,
+ LLVMAtomicOrderingSequentiallyConsistent,
+ false);
+#endif
+
+ result = LLVMBuildExtractValue(builder, result, 0, "");
+ } else {
+ LLVMAtomicRMWBinOp op;
+
+ switch(inst->Instruction.Opcode) {
+ case TGSI_OPCODE_ATOMUADD:
+ op = LLVMAtomicRMWBinOpAdd;
+ break;
+ case TGSI_OPCODE_ATOMXCHG:
+ op = LLVMAtomicRMWBinOpXchg;
+ break;
+ case TGSI_OPCODE_ATOMAND:
+ op = LLVMAtomicRMWBinOpAnd;
+ break;
+ case TGSI_OPCODE_ATOMOR:
+ op = LLVMAtomicRMWBinOpOr;
+ break;
+ case TGSI_OPCODE_ATOMXOR:
+ op = LLVMAtomicRMWBinOpXor;
+ break;
+ case TGSI_OPCODE_ATOMUMIN:
+ op = LLVMAtomicRMWBinOpUMin;
+ break;
+ case TGSI_OPCODE_ATOMUMAX:
+ op = LLVMAtomicRMWBinOpUMax;
+ break;
+ case TGSI_OPCODE_ATOMIMIN:
+ op = LLVMAtomicRMWBinOpMin;
+ break;
+ case TGSI_OPCODE_ATOMIMAX:
+ op = LLVMAtomicRMWBinOpMax;
+ break;
+ default:
+ unreachable("unknown atomic opcode");
+ }
+
+ result = LLVMBuildAtomicRMW(builder, op, ptr, arg,
+ LLVMAtomicOrderingSequentiallyConsistent,
+ false);
+ }
+ emit_data->output[emit_data->chan] = LLVMBuildBitCast(builder, result, emit_data->dst_type, "");
+}
+
static void atomic_emit(
const struct lp_build_tgsi_action *action,
struct lp_build_tgsi_context *bld_base,
struct lp_build_emit_data *emit_data)
{
+ struct si_shader_context *ctx = si_shader_context(bld_base);
struct gallivm_state *gallivm = bld_base->base.gallivm;
LLVMBuilderRef builder = gallivm->builder;
const struct tgsi_full_instruction * inst = emit_data->inst;
char intrinsic_name[40];
LLVMValueRef tmp;
+ if (inst->Src[0].Register.File == TGSI_FILE_MEMORY) {
+ atomic_emit_memory(ctx, emit_data);
+ return;
+ }
+
if (inst->Src[0].Register.File == TGSI_FILE_BUFFER ||
inst->Memory.Texture == TGSI_TEXTURE_BUFFER) {
snprintf(intrinsic_name, sizeof(intrinsic_name),