[Mesa-dev] [PATCH 11/20] radeonsi: split the shader key into 3 logical parts

Marek Olšák maraeo at gmail.com
Wed Nov 16 18:38:34 UTC 2016


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

key->part.*: prolog and epilog flags only
key->as_{ls,es}: special flags
key->mono.*: flags for monolithic compilation only
---
 src/gallium/drivers/radeonsi/si_pipe.h          |   4 +-
 src/gallium/drivers/radeonsi/si_shader.c        | 194 ++++++++++++------------
 src/gallium/drivers/radeonsi/si_shader.h        |  65 ++++----
 src/gallium/drivers/radeonsi/si_state.c         |   2 +-
 src/gallium/drivers/radeonsi/si_state_shaders.c | 132 ++++++++--------
 5 files changed, 203 insertions(+), 194 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index df2f130..847281e 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -456,18 +456,18 @@ static inline struct si_shader* si_get_vs_state(struct si_context *sctx)
 		return sctx->gs_shader.cso->gs_copy_shader;
 	else if (sctx->tes_shader.current)
 		return sctx->tes_shader.current;
 	else
 		return sctx->vs_shader.current;
 }
 
 static inline bool si_vs_exports_prim_id(struct si_shader *shader)
 {
 	if (shader->selector->type == PIPE_SHADER_VERTEX)
-		return shader->key.vs.epilog.export_prim_id;
+		return shader->key.part.vs.epilog.export_prim_id;
 	else if (shader->selector->type == PIPE_SHADER_TESS_EVAL)
-		return shader->key.tes.epilog.export_prim_id;
+		return shader->key.part.tes.epilog.export_prim_id;
 	else
 		return false;
 }
 
 #endif
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index 917e148..4e73d59 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -61,21 +61,21 @@ struct si_shader_output_values
 
 static void si_init_shader_ctx(struct si_shader_context *ctx,
 			       struct si_screen *sscreen,
 			       struct si_shader *shader,
 			       LLVMTargetMachineRef tm);
 
 static void si_llvm_emit_barrier(const struct lp_build_tgsi_action *action,
 				 struct lp_build_tgsi_context *bld_base,
 				 struct lp_build_emit_data *emit_data);
 
-static void si_dump_shader_key(unsigned shader, union si_shader_key *key,
+static void si_dump_shader_key(unsigned shader, struct si_shader_key *key,
 			       FILE *f);
 
 static void si_build_vs_prolog_function(struct si_shader_context *ctx,
 					union si_shader_part_key *key);
 static void si_build_vs_epilog_function(struct si_shader_context *ctx,
 					union si_shader_part_key *key);
 static void si_build_tcs_epilog_function(struct si_shader_context *ctx,
 					 union si_shader_part_key *key);
 static void si_build_ps_prolog_function(struct si_shader_context *ctx,
 					union si_shader_part_key *key);
@@ -409,21 +409,21 @@ static void declare_input_vs(
 		"llvm.SI.vs.load.input", ctx->v4f32, args, 3,
 		LP_FUNC_ATTR_READNONE);
 
 	/* Break up the vec4 into individual components */
 	for (chan = 0; chan < 4; chan++) {
 		LLVMValueRef llvm_chan = lp_build_const_int32(gallivm, chan);
 		out[chan] = LLVMBuildExtractElement(gallivm->builder,
 						    input, llvm_chan, "");
 	}
 
-	fix_fetch = (ctx->shader->key.vs.fix_fetch >> (2 * input_index)) & 3;
+	fix_fetch = (ctx->shader->key.mono.vs.fix_fetch >> (2 * input_index)) & 3;
 	if (fix_fetch) {
 		/* The hardware returns an unsigned value; convert it to a
 		 * signed one.
 		 */
 		LLVMValueRef tmp = out[3];
 		LLVMValueRef c30 = LLVMConstInt(ctx->i32, 30, 0);
 
 		/* First, recover the sign-extended signed integer value. */
 		if (fix_fetch == SI_FIX_FETCH_A2_SSCALED)
 			tmp = LLVMBuildFPToUI(gallivm->builder, tmp, ctx->i32, "");
@@ -1245,21 +1245,21 @@ static void interp_fs_input(struct si_shader_context *ctx,
 	 * vertices).
 	 *
 	 * Luckily, it doesn't matter, because we rely on the FLAT_SHADE state
 	 * to do the right thing. The only reason we use fs.constant is that
 	 * fs.interp cannot be used on integers, because they can be equal
 	 * to NaN.
 	 */
 	intr_name = interp_param ? "llvm.SI.fs.interp" : "llvm.SI.fs.constant";
 
 	if (semantic_name == TGSI_SEMANTIC_COLOR &&
-	    ctx->shader->key.ps.prolog.color_two_side) {
+	    ctx->shader->key.part.ps.prolog.color_two_side) {
 		LLVMValueRef args[4];
 		LLVMValueRef is_face_positive;
 		LLVMValueRef back_attr_number;
 
 		/* If BCOLOR0 is used, BCOLOR1 is at offset "num_inputs + 1",
 		 * otherwise it's at offset "num_inputs".
 		 */
 		unsigned back_attr_offset = num_interp_inputs;
 		if (semantic_index == 1 && colors_read_mask & 0xf)
 			back_attr_offset += 1;
@@ -1353,21 +1353,21 @@ static void declare_input_fs(
 	interp_param_idx = lookup_interp_param_index(decl->Interp.Interpolate,
 						     decl->Interp.Location);
 	if (interp_param_idx == -1)
 		return;
 	else if (interp_param_idx) {
 		interp_param = LLVMGetParam(ctx->main_fn, interp_param_idx);
 	}
 
 	if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
 	    decl->Interp.Interpolate == TGSI_INTERPOLATE_COLOR &&
-	    ctx->shader->key.ps.prolog.flatshade_colors)
+	    ctx->shader->key.part.ps.prolog.flatshade_colors)
 		interp_param = NULL; /* load the constant color */
 
 	interp_fs_input(ctx, input_index, decl->Semantic.Name,
 			decl->Semantic.Index, shader->selector->info.num_inputs,
 			shader->selector->info.colors_read, interp_param,
 			LLVMGetParam(main_fn, SI_PARAM_PRIM_MASK),
 			LLVMGetParam(main_fn, SI_PARAM_FRONT_FACE),
 			&out[0]);
 }
 
@@ -1825,27 +1825,27 @@ static void si_llvm_init_export_args(struct lp_build_tgsi_context *bld_base,
 	/* Specify whether the EXEC mask represents the valid mask */
 	args[1] = uint->zero;
 
 	/* Specify whether this is the last export */
 	args[2] = uint->zero;
 
 	/* Specify the target we are exporting */
 	args[3] = lp_build_const_int32(base->gallivm, target);
 
 	if (ctx->type == PIPE_SHADER_FRAGMENT) {
-		const union si_shader_key *key = &ctx->shader->key;
-		unsigned col_formats = key->ps.epilog.spi_shader_col_format;
+		const struct si_shader_key *key = &ctx->shader->key;
+		unsigned col_formats = key->part.ps.epilog.spi_shader_col_format;
 		int cbuf = target - V_008DFC_SQ_EXP_MRT;
 
 		assert(cbuf >= 0 && cbuf < 8);
 		spi_shader_col_format = (col_formats >> (cbuf * 4)) & 0xf;
-		is_int8 = (key->ps.epilog.color_is_int8 >> cbuf) & 0x1;
+		is_int8 = (key->part.ps.epilog.color_is_int8 >> cbuf) & 0x1;
 	}
 
 	args[4] = uint->zero; /* COMPR flag */
 	args[5] = base->undef;
 	args[6] = base->undef;
 	args[7] = base->undef;
 	args[8] = base->undef;
 
 	switch (spi_shader_col_format) {
 	case V_028714_SPI_SHADER_ZERO:
@@ -1984,27 +1984,27 @@ static void si_llvm_init_export_args(struct lp_build_tgsi_context *bld_base,
 		break;
 	}
 }
 
 static void si_alpha_test(struct lp_build_tgsi_context *bld_base,
 			  LLVMValueRef alpha)
 {
 	struct si_shader_context *ctx = si_shader_context(bld_base);
 	struct gallivm_state *gallivm = bld_base->base.gallivm;
 
-	if (ctx->shader->key.ps.epilog.alpha_func != PIPE_FUNC_NEVER) {
+	if (ctx->shader->key.part.ps.epilog.alpha_func != PIPE_FUNC_NEVER) {
 		LLVMValueRef alpha_ref = LLVMGetParam(ctx->main_fn,
 				SI_PARAM_ALPHA_REF);
 
 		LLVMValueRef alpha_pass =
 			lp_build_cmp(&bld_base->base,
-				     ctx->shader->key.ps.epilog.alpha_func,
+				     ctx->shader->key.part.ps.epilog.alpha_func,
 				     alpha, alpha_ref);
 		LLVMValueRef arg =
 			lp_build_select(&bld_base->base,
 					alpha_pass,
 					lp_build_const_float(gallivm, 1.0f),
 					lp_build_const_float(gallivm, -1.0f));
 
 		lp_build_intrinsic(gallivm->builder, "llvm.AMDGPU.kill",
 				   ctx->voidt, &arg, 1, 0);
 	} else {
@@ -2433,21 +2433,21 @@ static void si_copy_tcs_inputs(struct lp_build_tgsi_context *bld_base)
 	                lp_build_const_int32(gallivm, SI_HS_RING_TESS_OFFCHIP));
 
 	buffer_offset = LLVMGetParam(ctx->main_fn, ctx->param_oc_lds);
 
 	lds_vertex_stride = unpack_param(ctx, SI_PARAM_TCS_IN_LAYOUT, 13, 8);
 	lds_vertex_offset = LLVMBuildMul(gallivm->builder, invocation_id,
 	                                 lds_vertex_stride, "");
 	lds_base = get_tcs_in_current_patch_offset(ctx);
 	lds_base = LLVMBuildAdd(gallivm->builder, lds_base, lds_vertex_offset, "");
 
-	inputs = ctx->shader->key.tcs.epilog.inputs_to_copy;
+	inputs = ctx->shader->key.mono.tcs.inputs_to_copy;
 	while (inputs) {
 		unsigned i = u_bit_scan64(&inputs);
 
 		LLVMValueRef lds_ptr = LLVMBuildAdd(gallivm->builder, lds_base,
 		                            lp_build_const_int32(gallivm, 4 * i),
 		                             "");
 
 		LLVMValueRef buffer_addr = get_tcs_tes_buffer_address(ctx,
 		                              invocation_id,
 		                              lp_build_const_int32(gallivm, i));
@@ -2480,21 +2480,21 @@ static void si_write_tess_factors(struct lp_build_tgsi_context *bld_base,
 	 * not per-vertex.
 	 *
 	 * This can't jump, because invocation 0 executes this. It should
 	 * at least mask out the loads and stores for other invocations.
 	 */
 	lp_build_if(&if_ctx, gallivm,
 		    LLVMBuildICmp(gallivm->builder, LLVMIntEQ,
 				  invocation_id, bld_base->uint_bld.zero, ""));
 
 	/* Determine the layout of one tess factor element in the buffer. */
-	switch (shader->key.tcs.epilog.prim_mode) {
+	switch (shader->key.part.tcs.epilog.prim_mode) {
 	case PIPE_PRIM_LINES:
 		stride = 2; /* 2 dwords, 1 vec2 store */
 		outer_comps = 2;
 		inner_comps = 0;
 		break;
 	case PIPE_PRIM_TRIANGLES:
 		stride = 4; /* 4 dwords, 1 vec4 store */
 		outer_comps = 3;
 		inner_comps = 1;
 		break;
@@ -2867,53 +2867,53 @@ static void si_export_mrt_z(struct lp_build_tgsi_context *bld_base,
 static void si_export_mrt_color(struct lp_build_tgsi_context *bld_base,
 				LLVMValueRef *color, unsigned index,
 				unsigned samplemask_param,
 				bool is_last, struct si_ps_exports *exp)
 {
 	struct si_shader_context *ctx = si_shader_context(bld_base);
 	struct lp_build_context *base = &bld_base->base;
 	int i;
 
 	/* Clamp color */
-	if (ctx->shader->key.ps.epilog.clamp_color)
+	if (ctx->shader->key.part.ps.epilog.clamp_color)
 		for (i = 0; i < 4; i++)
 			color[i] = si_llvm_saturate(bld_base, color[i]);
 
 	/* Alpha to one */
-	if (ctx->shader->key.ps.epilog.alpha_to_one)
+	if (ctx->shader->key.part.ps.epilog.alpha_to_one)
 		color[3] = base->one;
 
 	/* Alpha test */
 	if (index == 0 &&
-	    ctx->shader->key.ps.epilog.alpha_func != PIPE_FUNC_ALWAYS)
+	    ctx->shader->key.part.ps.epilog.alpha_func != PIPE_FUNC_ALWAYS)
 		si_alpha_test(bld_base, color[3]);
 
 	/* Line & polygon smoothing */
-	if (ctx->shader->key.ps.epilog.poly_line_smoothing)
+	if (ctx->shader->key.part.ps.epilog.poly_line_smoothing)
 		color[3] = si_scale_alpha_by_sample_mask(bld_base, color[3],
 							 samplemask_param);
 
 	/* If last_cbuf > 0, FS_COLOR0_WRITES_ALL_CBUFS is true. */
-	if (ctx->shader->key.ps.epilog.last_cbuf > 0) {
+	if (ctx->shader->key.part.ps.epilog.last_cbuf > 0) {
 		LLVMValueRef args[8][9];
 		int c, last = -1;
 
 		/* Get the export arguments, also find out what the last one is. */
-		for (c = 0; c <= ctx->shader->key.ps.epilog.last_cbuf; c++) {
+		for (c = 0; c <= ctx->shader->key.part.ps.epilog.last_cbuf; c++) {
 			si_llvm_init_export_args(bld_base, color,
 						 V_008DFC_SQ_EXP_MRT + c, args[c]);
 			if (args[c][0] != bld_base->uint_bld.zero)
 				last = c;
 		}
 
 		/* Emit all exports. */
-		for (c = 0; c <= ctx->shader->key.ps.epilog.last_cbuf; c++) {
+		for (c = 0; c <= ctx->shader->key.part.ps.epilog.last_cbuf; c++) {
 			if (is_last && last == c) {
 				args[c][1] = bld_base->uint_bld.one; /* whether the EXEC mask is valid */
 				args[c][2] = bld_base->uint_bld.one; /* DONE bit */
 			} else if (args[c][0] == bld_base->uint_bld.zero)
 				continue; /* unnecessary NULL export */
 
 			memcpy(exp->args[exp->num++], args[c], sizeof(args[c]));
 		}
 	} else {
 		LLVMValueRef args[9];
@@ -5340,23 +5340,23 @@ static void create_function(struct si_shader_context *ctx)
 	params[SI_PARAM_SHADER_BUFFERS] = const_array(ctx->v4i32, SI_NUM_SHADER_BUFFERS);
 
 	switch (ctx->type) {
 	case PIPE_SHADER_VERTEX:
 		params[SI_PARAM_VERTEX_BUFFERS] = const_array(ctx->v16i8, SI_NUM_VERTEX_BUFFERS);
 		params[SI_PARAM_BASE_VERTEX] = ctx->i32;
 		params[SI_PARAM_START_INSTANCE] = ctx->i32;
 		params[SI_PARAM_DRAWID] = ctx->i32;
 		num_params = SI_PARAM_DRAWID+1;
 
-		if (shader->key.vs.as_es) {
+		if (shader->key.as_es) {
 			params[ctx->param_es2gs_offset = num_params++] = ctx->i32;
-		} else if (shader->key.vs.as_ls) {
+		} else if (shader->key.as_ls) {
 			params[SI_PARAM_LS_OUT_LAYOUT] = ctx->i32;
 			num_params = SI_PARAM_LS_OUT_LAYOUT+1;
 		} else {
 			if (shader->is_gs_copy_shader) {
 				num_params = SI_PARAM_RW_BUFFERS+1;
 			} else {
 				params[SI_PARAM_VS_STATE_BITS] = ctx->i32;
 				num_params = SI_PARAM_VS_STATE_BITS+1;
 			}
 
@@ -5376,21 +5376,21 @@ static void create_function(struct si_shader_context *ctx)
 		if (!shader->is_gs_copy_shader) {
 			/* Vertex load indices. */
 			ctx->param_vertex_index0 = num_params;
 
 			for (i = 0; i < shader->selector->info.num_inputs; i++)
 				params[num_params++] = ctx->i32;
 
 			num_prolog_vgprs += shader->selector->info.num_inputs;
 
 			/* PrimitiveID output. */
-			if (!shader->key.vs.as_es && !shader->key.vs.as_ls)
+			if (!shader->key.as_es && !shader->key.as_ls)
 				for (i = 0; i <= VS_EPILOG_PRIMID_LOC; i++)
 					returns[num_returns++] = ctx->f32;
 		}
 		break;
 
 	case PIPE_SHADER_TESS_CTRL:
 		params[SI_PARAM_TCS_OFFCHIP_LAYOUT] = ctx->i32;
 		params[SI_PARAM_TCS_OUT_OFFSETS] = ctx->i32;
 		params[SI_PARAM_TCS_OUT_LAYOUT] = ctx->i32;
 		params[SI_PARAM_TCS_IN_LAYOUT] = ctx->i32;
@@ -5410,40 +5410,40 @@ static void create_function(struct si_shader_context *ctx)
 			returns[num_returns++] = ctx->i32; /* SGPRs */
 
 		for (i = 0; i < 3; i++)
 			returns[num_returns++] = ctx->f32; /* VGPRs */
 		break;
 
 	case PIPE_SHADER_TESS_EVAL:
 		params[SI_PARAM_TCS_OFFCHIP_LAYOUT] = ctx->i32;
 		num_params = SI_PARAM_TCS_OFFCHIP_LAYOUT+1;
 
-		if (shader->key.tes.as_es) {
+		if (shader->key.as_es) {
 			params[ctx->param_oc_lds = num_params++] = ctx->i32;
 			params[ctx->param_tess_offchip = num_params++] = ctx->i32;
 			params[ctx->param_es2gs_offset = num_params++] = ctx->i32;
 		} else {
 			params[ctx->param_tess_offchip = num_params++] = ctx->i32;
 			declare_streamout_params(ctx, &shader->selector->so,
 						 params, ctx->i32, &num_params);
 			params[ctx->param_oc_lds = num_params++] = ctx->i32;
 		}
 		last_sgpr = num_params - 1;
 
 		/* VGPRs */
 		params[ctx->param_tes_u = num_params++] = ctx->f32;
 		params[ctx->param_tes_v = num_params++] = ctx->f32;
 		params[ctx->param_tes_rel_patch_id = num_params++] = ctx->i32;
 		params[ctx->param_tes_patch_id = num_params++] = ctx->i32;
 
 		/* PrimitiveID output. */
-		if (!shader->key.tes.as_es)
+		if (!shader->key.as_es)
 			for (i = 0; i <= VS_EPILOG_PRIMID_LOC; i++)
 				returns[num_returns++] = ctx->f32;
 		break;
 
 	case PIPE_SHADER_GEOMETRY:
 		params[SI_PARAM_GS2VS_OFFSET] = ctx->i32;
 		params[SI_PARAM_GS_WAVE_ID] = ctx->i32;
 		last_sgpr = SI_PARAM_GS_WAVE_ID;
 
 		/* VGPRs */
@@ -5583,42 +5583,42 @@ static void create_function(struct si_shader_context *ctx)
 	     bld_base->info->opcode_count[TGSI_OPCODE_DDX_FINE] > 0 ||
 	     bld_base->info->opcode_count[TGSI_OPCODE_DDY_FINE] > 0 ||
 	     bld_base->info->opcode_count[TGSI_OPCODE_INTERP_OFFSET] > 0 ||
 	     bld_base->info->opcode_count[TGSI_OPCODE_INTERP_SAMPLE] > 0))
 		ctx->lds =
 			LLVMAddGlobalInAddressSpace(gallivm->module,
 						    LLVMArrayType(ctx->i32, 64),
 						    "ddxy_lds",
 						    LOCAL_ADDR_SPACE);
 
-	if ((ctx->type == PIPE_SHADER_VERTEX && shader->key.vs.as_ls) ||
+	if ((ctx->type == PIPE_SHADER_VERTEX && shader->key.as_ls) ||
 	    ctx->type == PIPE_SHADER_TESS_CTRL ||
 	    ctx->type == PIPE_SHADER_TESS_EVAL)
 		declare_tess_lds(ctx);
 }
 
 /**
  * Load ESGS and GSVS ring buffer resource descriptors and save the variables
  * for later use.
  */
 static void preload_ring_buffers(struct si_shader_context *ctx)
 {
 	struct gallivm_state *gallivm =
 		ctx->soa.bld_base.base.gallivm;
 
 	LLVMValueRef buf_ptr = LLVMGetParam(ctx->main_fn,
 					    SI_PARAM_RW_BUFFERS);
 
 	if ((ctx->type == PIPE_SHADER_VERTEX &&
-	     ctx->shader->key.vs.as_es) ||
+	     ctx->shader->key.as_es) ||
 	    (ctx->type == PIPE_SHADER_TESS_EVAL &&
-	     ctx->shader->key.tes.as_es) ||
+	     ctx->shader->key.as_es) ||
 	    ctx->type == PIPE_SHADER_GEOMETRY) {
 		unsigned ring =
 			ctx->type == PIPE_SHADER_GEOMETRY ? SI_GS_RING_ESGS
 							     : SI_ES_RING_ESGS;
 		LLVMValueRef offset = lp_build_const_int32(gallivm, ring);
 
 		ctx->esgs_ring =
 			build_indexed_load_const(ctx, buf_ptr, offset);
 	}
 
@@ -5969,30 +5969,30 @@ static void si_shader_dump_stats(struct si_screen *sscreen,
 			   conf->lds_size, conf->scratch_bytes_per_wave,
 			   max_simd_waves, conf->spilled_sgprs,
 			   conf->spilled_vgprs);
 }
 
 static const char *si_get_shader_name(struct si_shader *shader,
 				      unsigned processor)
 {
 	switch (processor) {
 	case PIPE_SHADER_VERTEX:
-		if (shader->key.vs.as_es)
+		if (shader->key.as_es)
 			return "Vertex Shader as ES";
-		else if (shader->key.vs.as_ls)
+		else if (shader->key.as_ls)
 			return "Vertex Shader as LS";
 		else
 			return "Vertex Shader as VS";
 	case PIPE_SHADER_TESS_CTRL:
 		return "Tessellation Control Shader";
 	case PIPE_SHADER_TESS_EVAL:
-		if (shader->key.tes.as_es)
+		if (shader->key.as_es)
 			return "Tessellation Evaluation Shader as ES";
 		else
 			return "Tessellation Evaluation Shader as VS";
 	case PIPE_SHADER_GEOMETRY:
 		if (shader->is_gs_copy_shader)
 			return "GS Copy Shader as VS";
 		else
 			return "Geometry Shader";
 	case PIPE_SHADER_FRAGMENT:
 		return "Pixel Shader";
@@ -6214,69 +6214,69 @@ si_generate_gs_copy_shader(struct si_screen *sscreen,
 
 	FREE(outputs);
 
 	if (r != 0) {
 		FREE(shader);
 		shader = NULL;
 	}
 	return shader;
 }
 
-static void si_dump_shader_key(unsigned shader, union si_shader_key *key,
+static void si_dump_shader_key(unsigned shader, struct si_shader_key *key,
 			       FILE *f)
 {
 	int i;
 
 	fprintf(f, "SHADER KEY\n");
 
 	switch (shader) {
 	case PIPE_SHADER_VERTEX:
-		fprintf(f, "  instance_divisors = {");
-		for (i = 0; i < ARRAY_SIZE(key->vs.prolog.instance_divisors); i++)
+		fprintf(f, "  part.vs.prolog.instance_divisors = {");
+		for (i = 0; i < ARRAY_SIZE(key->part.vs.prolog.instance_divisors); i++)
 			fprintf(f, !i ? "%u" : ", %u",
-				key->vs.prolog.instance_divisors[i]);
+				key->part.vs.prolog.instance_divisors[i]);
 		fprintf(f, "}\n");
-		fprintf(f, "  as_es = %u\n", key->vs.as_es);
-		fprintf(f, "  as_ls = %u\n", key->vs.as_ls);
-		fprintf(f, "  export_prim_id = %u\n", key->vs.epilog.export_prim_id);
+		fprintf(f, "  part.vs.epilog.export_prim_id = %u\n", key->part.vs.epilog.export_prim_id);
+		fprintf(f, "  as_es = %u\n", key->as_es);
+		fprintf(f, "  as_ls = %u\n", key->as_ls);
 		break;
 
 	case PIPE_SHADER_TESS_CTRL:
-		fprintf(f, "  prim_mode = %u\n", key->tcs.epilog.prim_mode);
+		fprintf(f, "  part.tcs.epilog.prim_mode = %u\n", key->part.tcs.epilog.prim_mode);
 		break;
 
 	case PIPE_SHADER_TESS_EVAL:
-		fprintf(f, "  as_es = %u\n", key->tes.as_es);
-		fprintf(f, "  export_prim_id = %u\n", key->tes.epilog.export_prim_id);
+		fprintf(f, "  part.tes.epilog.export_prim_id = %u\n", key->part.tes.epilog.export_prim_id);
+		fprintf(f, "  as_es = %u\n", key->as_es);
 		break;
 
 	case PIPE_SHADER_GEOMETRY:
 	case PIPE_SHADER_COMPUTE:
 		break;
 
 	case PIPE_SHADER_FRAGMENT:
-		fprintf(f, "  prolog.color_two_side = %u\n", key->ps.prolog.color_two_side);
-		fprintf(f, "  prolog.flatshade_colors = %u\n", key->ps.prolog.flatshade_colors);
-		fprintf(f, "  prolog.poly_stipple = %u\n", key->ps.prolog.poly_stipple);
-		fprintf(f, "  prolog.force_persp_sample_interp = %u\n", key->ps.prolog.force_persp_sample_interp);
-		fprintf(f, "  prolog.force_linear_sample_interp = %u\n", key->ps.prolog.force_linear_sample_interp);
-		fprintf(f, "  prolog.force_persp_center_interp = %u\n", key->ps.prolog.force_persp_center_interp);
-		fprintf(f, "  prolog.force_linear_center_interp = %u\n", key->ps.prolog.force_linear_center_interp);
-		fprintf(f, "  prolog.bc_optimize_for_persp = %u\n", key->ps.prolog.bc_optimize_for_persp);
-		fprintf(f, "  prolog.bc_optimize_for_linear = %u\n", key->ps.prolog.bc_optimize_for_linear);
-		fprintf(f, "  epilog.spi_shader_col_format = 0x%x\n", key->ps.epilog.spi_shader_col_format);
-		fprintf(f, "  epilog.color_is_int8 = 0x%X\n", key->ps.epilog.color_is_int8);
-		fprintf(f, "  epilog.last_cbuf = %u\n", key->ps.epilog.last_cbuf);
-		fprintf(f, "  epilog.alpha_func = %u\n", key->ps.epilog.alpha_func);
-		fprintf(f, "  epilog.alpha_to_one = %u\n", key->ps.epilog.alpha_to_one);
-		fprintf(f, "  epilog.poly_line_smoothing = %u\n", key->ps.epilog.poly_line_smoothing);
-		fprintf(f, "  epilog.clamp_color = %u\n", key->ps.epilog.clamp_color);
+		fprintf(f, "  part.ps.prolog.color_two_side = %u\n", key->part.ps.prolog.color_two_side);
+		fprintf(f, "  part.ps.prolog.flatshade_colors = %u\n", key->part.ps.prolog.flatshade_colors);
+		fprintf(f, "  part.ps.prolog.poly_stipple = %u\n", key->part.ps.prolog.poly_stipple);
+		fprintf(f, "  part.ps.prolog.force_persp_sample_interp = %u\n", key->part.ps.prolog.force_persp_sample_interp);
+		fprintf(f, "  part.ps.prolog.force_linear_sample_interp = %u\n", key->part.ps.prolog.force_linear_sample_interp);
+		fprintf(f, "  part.ps.prolog.force_persp_center_interp = %u\n", key->part.ps.prolog.force_persp_center_interp);
+		fprintf(f, "  part.ps.prolog.force_linear_center_interp = %u\n", key->part.ps.prolog.force_linear_center_interp);
+		fprintf(f, "  part.ps.prolog.bc_optimize_for_persp = %u\n", key->part.ps.prolog.bc_optimize_for_persp);
+		fprintf(f, "  part.ps.prolog.bc_optimize_for_linear = %u\n", key->part.ps.prolog.bc_optimize_for_linear);
+		fprintf(f, "  part.ps.epilog.spi_shader_col_format = 0x%x\n", key->part.ps.epilog.spi_shader_col_format);
+		fprintf(f, "  part.ps.epilog.color_is_int8 = 0x%X\n", key->part.ps.epilog.color_is_int8);
+		fprintf(f, "  part.ps.epilog.last_cbuf = %u\n", key->part.ps.epilog.last_cbuf);
+		fprintf(f, "  part.ps.epilog.alpha_func = %u\n", key->part.ps.epilog.alpha_func);
+		fprintf(f, "  part.ps.epilog.alpha_to_one = %u\n", key->part.ps.epilog.alpha_to_one);
+		fprintf(f, "  part.ps.epilog.poly_line_smoothing = %u\n", key->part.ps.epilog.poly_line_smoothing);
+		fprintf(f, "  part.ps.epilog.clamp_color = %u\n", key->part.ps.epilog.clamp_color);
 		break;
 
 	default:
 		assert(0);
 	}
 }
 
 static void si_init_shader_ctx(struct si_shader_context *ctx,
 			       struct si_screen *sscreen,
 			       struct si_shader *shader,
@@ -6414,23 +6414,21 @@ struct si_vs_exports {
 static void si_eliminate_const_vs_outputs(struct si_shader_context *ctx)
 {
 	struct si_shader *shader = ctx->shader;
 	struct tgsi_shader_info *info = &shader->selector->info;
 	LLVMBasicBlockRef bb;
 	struct si_vs_exports exports;
 	bool removed_any = false;
 
 	exports.num = 0;
 
-	if ((ctx->type == PIPE_SHADER_VERTEX &&
-	     (shader->key.vs.as_es || shader->key.vs.as_ls)) ||
-	    (ctx->type == PIPE_SHADER_TESS_EVAL && shader->key.tes.as_es))
+	if (shader->key.as_es || shader->key.as_ls)
 		return;
 
 	/* Process all LLVM instructions. */
 	bb = LLVMGetFirstBasicBlock(ctx->main_fn);
 	while (bb) {
 		LLVMValueRef inst = LLVMGetFirstInstruction(bb);
 
 		while (inst) {
 			LLVMValueRef cur = inst;
 			inst = LLVMGetNextInstruction(inst);
@@ -6506,36 +6504,36 @@ static void si_eliminate_const_vs_outputs(struct si_shader_context *ctx)
 
 static bool si_compile_tgsi_main(struct si_shader_context *ctx,
 				 struct si_shader *shader)
 {
 	struct si_shader_selector *sel = shader->selector;
 	struct lp_build_tgsi_context *bld_base = &ctx->soa.bld_base;
 
 	switch (ctx->type) {
 	case PIPE_SHADER_VERTEX:
 		ctx->load_input = declare_input_vs;
-		if (shader->key.vs.as_ls)
+		if (shader->key.as_ls)
 			bld_base->emit_epilogue = si_llvm_emit_ls_epilogue;
-		else if (shader->key.vs.as_es)
+		else if (shader->key.as_es)
 			bld_base->emit_epilogue = si_llvm_emit_es_epilogue;
 		else
 			bld_base->emit_epilogue = si_llvm_emit_vs_epilogue;
 		break;
 	case PIPE_SHADER_TESS_CTRL:
 		bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_tcs;
 		bld_base->emit_fetch_funcs[TGSI_FILE_OUTPUT] = fetch_output_tcs;
 		bld_base->emit_store = store_output_tcs;
 		bld_base->emit_epilogue = si_llvm_emit_tcs_epilogue;
 		break;
 	case PIPE_SHADER_TESS_EVAL:
 		bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_tes;
-		if (shader->key.tes.as_es)
+		if (shader->key.as_es)
 			bld_base->emit_epilogue = si_llvm_emit_es_epilogue;
 		else
 			bld_base->emit_epilogue = si_llvm_emit_vs_epilogue;
 		break;
 	case PIPE_SHADER_GEOMETRY:
 		bld_base->emit_fetch_funcs[TGSI_FILE_INPUT] = fetch_input_gs;
 		bld_base->emit_epilogue = si_llvm_emit_gs_epilogue;
 		break;
 	case PIPE_SHADER_FRAGMENT:
 		ctx->load_input = declare_input_fs;
@@ -6574,21 +6572,21 @@ static bool si_compile_tgsi_main(struct si_shader_context *ctx,
 /**
  * Compute the VS prolog key, which contains all the information needed to
  * build the VS prolog function, and set shader->info bits where needed.
  */
 static void si_get_vs_prolog_key(struct si_shader *shader,
 				 union si_shader_part_key *key)
 {
 	struct tgsi_shader_info *info = &shader->selector->info;
 
 	memset(key, 0, sizeof(*key));
-	key->vs_prolog.states = shader->key.vs.prolog;
+	key->vs_prolog.states = shader->key.part.vs.prolog;
 	key->vs_prolog.num_input_sgprs = shader->info.num_input_sgprs;
 	key->vs_prolog.last_input = MAX2(1, info->num_inputs) - 1;
 
 	/* Set the instanceID flag. */
 	for (unsigned i = 0; i < info->num_inputs; i++)
 		if (key->vs_prolog.states.instance_divisors[i])
 			shader->info.uses_instanceid = true;
 }
 
 /**
@@ -6596,87 +6594,87 @@ static void si_get_vs_prolog_key(struct si_shader *shader,
  * build the VS epilog function, and set the PrimitiveID output offset.
  */
 static void si_get_vs_epilog_key(struct si_shader *shader,
 				 struct si_vs_epilog_bits *states,
 				 union si_shader_part_key *key)
 {
 	memset(key, 0, sizeof(*key));
 	key->vs_epilog.states = *states;
 
 	/* Set up the PrimitiveID output. */
-	if (shader->key.vs.epilog.export_prim_id) {
+	if (shader->key.part.vs.epilog.export_prim_id) {
 		unsigned index = shader->selector->info.num_outputs;
 		unsigned offset = shader->info.nr_param_exports++;
 
 		key->vs_epilog.prim_id_param_offset = offset;
 		assert(index < ARRAY_SIZE(shader->info.vs_output_param_offset));
 		shader->info.vs_output_param_offset[index] = offset;
 	}
 }
 
 /**
  * Compute the PS prolog key, which contains all the information needed to
  * build the PS prolog function, and set related bits in shader->config.
  */
 static void si_get_ps_prolog_key(struct si_shader *shader,
 				 union si_shader_part_key *key,
 				 bool separate_prolog)
 {
 	struct tgsi_shader_info *info = &shader->selector->info;
 
 	memset(key, 0, sizeof(*key));
-	key->ps_prolog.states = shader->key.ps.prolog;
+	key->ps_prolog.states = shader->key.part.ps.prolog;
 	key->ps_prolog.colors_read = info->colors_read;
 	key->ps_prolog.num_input_sgprs = shader->info.num_input_sgprs;
 	key->ps_prolog.num_input_vgprs = shader->info.num_input_vgprs;
 	key->ps_prolog.wqm = info->uses_derivatives &&
 		(key->ps_prolog.colors_read ||
 		 key->ps_prolog.states.force_persp_sample_interp ||
 		 key->ps_prolog.states.force_linear_sample_interp ||
 		 key->ps_prolog.states.force_persp_center_interp ||
 		 key->ps_prolog.states.force_linear_center_interp ||
 		 key->ps_prolog.states.bc_optimize_for_persp ||
 		 key->ps_prolog.states.bc_optimize_for_linear);
 
 	if (info->colors_read) {
 		unsigned *color = shader->selector->color_attr_index;
 
-		if (shader->key.ps.prolog.color_two_side) {
+		if (shader->key.part.ps.prolog.color_two_side) {
 			/* BCOLORs are stored after the last input. */
 			key->ps_prolog.num_interp_inputs = info->num_inputs;
 			key->ps_prolog.face_vgpr_index = shader->info.face_vgpr_index;
 			shader->config.spi_ps_input_ena |= S_0286CC_FRONT_FACE_ENA(1);
 		}
 
 		for (unsigned i = 0; i < 2; i++) {
 			unsigned interp = info->input_interpolate[color[i]];
 			unsigned location = info->input_interpolate_loc[color[i]];
 
 			if (!(info->colors_read & (0xf << i*4)))
 				continue;
 
 			key->ps_prolog.color_attr_index[i] = color[i];
 
-			if (shader->key.ps.prolog.flatshade_colors &&
+			if (shader->key.part.ps.prolog.flatshade_colors &&
 			    interp == TGSI_INTERPOLATE_COLOR)
 				interp = TGSI_INTERPOLATE_CONSTANT;
 
 			switch (interp) {
 			case TGSI_INTERPOLATE_CONSTANT:
 				key->ps_prolog.color_interp_vgpr_index[i] = -1;
 				break;
 			case TGSI_INTERPOLATE_PERSPECTIVE:
 			case TGSI_INTERPOLATE_COLOR:
 				/* Force the interpolation location for colors here. */
-				if (shader->key.ps.prolog.force_persp_sample_interp)
+				if (shader->key.part.ps.prolog.force_persp_sample_interp)
 					location = TGSI_INTERPOLATE_LOC_SAMPLE;
-				if (shader->key.ps.prolog.force_persp_center_interp)
+				if (shader->key.part.ps.prolog.force_persp_center_interp)
 					location = TGSI_INTERPOLATE_LOC_CENTER;
 
 				switch (location) {
 				case TGSI_INTERPOLATE_LOC_SAMPLE:
 					key->ps_prolog.color_interp_vgpr_index[i] = 0;
 					shader->config.spi_ps_input_ena |=
 						S_0286CC_PERSP_SAMPLE_ENA(1);
 					break;
 				case TGSI_INTERPOLATE_LOC_CENTER:
 					key->ps_prolog.color_interp_vgpr_index[i] = 2;
@@ -6687,23 +6685,23 @@ static void si_get_ps_prolog_key(struct si_shader *shader,
 					key->ps_prolog.color_interp_vgpr_index[i] = 4;
 					shader->config.spi_ps_input_ena |=
 						S_0286CC_PERSP_CENTROID_ENA(1);
 					break;
 				default:
 					assert(0);
 				}
 				break;
 			case TGSI_INTERPOLATE_LINEAR:
 				/* Force the interpolation location for colors here. */
-				if (shader->key.ps.prolog.force_linear_sample_interp)
+				if (shader->key.part.ps.prolog.force_linear_sample_interp)
 					location = TGSI_INTERPOLATE_LOC_SAMPLE;
-				if (shader->key.ps.prolog.force_linear_center_interp)
+				if (shader->key.part.ps.prolog.force_linear_center_interp)
 					location = TGSI_INTERPOLATE_LOC_CENTER;
 
 				/* The VGPR assignment for non-monolithic shaders
 				 * works because InitialPSInputAddr is set on the
 				 * main shader and PERSP_PULL_MODEL is never used.
 				 */
 				switch (location) {
 				case TGSI_INTERPOLATE_LOC_SAMPLE:
 					key->ps_prolog.color_interp_vgpr_index[i] =
 						separate_prolog ? 6 : 9;
@@ -6754,21 +6752,21 @@ static bool si_need_ps_prolog(const union si_shader_part_key *key)
  */
 static void si_get_ps_epilog_key(struct si_shader *shader,
 				 union si_shader_part_key *key)
 {
 	struct tgsi_shader_info *info = &shader->selector->info;
 	memset(key, 0, sizeof(*key));
 	key->ps_epilog.colors_written = info->colors_written;
 	key->ps_epilog.writes_z = info->writes_z;
 	key->ps_epilog.writes_stencil = info->writes_stencil;
 	key->ps_epilog.writes_samplemask = info->writes_samplemask;
-	key->ps_epilog.states = shader->key.ps.epilog;
+	key->ps_epilog.states = shader->key.part.ps.epilog;
 }
 
 /**
  * Build the GS prolog function. Rotate the input vertices for triangle strips
  * with adjacency.
  */
 static void si_build_gs_prolog_function(struct si_shader_context *ctx,
 					union si_shader_part_key *key)
 {
 	const unsigned num_sgprs = SI_GS_NUM_USER_SGPR + 2;
@@ -7064,72 +7062,72 @@ int si_compile_tgsi_shader(struct si_screen *sscreen,
 		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->info.num_inputs;
-		need_epilog = !shader->key.vs.as_es && !shader->key.vs.as_ls;
+		need_epilog = !shader->key.as_es && !shader->key.as_ls;
 
 		parts[need_prolog ? 1 : 0] = ctx.main_fn;
 
 		if (need_prolog) {
 			union si_shader_part_key prolog_key;
 			si_get_vs_prolog_key(shader, &prolog_key);
 			si_build_vs_prolog_function(&ctx, &prolog_key);
 			parts[0] = ctx.main_fn;
 		}
 
 		if (need_epilog) {
 			union si_shader_part_key epilog_key;
-			si_get_vs_epilog_key(shader, &shader->key.vs.epilog, &epilog_key);
+			si_get_vs_epilog_key(shader, &shader->key.part.vs.epilog, &epilog_key);
 			si_build_vs_epilog_function(&ctx, &epilog_key);
 			parts[need_prolog ? 2 : 1] = ctx.main_fn;
 		}
 
 		si_build_wrapper_function(&ctx, parts, 1 + need_prolog + need_epilog,
 					  need_prolog ? 1 : 0);
 	} else if (is_monolithic && ctx.type == PIPE_SHADER_TESS_CTRL) {
 		LLVMValueRef parts[2];
 		union si_shader_part_key epilog_key;
 
 		parts[0] = ctx.main_fn;
 
 		memset(&epilog_key, 0, sizeof(epilog_key));
-		epilog_key.tcs_epilog.states = shader->key.tcs.epilog;
+		epilog_key.tcs_epilog.states = shader->key.part.tcs.epilog;
 		si_build_tcs_epilog_function(&ctx, &epilog_key);
 		parts[1] = ctx.main_fn;
 
 		si_build_wrapper_function(&ctx, parts, 2, 0);
 	} else if (is_monolithic && ctx.type == PIPE_SHADER_TESS_EVAL &&
-		   !shader->key.tes.as_es) {
+		   !shader->key.as_es) {
 		LLVMValueRef parts[2];
 		union si_shader_part_key epilog_key;
 
 		parts[0] = ctx.main_fn;
 
-		si_get_vs_epilog_key(shader, &shader->key.tes.epilog, &epilog_key);
+		si_get_vs_epilog_key(shader, &shader->key.part.tes.epilog, &epilog_key);
 		si_build_vs_epilog_function(&ctx, &epilog_key);
 		parts[1] = ctx.main_fn;
 
 		si_build_wrapper_function(&ctx, parts, 2, 0);
 	} else if (is_monolithic && ctx.type == PIPE_SHADER_GEOMETRY) {
 		LLVMValueRef parts[2];
 		union si_shader_part_key prolog_key;
 
 		parts[1] = ctx.main_fn;
 
 		memset(&prolog_key, 0, sizeof(prolog_key));
-		prolog_key.gs_prolog.states = shader->key.gs.prolog;
+		prolog_key.gs_prolog.states = shader->key.part.gs.prolog;
 		si_build_gs_prolog_function(&ctx, &prolog_key);
 		parts[0] = ctx.main_fn;
 
 		si_build_wrapper_function(&ctx, parts, 2, 1);
 	} else if (is_monolithic && ctx.type == PIPE_SHADER_FRAGMENT) {
 		LLVMValueRef parts[3];
 		union si_shader_part_key prolog_key;
 		union si_shader_part_key epilog_key;
 		bool need_prolog;
 
@@ -7306,30 +7304,30 @@ si_get_shader_part(struct si_screen *sscreen,
 	struct gallivm_state *gallivm = &ctx.gallivm;
 
 	si_init_shader_ctx(&ctx, sscreen, &shader, tm);
 	ctx.type = type;
 
 	switch (type) {
 	case PIPE_SHADER_VERTEX:
 		break;
 	case PIPE_SHADER_TESS_CTRL:
 		assert(!prolog);
-		shader.key.tcs.epilog = key->tcs_epilog.states;
+		shader.key.part.tcs.epilog = key->tcs_epilog.states;
 		break;
 	case PIPE_SHADER_GEOMETRY:
 		assert(prolog);
 		break;
 	case PIPE_SHADER_FRAGMENT:
 		if (prolog)
-			shader.key.ps.prolog = key->ps_prolog.states;
+			shader.key.part.ps.prolog = key->ps_prolog.states;
 		else
-			shader.key.ps.epilog = key->ps_epilog.states;
+			shader.key.part.ps.epilog = key->ps_epilog.states;
 		break;
 	default:
 		unreachable("bad shader part");
 	}
 
 	build(&ctx, key);
 
 	/* Compile. */
 	si_llvm_finalize_module(&ctx,
 		r600_extra_shader_checks(&sscreen->b, PIPE_SHADER_FRAGMENT));
@@ -7543,42 +7541,42 @@ static bool si_shader_select_vs_parts(struct si_screen *sscreen,
 			si_get_shader_part(sscreen, &sscreen->vs_prologs,
 					   PIPE_SHADER_VERTEX, true,
 					   &prolog_key, tm, debug,
 					   si_build_vs_prolog_function,
 					   "Vertex Shader Prolog");
 		if (!shader->prolog)
 			return false;
 	}
 
 	/* Get the epilog. */
-	if (!shader->key.vs.as_es && !shader->key.vs.as_ls &&
+	if (!shader->key.as_es && !shader->key.as_ls &&
 	    !si_get_vs_epilog(sscreen, tm, shader, debug,
-			      &shader->key.vs.epilog))
+			      &shader->key.part.vs.epilog))
 		return false;
 
 	return true;
 }
 
 /**
  * Select and compile (or reuse) TES parts (epilog).
  */
 static bool si_shader_select_tes_parts(struct si_screen *sscreen,
 				       LLVMTargetMachineRef tm,
 				       struct si_shader *shader,
 				       struct pipe_debug_callback *debug)
 {
-	if (shader->key.tes.as_es)
+	if (shader->key.as_es)
 		return true;
 
 	/* TES compiled as VS. */
 	return si_get_vs_epilog(sscreen, tm, shader, debug,
-				&shader->key.tes.epilog);
+				&shader->key.part.tes.epilog);
 }
 
 /**
  * Compile the TCS epilog function. This writes tesselation factors to memory
  * based on the output primitive type of the tesselator (determined by TES).
  */
 static void si_build_tcs_epilog_function(struct si_shader_context *ctx,
 					 union si_shader_part_key *key)
 {
 	struct gallivm_state *gallivm = &ctx->gallivm;
@@ -7624,45 +7622,45 @@ static void si_build_tcs_epilog_function(struct si_shader_context *ctx,
  */
 static bool si_shader_select_tcs_parts(struct si_screen *sscreen,
 				       LLVMTargetMachineRef tm,
 				       struct si_shader *shader,
 				       struct pipe_debug_callback *debug)
 {
 	union si_shader_part_key epilog_key;
 
 	/* Get the epilog. */
 	memset(&epilog_key, 0, sizeof(epilog_key));
-	epilog_key.tcs_epilog.states = shader->key.tcs.epilog;
+	epilog_key.tcs_epilog.states = shader->key.part.tcs.epilog;
 
 	shader->epilog = si_get_shader_part(sscreen, &sscreen->tcs_epilogs,
 					    PIPE_SHADER_TESS_CTRL, false,
 					    &epilog_key, tm, debug,
 					    si_build_tcs_epilog_function,
 					    "Tessellation Control Shader Epilog");
 	return shader->epilog != NULL;
 }
 
 /**
  * Select and compile (or reuse) GS parts (prolog).
  */
 static bool si_shader_select_gs_parts(struct si_screen *sscreen,
 				      LLVMTargetMachineRef tm,
 				      struct si_shader *shader,
 				      struct pipe_debug_callback *debug)
 {
 	union si_shader_part_key prolog_key;
 
-	if (!shader->key.gs.prolog.tri_strip_adj_fix)
+	if (!shader->key.part.gs.prolog.tri_strip_adj_fix)
 		return true;
 
 	memset(&prolog_key, 0, sizeof(prolog_key));
-	prolog_key.gs_prolog.states = shader->key.gs.prolog;
+	prolog_key.gs_prolog.states = shader->key.part.gs.prolog;
 
 	shader->prolog = si_get_shader_part(sscreen, &sscreen->gs_prologs,
 					    PIPE_SHADER_GEOMETRY, true,
 					    &prolog_key, tm, debug,
 					    si_build_gs_prolog_function,
 					    "Geometry Shader Prolog");
 	return shader->prolog != NULL;
 }
 
 /**
@@ -8044,48 +8042,48 @@ static bool si_shader_select_ps_parts(struct si_screen *sscreen,
 	shader->epilog =
 		si_get_shader_part(sscreen, &sscreen->ps_epilogs,
 				   PIPE_SHADER_FRAGMENT, false,
 				   &epilog_key, tm, debug,
 				   si_build_ps_epilog_function,
 				   "Fragment Shader Epilog");
 	if (!shader->epilog)
 		return false;
 
 	/* Enable POS_FIXED_PT if polygon stippling is enabled. */
-	if (shader->key.ps.prolog.poly_stipple) {
+	if (shader->key.part.ps.prolog.poly_stipple) {
 		shader->config.spi_ps_input_ena |= S_0286CC_POS_FIXED_PT_ENA(1);
 		assert(G_0286CC_POS_FIXED_PT_ENA(shader->config.spi_ps_input_addr));
 	}
 
 	/* Set up the enable bits for per-sample shading if needed. */
-	if (shader->key.ps.prolog.force_persp_sample_interp &&
+	if (shader->key.part.ps.prolog.force_persp_sample_interp &&
 	    (G_0286CC_PERSP_CENTER_ENA(shader->config.spi_ps_input_ena) ||
 	     G_0286CC_PERSP_CENTROID_ENA(shader->config.spi_ps_input_ena))) {
 		shader->config.spi_ps_input_ena &= C_0286CC_PERSP_CENTER_ENA;
 		shader->config.spi_ps_input_ena &= C_0286CC_PERSP_CENTROID_ENA;
 		shader->config.spi_ps_input_ena |= S_0286CC_PERSP_SAMPLE_ENA(1);
 	}
-	if (shader->key.ps.prolog.force_linear_sample_interp &&
+	if (shader->key.part.ps.prolog.force_linear_sample_interp &&
 	    (G_0286CC_LINEAR_CENTER_ENA(shader->config.spi_ps_input_ena) ||
 	     G_0286CC_LINEAR_CENTROID_ENA(shader->config.spi_ps_input_ena))) {
 		shader->config.spi_ps_input_ena &= C_0286CC_LINEAR_CENTER_ENA;
 		shader->config.spi_ps_input_ena &= C_0286CC_LINEAR_CENTROID_ENA;
 		shader->config.spi_ps_input_ena |= S_0286CC_LINEAR_SAMPLE_ENA(1);
 	}
-	if (shader->key.ps.prolog.force_persp_center_interp &&
+	if (shader->key.part.ps.prolog.force_persp_center_interp &&
 	    (G_0286CC_PERSP_SAMPLE_ENA(shader->config.spi_ps_input_ena) ||
 	     G_0286CC_PERSP_CENTROID_ENA(shader->config.spi_ps_input_ena))) {
 		shader->config.spi_ps_input_ena &= C_0286CC_PERSP_SAMPLE_ENA;
 		shader->config.spi_ps_input_ena &= C_0286CC_PERSP_CENTROID_ENA;
 		shader->config.spi_ps_input_ena |= S_0286CC_PERSP_CENTER_ENA(1);
 	}
-	if (shader->key.ps.prolog.force_linear_center_interp &&
+	if (shader->key.part.ps.prolog.force_linear_center_interp &&
 	    (G_0286CC_LINEAR_SAMPLE_ENA(shader->config.spi_ps_input_ena) ||
 	     G_0286CC_LINEAR_CENTROID_ENA(shader->config.spi_ps_input_ena))) {
 		shader->config.spi_ps_input_ena &= C_0286CC_LINEAR_SAMPLE_ENA;
 		shader->config.spi_ps_input_ena &= C_0286CC_LINEAR_CENTROID_ENA;
 		shader->config.spi_ps_input_ena |= S_0286CC_LINEAR_CENTER_ENA(1);
 	}
 
 	/* POW_W_FLOAT requires that one of the perspective weights is enabled. */
 	if (G_0286CC_POS_W_FLOAT_ENA(shader->config.spi_ps_input_ena) &&
 	    !(shader->config.spi_ps_input_ena & 0xf)) {
@@ -8095,21 +8093,21 @@ static bool si_shader_select_ps_parts(struct si_screen *sscreen,
 
 	/* At least one pair of interpolation weights must be enabled. */
 	if (!(shader->config.spi_ps_input_ena & 0x7f)) {
 		shader->config.spi_ps_input_ena |= S_0286CC_LINEAR_CENTER_ENA(1);
 		assert(G_0286CC_LINEAR_CENTER_ENA(shader->config.spi_ps_input_addr));
 	}
 
 	/* The sample mask input is always enabled, because the API shader always
 	 * passes it through to the epilog. Disable it here if it's unused.
 	 */
-	if (!shader->key.ps.epilog.poly_line_smoothing &&
+	if (!shader->key.part.ps.epilog.poly_line_smoothing &&
 	    !shader->selector->info.reads_samplemask)
 		shader->config.spi_ps_input_ena &= C_0286CC_SAMPLE_COVERAGE_ENA;
 
 	return true;
 }
 
 static void si_fix_num_sgprs(struct si_shader *shader)
 {
 	unsigned min_sgprs = shader->info.num_input_sgprs + 2; /* VCC */
 
@@ -8124,28 +8122,26 @@ int si_shader_create(struct si_screen *sscreen, LLVMTargetMachineRef tm,
 	struct si_shader *mainp = sel->main_shader_part;
 	int r;
 
 	/* LS, ES, VS are compiled on demand if the main part hasn't been
 	 * compiled for that stage.
 	 *
 	 * Vertex shaders are compiled on demand when a vertex fetch
 	 * workaround must be applied.
 	 */
 	if (!mainp ||
+	    shader->key.as_es != mainp->key.as_es ||
+	    shader->key.as_ls != mainp->key.as_ls ||
 	    (sel->type == PIPE_SHADER_VERTEX &&
-	     (shader->key.vs.as_es != mainp->key.vs.as_es ||
-	      shader->key.vs.as_ls != mainp->key.vs.as_ls ||
-	      shader->key.vs.fix_fetch)) ||
-	    (sel->type == PIPE_SHADER_TESS_EVAL &&
-	     shader->key.tes.as_es != mainp->key.tes.as_es) ||
+	     shader->key.mono.vs.fix_fetch) ||
 	    (sel->type == PIPE_SHADER_TESS_CTRL &&
-	     shader->key.tcs.epilog.inputs_to_copy) ||
+	     shader->key.mono.tcs.inputs_to_copy) ||
 	    sel->type == PIPE_SHADER_COMPUTE) {
 		/* Monolithic shader (compiled as a whole, has many variants,
 		 * may take a long time to compile).
 		 */
 		r = si_compile_tgsi_shader(sscreen, tm, shader, true, debug);
 		if (r)
 			return r;
 	} else {
 		/* The shader consists of 2-3 parts:
 		 *
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index 59e7bfb..bed22c1 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -323,21 +323,20 @@ struct si_vs_epilog_bits {
 	 * - skip clipdist, culldist (including clipvertex code) exports based
 	 *   on which clip_plane_enable bits are set
 	 * - skip layer, viewport, clipdist, and culldist parameter exports
 	 *   if PS doesn't read them
 	 */
 };
 
 /* Common TCS bits between the shader key and the epilog key. */
 struct si_tcs_epilog_bits {
 	unsigned	prim_mode:3;
-	uint64_t	inputs_to_copy;
 };
 
 struct si_gs_prolog_bits {
 	unsigned	tri_strip_adj_fix:1;
 };
 
 /* Common PS bits between the shader key and the prolog key. */
 struct si_ps_prolog_bits {
 	unsigned	color_two_side:1;
 	unsigned	flatshade_colors:1;
@@ -391,44 +390,58 @@ union si_shader_part_key {
 	} ps_prolog;
 	struct {
 		struct si_ps_epilog_bits states;
 		unsigned	colors_written:8;
 		unsigned	writes_z:1;
 		unsigned	writes_stencil:1;
 		unsigned	writes_samplemask:1;
 	} ps_epilog;
 };
 
-union si_shader_key {
-	struct {
-		struct si_ps_prolog_bits prolog;
-		struct si_ps_epilog_bits epilog;
-	} ps;
-	struct {
-		struct si_vs_prolog_bits prolog;
-		struct si_vs_epilog_bits epilog;
-		unsigned	as_es:1; /* export shader */
-		unsigned	as_ls:1; /* local shader */
-
-		/* One pair of bits for every input: SI_FIX_FETCH_* enums. */
-		uint32_t	fix_fetch;
-	} vs;
-	struct {
-		struct si_tcs_epilog_bits epilog;
-	} tcs; /* tessellation control shader */
-	struct {
-		struct si_vs_epilog_bits epilog; /* same as VS */
-		unsigned	as_es:1; /* export shader */
-	} tes; /* tessellation evaluation shader */
-	struct {
-		struct si_gs_prolog_bits prolog;
-	} gs;
+struct si_shader_key {
+	/* Prolog and epilog flags. */
+	union {
+		struct {
+			struct si_ps_prolog_bits prolog;
+			struct si_ps_epilog_bits epilog;
+		} ps;
+		struct {
+			struct si_vs_prolog_bits prolog;
+			struct si_vs_epilog_bits epilog;
+		} vs;
+		struct {
+			struct si_tcs_epilog_bits epilog;
+		} tcs; /* tessellation control shader */
+		struct {
+			struct si_vs_epilog_bits epilog; /* same as VS */
+		} tes; /* tessellation evaluation shader */
+		struct {
+			struct si_gs_prolog_bits prolog;
+		} gs;
+	} part;
+
+	/* These two are initially set according to the NEXT_SHADER property,
+	 * or guessed if the property doesn't seem correct.
+	 */
+	unsigned as_es:1; /* export shader */
+	unsigned as_ls:1; /* local shader */
+
+	/* Flags for monolithic compilation only. */
+	union {
+		struct {
+			/* One pair of bits for every input: SI_FIX_FETCH_* enums. */
+			uint32_t	fix_fetch;
+		} vs;
+		struct {
+			uint64_t	inputs_to_copy; /* for fixed-func TCS */
+		} tcs;
+	} mono;
 };
 
 struct si_shader_config {
 	unsigned			num_sgprs;
 	unsigned			num_vgprs;
 	unsigned			spilled_sgprs;
 	unsigned			spilled_vgprs;
 	unsigned			lds_size;
 	unsigned			spi_ps_input_ena;
 	unsigned			spi_ps_input_addr;
@@ -463,21 +476,21 @@ struct si_shader_info {
 struct si_shader {
 	struct si_shader_selector	*selector;
 	struct si_shader		*next_variant;
 
 	struct si_shader_part		*prolog;
 	struct si_shader_part		*epilog;
 
 	struct si_pm4_state		*pm4;
 	struct r600_resource		*bo;
 	struct r600_resource		*scratch_bo;
-	union si_shader_key		key;
+	struct si_shader_key		key;
 	bool				is_binary_shared;
 	bool				is_gs_copy_shader;
 
 	/* The following data is all that's needed for binary shaders. */
 	struct radeon_shader_binary	binary;
 	struct si_shader_config		config;
 	struct si_shader_info		info;
 
 	/* Shader key + LLVM IR + disassembly + statistics.
 	 * Generated for debug contexts only.
diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
index 7e051a1..7d118b0 100644
--- a/src/gallium/drivers/radeonsi/si_state.c
+++ b/src/gallium/drivers/radeonsi/si_state.c
@@ -112,21 +112,21 @@ static void si_emit_cb_render_state(struct si_context *sctx, struct r600_atom *a
 	    sctx->ps_shader.cso &&
 	    (sctx->ps_shader.cso->info.colors_written & 0x3) != 0x3)
 		cb_target_mask = 0;
 
 	radeon_set_context_reg(cs, R_028238_CB_TARGET_MASK, cb_target_mask);
 
 	/* STONEY-specific register settings. */
 	if (sctx->b.family == CHIP_STONEY) {
 		unsigned spi_shader_col_format =
 			sctx->ps_shader.cso ?
-			sctx->ps_shader.current->key.ps.epilog.spi_shader_col_format : 0;
+			sctx->ps_shader.current->key.part.ps.epilog.spi_shader_col_format : 0;
 		unsigned sx_ps_downconvert = 0;
 		unsigned sx_blend_opt_epsilon = 0;
 		unsigned sx_blend_opt_control = 0;
 
 		for (i = 0; i < sctx->framebuffer.state.nr_cbufs; i++) {
 			struct r600_surface *surf =
 				(struct r600_surface*)sctx->framebuffer.state.cbufs[i];
 			unsigned format, swap, spi_format, colormask;
 			bool has_alpha, has_rgb;
 
diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
index d0869e3..3323d3c 100644
--- a/src/gallium/drivers/radeonsi/si_state_shaders.c
+++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
@@ -619,29 +619,29 @@ static void si_shader_vs(struct si_screen *sscreen, struct si_shader *shader,
 	if (shader->selector->type == PIPE_SHADER_TESS_EVAL)
 		si_set_tesseval_regs(sscreen, shader, pm4);
 }
 
 static unsigned si_get_ps_num_interp(struct si_shader *ps)
 {
 	struct tgsi_shader_info *info = &ps->selector->info;
 	unsigned num_colors = !!(info->colors_read & 0x0f) +
 			      !!(info->colors_read & 0xf0);
 	unsigned num_interp = ps->selector->info.num_inputs +
-			      (ps->key.ps.prolog.color_two_side ? num_colors : 0);
+			      (ps->key.part.ps.prolog.color_two_side ? num_colors : 0);
 
 	assert(num_interp <= 32);
 	return MIN2(num_interp, 32);
 }
 
 static unsigned si_get_spi_shader_col_format(struct si_shader *shader)
 {
-	unsigned value = shader->key.ps.epilog.spi_shader_col_format;
+	unsigned value = shader->key.part.ps.epilog.spi_shader_col_format;
 	unsigned i, num_targets = (util_last_bit(value) + 3) / 4;
 
 	/* If the i-th target format is set, all previous target formats must
 	 * be non-zero to avoid hangs.
 	 */
 	for (i = 0; i < num_targets; i++)
 		if (!(value & (0xf << (i * 4))))
 			value |= V_028714_SPI_SHADER_32_R << (i * 4);
 
 	return value;
@@ -698,44 +698,44 @@ static void si_shader_ps(struct si_shader *shader)
 	       G_0286CC_LINEAR_CENTROID_ENA(input_ena) ||
 	       G_0286CC_LINE_STIPPLE_TEX_ENA(input_ena));
 	/* POS_W_FLOAT_ENA requires one of the perspective weights. */
 	assert(!G_0286CC_POS_W_FLOAT_ENA(input_ena) ||
 	       G_0286CC_PERSP_SAMPLE_ENA(input_ena) ||
 	       G_0286CC_PERSP_CENTER_ENA(input_ena) ||
 	       G_0286CC_PERSP_CENTROID_ENA(input_ena) ||
 	       G_0286CC_PERSP_PULL_MODEL_ENA(input_ena));
 
 	/* Validate interpolation optimization flags (read as implications). */
-	assert(!shader->key.ps.prolog.bc_optimize_for_persp ||
+	assert(!shader->key.part.ps.prolog.bc_optimize_for_persp ||
 	       (G_0286CC_PERSP_CENTER_ENA(input_ena) &&
 		G_0286CC_PERSP_CENTROID_ENA(input_ena)));
-	assert(!shader->key.ps.prolog.bc_optimize_for_linear ||
+	assert(!shader->key.part.ps.prolog.bc_optimize_for_linear ||
 	       (G_0286CC_LINEAR_CENTER_ENA(input_ena) &&
 		G_0286CC_LINEAR_CENTROID_ENA(input_ena)));
-	assert(!shader->key.ps.prolog.force_persp_center_interp ||
+	assert(!shader->key.part.ps.prolog.force_persp_center_interp ||
 	       (!G_0286CC_PERSP_SAMPLE_ENA(input_ena) &&
 		!G_0286CC_PERSP_CENTROID_ENA(input_ena)));
-	assert(!shader->key.ps.prolog.force_linear_center_interp ||
+	assert(!shader->key.part.ps.prolog.force_linear_center_interp ||
 	       (!G_0286CC_LINEAR_SAMPLE_ENA(input_ena) &&
 		!G_0286CC_LINEAR_CENTROID_ENA(input_ena)));
-	assert(!shader->key.ps.prolog.force_persp_sample_interp ||
+	assert(!shader->key.part.ps.prolog.force_persp_sample_interp ||
 	       (!G_0286CC_PERSP_CENTER_ENA(input_ena) &&
 		!G_0286CC_PERSP_CENTROID_ENA(input_ena)));
-	assert(!shader->key.ps.prolog.force_linear_sample_interp ||
+	assert(!shader->key.part.ps.prolog.force_linear_sample_interp ||
 	       (!G_0286CC_LINEAR_CENTER_ENA(input_ena) &&
 		!G_0286CC_LINEAR_CENTROID_ENA(input_ena)));
 
 	/* Validate cases when the optimizations are off (read as implications). */
-	assert(shader->key.ps.prolog.bc_optimize_for_persp ||
+	assert(shader->key.part.ps.prolog.bc_optimize_for_persp ||
 	       !G_0286CC_PERSP_CENTER_ENA(input_ena) ||
 	       !G_0286CC_PERSP_CENTROID_ENA(input_ena));
-	assert(shader->key.ps.prolog.bc_optimize_for_linear ||
+	assert(shader->key.part.ps.prolog.bc_optimize_for_linear ||
 	       !G_0286CC_LINEAR_CENTER_ENA(input_ena) ||
 	       !G_0286CC_LINEAR_CENTROID_ENA(input_ena));
 
 	pm4 = si_get_shader_pm4_state(shader);
 	if (!pm4)
 		return;
 
 	/* SPI_BARYC_CNTL.POS_FLOAT_LOCATION
 	 * Possible vaules:
 	 * 0 -> Position = pixel center
@@ -811,32 +811,32 @@ static void si_shader_ps(struct si_shader *shader)
 		       S_00B02C_EXTRA_LDS_SIZE(shader->config.lds_size) |
 		       S_00B02C_USER_SGPR(SI_PS_NUM_USER_SGPR) |
 		       S_00B32C_SCRATCH_EN(shader->config.scratch_bytes_per_wave > 0));
 }
 
 static void si_shader_init_pm4_state(struct si_screen *sscreen,
                                      struct si_shader *shader)
 {
 	switch (shader->selector->type) {
 	case PIPE_SHADER_VERTEX:
-		if (shader->key.vs.as_ls)
+		if (shader->key.as_ls)
 			si_shader_ls(shader);
-		else if (shader->key.vs.as_es)
+		else if (shader->key.as_es)
 			si_shader_es(sscreen, shader);
 		else
 			si_shader_vs(sscreen, shader, NULL);
 		break;
 	case PIPE_SHADER_TESS_CTRL:
 		si_shader_hs(shader);
 		break;
 	case PIPE_SHADER_TESS_EVAL:
-		if (shader->key.tes.as_es)
+		if (shader->key.as_es)
 			si_shader_es(sscreen, shader);
 		else
 			si_shader_vs(sscreen, shader, NULL);
 		break;
 	case PIPE_SHADER_GEOMETRY:
 		si_shader_gs(shader);
 		break;
 	case PIPE_SHADER_FRAGMENT:
 		si_shader_ps(shader);
 		break;
@@ -850,182 +850,182 @@ static unsigned si_get_alpha_test_func(struct si_context *sctx)
 	/* Alpha-test should be disabled if colorbuffer 0 is integer. */
 	if (sctx->queued.named.dsa)
 		return sctx->queued.named.dsa->alpha_func;
 
 	return PIPE_FUNC_ALWAYS;
 }
 
 /* Compute the key for the hw shader variant */
 static inline void si_shader_selector_key(struct pipe_context *ctx,
 					  struct si_shader_selector *sel,
-					  union si_shader_key *key)
+					  struct si_shader_key *key)
 {
 	struct si_context *sctx = (struct si_context *)ctx;
 	unsigned i;
 
 	memset(key, 0, sizeof(*key));
 
 	switch (sel->type) {
 	case PIPE_SHADER_VERTEX:
 		if (sctx->vertex_elements) {
 			unsigned count = MIN2(sel->info.num_inputs,
 					      sctx->vertex_elements->count);
 			for (i = 0; i < count; ++i)
-				key->vs.prolog.instance_divisors[i] =
+				key->part.vs.prolog.instance_divisors[i] =
 					sctx->vertex_elements->elements[i].instance_divisor;
 
-			key->vs.fix_fetch =
+			key->mono.vs.fix_fetch =
 				sctx->vertex_elements->fix_fetch &
 				u_bit_consecutive(0, 2 * count);
 		}
 		if (sctx->tes_shader.cso)
-			key->vs.as_ls = 1;
+			key->as_ls = 1;
 		else if (sctx->gs_shader.cso)
-			key->vs.as_es = 1;
+			key->as_es = 1;
 
 		if (!sctx->gs_shader.cso && sctx->ps_shader.cso &&
 		    sctx->ps_shader.cso->info.uses_primid)
-			key->vs.epilog.export_prim_id = 1;
+			key->part.vs.epilog.export_prim_id = 1;
 		break;
 	case PIPE_SHADER_TESS_CTRL:
-		key->tcs.epilog.prim_mode =
+		key->part.tcs.epilog.prim_mode =
 			sctx->tes_shader.cso->info.properties[TGSI_PROPERTY_TES_PRIM_MODE];
 
 		if (sel == sctx->fixed_func_tcs_shader.cso)
-			key->tcs.epilog.inputs_to_copy = sctx->vs_shader.cso->outputs_written;
+			key->mono.tcs.inputs_to_copy = sctx->vs_shader.cso->outputs_written;
 		break;
 	case PIPE_SHADER_TESS_EVAL:
 		if (sctx->gs_shader.cso)
-			key->tes.as_es = 1;
+			key->as_es = 1;
 		else if (sctx->ps_shader.cso && sctx->ps_shader.cso->info.uses_primid)
-			key->tes.epilog.export_prim_id = 1;
+			key->part.tes.epilog.export_prim_id = 1;
 		break;
 	case PIPE_SHADER_GEOMETRY:
-		key->gs.prolog.tri_strip_adj_fix = sctx->gs_tri_strip_adj_fix;
+		key->part.gs.prolog.tri_strip_adj_fix = sctx->gs_tri_strip_adj_fix;
 		break;
 	case PIPE_SHADER_FRAGMENT: {
 		struct si_state_rasterizer *rs = sctx->queued.named.rasterizer;
 		struct si_state_blend *blend = sctx->queued.named.blend;
 
 		if (sel->info.properties[TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS] &&
 		    sel->info.colors_written == 0x1)
-			key->ps.epilog.last_cbuf = MAX2(sctx->framebuffer.state.nr_cbufs, 1) - 1;
+			key->part.ps.epilog.last_cbuf = MAX2(sctx->framebuffer.state.nr_cbufs, 1) - 1;
 
 		if (blend) {
 			/* Select the shader color format based on whether
 			 * blending or alpha are needed.
 			 */
-			key->ps.epilog.spi_shader_col_format =
+			key->part.ps.epilog.spi_shader_col_format =
 				(blend->blend_enable_4bit & blend->need_src_alpha_4bit &
 				 sctx->framebuffer.spi_shader_col_format_blend_alpha) |
 				(blend->blend_enable_4bit & ~blend->need_src_alpha_4bit &
 				 sctx->framebuffer.spi_shader_col_format_blend) |
 				(~blend->blend_enable_4bit & blend->need_src_alpha_4bit &
 				 sctx->framebuffer.spi_shader_col_format_alpha) |
 				(~blend->blend_enable_4bit & ~blend->need_src_alpha_4bit &
 				 sctx->framebuffer.spi_shader_col_format);
 
 			/* The output for dual source blending should have
 			 * the same format as the first output.
 			 */
 			if (blend->dual_src_blend)
-				key->ps.epilog.spi_shader_col_format |=
-					(key->ps.epilog.spi_shader_col_format & 0xf) << 4;
+				key->part.ps.epilog.spi_shader_col_format |=
+					(key->part.ps.epilog.spi_shader_col_format & 0xf) << 4;
 		} else
-			key->ps.epilog.spi_shader_col_format = sctx->framebuffer.spi_shader_col_format;
+			key->part.ps.epilog.spi_shader_col_format = sctx->framebuffer.spi_shader_col_format;
 
 		/* If alpha-to-coverage is enabled, we have to export alpha
 		 * even if there is no color buffer.
 		 */
-		if (!(key->ps.epilog.spi_shader_col_format & 0xf) &&
+		if (!(key->part.ps.epilog.spi_shader_col_format & 0xf) &&
 		    blend && blend->alpha_to_coverage)
-			key->ps.epilog.spi_shader_col_format |= V_028710_SPI_SHADER_32_AR;
+			key->part.ps.epilog.spi_shader_col_format |= V_028710_SPI_SHADER_32_AR;
 
 		/* On SI and CIK except Hawaii, the CB doesn't clamp outputs
 		 * to the range supported by the type if a channel has less
 		 * than 16 bits and the export format is 16_ABGR.
 		 */
 		if (sctx->b.chip_class <= CIK && sctx->b.family != CHIP_HAWAII)
-			key->ps.epilog.color_is_int8 = sctx->framebuffer.color_is_int8;
+			key->part.ps.epilog.color_is_int8 = sctx->framebuffer.color_is_int8;
 
 		/* Disable unwritten outputs (if WRITE_ALL_CBUFS isn't enabled). */
-		if (!key->ps.epilog.last_cbuf) {
-			key->ps.epilog.spi_shader_col_format &= sel->colors_written_4bit;
-			key->ps.epilog.color_is_int8 &= sel->info.colors_written;
+		if (!key->part.ps.epilog.last_cbuf) {
+			key->part.ps.epilog.spi_shader_col_format &= sel->colors_written_4bit;
+			key->part.ps.epilog.color_is_int8 &= sel->info.colors_written;
 		}
 
 		if (rs) {
 			bool is_poly = (sctx->current_rast_prim >= PIPE_PRIM_TRIANGLES &&
 					sctx->current_rast_prim <= PIPE_PRIM_POLYGON) ||
 				       sctx->current_rast_prim >= PIPE_PRIM_TRIANGLES_ADJACENCY;
 			bool is_line = !is_poly && sctx->current_rast_prim != PIPE_PRIM_POINTS;
 
-			key->ps.prolog.color_two_side = rs->two_side && sel->info.colors_read;
-			key->ps.prolog.flatshade_colors = rs->flatshade && sel->info.colors_read;
+			key->part.ps.prolog.color_two_side = rs->two_side && sel->info.colors_read;
+			key->part.ps.prolog.flatshade_colors = rs->flatshade && sel->info.colors_read;
 
 			if (sctx->queued.named.blend) {
-				key->ps.epilog.alpha_to_one = sctx->queued.named.blend->alpha_to_one &&
+				key->part.ps.epilog.alpha_to_one = sctx->queued.named.blend->alpha_to_one &&
 							      rs->multisample_enable;
 			}
 
-			key->ps.prolog.poly_stipple = rs->poly_stipple_enable && is_poly;
-			key->ps.epilog.poly_line_smoothing = ((is_poly && rs->poly_smooth) ||
+			key->part.ps.prolog.poly_stipple = rs->poly_stipple_enable && is_poly;
+			key->part.ps.epilog.poly_line_smoothing = ((is_poly && rs->poly_smooth) ||
 							      (is_line && rs->line_smooth)) &&
 							     sctx->framebuffer.nr_samples <= 1;
-			key->ps.epilog.clamp_color = rs->clamp_fragment_color;
+			key->part.ps.epilog.clamp_color = rs->clamp_fragment_color;
 
 			if (rs->force_persample_interp &&
 			    rs->multisample_enable &&
 			    sctx->framebuffer.nr_samples > 1 &&
 			    sctx->ps_iter_samples > 1) {
-				key->ps.prolog.force_persp_sample_interp =
+				key->part.ps.prolog.force_persp_sample_interp =
 					sel->info.uses_persp_center ||
 					sel->info.uses_persp_centroid;
 
-				key->ps.prolog.force_linear_sample_interp =
+				key->part.ps.prolog.force_linear_sample_interp =
 					sel->info.uses_linear_center ||
 					sel->info.uses_linear_centroid;
 			} else if (rs->multisample_enable &&
 				   sctx->framebuffer.nr_samples > 1) {
-				key->ps.prolog.bc_optimize_for_persp =
+				key->part.ps.prolog.bc_optimize_for_persp =
 					sel->info.uses_persp_center &&
 					sel->info.uses_persp_centroid;
-				key->ps.prolog.bc_optimize_for_linear =
+				key->part.ps.prolog.bc_optimize_for_linear =
 					sel->info.uses_linear_center &&
 					sel->info.uses_linear_centroid;
 			} else {
 				/* Make sure SPI doesn't compute more than 1 pair
 				 * of (i,j), which is the optimization here. */
-				key->ps.prolog.force_persp_center_interp =
+				key->part.ps.prolog.force_persp_center_interp =
 					sel->info.uses_persp_center +
 					sel->info.uses_persp_centroid +
 					sel->info.uses_persp_sample > 1;
 
-				key->ps.prolog.force_linear_center_interp =
+				key->part.ps.prolog.force_linear_center_interp =
 					sel->info.uses_linear_center +
 					sel->info.uses_linear_centroid +
 					sel->info.uses_linear_sample > 1;
 			}
 		}
 
-		key->ps.epilog.alpha_func = si_get_alpha_test_func(sctx);
+		key->part.ps.epilog.alpha_func = si_get_alpha_test_func(sctx);
 		break;
 	}
 	default:
 		assert(0);
 	}
 }
 
 /* Select the hw shader variant depending on the current state. */
 static int si_shader_select_with_key(struct si_screen *sscreen,
 				     struct si_shader_ctx_state *state,
-				     union si_shader_key *key,
+				     struct si_shader_key *key,
 				     LLVMTargetMachineRef tm,
 				     struct pipe_debug_callback *debug,
 				     bool wait,
 				     bool is_debug_context)
 {
 	struct si_shader_selector *sel = state->cso;
 	struct si_shader *current = state->current;
 	struct si_shader *iter, *shader = NULL;
 	int r;
 
@@ -1094,56 +1094,56 @@ static int si_shader_select_with_key(struct si_screen *sscreen,
 	}
 	state->current = shader;
 	pipe_mutex_unlock(sel->mutex);
 	return 0;
 }
 
 static int si_shader_select(struct pipe_context *ctx,
 			    struct si_shader_ctx_state *state)
 {
 	struct si_context *sctx = (struct si_context *)ctx;
-	union si_shader_key key;
+	struct si_shader_key key;
 
 	si_shader_selector_key(ctx, state->cso, &key);
 	return si_shader_select_with_key(sctx->screen, state, &key,
 					 sctx->tm, &sctx->b.debug, true,
 					 sctx->is_debug);
 }
 
 static void si_parse_next_shader_property(const struct tgsi_shader_info *info,
-					  union si_shader_key *key)
+					  struct si_shader_key *key)
 {
 	unsigned next_shader = info->properties[TGSI_PROPERTY_NEXT_SHADER];
 
 	switch (info->processor) {
 	case PIPE_SHADER_VERTEX:
 		switch (next_shader) {
 		case PIPE_SHADER_GEOMETRY:
-			key->vs.as_es = 1;
+			key->as_es = 1;
 			break;
 		case PIPE_SHADER_TESS_CTRL:
 		case PIPE_SHADER_TESS_EVAL:
-			key->vs.as_ls = 1;
+			key->as_ls = 1;
 			break;
 		default:
 			/* If POSITION isn't written, it can't be a HW VS.
 			 * Assume that it's a HW LS. (the next shader is TCS)
 			 * This heuristic is needed for separate shader objects.
 			 */
 			if (!info->writes_position)
 				key->as_ls = 1;
 		}
 		break;
 
 	case PIPE_SHADER_TESS_EVAL:
 		if (next_shader == PIPE_SHADER_GEOMETRY)
-			key->tes.as_es = 1;
+			key->as_es = 1;
 		break;
 	}
 }
 
 /**
  * Compile the main shader part or the monolithic shader as part of
  * si_shader_selector initialization. Since it can be done asynchronously,
  * there is no way to report compile failures to applications.
  */
 void si_init_shader_selector_async(void *job, int thread_index)
@@ -1207,43 +1207,43 @@ void si_init_shader_selector_async(void *job, int thread_index)
 				pipe_mutex_unlock(sscreen->shader_cache_mutex);
 			}
 		}
 
 		sel->main_shader_part = shader;
 	}
 
 	/* Pre-compilation. */
 	if (sscreen->b.debug_flags & DBG_PRECOMPILE) {
 		struct si_shader_ctx_state state = {sel};
-		union si_shader_key key;
+		struct si_shader_key key;
 
 		memset(&key, 0, sizeof(key));
 		si_parse_next_shader_property(&sel->info, &key);
 
 		/* Set reasonable defaults, so that the shader key doesn't
 		 * cause any code to be eliminated.
 		 */
 		switch (sel->type) {
 		case PIPE_SHADER_TESS_CTRL:
-			key.tcs.epilog.prim_mode = PIPE_PRIM_TRIANGLES;
+			key.part.tcs.epilog.prim_mode = PIPE_PRIM_TRIANGLES;
 			break;
 		case PIPE_SHADER_FRAGMENT:
-			key.ps.prolog.bc_optimize_for_persp =
+			key.part.ps.prolog.bc_optimize_for_persp =
 				sel->info.uses_persp_center &&
 				sel->info.uses_persp_centroid;
-			key.ps.prolog.bc_optimize_for_linear =
+			key.part.ps.prolog.bc_optimize_for_linear =
 				sel->info.uses_linear_center &&
 				sel->info.uses_linear_centroid;
-			key.ps.epilog.alpha_func = PIPE_FUNC_ALWAYS;
+			key.part.ps.epilog.alpha_func = PIPE_FUNC_ALWAYS;
 			for (i = 0; i < 8; i++)
 				if (sel->info.colors_written & (1 << i))
-					key.ps.epilog.spi_shader_col_format |=
+					key.part.ps.epilog.spi_shader_col_format |=
 						V_028710_SPI_SHADER_FP16_ABGR << (i * 4);
 			break;
 		}
 
 		if (si_shader_select_with_key(sscreen, &state, &key, tm, debug,
 					      false, sel->is_debug_context))
 			fprintf(stderr, "radeonsi: can't create a monolithic shader\n");
 	}
 
 	/* The GS copy shader is always pre-compiled. */
@@ -1514,32 +1514,32 @@ static void si_bind_ps_shader(struct pipe_context *ctx, void *state)
 	sctx->ps_shader.current = sel ? sel->first_variant : NULL;
 	sctx->do_update_shaders = true;
 	si_mark_atom_dirty(sctx, &sctx->cb_render_state);
 }
 
 static void si_delete_shader(struct si_context *sctx, struct si_shader *shader)
 {
 	if (shader->pm4) {
 		switch (shader->selector->type) {
 		case PIPE_SHADER_VERTEX:
-			if (shader->key.vs.as_ls)
+			if (shader->key.as_ls)
 				si_pm4_delete_state(sctx, ls, shader->pm4);
-			else if (shader->key.vs.as_es)
+			else if (shader->key.as_es)
 				si_pm4_delete_state(sctx, es, shader->pm4);
 			else
 				si_pm4_delete_state(sctx, vs, shader->pm4);
 			break;
 		case PIPE_SHADER_TESS_CTRL:
 			si_pm4_delete_state(sctx, hs, shader->pm4);
 			break;
 		case PIPE_SHADER_TESS_EVAL:
-			if (shader->key.tes.as_es)
+			if (shader->key.as_es)
 				si_pm4_delete_state(sctx, es, shader->pm4);
 			else
 				si_pm4_delete_state(sctx, vs, shader->pm4);
 			break;
 		case PIPE_SHADER_GEOMETRY:
 			if (shader->is_gs_copy_shader)
 				si_pm4_delete_state(sctx, vs, shader->pm4);
 			else
 				si_pm4_delete_state(sctx, gs, shader->pm4);
 			break;
@@ -1666,21 +1666,21 @@ static void si_emit_spi_map(struct si_context *sctx, struct r600_atom *atom)
 		radeon_emit(cs, si_get_ps_input_cntl(sctx, vs, name, index,
 						     interpolate));
 		num_written++;
 
 		if (name == TGSI_SEMANTIC_COLOR) {
 			assert(index < ARRAY_SIZE(bcol_interp));
 			bcol_interp[index] = interpolate;
 		}
 	}
 
-	if (ps->key.ps.prolog.color_two_side) {
+	if (ps->key.part.ps.prolog.color_two_side) {
 		unsigned bcol = TGSI_SEMANTIC_BCOLOR;
 
 		for (i = 0; i < 2; i++) {
 			if (!(psinfo->colors_read & (0xf << (i * 4))))
 				continue;
 
 			radeon_emit(cs, si_get_ps_input_cntl(sctx, vs, bcol,
 							     i, bcol_interp[i]));
 			num_written++;
 		}
@@ -2274,22 +2274,22 @@ bool si_update_shaders(struct si_context *sctx)
 		}
 
 		if (sctx->b.family == CHIP_STONEY && si_pm4_state_changed(sctx, ps))
 			si_mark_atom_dirty(sctx, &sctx->cb_render_state);
 
 		if (sctx->ps_db_shader_control != db_shader_control) {
 			sctx->ps_db_shader_control = db_shader_control;
 			si_mark_atom_dirty(sctx, &sctx->db_render_state);
 		}
 
-		if (sctx->smoothing_enabled != sctx->ps_shader.current->key.ps.epilog.poly_line_smoothing) {
-			sctx->smoothing_enabled = sctx->ps_shader.current->key.ps.epilog.poly_line_smoothing;
+		if (sctx->smoothing_enabled != sctx->ps_shader.current->key.part.ps.epilog.poly_line_smoothing) {
+			sctx->smoothing_enabled = sctx->ps_shader.current->key.part.ps.epilog.poly_line_smoothing;
 			si_mark_atom_dirty(sctx, &sctx->msaa_config);
 
 			if (sctx->b.chip_class == SI)
 				si_mark_atom_dirty(sctx, &sctx->db_render_state);
 
 			if (sctx->framebuffer.nr_samples <= 1)
 				si_mark_atom_dirty(sctx, &sctx->msaa_sample_locs.atom);
 		}
 	}
 
-- 
2.7.4



More information about the mesa-dev mailing list