summaryrefslogtreecommitdiff
path: root/src/broadcom/compiler/nir_to_vir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/broadcom/compiler/nir_to_vir.c')
-rw-r--r--src/broadcom/compiler/nir_to_vir.c62
1 files changed, 58 insertions, 4 deletions
diff --git a/src/broadcom/compiler/nir_to_vir.c b/src/broadcom/compiler/nir_to_vir.c
index 2a4dac723f6..223e7f00cc8 100644
--- a/src/broadcom/compiler/nir_to_vir.c
+++ b/src/broadcom/compiler/nir_to_vir.c
@@ -3900,9 +3900,25 @@ vir_remove_thrsw(struct v3d_compile *c)
c->last_thrsw = NULL;
}
-void
-vir_emit_last_thrsw(struct v3d_compile *c)
+/**
+ * This makes sure we have a top-level last thread switch which signals the
+ * start of the last thread section, which may include adding a new thrsw
+ * instruction if needed. We don't allow spilling in the last thread section, so
+ * if we need to do any spills that inject additional thread switches later on,
+ * we ensure this thread switch will still be the last thread switch in the
+ * program, which makes last thread switch signalling a lot easier when we have
+ * spilling. If in the end we don't need to spill to compile the program and we
+ * injected a new thread switch instruction here only for that, we will
+ * eventually restore the previous last thread switch and remove the one we
+ * added here.
+ */
+static void
+vir_emit_last_thrsw(struct v3d_compile *c,
+ struct qinst **restore_last_thrsw,
+ bool *restore_scoreboard_lock)
{
+ *restore_last_thrsw = c->last_thrsw;
+
/* On V3D before 4.1, we need a TMU op to be outstanding when thread
* switching, so disable threads if we didn't do any TMU ops (each of
* which would have emitted a THRSW).
@@ -3911,7 +3927,7 @@ vir_emit_last_thrsw(struct v3d_compile *c)
c->threads = 1;
if (c->last_thrsw)
vir_remove_thrsw(c);
- return;
+ *restore_last_thrsw = NULL;
}
/* If we're threaded and the last THRSW was in conditional code, then
@@ -3934,8 +3950,34 @@ vir_emit_last_thrsw(struct v3d_compile *c)
vir_emit_thrsw(c);
}
+ /* If we have not inserted a last thread switch yet, do it now to ensure
+ * any potential spilling we do happens before this. If we don't spill
+ * in the end, we will restore the previous one.
+ */
+ if (*restore_last_thrsw == c->last_thrsw) {
+ if (*restore_last_thrsw)
+ (*restore_last_thrsw)->is_last_thrsw = false;
+ *restore_scoreboard_lock = c->lock_scoreboard_on_first_thrsw;
+ vir_emit_thrsw(c);
+ } else {
+ *restore_last_thrsw = c->last_thrsw;
+ }
+
+ assert(c->last_thrsw);
+ c->last_thrsw->is_last_thrsw = true;
+}
+
+static void
+vir_restore_last_thrsw(struct v3d_compile *c,
+ struct qinst *thrsw,
+ bool scoreboard_lock)
+{
+ assert(c->last_thrsw);
+ vir_remove_instruction(c, c->last_thrsw);
+ c->last_thrsw = thrsw;
if (c->last_thrsw)
c->last_thrsw->is_last_thrsw = true;
+ c->lock_scoreboard_on_first_thrsw = scoreboard_lock;
}
/* There's a flag in the shader for "center W is needed for reasons other than
@@ -3973,8 +4015,14 @@ v3d_nir_to_vir(struct v3d_compile *c)
nir_to_vir(c);
+ bool restore_scoreboard_lock = false;
+ struct qinst *restore_last_thrsw;
+
/* Emit the last THRSW before STVPM and TLB writes. */
- vir_emit_last_thrsw(c);
+ vir_emit_last_thrsw(c,
+ &restore_last_thrsw,
+ &restore_scoreboard_lock);
+
switch (c->s->info.stage) {
case MESA_SHADER_FRAGMENT:
@@ -4073,6 +4121,12 @@ v3d_nir_to_vir(struct v3d_compile *c)
vir_remove_thrsw(c);
}
+ /* If we didn't spill, then remove the last thread switch we injected
+ * artificially (if any) and restore the previous one.
+ */
+ if (!c->spills && c->last_thrsw != restore_last_thrsw)
+ vir_restore_last_thrsw(c, restore_last_thrsw, restore_scoreboard_lock);
+
if (c->spills &&
(V3D_DEBUG & (V3D_DEBUG_VIR |
v3d_debug_flag_for_shader_stage(c->s->info.stage)))) {