* channel is active.
*/
if (c->execute.file != QFILE_NULL) {
+ struct qinst *mov;
+
qir_SF(c, c->execute);
- qir_MOV_cond(c, QPU_COND_ZS, qregs[chan], result);
+ mov = qir_MOV_cond(c, QPU_COND_ZS, qregs[chan], result);
+ mov->cond_is_exec_mask = true;
} else {
qir_MOV_dest(c, qregs[chan], result);
}
struct qreg dst;
struct qreg *src;
bool sf;
+ bool cond_is_exec_mask;
uint8_t cond;
};
QPU_SMALL_IMM_MUL_ROT + rot)));
}
-static inline void
+static inline struct qinst *
qir_MOV_cond(struct vc4_compile *c, uint8_t cond,
struct qreg dest, struct qreg src)
{
- qir_MOV_dest(c, dest, src)->cond = cond;
+ struct qinst *mov = qir_MOV_dest(c, dest, src);
+ mov->cond = cond;
+ return mov;
}
static inline struct qinst *
if (BITSET_TEST(block->use, var) || BITSET_TEST(block->def, var))
return;
- /* Easy, common case: unconditional full register update. */
- if (inst->cond == QPU_COND_ALWAYS && !inst->dst.pack) {
+ /* Easy, common case: unconditional full register update.
+ *
+ * We treat conditioning on the exec mask as the same as not being
+ * conditional. This makes sure that if the register gets set on
+ * either side of an if, it is treated as being screened off before
+ * the if. Otherwise, if there was no intervening def, its live
+ * interval doesn't extend back to the start of he program, and if too
+ * many registers did that we'd fail to register allocate.
+ */
+ if ((inst->cond == QPU_COND_ALWAYS ||
+ inst->cond_is_exec_mask) && !inst->dst.pack) {
BITSET_SET(block->def, var);
return;
}