[Mesa-dev] [PATCH 1/3] ac: first parse VS exports before eliminating constant ones
Marek Olšák
maraeo at gmail.com
Mon May 1 12:42:59 UTC 2017
From: Marek Olšák <marek.olsak at amd.com>
A later commit will make use of this.
---
src/amd/common/ac_llvm_build.c | 82 +++++++++++++++++++++++++++++-------------
1 file changed, 58 insertions(+), 24 deletions(-)
diff --git a/src/amd/common/ac_llvm_build.c b/src/amd/common/ac_llvm_build.c
index ba92e7e..4856c06 100644
--- a/src/amd/common/ac_llvm_build.c
+++ b/src/amd/common/ac_llvm_build.c
@@ -1170,97 +1170,111 @@ void ac_get_image_intr_name(const char *base_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);
}
}
#define AC_EXP_TARGET (HAVE_LLVM >= 0x0500 ? 0 : 3)
#define AC_EXP_OUT0 (HAVE_LLVM >= 0x0500 ? 2 : 5)
+enum ac_ir_type {
+ AC_IR_UNDEF,
+ AC_IR_CONST,
+ AC_IR_VALUE,
+};
+
+struct ac_vs_exp_chan
+{
+ LLVMValueRef value;
+ float const_float;
+ enum ac_ir_type type;
+};
+
+struct ac_vs_exp_inst {
+ unsigned offset;
+ LLVMValueRef inst;
+ struct ac_vs_exp_chan chan[4];
+};
+
+struct ac_vs_exports {
+ unsigned num;
+ struct ac_vs_exp_inst exp[VARYING_SLOT_MAX];
+};
+
/* Return true if the PARAM export has been eliminated. */
static bool ac_eliminate_const_output(uint8_t *vs_output_param_offset,
uint32_t num_outputs,
- LLVMValueRef inst, unsigned offset)
+ struct ac_vs_exp_inst *exp)
{
unsigned i, default_val; /* SPI_PS_INPUT_CNTL_i.DEFAULT_VAL */
bool is_zero[4] = {}, is_one[4] = {};
for (i = 0; i < 4; i++) {
- LLVMBool loses_info;
- LLVMValueRef p = LLVMGetOperand(inst, AC_EXP_OUT0 + i);
-
/* It's a constant expression. Undef outputs are eliminated too. */
- if (LLVMIsUndef(p)) {
+ if (exp->chan[i].type == AC_IR_UNDEF) {
is_zero[i] = true;
is_one[i] = true;
- } else if (LLVMIsAConstantFP(p)) {
- double a = LLVMConstRealGetDouble(p, &loses_info);
-
- if (a == 0)
+ } else if (exp->chan[i].type == AC_IR_CONST) {
+ if (exp->chan[i].const_float == 0)
is_zero[i] = true;
- else if (a == 1)
+ else if (exp->chan[i].const_float == 1)
is_one[i] = true;
else
return false; /* other constant */
} else
return false;
}
/* Only certain combinations of 0 and 1 can be eliminated. */
if (is_zero[0] && is_zero[1] && is_zero[2])
default_val = is_zero[3] ? 0 : 1;
else if (is_one[0] && is_one[1] && is_one[2])
default_val = is_zero[3] ? 2 : 3;
else
return false;
/* The PARAM export can be represented as DEFAULT_VAL. Kill it. */
- LLVMInstructionEraseFromParent(inst);
+ LLVMInstructionEraseFromParent(exp->inst);
/* Change OFFSET to DEFAULT_VAL. */
for (i = 0; i < num_outputs; i++) {
- if (vs_output_param_offset[i] == offset) {
+ if (vs_output_param_offset[i] == exp->offset) {
vs_output_param_offset[i] =
AC_EXP_PARAM_DEFAULT_VAL_0000 + default_val;
break;
}
}
return true;
}
-struct ac_vs_exports {
- unsigned num;
- unsigned offset[VARYING_SLOT_MAX];
- LLVMValueRef inst[VARYING_SLOT_MAX];
-};
-
void ac_eliminate_const_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;
exports.num = 0;
/* Process all LLVM instructions. */
bb = LLVMGetFirstBasicBlock(main_fn);
while (bb) {
LLVMValueRef inst = LLVMGetFirstInstruction(bb);
while (inst) {
LLVMValueRef cur = inst;
inst = LLVMGetNextInstruction(inst);
+ struct ac_vs_exp_inst exp;
if (LLVMGetInstructionOpcode(cur) != LLVMCall)
continue;
LLVMValueRef callee = ac_llvm_get_called_value(cur);
if (!ac_llvm_is_function(callee))
continue;
const char *name = LLVMGetValueName(callee);
@@ -1273,54 +1287,74 @@ void ac_eliminate_const_vs_outputs(struct ac_llvm_context *ctx,
continue;
LLVMValueRef arg = LLVMGetOperand(cur, AC_EXP_TARGET);
unsigned target = LLVMConstIntGetZExtValue(arg);
if (target < V_008DFC_SQ_EXP_PARAM)
continue;
target -= V_008DFC_SQ_EXP_PARAM;
+ /* Parse the instruction. */
+ memset(&exp, 0, sizeof(exp));
+ exp.offset = target;
+ exp.inst = cur;
+
+ for (unsigned i = 0; i < 4; i++) {
+ LLVMValueRef v = LLVMGetOperand(cur, AC_EXP_OUT0 + i);
+
+ exp.chan[i].value = v;
+
+ if (LLVMIsUndef(v)) {
+ exp.chan[i].type = AC_IR_UNDEF;
+ } 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. */
if (ac_eliminate_const_output(vs_output_param_offset,
- num_outputs, cur, target)) {
+ num_outputs, &exp)) {
removed_any = true;
} else {
- exports.offset[exports.num] = target;
- exports.inst[exports.num] = cur;
- exports.num++;
+ 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.
*/
if (removed_any) {
uint8_t current_offset[VARYING_SLOT_MAX];
unsigned new_count = 0;
unsigned out, i;
/* Make a copy of the offsets. We need the old version while
* we are modifying some of them. */
memcpy(current_offset, vs_output_param_offset,
sizeof(current_offset));
for (i = 0; i < exports.num; i++) {
- unsigned offset = exports.offset[i];
+ unsigned offset = exports.exp[i].offset;
for (out = 0; out < num_outputs; out++) {
if (current_offset[out] != offset)
continue;
- LLVMSetOperand(exports.inst[i], AC_EXP_TARGET,
+ LLVMSetOperand(exports.exp[i].inst, AC_EXP_TARGET,
LLVMConstInt(ctx->i32,
V_008DFC_SQ_EXP_PARAM + new_count, 0));
vs_output_param_offset[out] = new_count;
new_count++;
break;
}
}
*num_param_exports = new_count;
}
}
--
2.7.4
More information about the mesa-dev
mailing list