}
static bool
-is_constant_value(struct vc4_compile *c, struct qinst **defs, struct qreg reg,
+is_constant_value(struct vc4_compile *c, struct qreg reg,
uint32_t val)
{
if (reg.file == QFILE_UNIF &&
+ !reg.pack &&
c->uniform_contents[reg.index] == QUNIFORM_CONSTANT &&
c->uniform_data[reg.index] == val) {
return true;
}
static bool
-is_zero(struct vc4_compile *c, struct qinst **defs, struct qreg reg)
+is_zero(struct vc4_compile *c, struct qreg reg)
{
- reg = qir_follow_movs(defs, reg);
- return is_constant_value(c, defs, reg, 0);
+ reg = qir_follow_movs(c, reg);
+ return is_constant_value(c, reg, 0);
}
static bool
-is_1f(struct vc4_compile *c, struct qinst **defs, struct qreg reg)
+is_1f(struct vc4_compile *c, struct qreg reg)
{
- reg = qir_follow_movs(defs, reg);
- return is_constant_value(c, defs, reg, fui(1.0));
+ reg = qir_follow_movs(c, reg);
+ return is_constant_value(c, reg, fui(1.0));
}
static void
replace_with_mov(struct vc4_compile *c, struct qinst *inst, struct qreg arg)
{
dump_from(c, inst);
- inst->op = QOP_MOV;
+ if (qir_is_mul(inst))
+ inst->op = QOP_MMOV;
+ else if (qir_is_float_input(inst))
+ inst->op = QOP_FMOV;
+ else
+ inst->op = QOP_MOV;
inst->src[0] = arg;
inst->src[1] = c->undef;
dump_to(c, inst);
static bool
replace_x_0_with_x(struct vc4_compile *c,
- struct qinst **defs,
struct qinst *inst,
int arg)
{
- if (!is_zero(c, defs, inst->src[arg]))
+ if (!is_zero(c, inst->src[arg]))
return false;
replace_with_mov(c, inst, inst->src[1 - arg]);
return true;
static bool
replace_x_0_with_0(struct vc4_compile *c,
- struct qinst **defs,
struct qinst *inst,
int arg)
{
- if (!is_zero(c, defs, inst->src[arg]))
+ if (!is_zero(c, inst->src[arg]))
return false;
replace_with_mov(c, inst, inst->src[arg]);
return true;
static bool
fmul_replace_one(struct vc4_compile *c,
- struct qinst **defs,
struct qinst *inst,
int arg)
{
- if (!is_1f(c, defs, inst->src[arg]))
+ if (!is_1f(c, inst->src[arg]))
return false;
replace_with_mov(c, inst, inst->src[1 - arg]);
return true;
qir_opt_algebraic(struct vc4_compile *c)
{
bool progress = false;
- struct simple_node *node;
- struct qinst *defs[c->num_temps];
-
- foreach(node, &c->instructions) {
- struct qinst *inst = (struct qinst *)node;
-
- if (inst->dst.file == QFILE_TEMP)
- defs[inst->dst.index] = inst;
+ list_for_each_entry(struct qinst, inst, &c->instructions, link) {
switch (inst->op) {
- case QOP_SF:
- /* SF just looks at the sign bit, or whether all the
- * bits are 0. This is preserved across an itof
- * transformation.
- */
- if (inst->src[0].file == QFILE_TEMP &&
- defs[inst->src[0].index]->op == QOP_ITOF) {
- dump_from(c, inst);
- inst->src[0] =
- defs[inst->src[0].index]->src[0];
- progress = true;
- dump_to(c, inst);
- break;
- }
- break;
-
- case QOP_SEL_X_Y_ZS:
- case QOP_SEL_X_Y_ZC:
- case QOP_SEL_X_Y_NS:
- case QOP_SEL_X_Y_NC:
- if (qir_reg_equals(inst->src[0], inst->src[1])) {
- /* Turn "dst = (sf == x) ? a : a)" into
- * "dst = a"
- */
- replace_with_mov(c, inst, inst->src[1]);
- progress = true;
- break;
- }
-
- if (is_zero(c, defs, inst->src[1])) {
- /* Replace references to a 0 uniform value
- * with the SEL_X_0 equivalent.
- */
- dump_from(c, inst);
- inst->op -= (QOP_SEL_X_Y_ZS - QOP_SEL_X_0_ZS);
- inst->src[1] = c->undef;
+ case QOP_FMIN:
+ if (is_1f(c, inst->src[1]) &&
+ inst->src[0].pack >= QPU_UNPACK_8D_REP &&
+ inst->src[0].pack <= QPU_UNPACK_8D) {
+ replace_with_mov(c, inst, inst->src[0]);
progress = true;
- dump_to(c, inst);
- break;
}
+ break;
- if (is_zero(c, defs, inst->src[0])) {
- /* Replace references to a 0 uniform value
- * with the SEL_X_0 equivalent, flipping the
- * condition being evaluated since the operand
- * order is flipped.
- */
- dump_from(c, inst);
- inst->op -= QOP_SEL_X_Y_ZS;
- inst->op ^= 1;
- inst->op += QOP_SEL_X_0_ZS;
- inst->src[0] = inst->src[1];
- inst->src[1] = c->undef;
+ case QOP_FMAX:
+ if (is_zero(c, inst->src[1]) &&
+ inst->src[0].pack >= QPU_UNPACK_8D_REP &&
+ inst->src[0].pack <= QPU_UNPACK_8D) {
+ replace_with_mov(c, inst, inst->src[0]);
progress = true;
- dump_to(c, inst);
- break;
}
-
break;
case QOP_FSUB:
case QOP_SUB:
- if (is_zero(c, defs, inst->src[1])) {
+ if (is_zero(c, inst->src[1])) {
replace_with_mov(c, inst, inst->src[0]);
+ progress = true;
}
break;
case QOP_ADD:
- if (replace_x_0_with_x(c, defs, inst, 0) ||
- replace_x_0_with_x(c, defs, inst, 1)) {
+ if (replace_x_0_with_x(c, inst, 0) ||
+ replace_x_0_with_x(c, inst, 1)) {
progress = true;
break;
}
break;
case QOP_FADD:
- if (replace_x_0_with_x(c, defs, inst, 0) ||
- replace_x_0_with_x(c, defs, inst, 1)) {
+ if (replace_x_0_with_x(c, inst, 0) ||
+ replace_x_0_with_x(c, inst, 1)) {
progress = true;
break;
}
/* FADD(a, FSUB(0, b)) -> FSUB(a, b) */
if (inst->src[1].file == QFILE_TEMP &&
- defs[inst->src[1].index]->op == QOP_FSUB) {
- struct qinst *fsub = defs[inst->src[1].index];
- if (is_zero(c, defs, fsub->src[0])) {
+ c->defs[inst->src[1].index] &&
+ c->defs[inst->src[1].index]->op == QOP_FSUB) {
+ struct qinst *fsub = c->defs[inst->src[1].index];
+ if (is_zero(c, fsub->src[0])) {
dump_from(c, inst);
inst->op = QOP_FSUB;
inst->src[1] = fsub->src[1];
/* FADD(FSUB(0, b), a) -> FSUB(a, b) */
if (inst->src[0].file == QFILE_TEMP &&
- defs[inst->src[0].index]->op == QOP_FSUB) {
- struct qinst *fsub = defs[inst->src[0].index];
- if (is_zero(c, defs, fsub->src[0])) {
+ c->defs[inst->src[0].index] &&
+ c->defs[inst->src[0].index]->op == QOP_FSUB) {
+ struct qinst *fsub = c->defs[inst->src[0].index];
+ if (is_zero(c, fsub->src[0])) {
dump_from(c, inst);
inst->op = QOP_FSUB;
inst->src[0] = inst->src[1];
break;
case QOP_FMUL:
- if (replace_x_0_with_0(c, defs, inst, 0) ||
- replace_x_0_with_0(c, defs, inst, 1) ||
- fmul_replace_one(c, defs, inst, 0) ||
- fmul_replace_one(c, defs, inst, 1)) {
+ if (!inst->dst.pack &&
+ (replace_x_0_with_0(c, inst, 0) ||
+ replace_x_0_with_0(c, inst, 1) ||
+ fmul_replace_one(c, inst, 0) ||
+ fmul_replace_one(c, inst, 1))) {
+ progress = true;
+ break;
+ }
+ break;
+
+ case QOP_MUL24:
+ if (!inst->dst.pack &&
+ (replace_x_0_with_0(c, inst, 0) ||
+ replace_x_0_with_0(c, inst, 1))) {
progress = true;
break;
}
break;
case QOP_AND:
- if (replace_x_0_with_0(c, defs, inst, 0) ||
- replace_x_0_with_0(c, defs, inst, 1)) {
+ if (replace_x_0_with_0(c, inst, 0) ||
+ replace_x_0_with_0(c, inst, 1)) {
progress = true;
break;
}
- if (is_constant_value(c, defs, inst->src[0], ~0)) {
+ if (is_constant_value(c, inst->src[0], ~0)) {
replace_with_mov(c, inst, inst->src[1]);
progress = true;
break;
}
- if (is_constant_value(c, defs, inst->src[1], ~0)) {
+ if (is_constant_value(c, inst->src[1], ~0)) {
replace_with_mov(c, inst, inst->src[0]);
progress = true;
break;
break;
case QOP_OR:
- if (replace_x_0_with_x(c, defs, inst, 0) ||
- replace_x_0_with_x(c, defs, inst, 1)) {
+ if (replace_x_0_with_x(c, inst, 0) ||
+ replace_x_0_with_x(c, inst, 1)) {
+ progress = true;
+ break;
+ }
+ break;
+
+ case QOP_RCP:
+ if (is_1f(c, inst->src[0])) {
+ replace_with_mov(c, inst, inst->src[0]);
progress = true;
break;
}