[Mesa-dev] [PATCH 28/61] radeonsi/gfx9: set EXEC for non-mono merged shaders, add a barrier between them

Marek Olšák maraeo at gmail.com
Mon Apr 24 08:45:25 UTC 2017


From: Marek Olšák <marek.olsak at amd.com>

---
 src/gallium/drivers/radeonsi/si_shader.c | 43 ++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 4bdbe2f..823ffff 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -7209,23 +7209,36 @@ static void si_count_scratch_private_memory(struct si_shader_context *ctx)
 			LLVMTypeRef type = LLVMGetElementType(LLVMTypeOf(inst));
 			/* No idea why LLVM aligns allocas to 4 elements. */
 			unsigned alignment = LLVMGetAlignment(inst);
 			unsigned dw_size = align(llvm_get_type_size(type) / 4, alignment);
 			ctx->shader->config.private_mem_vgprs += dw_size;
 		}
 		bb = LLVMGetNextBasicBlock(bb);
 	}
 }
 
+static void si_init_exec_from_input(struct si_shader_context *ctx,
+				    unsigned param, unsigned bitoffset)
+{
+	LLVMValueRef args[] = {
+		LLVMGetParam(ctx->main_fn, param),
+		LLVMConstInt(ctx->i32, bitoffset, 0),
+	};
+	lp_build_intrinsic(ctx->gallivm.builder,
+			   "llvm.amdgcn.init.exec.from.input",
+			   ctx->voidt, args, 2, LP_FUNC_ATTR_CONVERGENT);
+}
+
 static bool si_compile_tgsi_main(struct si_shader_context *ctx,
-				 struct si_shader *shader)
+				 bool is_monolithic)
 {
+	struct si_shader *shader = ctx->shader;
 	struct si_shader_selector *sel = shader->selector;
 	struct lp_build_tgsi_context *bld_base = &ctx->bld_base;
 
 	switch (ctx->type) {
 	case PIPE_SHADER_VERTEX:
 		ctx->load_input = declare_input_vs;
 		if (shader->key.as_ls)
 			bld_base->emit_epilogue = si_llvm_emit_ls_epilogue;
 		else if (shader->key.as_es)
 			bld_base->emit_epilogue = si_llvm_emit_es_epilogue;
@@ -7257,20 +7270,43 @@ static bool si_compile_tgsi_main(struct si_shader_context *ctx,
 		ctx->declare_memory_region = declare_compute_memory;
 		break;
 	default:
 		assert(!"Unsupported shader type");
 		return false;
 	}
 
 	create_function(ctx);
 	preload_ring_buffers(ctx);
 
+	/* For GFX9 merged shaders:
+	 * - Set EXEC. If the prolog is present, set EXEC there instead.
+	 * - Add a barrier before the second shader.
+	 *
+	 * The same thing for monolithic shaders is done in
+	 * si_build_wrapper_function.
+	 */
+	if (ctx->screen->b.chip_class >= GFX9 && !is_monolithic) {
+		if (sel->info.num_instructions > 1 && /* not empty shader */
+		    (shader->key.as_es || shader->key.as_ls) &&
+		    (ctx->type == PIPE_SHADER_TESS_EVAL ||
+		     (ctx->type == PIPE_SHADER_VERTEX &&
+		      !sel->vs_needs_prolog))) {
+			si_init_exec_from_input(ctx,
+						ctx->param_merged_wave_info, 0);
+		} else if (ctx->type == PIPE_SHADER_TESS_CTRL ||
+			   ctx->type == PIPE_SHADER_GEOMETRY) {
+			si_init_exec_from_input(ctx,
+						ctx->param_merged_wave_info, 8);
+			si_llvm_emit_barrier(NULL, bld_base, NULL);
+		}
+	}
+
 	if (ctx->type == PIPE_SHADER_GEOMETRY) {
 		int i;
 		for (i = 0; i < 4; i++) {
 			ctx->gs_next_vertex[i] =
 				lp_build_alloca(&ctx->gallivm,
 						ctx->i32, "");
 		}
 	}
 
 	if (!lp_build_tgsi_llvm(bld_base, sel->tokens)) {
@@ -7771,21 +7807,21 @@ int si_compile_tgsi_shader(struct si_screen *sscreen,
 	si_llvm_context_set_tgsi(&ctx, shader);
 	ctx.separate_prolog = !is_monolithic;
 
 	memset(shader->info.vs_output_param_offset, EXP_PARAM_UNDEFINED,
 	       sizeof(shader->info.vs_output_param_offset));
 
 	shader->info.uses_instanceid = sel->info.uses_instanceid;
 
 	ctx.load_system_value = declare_system_value;
 
-	if (!si_compile_tgsi_main(&ctx, shader)) {
+	if (!si_compile_tgsi_main(&ctx, is_monolithic)) {
 		si_llvm_dispose(&ctx);
 		return -1;
 	}
 
 	if (is_monolithic && ctx.type == PIPE_SHADER_VERTEX) {
 		LLVMValueRef parts[3];
 		bool need_prolog;
 		bool need_epilog;
 
 		need_prolog = sel->vs_needs_prolog;
@@ -8121,20 +8157,23 @@ static void si_build_vs_prolog_function(struct si_shader_context *ctx,
 
 	/* Vertex load indices. */
 	for (i = 0; i <= key->vs_prolog.last_input; i++)
 		returns[num_returns++] = ctx->f32;
 
 	/* Create the function. */
 	si_create_function(ctx, "vs_prolog", returns, num_returns, params,
 			   num_params, last_sgpr);
 	func = ctx->main_fn;
 
+	if (key->vs_prolog.num_merged_next_stage_vgprs)
+		si_init_exec_from_input(ctx, 3, 0);
+
 	/* Copy inputs to outputs. This should be no-op, as the registers match,
 	 * but it will prevent the compiler from overwriting them unintentionally.
 	 */
 	ret = ctx->return_value;
 	for (i = 0; i < key->vs_prolog.num_input_sgprs; i++) {
 		LLVMValueRef p = LLVMGetParam(func, i);
 		ret = LLVMBuildInsertValue(gallivm->builder, ret, p, i, "");
 	}
 	for (; i < num_params; i++) {
 		LLVMValueRef p = LLVMGetParam(func, i);
-- 
2.7.4



More information about the mesa-dev mailing list