aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlyssa Rosenzweig <[email protected]>2020-05-11 20:22:16 -0400
committerMarge Bot <[email protected]>2020-05-12 22:30:41 +0000
commit3228b3106a672e79093f2186f3e040a7579cd7b4 (patch)
treec6f3a0a774b1d21b76d71e22a59d113f6931b911
parent0da03c68ae3e16a339e41b967fcb689666f02296 (diff)
pan/mdg: Analyze helper invocation termination
Signed-off-by: Alyssa Rosenzweig <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5014>
-rw-r--r--src/panfrost/Makefile.sources1
-rw-r--r--src/panfrost/midgard/compiler.h9
-rw-r--r--src/panfrost/midgard/meson.build1
-rw-r--r--src/panfrost/midgard/midgard_helper_invocations.c97
-rw-r--r--src/panfrost/midgard/midgard_print.c4
5 files changed, 112 insertions, 0 deletions
diff --git a/src/panfrost/Makefile.sources b/src/panfrost/Makefile.sources
index 2e9a026f27d..06062b16749 100644
--- a/src/panfrost/Makefile.sources
+++ b/src/panfrost/Makefile.sources
@@ -47,6 +47,7 @@ midgard_FILES := \
midgard/midgard_emit.c \
midgard/midgard.h \
midgard/midgard_liveness.c \
+ midgard/midgard_helper_invocations.c \
midgard/midgard_nir.h \
midgard/midgard_ops.c \
midgard/midgard_ops.h \
diff --git a/src/panfrost/midgard/compiler.h b/src/panfrost/midgard/compiler.h
index 5158ea6a85c..6db0cfea466 100644
--- a/src/panfrost/midgard/compiler.h
+++ b/src/panfrost/midgard/compiler.h
@@ -104,6 +104,10 @@ typedef struct midgard_instruction {
/* Special fields for an ALU instruction */
midgard_reg_info registers;
+ /* For textures: should helpers execute this instruction (instead of
+ * just helping with derivatives)? Should helpers terminate after? */
+ bool helper_terminate;
+
/* I.e. (1 << alu_bit) */
int unit;
@@ -179,6 +183,9 @@ typedef struct midgard_block {
/* Indicates this is a fixed-function fragment epilogue block */
bool epilogue;
+
+ /* Are helper invocations required by this block? */
+ bool helpers_in;
} midgard_block;
typedef struct midgard_bundle {
@@ -626,6 +633,8 @@ midgard_lower_derivatives(compiler_context *ctx, midgard_block *block);
bool mir_op_computes_derivatives(gl_shader_stage stage, unsigned op);
+void mir_analyze_helper_terminate(compiler_context *ctx);
+
/* Final emission */
void emit_binary_bundle(
diff --git a/src/panfrost/midgard/meson.build b/src/panfrost/midgard/meson.build
index fc0cd85f4df..b719af8bda9 100644
--- a/src/panfrost/midgard/meson.build
+++ b/src/panfrost/midgard/meson.build
@@ -27,6 +27,7 @@ libpanfrost_midgard_files = files(
'midgard_schedule.c',
'midgard_derivatives.c',
'midgard_emit.c',
+ 'midgard_helper_invocations.c',
'midgard_ra.c',
'midgard_ra_pipeline.c',
'midgard_liveness.c',
diff --git a/src/panfrost/midgard/midgard_helper_invocations.c b/src/panfrost/midgard/midgard_helper_invocations.c
index 32bcbd4d823..9f8c68a8125 100644
--- a/src/panfrost/midgard/midgard_helper_invocations.c
+++ b/src/panfrost/midgard/midgard_helper_invocations.c
@@ -61,3 +61,100 @@
* with union as the join operation and the generating set being the union of
* sources of instructions writing executed values.
*/
+
+/* Does a block use helpers directly */
+static bool
+mir_block_uses_helpers(gl_shader_stage stage, midgard_block *block)
+{
+ mir_foreach_instr_in_block(block, ins) {
+ if (ins->type != TAG_TEXTURE_4) continue;
+ if (mir_op_computes_derivatives(stage, ins->texture.op))
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+mir_block_terminates_helpers(midgard_block *block)
+{
+ /* Can't terminate if there are no helpers */
+ if (!block->helpers_in)
+ return false;
+
+ /* Can't terminate if a successor needs helpers */
+ pan_foreach_successor((&block->base), succ) {
+ if (((midgard_block *) succ)->helpers_in)
+ return false;
+ }
+
+ /* Otherwise we terminate */
+ return true;
+}
+
+void
+mir_analyze_helper_terminate(compiler_context *ctx)
+{
+ /* Set blocks as directly requiring helpers, and if they do add them to
+ * the worklist to propagate to their predecessors */
+
+ struct set *worklist = _mesa_set_create(NULL,
+ _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
+ struct set *visited = _mesa_set_create(NULL,
+ _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
+ mir_foreach_block(ctx, _block) {
+ midgard_block *block = (midgard_block *) _block;
+ block->helpers_in |= mir_block_uses_helpers(ctx->stage, block);
+
+ if (block->helpers_in)
+ _mesa_set_add(worklist, _block);
+ }
+
+ /* Next, propagate back. Since there are a finite number of blocks, the
+ * worklist (a subset of all the blocks) is finite. Since a block can
+ * only be added to the worklist if it is not on the visited list and
+ * the visited list - also a subset of the blocks - grows every
+ * iteration, the algorithm must terminate. */
+
+ struct set_entry *cur;
+
+ while((cur = _mesa_set_next_entry(worklist, NULL)) != NULL) {
+ /* Pop off a block requiring helpers */
+ pan_block *blk = (struct pan_block *) cur->key;
+ _mesa_set_remove(worklist, cur);
+
+ /* Its predecessors also require helpers */
+ pan_foreach_predecessor(blk, pred) {
+ if (!_mesa_set_search(visited, pred)) {
+ ((midgard_block *) pred)->helpers_in = true;
+ _mesa_set_add(worklist, pred);
+ }
+ }
+
+ _mesa_set_add(visited, blk);
+ }
+
+ _mesa_set_destroy(visited, NULL);
+ _mesa_set_destroy(worklist, NULL);
+
+ /* Finally, set helper_terminate on the last derivative-calculating
+ * instruction in a block that terminates helpers */
+ mir_foreach_block(ctx, _block) {
+ midgard_block *block = (midgard_block *) _block;
+
+ if (!mir_block_terminates_helpers(block))
+ continue;
+
+ mir_foreach_instr_in_block_rev(block, ins) {
+ if (ins->type != TAG_TEXTURE_4) continue;
+ if (!mir_op_computes_derivatives(ctx->stage, ins->texture.op)) continue;
+
+ ins->helper_terminate = true;
+ break;
+ }
+ }
+}
diff --git a/src/panfrost/midgard/midgard_print.c b/src/panfrost/midgard/midgard_print.c
index 89b853ce3cb..002026a16b5 100644
--- a/src/panfrost/midgard/midgard_print.c
+++ b/src/panfrost/midgard/midgard_print.c
@@ -328,6 +328,10 @@ mir_print_instruction(midgard_instruction *ins)
case TAG_TEXTURE_4: {
printf("texture");
+
+ if (ins->helper_terminate)
+ printf(".terminate");
+
break;
}