aboutsummaryrefslogtreecommitdiffstats
path: root/src/broadcom/compiler/qpu_validate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/broadcom/compiler/qpu_validate.c')
-rw-r--r--src/broadcom/compiler/qpu_validate.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/broadcom/compiler/qpu_validate.c b/src/broadcom/compiler/qpu_validate.c
index 3b2c10eabc6..4ef587c1d52 100644
--- a/src/broadcom/compiler/qpu_validate.c
+++ b/src/broadcom/compiler/qpu_validate.c
@@ -39,6 +39,10 @@ struct v3d_qpu_validate_state {
const struct v3d_qpu_instr *last;
int ip;
int last_sfu_write;
+ int last_branch_ip;
+ int last_thrsw_ip;
+ bool last_thrsw_found;
+ int thrsw_count;
};
static void
@@ -63,6 +67,18 @@ fail_instr(struct v3d_qpu_validate_state *state, const char *msg)
}
static bool
+in_branch_delay_slots(struct v3d_qpu_validate_state *state)
+{
+ return (state->ip - state->last_branch_ip) < 3;
+}
+
+static bool
+in_thrsw_delay_slots(struct v3d_qpu_validate_state *state)
+{
+ return (state->ip - state->last_thrsw_ip) < 3;
+}
+
+static bool
qpu_magic_waddr_matches(const struct v3d_qpu_instr *inst,
bool (*predicate)(enum v3d_qpu_waddr waddr))
{
@@ -136,6 +152,19 @@ qpu_validate_inst(struct v3d_qpu_validate_state *state, struct qinst *qinst)
}
}
+ if (in_thrsw_delay_slots(state)) {
+ /* There's no way you want to start SFU during the THRSW delay
+ * slots, since the result would land in the other thread.
+ */
+ if (sfu_writes) {
+ fail_instr(state,
+ "SFU write started during THRSW delay slots ");
+ }
+
+ if (inst->sig.ldvary)
+ fail_instr(state, "LDVARY during THRSW delay slots");
+ }
+
(void)qpu_magic_waddr_matches; /* XXX */
/* SFU r4 results come back two instructions later. No doing
@@ -170,6 +199,35 @@ qpu_validate_inst(struct v3d_qpu_validate_state *state, struct qinst *qinst)
if (sfu_writes)
state->last_sfu_write = state->ip;
+
+ if (inst->sig.thrsw) {
+ if (in_branch_delay_slots(state))
+ fail_instr(state, "THRSW in a branch delay slot.");
+
+ 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.
+ */
+ if (state->last_thrsw_found)
+ fail_instr(state, "Two last-THRSW signals");
+ state->last_thrsw_found = true;
+ } else {
+ if (in_thrsw_delay_slots(state)) {
+ fail_instr(state,
+ "THRSW too close to another THRSW.");
+ }
+ state->thrsw_count++;
+ state->last_thrsw_ip = state->ip;
+ }
+ }
+
+ if (inst->type == V3D_QPU_INSTR_TYPE_BRANCH) {
+ if (in_branch_delay_slots(state))
+ fail_instr(state, "branch in a branch delay slot.");
+ if (in_thrsw_delay_slots(state))
+ fail_instr(state, "branch in a THRSW delay slot.");
+ state->last_branch_ip = state->ip;
+ }
}
static void
@@ -201,10 +259,22 @@ qpu_validate(struct v3d_compile *c)
struct v3d_qpu_validate_state state = {
.c = c,
.last_sfu_write = -10,
+ .last_thrsw_ip = -10,
+ .last_branch_ip = -10,
.ip = 0,
};
vir_for_each_block(block, c) {
qpu_validate_block(&state, block);
}
+
+ if (state.thrsw_count > 1 && !state.last_thrsw_found) {
+ fail_instr(&state,
+ "thread switch found without last-THRSW in program");
+ }
+
+ if (state.thrsw_count == 0 ||
+ (state.last_thrsw_found && state.thrsw_count == 1)) {
+ fail_instr(&state, "No program-end THRSW found");
+ }
}