broadcom/vc5: Add QPU validation for register writes after thrend.
authorEric Anholt <eric@anholt.net>
Wed, 25 Apr 2018 20:51:47 +0000 (13:51 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 26 Apr 2018 18:30:22 +0000 (11:30 -0700)
The next shader gets to start writing the register file during these
slots, so make sure we don't stomp over them.

The only case of hitting this that I could imagine would be dead writes.

src/broadcom/compiler/qpu_validate.c

index 4ef587c1d52bdab30ce7afceeb09de1c01e36592..492f2e64d09ba0b790ac479ffb0f9a252dd3182a 100644 (file)
@@ -41,7 +41,15 @@ struct v3d_qpu_validate_state {
         int last_sfu_write;
         int last_branch_ip;
         int last_thrsw_ip;
+
+        /* Set when we've found the last-THRSW signal, or if we were started
+         * in single-segment mode.
+         */
         bool last_thrsw_found;
+
+        /* Set when we've found the THRSW after the last THRSW */
+        bool thrend_found;
+
         int thrsw_count;
 };
 
@@ -204,6 +212,9 @@ qpu_validate_inst(struct v3d_qpu_validate_state *state, struct qinst *qinst)
                 if (in_branch_delay_slots(state))
                         fail_instr(state, "THRSW in a branch delay slot.");
 
+                if (state->last_thrsw_found)
+                        state->thrend_found = true;
+
                 if (state->last_thrsw_ip == state->ip - 1) {
                         /* If it's the second THRSW in a row, then it's just a
                          * last-thrsw signal.
@@ -221,6 +232,23 @@ qpu_validate_inst(struct v3d_qpu_validate_state *state, struct qinst *qinst)
                 }
         }
 
+        if (state->thrend_found &&
+            state->last_thrsw_ip - state->ip <= 2 &&
+            inst->type == V3D_QPU_INSTR_TYPE_ALU) {
+                if ((inst->alu.add.op != V3D_QPU_A_NOP &&
+                     !inst->alu.add.magic_write)) {
+                        fail_instr(state, "RF write after THREND");
+                }
+
+                if ((inst->alu.mul.op != V3D_QPU_M_NOP &&
+                     !inst->alu.mul.magic_write)) {
+                        fail_instr(state, "RF write after THREND");
+                }
+
+                if (v3d_qpu_sig_writes_address(devinfo, &inst->sig))
+                        fail_instr(state, "RF write after THREND");
+        }
+
         if (inst->type == V3D_QPU_INSTR_TYPE_BRANCH) {
                 if (in_branch_delay_slots(state))
                         fail_instr(state, "branch in a branch delay slot.");
@@ -262,6 +290,8 @@ qpu_validate(struct v3d_compile *c)
                 .last_thrsw_ip = -10,
                 .last_branch_ip = -10,
                 .ip = 0,
+
+                .last_thrsw_found = !c->last_thrsw,
         };
 
         vir_for_each_block(block, c) {
@@ -273,8 +303,6 @@ qpu_validate(struct v3d_compile *c)
                            "thread switch found without last-THRSW in program");
         }
 
-        if (state.thrsw_count == 0 ||
-            (state.last_thrsw_found && state.thrsw_count == 1)) {
+        if (!state.thrend_found)
                 fail_instr(&state, "No program-end THRSW found");
-        }
 }