vir_dump_inst(c, inst);
fprintf(stderr, "\n");
}
- assert(inst->qpu.flags.apf == V3D_QPU_PF_NONE);
- assert(inst->qpu.flags.mpf == V3D_QPU_PF_NONE);
- assert(inst->qpu.flags.auf == V3D_QPU_UF_NONE);
- assert(inst->qpu.flags.muf == V3D_QPU_UF_NONE);
+ assert(!v3d_qpu_writes_flags(&inst->qpu));
vir_remove_instruction(c, inst);
}
has_nonremovable_reads(struct v3d_compile *c, struct qinst *inst)
{
for (int i = 0; i < vir_get_nsrc(inst); i++) {
- if (inst->src[i].file == QFILE_VPM) {
- /* Instance ID, Vertex ID: Should have been removed at
- * the NIR level
- */
- if (inst->src[i].index == ~0)
- return true;
+ if (inst->src[i].file == QFILE_VPM)
+ return true;
+ }
- uint32_t attr = inst->src[i].index / 4;
- uint32_t offset = inst->src[i].index % 4;
+ return false;
+}
- if (c->vattr_sizes[attr] != offset)
- return true;
+static bool
+can_write_to_null(struct v3d_compile *c, struct qinst *inst)
+{
+ /* The SFU instructions must write to a physical register. */
+ if (c->devinfo->ver >= 41 && v3d_qpu_uses_sfu(&inst->qpu))
+ return false;
- /* Can't get rid of the last VPM read, or the
- * simulator (at least) throws an error.
- */
- uint32_t total_size = 0;
- for (uint32_t i = 0; i < ARRAY_SIZE(c->vattr_sizes); i++)
- total_size += c->vattr_sizes[i];
- if (total_size == 1)
- return true;
- }
+ return true;
+}
+
+static void
+vir_dce_flags(struct v3d_compile *c, struct qinst *inst)
+{
+ if (debug) {
+ fprintf(stderr,
+ "Removing flags write from: ");
+ vir_dump_inst(c, inst);
+ fprintf(stderr, "\n");
}
- return false;
+ assert(inst->qpu.type == V3D_QPU_INSTR_TYPE_ALU);
+
+ inst->qpu.flags.apf = V3D_QPU_PF_NONE;
+ inst->qpu.flags.mpf = V3D_QPU_PF_NONE;
+ inst->qpu.flags.auf = V3D_QPU_UF_NONE;
+ inst->qpu.flags.muf = V3D_QPU_UF_NONE;
}
bool
bool progress = false;
bool *used = calloc(c->num_temps, sizeof(bool));
+ /* Defuse the "are you removing the cursor?" assertion in the core.
+ * You'll need to set up a new cursor for any new instructions after
+ * doing DCE (which we would expect, anyway).
+ */
+ c->cursor.link = NULL;
+
vir_for_each_inst_inorder(inst, c) {
for (int i = 0; i < vir_get_nsrc(inst); i++) {
if (inst->src[i].file == QFILE_TEMP)
}
vir_for_each_block(block, c) {
+ struct qinst *last_flags_write = NULL;
+
vir_for_each_inst_safe(inst, block) {
+ /* If this instruction reads the flags, we can't
+ * remove the flags generation for it.
+ */
+ if (v3d_qpu_reads_flags(&inst->qpu))
+ last_flags_write = NULL;
+
if (inst->dst.file != QFILE_NULL &&
!(inst->dst.file == QFILE_TEMP &&
!used[inst->dst.index])) {
if (vir_has_side_effects(c, inst))
continue;
- if (inst->qpu.flags.apf != V3D_QPU_PF_NONE ||
- inst->qpu.flags.mpf != V3D_QPU_PF_NONE ||
- inst->qpu.flags.auf != V3D_QPU_UF_NONE ||
- inst->qpu.flags.muf != V3D_QPU_UF_NONE ||
+ if (v3d_qpu_writes_flags(&inst->qpu)) {
+ /* If we obscure a previous flags write,
+ * drop it.
+ */
+ if (last_flags_write &&
+ (inst->qpu.flags.apf != V3D_QPU_PF_NONE ||
+ inst->qpu.flags.mpf != V3D_QPU_PF_NONE)) {
+ vir_dce_flags(c, last_flags_write);
+ progress = true;
+ }
+
+ last_flags_write = inst;
+ }
+
+ if (v3d_qpu_writes_flags(&inst->qpu) ||
has_nonremovable_reads(c, inst)) {
/* If we can't remove the instruction, but we
* don't need its destination value, just
* it's nicer to read the VIR code without
* unused destination regs.
*/
- if (inst->dst.file == QFILE_TEMP) {
+ if (inst->dst.file == QFILE_TEMP &&
+ can_write_to_null(c, inst)) {
if (debug) {
fprintf(stderr,
"Removing dst from: ");
continue;
}
- for (int i = 0; i < vir_get_nsrc(inst); i++) {
- if (inst->src[i].file != QFILE_VPM)
- continue;
- uint32_t attr = inst->src[i].index / 4;
- uint32_t offset = (inst->src[i].index % 4);
-
- if (c->vattr_sizes[attr] == offset) {
- c->num_inputs--;
- c->vattr_sizes[attr]--;
- }
- }
-
+ assert(inst != last_flags_write);
dce(c, inst);
progress = true;
continue;