Some unit tests would be great. Signed-off-by: Christian Gmeiner <christian.gmei...@gmail.com> --- src/etnaviv/compiler/eir.h | 10 +- src/etnaviv/compiler/eir_register_allocate.c | 176 ++++++++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-)
diff --git a/src/etnaviv/compiler/eir.h b/src/etnaviv/compiler/eir.h index f2652863de6..bbde10cde08 100644 --- a/src/etnaviv/compiler/eir.h +++ b/src/etnaviv/compiler/eir.h @@ -29,6 +29,7 @@ #define H_EIR #include <assert.h> +#include "compiler/shader_enums.h" #include "util/list.h" #include "util/u_dynarray.h" #include "util/u_math.h" @@ -40,6 +41,7 @@ extern "C"{ struct eir; struct eir_block; +struct eir_compiler; struct eir_ra_reg_set; struct eir_register @@ -149,10 +151,13 @@ struct eir * and the used components per register */ struct util_dynarray reg_alloc; - /* keep track of number of allocated uniforms */ + /* keep track of number of allocated uniforms - pre RA */ struct util_dynarray uniform_alloc; unsigned uniform_offset; + /* total used temp register - post RA */ + unsigned num_temps; + /* Live ranges of temp registers */ int *temp_start, *temp_end; }; @@ -301,6 +306,9 @@ eir_temp_range_end(const struct eir* ir, unsigned n); struct eir_ra_reg_set * eir_ra_alloc_reg_set(void *memctx); +bool +eir_register_allocate(struct eir *ir, gl_shader_stage type, struct eir_compiler *compiler); + uint32_t * eir_assemble(const struct eir *ir, struct eir_info *info); diff --git a/src/etnaviv/compiler/eir_register_allocate.c b/src/etnaviv/compiler/eir_register_allocate.c index 332d686add9..e02fc37a5ef 100644 --- a/src/etnaviv/compiler/eir_register_allocate.c +++ b/src/etnaviv/compiler/eir_register_allocate.c @@ -164,7 +164,7 @@ eir_ra_alloc_reg_set(void *memctx) } } - unsigned int **q_values = ralloc_array(set, unsigned *, EIR_NUM_REG_CLASSES); + unsigned int **q_values = ralloc_array(set, unsigned *, EIR_NUM_REG_CLASSES); for (int i = 0; i < EIR_NUM_REG_CLASSES; i++) { q_values[i] = rzalloc_array(q_values, unsigned, EIR_NUM_REG_CLASSES); for (int j = 0; j < EIR_NUM_REG_CLASSES; j++) @@ -177,3 +177,177 @@ eir_ra_alloc_reg_set(void *memctx) return set; } + +static bool +interferes(const struct eir *ir, int a, int b) +{ + return !((eir_temp_range_end(ir, a) <= eir_temp_range_start(ir, b)) || + (eir_temp_range_end(ir, b) <= eir_temp_range_start(ir, a))); +} + +static inline void +reswizzle(struct eir_register *reg, int virt_reg) +{ + static const unsigned swizzle[EIR_NUM_REG_TYPES] = { + INST_SWIZ(0, 1, 2, 3), /* XYZW */ + INST_SWIZ(0, 1, 2, 2), /* XYZ */ + INST_SWIZ(0, 1, 3, 3), /* XYW */ + INST_SWIZ(0, 2, 3, 3), /* XZW */ + INST_SWIZ(1, 2, 3, 3), /* YZW */ + INST_SWIZ(0, 1, 1, 1), /* XY */ + INST_SWIZ(0, 2, 2, 2), /* XZ */ + INST_SWIZ(0, 3, 3, 3), /* XW */ + INST_SWIZ(1, 2, 2, 2), /* YZ */ + INST_SWIZ(1, 3, 3, 3), /* YW */ + INST_SWIZ(2, 3, 3, 3), /* ZW */ + INST_SWIZ(0, 0, 0, 0), /* X */ + INST_SWIZ(1, 1, 1 ,1), /* Y */ + INST_SWIZ(2, 2, 2, 2), /* Z */ + INST_SWIZ(3, 3, 3, 3), /* W */ + }; + + const int type = eir_reg_get_type(virt_reg); + reg->swizzle = swizzle[type]; +} + +static unsigned inline +result(struct ra_graph *g, unsigned reg) +{ + const int virt_reg = ra_get_node_reg(g, reg); + + return etna_reg_get_base(virt_reg); +} + +static void +assign(struct eir_register *reg, struct ra_graph *g, unsigned *num_temps) +{ + if (reg->type != EIR_REG_TEMP) + return; + + const int virt_reg = ra_get_node_reg(g, reg->index); + + /* + * convert virtual register back to hw register + * and change swizzle if needed + */ + reg->index = etna_reg_get_base(virt_reg); + + if (eir_reg_get_type(virt_reg) != EIR_REG_CLASS_VEC4) + reswizzle(reg, virt_reg); + + *num_temps = MAX2(*num_temps, reg->index + 1); +} + +bool +eir_register_allocate(struct eir *ir, gl_shader_stage type, struct eir_compiler *compiler) +{ + int num = util_dynarray_num_elements(&ir->reg_alloc, unsigned); + + if (num == 0) + return true; + + int frag_varying_pos = -1; + + if (type == MESA_SHADER_FRAGMENT) { + for (unsigned i = 0; i < ir->num_inputs; i++) { + if (ir->inputs[i].slot == VARYING_SLOT_POS) { + frag_varying_pos = i; + break; + } + } + + /* allocate one extra register for hardwired t0 register */ + if (frag_varying_pos == -1) { + num++; + frag_varying_pos = num - 1; + } + } + + struct ra_graph *g = ra_alloc_interference_graph(compiler->set->regs, num); + unsigned num_temps = 0; + + assert(g); + assert(ir->temp_start); + assert(ir->temp_end); + + unsigned i = 0; + util_dynarray_foreach(&ir->reg_alloc, unsigned, num_components) { + switch (*num_components) { + case 1: + ra_set_node_class(g, i, compiler->set->class[EIR_REG_CLASS_VIRT_SCALAR]); + break; + case 2: + ra_set_node_class(g, i, compiler->set->class[EIR_REG_CLASS_VIRT_VEC2]); + break; + case 3: + ra_set_node_class(g, i, compiler->set->class[EIR_REG_CLASS_VIRT_VEC3]); + break; + case 4: + ra_set_node_class(g, i, compiler->set->class[EIR_REG_CLASS_VEC4]); + break; + default: + unreachable("not supported num_components"); + break; + } + + i++; + } + + /* TODO: handle scalar opcodes */ +#if 0 + eir_for_each_block(block, ir) { + eir_for_each_inst(inst, block) { + if (gc_op_is_scalar(inst->gc.opcode)) { + ra_set_node_reg(g, ) + } + } + } +#endif + + for (unsigned i = 0; i < num; i++) + for (unsigned j = 0; j < i; j++) + if (interferes(ir, i, j)) + ra_add_node_interference(g, i, j); + + if (type == MESA_SHADER_FRAGMENT) { + for (unsigned i = 0; i < num; i++) { + for (int j = 0; j < i; j++) { + ra_add_node_interference(g, i, j); + } + } + + /* hard code frag_color_out_idx to register t0 */ + ra_set_node_reg(g, frag_varying_pos, 0); + } + + bool success = ra_allocate(g); + if (!success) + goto out; + + eir_for_each_block(block, ir) { + eir_for_each_inst(inst, block) { + assign(&inst->dst, g, &num_temps); + assign(&inst->src[0], g, &num_temps); + assign(&inst->src[1], g, &num_temps); + assign(&inst->src[2], g, &num_temps); + } + } + + /* update outputs array */ + for (unsigned i = 0; i < ir->num_outputs; i++) + ir->outputs[i].reg = result(g, i); + + ir->num_temps = num_temps; + + /* free live ranges information as they are not needed anymore */ + ralloc_free(ir->temp_start); + ralloc_free(ir->temp_end); + + ir->temp_start = NULL; + ir->temp_end = NULL; + +out: + ralloc_free(g); + + return success; +} -- 2.21.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev