mirror of https://gitlab.freedesktop.org/mesa/mesa
240 lines
6.1 KiB
C
240 lines
6.1 KiB
C
/*
|
|
* Copyright 2023 Valve Corporation
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "compiler.h"
|
|
#include "midgard.h"
|
|
#include "midgard_ops.h"
|
|
#include "nir.h"
|
|
|
|
static bool
|
|
is_inot(midgard_instruction *I)
|
|
{
|
|
return I->type == TAG_ALU_4 && I->op == midgard_alu_op_inor &&
|
|
I->has_inline_constant && I->inline_constant == 0;
|
|
}
|
|
|
|
static bool
|
|
try_fold_fmov_src(midgard_instruction *use, unsigned src_idx,
|
|
midgard_instruction *fmov)
|
|
{
|
|
if (use->type != TAG_ALU_4)
|
|
return false;
|
|
if (fmov->has_constants || fmov->has_inline_constant)
|
|
return false;
|
|
if (mir_nontrivial_outmod(fmov))
|
|
return false;
|
|
|
|
/* Don't propagate into non-float instructions */
|
|
if (nir_alu_type_get_base_type(use->src_types[src_idx]) != nir_type_float)
|
|
return false;
|
|
|
|
/* TODO: Size conversions not handled yet */
|
|
if (use->src_types[src_idx] != fmov->src_types[1])
|
|
return false;
|
|
|
|
if (use->src_abs[src_idx]) {
|
|
/* abs(abs(x)) = abs(x) and abs(-x) = abs(x) */
|
|
} else {
|
|
/* -(-(abs(x))) = abs(x) */
|
|
use->src_abs[src_idx] = fmov->src_abs[1];
|
|
use->src_neg[src_idx] ^= fmov->src_neg[1];
|
|
}
|
|
|
|
use->src[src_idx] = fmov->src[1];
|
|
mir_compose_swizzle(use->swizzle[src_idx], fmov->swizzle[1],
|
|
use->swizzle[src_idx]);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
try_fold_inot(midgard_instruction *use, unsigned src_idx,
|
|
midgard_instruction *inot)
|
|
{
|
|
/* TODO: Size conversions not handled yet */
|
|
if (nir_alu_type_get_type_size(use->src_types[src_idx]) !=
|
|
nir_alu_type_get_type_size(inot->src_types[0]))
|
|
return false;
|
|
|
|
if (use->compact_branch) {
|
|
use->branch.invert_conditional ^= true;
|
|
} else if (use->type == TAG_ALU_4) {
|
|
switch (use->op) {
|
|
case midgard_alu_op_iand:
|
|
case midgard_alu_op_ior:
|
|
case midgard_alu_op_ixor:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
use->src_invert[src_idx] ^= true;
|
|
mir_compose_swizzle(use->swizzle[src_idx], inot->swizzle[0],
|
|
use->swizzle[src_idx]);
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
use->src[src_idx] = inot->src[0];
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
midgard_opt_prop_forward(compiler_context *ctx)
|
|
{
|
|
bool progress = false;
|
|
|
|
midgard_instruction **defs =
|
|
calloc(ctx->temp_count, sizeof(midgard_instruction *));
|
|
|
|
mir_foreach_block(ctx, block_) {
|
|
midgard_block *block = (midgard_block *)block_;
|
|
|
|
mir_foreach_instr_in_block(block, I) {
|
|
/* Record SSA defs */
|
|
if (mir_is_ssa(I->dest)) {
|
|
assert(I->dest < ctx->temp_count);
|
|
defs[I->dest] = I;
|
|
}
|
|
|
|
mir_foreach_src(I, s) {
|
|
unsigned src = I->src[s];
|
|
if (!mir_is_ssa(src))
|
|
continue;
|
|
|
|
/* Try to fold a source mod in */
|
|
assert(src < ctx->temp_count);
|
|
midgard_instruction *def = defs[src];
|
|
if (def == NULL)
|
|
continue;
|
|
|
|
if (def->type == TAG_ALU_4 && def->op == midgard_alu_op_fmov) {
|
|
progress |= try_fold_fmov_src(I, s, def);
|
|
} else if (is_inot(def)) {
|
|
progress |= try_fold_inot(I, s, def);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
free(defs);
|
|
return progress;
|
|
}
|
|
|
|
enum outmod_state {
|
|
outmod_unknown = 0,
|
|
outmod_clamp_0_1,
|
|
outmod_clamp_m1_1,
|
|
outmod_clamp_0_inf,
|
|
outmod_incompatible,
|
|
};
|
|
|
|
static enum outmod_state
|
|
outmod_to_state(unsigned outmod)
|
|
{
|
|
switch (outmod) {
|
|
case midgard_outmod_clamp_0_1:
|
|
return outmod_clamp_0_1;
|
|
case midgard_outmod_clamp_m1_1:
|
|
return outmod_clamp_m1_1;
|
|
case midgard_outmod_clamp_0_inf:
|
|
return outmod_clamp_0_inf;
|
|
default:
|
|
return outmod_incompatible;
|
|
}
|
|
}
|
|
|
|
static enum outmod_state
|
|
union_outmod_state(enum outmod_state a, enum outmod_state b)
|
|
{
|
|
if (a == outmod_unknown)
|
|
return b;
|
|
else if (b == outmod_unknown)
|
|
return a;
|
|
else if (a == b)
|
|
return a /* b */;
|
|
else
|
|
return outmod_incompatible;
|
|
}
|
|
|
|
static bool
|
|
midgard_opt_prop_backward(compiler_context *ctx)
|
|
{
|
|
bool progress = false;
|
|
enum outmod_state *state = calloc(ctx->temp_count, sizeof(*state));
|
|
BITSET_WORD *folded = calloc(BITSET_WORDS(ctx->temp_count), sizeof(*folded));
|
|
|
|
/* Scan for outmod states */
|
|
mir_foreach_instr_global(ctx, I) {
|
|
if (I->type == TAG_ALU_4 && I->op == midgard_alu_op_fmov &&
|
|
!I->src_neg[1] && !I->src_abs[1] && mir_is_ssa(I->src[1])) {
|
|
|
|
enum outmod_state outmod = outmod_to_state(I->outmod);
|
|
state[I->src[1]] = union_outmod_state(state[I->src[1]], outmod);
|
|
} else {
|
|
/* Anything used as any other source cannot have an outmod folded in */
|
|
mir_foreach_src(I, s) {
|
|
if (mir_is_ssa(I->src[s]))
|
|
state[I->src[s]] = outmod_incompatible;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Apply outmods */
|
|
mir_foreach_instr_global(ctx, I) {
|
|
if (!mir_is_ssa(I->dest))
|
|
continue;
|
|
|
|
if (I->type != TAG_ALU_4 && I->type != TAG_TEXTURE_4)
|
|
continue;
|
|
|
|
if (nir_alu_type_get_base_type(I->dest_type) != nir_type_float)
|
|
continue;
|
|
|
|
if (I->outmod != midgard_outmod_none)
|
|
continue;
|
|
|
|
switch (state[I->dest]) {
|
|
case outmod_clamp_0_1:
|
|
I->outmod = midgard_outmod_clamp_0_1;
|
|
break;
|
|
case outmod_clamp_m1_1:
|
|
I->outmod = midgard_outmod_clamp_m1_1;
|
|
break;
|
|
case outmod_clamp_0_inf:
|
|
I->outmod = midgard_outmod_clamp_0_inf;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (I->outmod != midgard_outmod_none) {
|
|
BITSET_SET(folded, I->dest);
|
|
}
|
|
}
|
|
|
|
/* Strip outmods from FMOVs to let copyprop go ahead */
|
|
mir_foreach_instr_global(ctx, I) {
|
|
if (I->type == TAG_ALU_4 && I->op == midgard_alu_op_fmov &&
|
|
mir_is_ssa(I->src[1]) && BITSET_TEST(folded, I->src[1])) {
|
|
|
|
I->outmod = midgard_outmod_none;
|
|
}
|
|
}
|
|
|
|
free(state);
|
|
free(folded);
|
|
return progress;
|
|
}
|
|
|
|
bool
|
|
midgard_opt_prop(compiler_context *ctx)
|
|
{
|
|
bool progress = false;
|
|
mir_compute_temp_count(ctx);
|
|
progress |= midgard_opt_prop_forward(ctx);
|
|
progress |= midgard_opt_prop_backward(ctx);
|
|
return progress;
|
|
}
|