bld_base->op_actions[TGSI_OPCODE_BARRIER].emit = si_llvm_emit_barrier;
}
+/* Return true if the PARAM export has been eliminated. */
+static bool si_eliminate_const_output(struct si_shader_context *ctx,
+ LLVMValueRef inst, unsigned offset)
+{
+ struct si_shader *shader = ctx->shader;
+ unsigned num_outputs = shader->selector->info.num_outputs;
+ 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, 5 + i);
+ if (!LLVMIsConstant(p))
+ return false;
+
+ /* It's a constant expression. Undef outputs are eliminated too. */
+ if (LLVMIsUndef(p)) {
+ is_zero[i] = true;
+ is_one[i] = true;
+ } else {
+ 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 */
+ }
+ }
+
+ /* 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 (shader->info.vs_output_param_offset[i] == offset) {
+ shader->info.vs_output_param_offset[i] =
+ EXP_PARAM_DEFAULT_VAL_0000 + default_val;
+ break;
+ }
+ }
+ return true;
+}
+
+struct si_vs_exports {
+ unsigned num;
+ unsigned offset[SI_MAX_VS_OUTPUTS];
+ LLVMValueRef inst[SI_MAX_VS_OUTPUTS];
+};
+
+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))
+ return;
+
+ /* Process all LLVM instructions. */
+ bb = LLVMGetFirstBasicBlock(ctx->main_fn);
+ while (bb) {
+ LLVMValueRef inst = LLVMGetFirstInstruction(bb);
+
+ while (inst) {
+ LLVMValueRef cur = inst;
+ inst = LLVMGetNextInstruction(inst);
+
+ if (LLVMGetInstructionOpcode(cur) != LLVMCall)
+ continue;
+
+ LLVMValueRef callee = LLVMGetCalledValue(cur);
+ LLVMValueKind kind = LLVMGetValueKind(callee);
+
+ if (kind != LLVMFunctionValueKind)
+ continue;
+
+ const char *name = LLVMGetValueName(callee);
+ unsigned num_args = LLVMCountParams(callee);
+
+ /* Check if this is an export instruction. */
+ if (num_args != 9 || strcmp(name, "llvm.SI.export"))
+ continue;
+
+ LLVMValueRef arg = LLVMGetOperand(cur, 3);
+ unsigned target = LLVMConstIntGetZExtValue(arg);
+
+ if (target < V_008DFC_SQ_EXP_PARAM)
+ continue;
+
+ target -= V_008DFC_SQ_EXP_PARAM;
+
+ /* Eliminate constant value PARAM exports. */
+ if (si_eliminate_const_output(ctx, 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) {
+ ubyte current_offset[SI_MAX_VS_OUTPUTS];
+ 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. */
+ assert(sizeof(current_offset) ==
+ sizeof(shader->info.vs_output_param_offset));
+ memcpy(current_offset, shader->info.vs_output_param_offset,
+ sizeof(current_offset));
+
+ for (i = 0; i < exports.num; i++) {
+ unsigned offset = exports.offset[i];
+
+ for (out = 0; out < info->num_outputs; out++) {
+ if (current_offset[out] != offset)
+ continue;
+
+ LLVMSetOperand(exports.inst[i], 3,
+ LLVMConstInt(ctx->i32,
+ V_008DFC_SQ_EXP_PARAM + new_count, 0));
+ shader->info.vs_output_param_offset[out] = new_count;
+ new_count++;
+ break;
+ }
+ }
+ shader->info.nr_param_exports = new_count;
+ }
+}
+
int si_compile_tgsi_shader(struct si_screen *sscreen,
LLVMTargetMachineRef tm,
struct si_shader *shader,
si_init_shader_ctx(&ctx, sscreen, shader, tm);
ctx.is_monolithic = is_monolithic;
+ memset(shader->info.vs_output_param_offset, 0xff,
+ sizeof(shader->info.vs_output_param_offset));
+
shader->info.uses_instanceid = sel->info.uses_instanceid;
bld_base = &ctx.soa.bld_base;
si_llvm_finalize_module(&ctx,
r600_extra_shader_checks(&sscreen->b, ctx.type));
+ /* Post-optimization transformations. */
+ si_eliminate_const_vs_outputs(&ctx);
+
+ /* Compile to bytecode. */
r = si_compile_llvm(sscreen, &shader->binary, &shader->config, tm,
mod, debug, ctx.type, "TGSI shader");
if (r) {
unsigned index, unsigned interpolate)
{
struct tgsi_shader_info *vsinfo = &vs->selector->info;
- unsigned j, ps_input_cntl = 0;
+ unsigned j, offset, ps_input_cntl = 0;
if (interpolate == TGSI_INTERPOLATE_CONSTANT ||
(interpolate == TGSI_INTERPOLATE_COLOR && sctx->flatshade))
for (j = 0; j < vsinfo->num_outputs; j++) {
if (name == vsinfo->output_semantic_name[j] &&
index == vsinfo->output_semantic_index[j]) {
- ps_input_cntl |= S_028644_OFFSET(vs->info.vs_output_param_offset[j]);
+ offset = vs->info.vs_output_param_offset[j];
+
+ if (offset <= EXP_PARAM_OFFSET_31) {
+ /* The input is loaded from parameter memory. */
+ ps_input_cntl |= S_028644_OFFSET(offset);
+ } else if (!G_028644_PT_SPRITE_TEX(ps_input_cntl)) {
+ /* The input is a DEFAULT_VAL constant. */
+ assert(offset >= EXP_PARAM_DEFAULT_VAL_0000 &&
+ offset <= EXP_PARAM_DEFAULT_VAL_1111);
+
+ offset -= EXP_PARAM_DEFAULT_VAL_0000;
+ ps_input_cntl = S_028644_OFFSET(0x20) |
+ S_028644_DEFAULT_VAL(offset);
+ }
break;
}
}