diff options
author | Bas Nieuwenhuizen <[email protected]> | 2016-03-29 13:20:26 +0200 |
---|---|---|
committer | Bas Nieuwenhuizen <[email protected]> | 2016-04-19 18:10:31 +0200 |
commit | b082147b788ee45862f8d1b0e1b47478d6b99447 (patch) | |
tree | 670887a06d53257f8eb400eef1de3f5b95a07610 | |
parent | 8acf3e501b40aa30371105c18187441085369dfe (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.c | 77 |
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), |