[Mesa-dev] [RFC PATCH 02/17] eir: add legalization
Christian Gmeiner
christian.gmeiner at gmail.com
Fri May 10 09:09:00 UTC 2019
- if shader is empty add a NOP instruction
- avoid multiple uniform src for alu ops
- resolve jump target
Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
---
src/etnaviv/compiler/eir.h | 3 +
src/etnaviv/compiler/eir_legalize.c | 177 ++++++++++++++++++++
src/etnaviv/compiler/meson.build | 1 +
src/etnaviv/compiler/tests/eir_legalize.cpp | 136 +++++++++++++++
src/etnaviv/compiler/tests/meson.build | 10 ++
5 files changed, 327 insertions(+)
create mode 100644 src/etnaviv/compiler/eir_legalize.c
create mode 100644 src/etnaviv/compiler/tests/eir_legalize.cpp
diff --git a/src/etnaviv/compiler/eir.h b/src/etnaviv/compiler/eir.h
index e2185b004f1..a05b12de94b 100644
--- a/src/etnaviv/compiler/eir.h
+++ b/src/etnaviv/compiler/eir.h
@@ -282,6 +282,9 @@ eir_assign_output(struct eir *ir, unsigned idx, unsigned slot, unsigned ncomp)
ir->num_outputs = MAX2(ir->num_outputs, idx + 1);
}
+void
+eir_legalize(struct eir *ir);
+
void
eir_calculate_live_intervals(struct eir *ir);
diff --git a/src/etnaviv/compiler/eir_legalize.c b/src/etnaviv/compiler/eir_legalize.c
new file mode 100644
index 00000000000..94f5c2bd12b
--- /dev/null
+++ b/src/etnaviv/compiler/eir_legalize.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "eir.h"
+#include "etnaviv/gc/gc_instr.h"
+
+static int
+invalid_uniform_usage(const struct eir_instruction *inst)
+{
+ const struct gc_instr *gc = &inst->gc;
+ int invalid = 0;
+ bool first_uniform = true;
+ int index;
+
+ if (gc->type != GC_OP_TYPE_ALU)
+ return 0;
+
+ for (unsigned i = 0; i < gc_op_num_src(gc->opcode); i++) {
+ const struct eir_register *src = &inst->src[i];
+
+ if (src->type != EIR_REG_UNIFORM)
+ continue;
+
+ if (first_uniform) {
+ index = src->index;
+ first_uniform = false;
+ continue;
+ }
+
+ if (src->index == index)
+ continue;
+
+ invalid |= 1 << i;
+ }
+
+ return invalid;
+}
+
+static void
+legalize_uniform_usage(struct eir_block *block, struct eir_instruction *inst)
+{
+ /*
+ * The hardware does not allow two or more different uniform registers to be used as
+ * sources in the same ALU instruction. Emit mov instructions to temporary registers
+ * for all but one uniform register in this case.
+ */
+ int mask = invalid_uniform_usage(inst);
+
+ while (mask) {
+ const int i = ffs(mask) - 1;
+ struct eir_register *src = &inst->src[i];
+ struct eir_register tmp = eir_temp_register(block->ir, 4);
+
+ tmp.writemask = 0xf; /* TODO */
+
+ eir_MOV(block, &tmp, src);
+ src->type = EIR_REG_TEMP;
+ src->index = tmp.index;
+
+ mask &= ~(1 << i);
+ }
+}
+
+static void
+legalize_block(struct eir_block *block)
+{
+ struct list_head instr_list;
+
+ /*
+ * Remove all the instructions from the list, we'll be adding
+ * them back in as we go
+ */
+ list_replace(&block->instr_list, &instr_list);
+ list_inithead(&block->instr_list);
+
+ list_for_each_entry_safe (struct eir_instruction, inst, &instr_list, node) {
+ legalize_uniform_usage(block, inst);
+ list_addtail(&inst->node, &block->instr_list);
+ }
+}
+
+struct block_data {
+ unsigned start_ip;
+ unsigned end_ip;
+};
+
+static void
+resolve_jumps(struct eir *ir)
+{
+ void *mem_ctx = ralloc_context(NULL);
+ unsigned ip = 0;
+ assert(mem_ctx);
+
+ eir_for_each_block(block, ir) {
+ struct block_data *bd = rzalloc(mem_ctx, struct block_data);
+
+ assert(bd);
+ assert(!block->data);
+ block->data = bd;
+
+ /* determine start and end IP for this block */
+ bd->start_ip = ip;
+ eir_for_each_inst(inst, block) {
+ ip++;
+ }
+ bd->end_ip = ip;
+ }
+
+ eir_for_each_block(block, ir) {
+ const struct block_data *bd;
+
+ /* the end block of the program has no branch */
+ if (!block->successors[0])
+ continue;
+
+ bd = block->successors[0]->data;
+
+ eir_for_each_inst(inst, block) {
+ if (inst->gc.type != GC_OP_TYPE_BRANCH)
+ continue;
+
+ inst->gc.branch.imm = bd->start_ip;
+
+ /*
+ * if there is a empty block at the end of the shader an
+ * extra NOP should be generated as jump target
+ */
+ if (list_empty(&block->successors[0]->instr_list))
+ eir_NOP(block->successors[0]);
+ }
+ }
+
+ ralloc_free(mem_ctx);
+ eir_for_each_block(block, ir)
+ block->data = NULL;
+}
+
+void
+eir_legalize(struct eir *ir)
+{
+ eir_for_each_block(block, ir)
+ legalize_block(block);
+
+ resolve_jumps(ir);
+
+ /* add NOP if the only block has no instructions */
+ if (ir->blocks == 1) {
+ struct eir_block *block = list_first_entry(&ir->block_list, struct eir_block, node);
+
+ if (list_empty(&block->instr_list))
+ eir_NOP(block);
+ }
+}
diff --git a/src/etnaviv/compiler/meson.build b/src/etnaviv/compiler/meson.build
index 8affe6ebd48..c83399d5297 100644
--- a/src/etnaviv/compiler/meson.build
+++ b/src/etnaviv/compiler/meson.build
@@ -23,6 +23,7 @@
libetnaviv_compiler_files = files(
'eir.c',
'eir.h',
+ 'eir_legalize.c',
'eir_uniform.c',
)
diff --git a/src/etnaviv/compiler/tests/eir_legalize.cpp b/src/etnaviv/compiler/tests/eir_legalize.cpp
new file mode 100644
index 00000000000..7968ccc9783
--- /dev/null
+++ b/src/etnaviv/compiler/tests/eir_legalize.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 Etnaviv Project
+ * Copyright (C) 2017 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include <gtest/gtest.h>
+#include "etnaviv/compiler/eir.h"
+
+TEST (LegalizeTest, EmptyShader)
+{
+ struct eir *ir = eir_create();
+ struct eir_block *block = eir_block_create(ir);
+
+ eir_legalize(ir);
+
+ ASSERT_EQ(list_length(&block->instr_list), 1);
+ struct eir_instruction *nop = list_first_entry(&block->instr_list, struct eir_instruction, node);
+ ASSERT_EQ(nop->gc.opcode, GC_NOP);
+
+ eir_destroy(ir);
+}
+
+TEST (LegalizeTest, UniformsTwoSame)
+{
+ struct eir *ir = eir_create();
+ struct eir_block *block = eir_block_create(ir);
+ struct eir_register dst = eir_temp_register(ir, 4);
+ struct eir_register src = eir_uniform_register_ui(ir, 1);
+
+ dst.writemask = 0xf;
+
+ eir_ADD(block, &dst, &src, &src);
+
+ eir_legalize(ir);
+
+ ASSERT_EQ(list_length(&block->instr_list), 1);
+ struct eir_instruction *add = list_first_entry(&block->instr_list, struct eir_instruction, node);
+ ASSERT_EQ(add->gc.opcode, GC_ADD);
+
+ eir_destroy(ir);
+}
+
+TEST (LegalizeTest, UniformsThreeSame)
+{
+ struct eir *ir = eir_create();
+ struct eir_block *block = eir_block_create(ir);
+ struct eir_register dst = eir_temp_register(ir, 4);
+ struct eir_register src = eir_uniform_register_ui(ir, 1);
+
+ dst.writemask = 0xf;
+
+ eir_MAD(block, &dst, &src, &src, &src);
+
+ eir_legalize(ir);
+
+ ASSERT_EQ(list_length(&block->instr_list), 1);
+ struct eir_instruction *mad = list_first_entry(&block->instr_list, struct eir_instruction, node);
+ ASSERT_EQ(mad->gc.opcode, GC_MAD);
+
+ eir_destroy(ir);
+}
+
+
+TEST (LegalizeTest, UniformsTwoDifferent)
+{
+ static const uint32_t val0[] = { 0, 1, 2, 3 };
+ static const uint32_t val1[] = { 4, 5, 6, 7 };
+ struct eir *ir = eir_create();
+ struct eir_block *block = eir_block_create(ir);
+ struct eir_register dst = eir_temp_register(ir, 4);
+ struct eir_register src0 = eir_uniform_register_vec4_ui(ir, 4, val0);
+ struct eir_register src1 = eir_uniform_register_vec4_ui(ir, 4, val1);
+
+ dst.writemask = 0xf;
+
+ eir_ADD(block, &dst, &src0, &src1);
+
+ eir_legalize(ir);
+
+ ASSERT_EQ(list_length(&block->instr_list), 2);
+ struct eir_instruction *mov = list_first_entry(&block->instr_list, struct eir_instruction, node);
+ ASSERT_EQ(mov->gc.opcode, GC_MOV);
+ ASSERT_EQ(mov->src[0].index, 1);
+ ASSERT_EQ(mov->src[0].type, eir_register::EIR_REG_UNIFORM);
+
+ eir_destroy(ir);
+}
+
+TEST (LegalizeTest, UniformsThreeDifferent)
+{
+ static const uint32_t val0[] = { 0, 1, 2, 3 };
+ static const uint32_t val1[] = { 4, 5, 6, 7 };
+ static const uint32_t val2[] = { 8, 9, 10, 11 };
+ struct eir *ir = eir_create();
+ struct eir_block *block = eir_block_create(ir);
+ struct eir_register dst = eir_temp_register(ir, 4);
+ struct eir_register src0 = eir_uniform_register_vec4_ui(ir, 4, val0);
+ struct eir_register src1 = eir_uniform_register_vec4_ui(ir, 4, val1);
+ struct eir_register src2 = eir_uniform_register_vec4_ui(ir, 4, val2);
+
+ dst.writemask = 0xf;
+
+ eir_MAD(block, &dst, &src0, &src1, &src2);
+
+ eir_legalize(ir);
+
+ ASSERT_EQ(list_length(&block->instr_list), 3);
+ struct eir_instruction *mov = list_first_entry(&block->instr_list, struct eir_instruction, node);
+ ASSERT_EQ(mov->gc.opcode, GC_MOV);
+ ASSERT_EQ(mov->src[0].index, 1);
+ ASSERT_EQ(mov->src[0].type, eir_register::EIR_REG_UNIFORM);
+
+ eir_destroy(ir);
+}
diff --git a/src/etnaviv/compiler/tests/meson.build b/src/etnaviv/compiler/tests/meson.build
index c7506f04ed5..f82acae5f1a 100644
--- a/src/etnaviv/compiler/tests/meson.build
+++ b/src/etnaviv/compiler/tests/meson.build
@@ -42,3 +42,13 @@ test(
)
)
+test(
+ 'eir_legalize',
+ executable(
+ 'eir_legalize', 'eir_legalize.cpp',
+ cpp_args : [cpp_vis_args, cpp_msvc_compat_args],
+ link_with: [libetnaviv_gc, libetnaviv_compiler, libmesa_util],
+ include_directories: [inc_common, inc_etnaviv],
+ dependencies : [dep_clock, dep_thread, idep_gtest],
+ )
+)
--
2.21.0
More information about the mesa-dev
mailing list