summaryrefslogtreecommitdiffstats
path: root/src/amd
diff options
context:
space:
mode:
authorDave Airlie <[email protected]>2017-04-25 23:33:29 +0100
committerDave Airlie <[email protected]>2017-04-27 05:17:47 +0100
commite2659176cef99f5761c01aebe992a75a7aea842f (patch)
tree61319582b8caad80810e62f4697e19a43dad3ef2 /src/amd
parent9da104593386f6e8ddec8f0d9d288aceb8908fe1 (diff)
radeonsi/ac: move vertex export remove to common code.
This code can be shared by radv, we bump the max to VARYING_SLOT_MAX here, but that shouldn't have too much fallout. Reviewed-by: Marek Olšák <[email protected]> Reviewed-by: Nicolai Hähnle <[email protected]> Reviewed-by: Bas Nieuwenhuizen <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
Diffstat (limited to 'src/amd')
-rw-r--r--src/amd/common/ac_exp_param.h40
-rw-r--r--src/amd/common/ac_llvm_build.c156
-rw-r--r--src/amd/common/ac_llvm_build.h6
-rw-r--r--src/amd/common/ac_llvm_helper.cpp18
-rw-r--r--src/amd/common/ac_llvm_util.h2
5 files changed, 221 insertions, 1 deletions
diff --git a/src/amd/common/ac_exp_param.h b/src/amd/common/ac_exp_param.h
new file mode 100644
index 00000000000..b97ce8154e0
--- /dev/null
+++ b/src/amd/common/ac_exp_param.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+#ifndef AC_EXP_PARAM_H
+#define AC_EXP_PARAM_H
+
+enum {
+ /* SPI_PS_INPUT_CNTL_i.OFFSET[0:4] */
+ AC_EXP_PARAM_OFFSET_0 = 0,
+ AC_EXP_PARAM_OFFSET_31 = 31,
+ /* SPI_PS_INPUT_CNTL_i.DEFAULT_VAL[0:1] */
+ AC_EXP_PARAM_DEFAULT_VAL_0000 = 64,
+ AC_EXP_PARAM_DEFAULT_VAL_0001,
+ AC_EXP_PARAM_DEFAULT_VAL_1110,
+ AC_EXP_PARAM_DEFAULT_VAL_1111,
+ AC_EXP_PARAM_UNDEFINED = 255,
+};
+
+#endif
diff --git a/src/amd/common/ac_llvm_build.c b/src/amd/common/ac_llvm_build.c
index d45094c8624..9729756de4e 100644
--- a/src/amd/common/ac_llvm_build.c
+++ b/src/amd/common/ac_llvm_build.c
@@ -33,11 +33,13 @@
#include <stdio.h>
#include "ac_llvm_util.h"
-
+#include "ac_exp_param.h"
#include "util/bitscan.h"
#include "util/macros.h"
#include "sid.h"
+#include "shader_enums.h"
+
/* Initialize module-independent parts of the context.
*
* The caller is responsible for initializing ctx::module and ctx::builder.
@@ -1244,3 +1246,155 @@ void ac_get_image_intr_name(const char *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)
+
+/* 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)
+{
+ 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)) {
+ is_zero[i] = true;
+ is_one[i] = true;
+ } else if (LLVMIsAConstantFP(p)) {
+ double a = LLVMConstRealGetDouble(p, &loses_info);
+
+ if (a == 0)
+ is_zero[i] = true;
+ else if (a == 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);
+
+ /* Change OFFSET to DEFAULT_VAL. */
+ for (i = 0; i < num_outputs; i++) {
+ if (vs_output_param_offset[i] == 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;
+
+ assert(num_outputs <= VARYING_SLOT_MAX);
+ 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);
+
+ 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);
+ unsigned num_args = LLVMCountParams(callee);
+
+ /* Check if this is an export instruction. */
+ if ((num_args != 9 && num_args != 8) ||
+ (strcmp(name, "llvm.SI.export") &&
+ strcmp(name, "llvm.amdgcn.exp.f32")))
+ 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;
+
+ /* Eliminate constant value PARAM exports. */
+ if (ac_eliminate_const_output(vs_output_param_offset,
+ num_outputs, cur, target)) {
+ removed_any = true;
+ } else {
+ exports.offset[exports.num] = target;
+ exports.inst[exports.num] = cur;
+ exports.num++;
+ }
+ }
+ 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];
+
+ for (out = 0; out < num_outputs; out++) {
+ if (current_offset[out] != offset)
+ continue;
+
+ LLVMSetOperand(exports.inst[i], 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;
+ }
+}
diff --git a/src/amd/common/ac_llvm_build.h b/src/amd/common/ac_llvm_build.h
index d6edcded331..1c3610a5e69 100644
--- a/src/amd/common/ac_llvm_build.h
+++ b/src/amd/common/ac_llvm_build.h
@@ -239,6 +239,12 @@ void ac_get_image_intr_name(const char *base_name,
LLVMTypeRef coords_type,
LLVMTypeRef rsrc_type,
char *out_name, unsigned out_len);
+
+void ac_eliminate_const_vs_outputs(struct ac_llvm_context *ac,
+ LLVMValueRef main_fn,
+ uint8_t *vs_output_param_offset,
+ uint32_t num_outputs,
+ uint8_t *num_param_exports);
#ifdef __cplusplus
}
#endif
diff --git a/src/amd/common/ac_llvm_helper.cpp b/src/amd/common/ac_llvm_helper.cpp
index 11fa80920d6..03877d5ee1e 100644
--- a/src/amd/common/ac_llvm_helper.cpp
+++ b/src/amd/common/ac_llvm_helper.cpp
@@ -61,3 +61,21 @@ bool ac_is_sgpr_param(LLVMValueRef arg)
return AS.hasAttribute(ArgNo + 1, llvm::Attribute::ByVal) ||
AS.hasAttribute(ArgNo + 1, llvm::Attribute::InReg);
}
+
+LLVMValueRef ac_llvm_get_called_value(LLVMValueRef call)
+{
+#if HAVE_LLVM >= 0x0309
+ return LLVMGetCalledValue(call);
+#else
+ return llvm::wrap(llvm::CallSite(llvm::unwrap<llvm::Instruction>(call)).getCalledValue());
+#endif
+}
+
+bool ac_llvm_is_function(LLVMValueRef v)
+{
+#if HAVE_LLVM >= 0x0309
+ return LLVMGetValueKind(v) == LLVMFunctionValueKind;
+#else
+ return llvm::isa<llvm::Function>(llvm::unwrap(v));
+#endif
+}
diff --git a/src/amd/common/ac_llvm_util.h b/src/amd/common/ac_llvm_util.h
index faecf1efd01..38e7dde5b63 100644
--- a/src/amd/common/ac_llvm_util.h
+++ b/src/amd/common/ac_llvm_util.h
@@ -64,6 +64,8 @@ void ac_add_func_attributes(LLVMContextRef ctx, LLVMValueRef function,
unsigned attrib_mask);
void ac_dump_module(LLVMModuleRef module);
+LLVMValueRef ac_llvm_get_called_value(LLVMValueRef call);
+bool ac_llvm_is_function(LLVMValueRef v);
#ifdef __cplusplus
}
#endif