- if shader is empty add a NOP instruction - avoid multiple uniform src for alu ops - resolve jump target
Signed-off-by: Christian Gmeiner <christian.gmei...@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.gmei...@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.gmei...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev