defs[inst->dst.index] = inst;
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:
enum qop op;
struct qreg src[4];
/**
- * If the instruction depends on the flags, how many QOP_SFs have been
+ * If the instruction depends on the flags, how many SFs have been
* seen before this instruction, or if it depends on r4, how many r4
* writes have been seen.
*/
{
bool progress = false;
struct simple_node *node, *t;
- struct qinst *last_sf = NULL;
uint32_t sf_count = 0, r4_count = 0;
struct hash_table *ht = _mesa_hash_table_create(NULL, NULL,
if (qir_has_side_effects(c, inst) ||
qir_has_side_effect_reads(c, inst)) {
- if (inst->op == QOP_TLB_DISCARD_SETUP)
- last_sf = NULL;
continue;
}
- if (inst->op == QOP_SF) {
- if (last_sf &&
- qir_reg_equals(last_sf->src[0], inst->src[0])) {
- if (debug) {
- fprintf(stderr,
- "Removing redundant SF: ");
- qir_dump_inst(c, inst);
- fprintf(stderr, "\n");
- }
- qir_remove_instruction(inst);
- progress = true;
- continue;
- } else {
- last_sf = inst;
- sf_count++;
- }
+ if (inst->sf) {
+ sf_count++;
} else {
struct qinst *cse = vc4_find_cse(c, ht, inst,
sf_count, r4_count);
qir_dump_inst(c, inst);
fprintf(stderr, "\n");
}
+ assert(!inst->sf);
qir_remove_instruction(inst);
}
if (inst->dst.file == QFILE_TEMP &&
!used[inst->dst.index] &&
+ !inst->sf &&
(!qir_has_side_effects(c, inst) ||
inst->op == QOP_TEX_RESULT) &&
!has_nonremovable_reads(c, inst)) {
if (qir_depends_on_flags(inst))
sf_used = true;
- if (inst->op == QOP_SF) {
+ if (inst->sf) {
if (!sf_used) {
- dce(c, inst);
+ if (debug) {
+ fprintf(stderr, "Removing SF on: ");
+ qir_dump_inst(c, inst);
+ fprintf(stderr, "\n");
+ }
+
+ inst->sf = false;
progress = true;
- continue;
}
sf_used = false;
}
if (qir_is_multi_instruction(inst))
continue;
- if (qir_depends_on_flags(inst))
+ if (qir_depends_on_flags(inst) || inst->sf)
continue;
if (qir_has_side_effects(c, inst) ||
/* Move the generating instruction to the end of the program
* to maintain the order of the VPM writes.
*/
+ assert(!vpm_writes[i]->sf);
move_to_tail(&vpm_writes[i]->link, &inst->link);
qir_remove_instruction(vpm_writes[i]);
}
tgsi_parse_free(&c->parser);
+ if (vc4_debug & VC4_DEBUG_QIR) {
+ fprintf(stderr, "%s prog %d/%d pre-opt QIR:\n",
+ qir_get_stage_name(c->stage),
+ c->program_id, c->variant_id);
+ qir_dump(c);
+ }
qir_optimize(c);
[QOP_XOR] = { "xor", 1, 2 },
[QOP_NOT] = { "not", 1, 1 },
- [QOP_SF] = { "sf", 0, 1 },
[QOP_SEL_X_0_NS] = { "fsel_x_0_ns", 1, 1, false, true },
[QOP_SEL_X_0_NC] = { "fsel_x_0_nc", 1, 1, false, true },
[QOP_SEL_X_0_ZS] = { "fsel_x_0_zs", 1, 1, false, true },
void
qir_dump_inst(struct vc4_compile *c, struct qinst *inst)
{
- fprintf(stderr, "%s ", qir_get_op_name(inst->op));
+ fprintf(stderr, "%s%s ",
+ qir_get_op_name(inst->op),
+ inst->sf ? ".sf" : "");
qir_print_reg(c, inst->dst, true);
for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) {
return names[stage];
}
+void
+qir_SF(struct vc4_compile *c, struct qreg src)
+{
+ assert(!is_empty_list(&c->instructions));
+ struct qinst *last_inst = (struct qinst *)c->instructions.prev;
+ if (last_inst->dst.file != src.file ||
+ last_inst->dst.index != src.index ||
+ qir_is_multi_instruction(last_inst)) {
+ src = qir_MOV(c, src);
+ last_inst = (struct qinst *)c->instructions.prev;
+ }
+ last_inst->sf = true;
+}
+
#define OPTPASS(func) \
do { \
bool stage_progress = func(c); \
#ifndef VC4_QIR_H
#define VC4_QIR_H
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
QOP_XOR,
QOP_NOT,
- /* Sets the flag register according to src. */
- QOP_SF,
-
/* Note: Orderings of these compares must be the same as in
* qpu_defines.h. Selects the src[0] if the ns flag bit is set,
* otherwise 0. */
enum qop op;
struct qreg dst;
struct qreg *src;
+ bool sf;
};
enum qstage {
void qpu_schedule_instructions(struct vc4_compile *c);
+void qir_SF(struct vc4_compile *c, struct qreg src);
+
#define QIR_ALU0(name) \
static inline struct qreg \
qir_##name(struct vc4_compile *c) \
QIR_ALU2(FSUB)
QIR_ALU2(FMUL)
QIR_ALU2(MUL24)
-QIR_NODST_1(SF)
QIR_ALU1(SEL_X_0_ZS)
QIR_ALU1(SEL_X_0_ZC)
QIR_ALU1(SEL_X_0_NS)
}
break;
- case QOP_SF:
- queue(c, qpu_a_MOV(qpu_ra(QPU_W_NOP), src[0]));
- *last_inst(c) |= QPU_SF;
- break;
-
case QOP_SEL_X_0_ZS:
case QOP_SEL_X_0_ZC:
case QOP_SEL_X_0_NS:
break;
}
+
+ if (qinst->sf) {
+ assert(!qir_is_multi_instruction(qinst));
+ *last_inst(c) |= QPU_SF;
+ }
}
qpu_schedule_instructions(c);