[Mesa-dev] [PATCH 3/3] ac: eliminate duplicated VS exports

Marek Olšák maraeo at gmail.com
Mon May 1 12:43:01 UTC 2017


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

Only very few shaders have them (from 48486 shaders):

shaders/private/left_4_dead_2/765.shader_test - ac: 1 matches 2
shaders/private/left_4_dead_2/877.shader_test - ac: 1 matches 6
shaders/private/left_4_dead_2/2141.shader_test - ac: 1 matches 6
shaders/private/ue4_effects_cave/11.shader_test - ac: 4 matches 5
shaders/private/ue4_effects_cave/14.shader_test - ac: 5 matches 6
shaders/private/ue4_effects_cave/46.shader_test - ac: 5 matches 6
shaders/private/ue4_effects_cave/42.shader_test - ac: 4 matches 5
shaders/private/ue4_effects_cave/104.shader_test - ac: 4 matches 5
shaders/private/f1-2015/336.shader_test - ac: 3 matches 4
shaders/private/f1-2015/948.shader_test - ac: 6 matches 7
shaders/private/f1-2015/602.shader_test - ac: 0 matches 3
shaders/private/f1-2015/600.shader_test - ac: 0 matches 3
shaders/private/f1-2015/1214.shader_test - ac: 0 matches 1
shaders/private/f1-2015/988.shader_test - ac: 4 matches 5
shaders/private/ue4_elemental/149.shader_test - ac: 3 matches 4
shaders/private/ue4_elemental/346.shader_test - ac: 4 matches 5
shaders/private/ue4_elemental/178.shader_test - ac: 3 matches 4
shaders/private/ue4_elemental/136.shader_test - ac: 4 matches 5
shaders/private/ue4_elemental/168.shader_test - ac: 4 matches 5
shaders/private/ue4_elemental/690.shader_test - ac: 3 matches 4
shaders/private/ue4_elemental/19.shader_test - ac: 5 matches 6
shaders/private/dota2/1901.shader_test - ac: 0 matches 5
shaders/private/dota2/1357.shader_test - ac: 0 matches 5
shaders/private/dota2/1375.shader_test - ac: 0 matches 5
shaders/private/dota2/1369.shader_test - ac: 0 matches 5
shaders/private/dota2/1583.shader_test - ac: 0 matches 5
shaders/private/dota2/1811.shader_test - ac: 0 matches 5
shaders/private/dota2/1893.shader_test - ac: 0 matches 5
shaders/private/dota2/1533.shader_test - ac: 0 matches 5
shaders/private/dota2/1951.shader_test - ac: 0 matches 5
shaders/private/dota2/1361.shader_test - ac: 0 matches 5
shaders/private/mad_max/2792.shader_test - ac: 0 matches 1
shaders/private/mad_max/2794.shader_test - ac: 0 matches 1
shaders/private/mad_max/2780.shader_test - ac: 0 matches 1
shaders/private/mad_max/2902.shader_test - ac: 0 matches 1
shaders/private/bioshock-infinite/3050.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/2544.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/3062.shader_test - ac: 3 matches 8
shaders/private/bioshock-infinite/2012.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/3058.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/3270.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/732.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/3026.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/3258.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/3198.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/3046.shader_test - ac: 3 matches 7
shaders/private/bioshock-infinite/3168.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/2550.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/3210.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/3032.shader_test - ac: 3 matches 6
shaders/private/bioshock-infinite/668.shader_test - ac: 3 matches 7
---
 src/amd/common/ac_llvm_build.c | 81 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/src/amd/common/ac_llvm_build.c b/src/amd/common/ac_llvm_build.c
index ada348d..9853d17 100644
--- a/src/amd/common/ac_llvm_build.c
+++ b/src/amd/common/ac_llvm_build.c
@@ -1240,20 +1240,94 @@ static bool ac_eliminate_const_output(uint8_t *vs_output_param_offset,
 	for (i = 0; i < num_outputs; i++) {
 		if (vs_output_param_offset[i] == exp->offset) {
 			vs_output_param_offset[i] =
 				AC_EXP_PARAM_DEFAULT_VAL_0000 + default_val;
 			break;
 		}
 	}
 	return true;
 }
 
+static bool ac_eliminate_duplicated_output(uint8_t *vs_output_param_offset,
+					   uint32_t num_outputs,
+					   struct ac_vs_exports *processed,
+				           struct ac_vs_exp_inst *exp)
+{
+	unsigned p, copy_back_channels = 0;
+
+	/* See if the output is already in the list of processed outputs.
+	 * The LLVMValueRef comparison relies on SSA.
+	 */
+	for (p = 0; p < processed->num; p++) {
+		bool different = false;
+
+		for (unsigned j = 0; j < 4; j++) {
+			struct ac_vs_exp_chan *c1 = &processed->exp[p].chan[j];
+			struct ac_vs_exp_chan *c2 = &exp->chan[j];
+
+			/* Treat undef as a match. */
+			if (c2->type == AC_IR_UNDEF)
+				continue;
+
+			/* If c1 is undef but c2 isn't, we can copy c2 to c1
+			 * and consider the instruction duplicated.
+			 */
+			if (c1->type == AC_IR_UNDEF) {
+				copy_back_channels |= 1 << j;
+				continue;
+			}
+
+			/* Test whether the channels are not equal. */
+			if (c1->type != c2->type ||
+			    (c1->type == AC_IR_CONST &&
+			     c1->const_float != c2->const_float) ||
+			    (c1->type == AC_IR_VALUE &&
+			     c1->value != c2->value)) {
+				different = true;
+				break;
+			}
+		}
+		if (!different)
+			break;
+
+		copy_back_channels = 0;
+	}
+	if (p == processed->num)
+		return false;
+
+	/* If a match was found, but the matching export has undef where the new
+	 * one has a normal value, copy the normal value to the undef channel.
+	 */
+	struct ac_vs_exp_inst *match = &processed->exp[p];
+
+	while (copy_back_channels) {
+		unsigned chan = u_bit_scan(&copy_back_channels);
+
+		assert(match->chan[chan].type == AC_IR_UNDEF);
+		LLVMSetOperand(match->inst, AC_EXP_OUT0 + chan,
+			       exp->chan[chan].value);
+		match->chan[chan] = exp->chan[chan];
+	}
+
+	/* The PARAM export is duplicated. Kill it. */
+	LLVMInstructionEraseFromParent(exp->inst);
+
+	/* Change OFFSET to the matching export. */
+	for (unsigned i = 0; i < num_outputs; i++) {
+		if (vs_output_param_offset[i] == exp->offset) {
+			vs_output_param_offset[i] = match->offset;
+			break;
+		}
+	}
+	return true;
+}
+
 void ac_optimize_vs_outputs(struct ac_llvm_context *ctx,
 			    LLVMValueRef main_fn,
 			    uint8_t *vs_output_param_offset,
 			    uint32_t num_outputs,
 			    uint8_t *num_param_exports)
 {
 	LLVMBasicBlockRef bb;
 	bool removed_any = false;
 	struct ac_vs_exports exports;
 
@@ -1309,23 +1383,26 @@ void ac_optimize_vs_outputs(struct ac_llvm_context *ctx,
 				} else if (LLVMIsAConstantFP(v)) {
 					LLVMBool loses_info;
 					exp.chan[i].type = AC_IR_CONST;
 					exp.chan[i].const_float =
 						LLVMConstRealGetDouble(v, &loses_info);
 				} else {
 					exp.chan[i].type = AC_IR_VALUE;
 				}
 			}
 
-			/* Eliminate constant value PARAM exports. */
+			/* Eliminate constant and duplicated PARAM exports. */
 			if (ac_eliminate_const_output(vs_output_param_offset,
-						      num_outputs, &exp)) {
+						      num_outputs, &exp) ||
+			    ac_eliminate_duplicated_output(vs_output_param_offset,
+							   num_outputs, &exports,
+							   &exp)) {
 				removed_any = true;
 			} else {
 				exports.exp[exports.num++] = exp;
 			}
 		}
 		bb = LLVMGetNextBasicBlock(bb);
 	}
 
 	/* Remove holes in export memory due to removed PARAM exports.
 	 * This is done by renumbering all PARAM exports.
-- 
2.7.4



More information about the mesa-dev mailing list