From: Marek Olšák <marek.ol...@amd.com> --- src/gallium/drivers/radeonsi/si_shader.c | 114 ++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 10 deletions(-)
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index 6ccb407..467d0bd 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -3436,22 +3436,37 @@ static void load_fetch_args( emit_data->args[0] = coords; emit_data->args[1] = rsrc; emit_data->args[2] = lp_build_const_int32(gallivm, 15); /* dmask */ emit_data->arg_count = 3; image_append_args(ctx, emit_data, target, false, false); } } } +static unsigned get_load_intr_attribs(bool readonly_memory) +{ + /* READNONE means writes can't affect it, while READONLY means that + * writes can affect it. */ + return readonly_memory ? LP_FUNC_ATTR_READNONE : + LP_FUNC_ATTR_READONLY; +} + +static unsigned get_store_intr_attribs(bool writeonly_memory) +{ + return writeonly_memory ? LP_FUNC_ATTR_INACCESSIBLE_MEM_ONLY : + LP_FUNC_ATTR_WRITEONLY; +} + static void load_emit_buffer(struct si_shader_context *ctx, - struct lp_build_emit_data *emit_data) + struct lp_build_emit_data *emit_data, + bool readonly_memory) { const struct tgsi_full_instruction *inst = emit_data->inst; struct gallivm_state *gallivm = &ctx->gallivm; LLVMBuilderRef builder = gallivm->builder; uint writemask = inst->Dst[0].Register.WriteMask; uint count = util_last_bit(writemask); const char *intrinsic_name; LLVMTypeRef dst_type; switch (count) { @@ -3465,21 +3480,21 @@ static void load_emit_buffer(struct si_shader_context *ctx, break; default: // 3 & 4 intrinsic_name = "llvm.amdgcn.buffer.load.v4f32"; dst_type = ctx->v4f32; count = 4; } emit_data->output[emit_data->chan] = lp_build_intrinsic( builder, intrinsic_name, dst_type, emit_data->args, emit_data->arg_count, - LP_FUNC_ATTR_READONLY); + get_load_intr_attribs(readonly_memory)); } static LLVMValueRef get_memory_ptr(struct si_shader_context *ctx, const struct tgsi_full_instruction *inst, LLVMTypeRef type, int arg) { struct gallivm_state *gallivm = &ctx->gallivm; LLVMBuilderRef builder = gallivm->builder; LLVMValueRef offset, ptr; int addr_space; @@ -3541,62 +3556,132 @@ static void get_image_intr_name(const char *base_name, ac_build_type_name_for_intr(data_type, data_type_name, sizeof(data_type_name)); ac_build_type_name_for_intr(rsrc_type, rsrc_type_name, sizeof(rsrc_type_name)); snprintf(out_name, out_len, "%s.%s.%s.%s", base_name, data_type_name, coords_type_name, rsrc_type_name); } } +/** + * Return true if the memory accessed by a LOAD or STORE instruction is + * read-only or write-only, respectively. + * + * \param shader_buffers_reverse_access_mask + * For LOAD, set this to (store | atomic) slot usage in the shader. + * For STORE, set this to (load | atomic) slot usage in the shader. + * \param images_reverse_access_mask Same as above, but for images. + */ +static bool is_oneway_access_only(const struct tgsi_full_instruction *inst, + const struct tgsi_shader_info *info, + unsigned shader_buffers_reverse_access_mask, + unsigned images_reverse_access_mask) +{ + /* RESTRICT means NOALIAS. + * If there are no writes, we can assume the accessed memory is read-only. + * If there are no reads, we can assume the accessed memory is write-only. + */ + if (inst->Memory.Qualifier & TGSI_MEMORY_RESTRICT) { + unsigned reverse_access_mask; + + if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) { + reverse_access_mask = shader_buffers_reverse_access_mask; + } else if (inst->Memory.Texture == TGSI_TEXTURE_BUFFER) { + reverse_access_mask = info->images_buffers & + images_reverse_access_mask; + } else { + reverse_access_mask = ~info->images_buffers & + images_reverse_access_mask; + } + + if (inst->Src[0].Register.Indirect) { + if (!reverse_access_mask) + return true; + } else { + if (!(reverse_access_mask & + (1u << inst->Src[0].Register.Index))) + return true; + } + } + + /* If there are no buffer writes (for both shader buffers & image + * buffers), it implies that buffer memory is read-only. + * If there are no buffer reads (for both shader buffers & image + * buffers), it implies that buffer memory is write-only. + * + * Same for the case when there are no writes/reads for non-buffer + * images. + */ + if (inst->Src[0].Register.File == TGSI_FILE_BUFFER || + (inst->Src[0].Register.File == TGSI_FILE_IMAGE && + inst->Memory.Texture == TGSI_TEXTURE_BUFFER)) { + if (!shader_buffers_reverse_access_mask && + !(info->images_buffers & images_reverse_access_mask)) + return true; + } else { + if (!(~info->images_buffers & images_reverse_access_mask)) + return true; + } + return false; +} + static void load_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; + const struct tgsi_shader_info *info = &ctx->shader->selector->info; char intrinsic_name[64]; + bool readonly_memory = false; if (inst->Src[0].Register.File == TGSI_FILE_MEMORY) { load_emit_memory(ctx, emit_data); return; } if (inst->Memory.Qualifier & TGSI_MEMORY_VOLATILE) emit_waitcnt(ctx, VM_CNT); + readonly_memory = is_oneway_access_only(inst, info, + info->shader_buffers_store | + info->shader_buffers_atomic, + info->images_store | + info->images_atomic); + if (inst->Src[0].Register.File == TGSI_FILE_BUFFER) { - load_emit_buffer(ctx, emit_data); + load_emit_buffer(ctx, emit_data, readonly_memory); return; } if (inst->Memory.Texture == TGSI_TEXTURE_BUFFER) { emit_data->output[emit_data->chan] = lp_build_intrinsic( builder, "llvm.amdgcn.buffer.load.format.v4f32", emit_data->dst_type, emit_data->args, emit_data->arg_count, - LP_FUNC_ATTR_READONLY); + get_load_intr_attribs(readonly_memory)); } else { get_image_intr_name("llvm.amdgcn.image.load", emit_data->dst_type, /* vdata */ LLVMTypeOf(emit_data->args[0]), /* coords */ LLVMTypeOf(emit_data->args[1]), /* rsrc */ intrinsic_name, sizeof(intrinsic_name)); emit_data->output[emit_data->chan] = lp_build_intrinsic( builder, intrinsic_name, emit_data->dst_type, emit_data->args, emit_data->arg_count, - LP_FUNC_ATTR_READONLY); + get_load_intr_attribs(readonly_memory)); } } static void store_fetch_args( 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; @@ -3654,21 +3739,22 @@ static void store_fetch_args( emit_data->args[3] = lp_build_const_int32(gallivm, 15); /* dmask */ emit_data->arg_count = 4; image_append_args(ctx, emit_data, target, false, force_glc); } } } static void store_emit_buffer( struct si_shader_context *ctx, - struct lp_build_emit_data *emit_data) + struct lp_build_emit_data *emit_data, + bool writeonly_memory) { const struct tgsi_full_instruction *inst = emit_data->inst; struct gallivm_state *gallivm = &ctx->gallivm; LLVMBuilderRef builder = gallivm->builder; struct lp_build_context *uint_bld = &ctx->bld_base.uint_bld; LLVMValueRef base_data = emit_data->args[0]; LLVMValueRef base_offset = emit_data->args[3]; unsigned writemask = inst->Dst[0].Register.WriteMask; while (writemask) { @@ -3721,21 +3807,21 @@ static void store_emit_buffer( builder, offset, lp_build_const_int32(gallivm, start * 4), ""); } emit_data->args[0] = data; emit_data->args[3] = offset; lp_build_intrinsic( builder, intrinsic_name, emit_data->dst_type, emit_data->args, emit_data->arg_count, - LP_FUNC_ATTR_WRITEONLY); + get_store_intr_attribs(writeonly_memory)); } } static void store_emit_memory( struct si_shader_context *ctx, struct lp_build_emit_data *emit_data) { const struct tgsi_full_instruction *inst = emit_data->inst; struct gallivm_state *gallivm = &ctx->gallivm; struct lp_build_context *base = &ctx->bld_base.base; @@ -3759,54 +3845,62 @@ static void store_emit_memory( static void store_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; + const struct tgsi_shader_info *info = &ctx->shader->selector->info; unsigned target = inst->Memory.Texture; char intrinsic_name[64]; + bool writeonly_memory = false; if (inst->Dst[0].Register.File == TGSI_FILE_MEMORY) { store_emit_memory(ctx, emit_data); return; } if (inst->Memory.Qualifier & TGSI_MEMORY_VOLATILE) emit_waitcnt(ctx, VM_CNT); + writeonly_memory = is_oneway_access_only(inst, info, + info->shader_buffers_load | + info->shader_buffers_atomic, + info->images_load | + info->images_atomic); + if (inst->Dst[0].Register.File == TGSI_FILE_BUFFER) { - store_emit_buffer(ctx, emit_data); + store_emit_buffer(ctx, emit_data, writeonly_memory); return; } if (target == TGSI_TEXTURE_BUFFER) { emit_data->output[emit_data->chan] = lp_build_intrinsic( builder, "llvm.amdgcn.buffer.store.format.v4f32", emit_data->dst_type, emit_data->args, emit_data->arg_count, - LP_FUNC_ATTR_WRITEONLY); + get_store_intr_attribs(writeonly_memory)); } else { get_image_intr_name("llvm.amdgcn.image.store", LLVMTypeOf(emit_data->args[0]), /* vdata */ LLVMTypeOf(emit_data->args[1]), /* coords */ LLVMTypeOf(emit_data->args[2]), /* rsrc */ intrinsic_name, sizeof(intrinsic_name)); emit_data->output[emit_data->chan] = lp_build_intrinsic( builder, intrinsic_name, emit_data->dst_type, emit_data->args, emit_data->arg_count, - LP_FUNC_ATTR_WRITEONLY); + get_store_intr_attribs(writeonly_memory)); } } static void atomic_fetch_args( 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; -- 2.7.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev