diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c index 2f64dff4e2a..3cf9cc6971b 100644 --- a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c +++ b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c @@ -43,172 +43,6 @@ #include "radeon_regalloc.h" #include "radeon_variable.h" -#define VERBOSE 0 - -#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) - - - -struct register_info { - struct live_intervals Live[4]; - - unsigned int Used:1; - unsigned int Allocated:1; - unsigned int File:3; - unsigned int Index:RC_REGISTER_INDEX_BITS; - unsigned int Writemask; -}; - -struct regalloc_state { - struct radeon_compiler * C; - - struct register_info * Input; - unsigned int NumInputs; - - struct register_info * Temporary; - unsigned int NumTemporaries; - - unsigned int Simple; - int LoopEnd; -}; - -struct rc_class { - enum rc_reg_class ID; - - unsigned int WritemaskCount; - - /** List of writemasks that belong to this class */ - unsigned int Writemasks[3]; - - -}; - -static const struct rc_class rc_class_list [] = { - {RC_REG_CLASS_SINGLE, 3, - {RC_MASK_X, - RC_MASK_Y, - RC_MASK_Z}}, - {RC_REG_CLASS_DOUBLE, 3, - {RC_MASK_X | RC_MASK_Y, - RC_MASK_X | RC_MASK_Z, - RC_MASK_Y | RC_MASK_Z}}, - {RC_REG_CLASS_TRIPLE, 1, - {RC_MASK_X | RC_MASK_Y | RC_MASK_Z, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_ALPHA, 1, - {RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_SINGLE_PLUS_ALPHA, 3, - {RC_MASK_X | RC_MASK_W, - RC_MASK_Y | RC_MASK_W, - RC_MASK_Z | RC_MASK_W}}, - {RC_REG_CLASS_DOUBLE_PLUS_ALPHA, 3, - {RC_MASK_X | RC_MASK_Y | RC_MASK_W, - RC_MASK_X | RC_MASK_Z | RC_MASK_W, - RC_MASK_Y | RC_MASK_Z | RC_MASK_W}}, - {RC_REG_CLASS_TRIPLE_PLUS_ALPHA, 1, - {RC_MASK_X | RC_MASK_Y | RC_MASK_Z | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_X, 1, - {RC_MASK_X, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_Y, 1, - {RC_MASK_Y, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_Z, 1, - {RC_MASK_Z, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_XY, 1, - {RC_MASK_X | RC_MASK_Y, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_YZ, 1, - {RC_MASK_Y | RC_MASK_Z, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_XZ, 1, - {RC_MASK_X | RC_MASK_Z, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_XW, 1, - {RC_MASK_X | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_YW, 1, - {RC_MASK_Y | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_ZW, 1, - {RC_MASK_Z | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_XYW, 1, - {RC_MASK_X | RC_MASK_Y | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_YZW, 1, - {RC_MASK_Y | RC_MASK_Z | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}}, - {RC_REG_CLASS_XZW, 1, - {RC_MASK_X | RC_MASK_Z | RC_MASK_W, - RC_MASK_NONE, - RC_MASK_NONE}} -}; - -static void print_live_intervals(struct live_intervals * src) -{ - if (!src || !src->Used) { - DBG("(null)"); - return; - } - - DBG("(%i,%i)", src->Start, src->End); -} - -static int overlap_live_intervals(struct live_intervals * a, struct live_intervals * b) -{ - if (VERBOSE) { - DBG("overlap_live_intervals: "); - print_live_intervals(a); - DBG(" to "); - print_live_intervals(b); - DBG("\n"); - } - - if (!a->Used || !b->Used) { - DBG(" unused interval\n"); - return 0; - } - - if (a->Start > b->Start) { - if (a->Start < b->End) { - DBG(" overlap\n"); - return 1; - } - } else if (b->Start > a->Start) { - if (b->Start < a->End) { - DBG(" overlap\n"); - return 1; - } - } else { /* a->Start == b->Start */ - if (a->Start != a->End && b->Start != b->End) { - DBG(" overlap\n"); - return 1; - } - } - - DBG(" no overlap\n"); - - return 0; -} - static void scan_read_callback(void * data, struct rc_instruction * inst, rc_register_file file, unsigned int index, unsigned int mask) { @@ -284,26 +118,6 @@ static unsigned int is_derivative(rc_opcode op) return (op == RC_OPCODE_DDX || op == RC_OPCODE_DDY); } -static int find_class( - const struct rc_class * classes, - unsigned int writemask, - unsigned int max_writemask_count) -{ - unsigned int i; - for (i = 0; i < RC_REG_CLASS_COUNT; i++) { - unsigned int j; - if (classes[i].WritemaskCount > max_writemask_count) { - continue; - } - for (j = 0; j < 3; j++) { - if (classes[i].Writemasks[j] == writemask) { - return i; - } - } - } - return -1; -} - struct variable_get_class_cb_data { unsigned int * can_change_writemask; unsigned int conversion_swizzle; @@ -323,7 +137,7 @@ static void variable_get_class_read_cb( } } -static enum rc_reg_class variable_get_class( +static unsigned variable_get_class( struct rc_variable * variable, const struct rc_class * classes) { @@ -347,7 +161,7 @@ static enum rc_reg_class variable_get_class( /* Check if it is possible to do swizzle packing for r300/r400 * without creating non-native swizzles. */ - class_index = find_class(classes, writemask, 3); + class_index = rc_find_class(classes, writemask, 3); if (class_index < 0) { goto error; } @@ -432,7 +246,7 @@ static enum rc_reg_class variable_get_class( } } - class_index = find_class(classes, writemask, + class_index = rc_find_class(classes, writemask, can_change_writemask ? 3 : 1); done: if (class_index > -1) { @@ -446,72 +260,6 @@ error: } } -static unsigned int overlap_live_intervals_array( - struct live_intervals * a, - struct live_intervals * b) -{ - unsigned int a_chan, b_chan; - for (a_chan = 0; a_chan < 4; a_chan++) { - for (b_chan = 0; b_chan < 4; b_chan++) { - if (overlap_live_intervals(&a[a_chan], &b[b_chan])) { - return 1; - } - } - } - return 0; -} - -static unsigned int reg_get_index(int reg) -{ - return reg / RC_MASK_XYZW; -} - -static unsigned int reg_get_writemask(int reg) -{ - return (reg % RC_MASK_XYZW) + 1; -} - -static int get_reg_id(unsigned int index, unsigned int writemask) -{ - assert(writemask); - if (writemask == 0) { - return 0; - } - return (index * RC_MASK_XYZW) + (writemask - 1); -} - -#if VERBOSE -static void print_reg(int reg) -{ - unsigned int index = reg_get_index(reg); - unsigned int mask = reg_get_writemask(reg); - fprintf(stderr, "Temp[%u].%c%c%c%c", index, - mask & RC_MASK_X ? 'x' : '_', - mask & RC_MASK_Y ? 'y' : '_', - mask & RC_MASK_Z ? 'z' : '_', - mask & RC_MASK_W ? 'w' : '_'); -} -#endif - -static void add_register_conflicts( - struct ra_regs * regs, - unsigned int max_temp_regs) -{ - unsigned int index, a_mask, b_mask; - for (index = 0; index < max_temp_regs; index++) { - for(a_mask = 1; a_mask <= RC_MASK_XYZW; a_mask++) { - for (b_mask = a_mask + 1; b_mask <= RC_MASK_XYZW; - b_mask++) { - if (a_mask & b_mask) { - ra_add_reg_conflict(regs, - get_reg_id(index, a_mask), - get_reg_id(index, b_mask)); - } - } - } - } -} - static void do_advanced_regalloc(struct regalloc_state * s) { @@ -585,7 +333,7 @@ static void do_advanced_regalloc(struct regalloc_state * s) while (var_a) { struct rc_variable * var_b = b->Item; while (var_b) { - if (overlap_live_intervals_array(var_a->Live, var_b->Live)) { + if (rc_overlap_live_intervals_array(var_a->Live, var_b->Live)) { ra_add_node_interference(graph, node_index, b_index); } @@ -604,7 +352,7 @@ static void do_advanced_regalloc(struct regalloc_state * s) for (var_ptr = variables, node_index = 0; var_ptr; var_ptr = var_ptr->Next, node_index++) { struct rc_variable * var = var_ptr->Item; - if (overlap_live_intervals_array(s->Input[i].Live, + if (rc_overlap_live_intervals_array(s->Input[i].Live, var->Live)) { ra_add_node_interference(graph, node_index, node_count + input_node); @@ -642,107 +390,6 @@ static void do_advanced_regalloc(struct regalloc_state * s) ralloc_free(graph); } -void rc_init_regalloc_state(struct rc_regalloc_state *s) -{ - unsigned i, j, index; - unsigned **ra_q_values; - - /* Pre-computed q values. This array describes the maximum number of - * a class's [row] registers that are in conflict with a single - * register from another class [column]. - * - * For example: - * q_values[0][2] is 3, because a register from class 2 - * (RC_REG_CLASS_TRIPLE) may conflict with at most 3 registers from - * class 0 (RC_REG_CLASS_SINGLE) e.g. T0.xyz conflicts with T0.x, T0.y, - * and T0.z. - * - * q_values[2][0] is 1, because a register from class 0 - * (RC_REG_CLASS_SINGLE) may conflict with at most 1 register from - * class 2 (RC_REG_CLASS_TRIPLE) e.g. T0.x conflicts with T0.xyz - * - * The q values for each register class [row] will never be greater - * than the maximum number of writemask combinations for that class. - * - * For example: - * - * Class 2 (RC_REG_CLASS_TRIPLE) only has 1 writemask combination, - * so no value in q_values[2][0..RC_REG_CLASS_COUNT] will be greater - * than 1. - */ - const unsigned q_values[RC_REG_CLASS_COUNT][RC_REG_CLASS_COUNT] = { - {1, 2, 3, 0, 1, 2, 3, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2}, - {2, 3, 3, 0, 2, 3, 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 3}, - {1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, - {1, 2, 3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3}, - {2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1}, - {1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}, - {1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1}, - {1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1}, - {1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1}, - {1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - }; - - /* Allocate the main ra data structure */ - s->regs = ra_alloc_reg_set(NULL, R500_PFS_NUM_TEMP_REGS * RC_MASK_XYZW, - true); - - s->class_list = rc_class_list; - - /* Create the register classes */ - for (i = 0; i < RC_REG_CLASS_COUNT; i++) { - const struct rc_class *class = &s->class_list[i]; - s->classes[class->ID] = ra_alloc_reg_class(s->regs); - - /* Assign registers to the classes */ - for (index = 0; index < R500_PFS_NUM_TEMP_REGS; index++) { - for (j = 0; j < class->WritemaskCount; j++) { - int reg_id = get_reg_id(index, - class->Writemasks[j]); - ra_class_add_reg(s->classes[class->ID], reg_id); - } - } - } - - /* Set the q values. The q_values array is indexed based on - * the rc_reg_class ID (RC_REG_CLASS_*) which might be - * different than the ID assigned to that class by ra. - * This why we need to manually construct this list. - */ - ra_q_values = MALLOC(RC_REG_CLASS_COUNT * sizeof(unsigned *)); - - for (i = 0; i < RC_REG_CLASS_COUNT; i++) { - ra_q_values[i] = MALLOC(RC_REG_CLASS_COUNT * sizeof(unsigned)); - for (j = 0; j < RC_REG_CLASS_COUNT; j++) { - ra_q_values[i][j] = q_values[i][j]; - } - } - - /* Add register conflicts */ - add_register_conflicts(s->regs, R500_PFS_NUM_TEMP_REGS); - - ra_set_finalize(s->regs, ra_q_values); - - for (i = 0; i < RC_REG_CLASS_COUNT; i++) { - FREE(ra_q_values[i]); - } - FREE(ra_q_values); -} - -void rc_destroy_regalloc_state(struct rc_regalloc_state *s) -{ - ralloc_free(s->regs); -} - /** * @param user This parameter should be a pointer to an integer value. If this * integer value is zero, then a simple register allocator will be used that diff --git a/src/gallium/drivers/r300/compiler/radeon_regalloc.c b/src/gallium/drivers/r300/compiler/radeon_regalloc.c new file mode 100644 index 00000000000..d93b950cf6f --- /dev/null +++ b/src/gallium/drivers/r300/compiler/radeon_regalloc.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2009 Nicolai Haehnle. + * Copyright 2011 Tom Stellard + * + * All Rights Reserved. + * + * 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, sublicense, 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 NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "radeon_regalloc.h" + +#define VERBOSE 0 + +#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0) + +const struct rc_class rc_class_list [] = { + {RC_REG_CLASS_SINGLE, 3, + {RC_MASK_X, + RC_MASK_Y, + RC_MASK_Z}}, + {RC_REG_CLASS_DOUBLE, 3, + {RC_MASK_X | RC_MASK_Y, + RC_MASK_X | RC_MASK_Z, + RC_MASK_Y | RC_MASK_Z}}, + {RC_REG_CLASS_TRIPLE, 1, + {RC_MASK_X | RC_MASK_Y | RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_ALPHA, 1, + {RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_SINGLE_PLUS_ALPHA, 3, + {RC_MASK_X | RC_MASK_W, + RC_MASK_Y | RC_MASK_W, + RC_MASK_Z | RC_MASK_W}}, + {RC_REG_CLASS_DOUBLE_PLUS_ALPHA, 3, + {RC_MASK_X | RC_MASK_Y | RC_MASK_W, + RC_MASK_X | RC_MASK_Z | RC_MASK_W, + RC_MASK_Y | RC_MASK_Z | RC_MASK_W}}, + {RC_REG_CLASS_TRIPLE_PLUS_ALPHA, 1, + {RC_MASK_X | RC_MASK_Y | RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_X, 1, + {RC_MASK_X, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_Y, 1, + {RC_MASK_Y, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_Z, 1, + {RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XY, 1, + {RC_MASK_X | RC_MASK_Y, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_YZ, 1, + {RC_MASK_Y | RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XZ, 1, + {RC_MASK_X | RC_MASK_Z, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XW, 1, + {RC_MASK_X | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_YW, 1, + {RC_MASK_Y | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_ZW, 1, + {RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XYW, 1, + {RC_MASK_X | RC_MASK_Y | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_YZW, 1, + {RC_MASK_Y | RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}}, + {RC_REG_CLASS_XZW, 1, + {RC_MASK_X | RC_MASK_Z | RC_MASK_W, + RC_MASK_NONE, + RC_MASK_NONE}} +}; + +static void print_live_intervals(struct live_intervals * src) +{ + if (!src || !src->Used) { + DBG("(null)"); + return; + } + + DBG("(%i,%i)", src->Start, src->End); +} + +static int overlap_live_intervals(struct live_intervals * a, struct live_intervals * b) +{ + if (VERBOSE) { + DBG("overlap_live_intervals: "); + print_live_intervals(a); + DBG(" to "); + print_live_intervals(b); + DBG("\n"); + } + + if (!a->Used || !b->Used) { + DBG(" unused interval\n"); + return 0; + } + + if (a->Start > b->Start) { + if (a->Start < b->End) { + DBG(" overlap\n"); + return 1; + } + } else if (b->Start > a->Start) { + if (b->Start < a->End) { + DBG(" overlap\n"); + return 1; + } + } else { /* a->Start == b->Start */ + if (a->Start != a->End && b->Start != b->End) { + DBG(" overlap\n"); + return 1; + } + } + + DBG(" no overlap\n"); + + return 0; +} + +int rc_find_class( + const struct rc_class * classes, + unsigned int writemask, + unsigned int max_writemask_count) +{ + unsigned int i; + for (i = 0; i < RC_REG_CLASS_COUNT; i++) { + unsigned int j; + if (classes[i].WritemaskCount > max_writemask_count) { + continue; + } + for (j = 0; j < 3; j++) { + if (classes[i].Writemasks[j] == writemask) { + return i; + } + } + } + return -1; +} + +unsigned int rc_overlap_live_intervals_array( + struct live_intervals * a, + struct live_intervals * b) +{ + unsigned int a_chan, b_chan; + for (a_chan = 0; a_chan < 4; a_chan++) { + for (b_chan = 0; b_chan < 4; b_chan++) { + if (overlap_live_intervals(&a[a_chan], &b[b_chan])) { + return 1; + } + } + } + return 0; +} + +#if VERBOSE +static void print_reg(int reg) +{ + unsigned int index = reg_get_index(reg); + unsigned int mask = reg_get_writemask(reg); + fprintf(stderr, "Temp[%u].%c%c%c%c", index, + mask & RC_MASK_X ? 'x' : '_', + mask & RC_MASK_Y ? 'y' : '_', + mask & RC_MASK_Z ? 'z' : '_', + mask & RC_MASK_W ? 'w' : '_'); +} +#endif + +static void add_register_conflicts( + struct ra_regs * regs, + unsigned int max_temp_regs) +{ + unsigned int index, a_mask, b_mask; + for (index = 0; index < max_temp_regs; index++) { + for(a_mask = 1; a_mask <= RC_MASK_XYZW; a_mask++) { + for (b_mask = a_mask + 1; b_mask <= RC_MASK_XYZW; + b_mask++) { + if (a_mask & b_mask) { + ra_add_reg_conflict(regs, + get_reg_id(index, a_mask), + get_reg_id(index, b_mask)); + } + } + } + } +} + +void rc_init_regalloc_state(struct rc_regalloc_state *s) +{ + unsigned i, j, index; + unsigned **ra_q_values; + + /* Pre-computed q values. This array describes the maximum number of + * a class's [row] registers that are in conflict with a single + * register from another class [column]. + * + * For example: + * q_values[0][2] is 3, because a register from class 2 + * (RC_REG_CLASS_TRIPLE) may conflict with at most 3 registers from + * class 0 (RC_REG_CLASS_SINGLE) e.g. T0.xyz conflicts with T0.x, T0.y, + * and T0.z. + * + * q_values[2][0] is 1, because a register from class 0 + * (RC_REG_CLASS_SINGLE) may conflict with at most 1 register from + * class 2 (RC_REG_CLASS_TRIPLE) e.g. T0.x conflicts with T0.xyz + * + * The q values for each register class [row] will never be greater + * than the maximum number of writemask combinations for that class. + * + * For example: + * + * Class 2 (RC_REG_CLASS_TRIPLE) only has 1 writemask combination, + * so no value in q_values[2][0..RC_REG_CLASS_COUNT] will be greater + * than 1. + */ + const unsigned q_values[RC_REG_CLASS_COUNT][RC_REG_CLASS_COUNT] = { + {1, 2, 3, 0, 1, 2, 3, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2}, + {2, 3, 3, 0, 2, 3, 3, 2, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 3}, + {1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, + {1, 2, 3, 3, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3}, + {2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1}, + {1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}, + {1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + }; + + /* Allocate the main ra data structure */ + s->regs = ra_alloc_reg_set(NULL, R500_PFS_NUM_TEMP_REGS * RC_MASK_XYZW, + true); + + s->class_list = rc_class_list; + + /* Create the register classes */ + for (i = 0; i < RC_REG_CLASS_COUNT; i++) { + const struct rc_class *class = &rc_class_list[i]; + s->classes[class->ID] = ra_alloc_reg_class(s->regs); + + /* Assign registers to the classes */ + for (index = 0; index < R500_PFS_NUM_TEMP_REGS; index++) { + for (j = 0; j < class->WritemaskCount; j++) { + int reg_id = get_reg_id(index, + class->Writemasks[j]); + ra_class_add_reg(s->classes[class->ID], reg_id); + } + } + } + + /* Set the q values. The q_values array is indexed based on + * the rc_reg_class ID (RC_REG_CLASS_*) which might be + * different than the ID assigned to that class by ra. + * This why we need to manually construct this list. + */ + ra_q_values = MALLOC(RC_REG_CLASS_COUNT * sizeof(unsigned *)); + + for (i = 0; i < RC_REG_CLASS_COUNT; i++) { + ra_q_values[i] = MALLOC(RC_REG_CLASS_COUNT * sizeof(unsigned)); + for (j = 0; j < RC_REG_CLASS_COUNT; j++) { + ra_q_values[i][j] = q_values[i][j]; + } + } + + /* Add register conflicts */ + add_register_conflicts(s->regs, R500_PFS_NUM_TEMP_REGS); + + ra_set_finalize(s->regs, ra_q_values); + + for (i = 0; i < RC_REG_CLASS_COUNT; i++) { + FREE(ra_q_values[i]); + } + FREE(ra_q_values); +} + +void rc_destroy_regalloc_state(struct rc_regalloc_state *s) +{ + ralloc_free(s->regs); +} diff --git a/src/gallium/drivers/r300/compiler/radeon_regalloc.h b/src/gallium/drivers/r300/compiler/radeon_regalloc.h index 6c2f1cef275..81319d81c8f 100644 --- a/src/gallium/drivers/r300/compiler/radeon_regalloc.h +++ b/src/gallium/drivers/r300/compiler/radeon_regalloc.h @@ -1,4 +1,6 @@ /* + * Copyright (C) 2009 Nicolai Haehnle. + * Copyright 2011 Tom Stellard * Copyright 2012 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +28,12 @@ #ifndef RADEON_REGALLOC_H #define RADEON_REGALLOC_H +#include "util/register_allocate.h" +#include "util/u_memory.h" +#include "util/ralloc.h" + +#include "radeon_variable.h" + struct ra_regs; enum rc_reg_class { @@ -57,6 +65,66 @@ struct rc_regalloc_state { const struct rc_class *class_list; }; +struct register_info { + struct live_intervals Live[4]; + + unsigned int Used:1; + unsigned int Allocated:1; + unsigned int File:3; + unsigned int Index:RC_REGISTER_INDEX_BITS; + unsigned int Writemask; +}; + +struct regalloc_state { + struct radeon_compiler * C; + + struct register_info * Input; + unsigned int NumInputs; + + struct register_info * Temporary; + unsigned int NumTemporaries; + + unsigned int Simple; + int LoopEnd; +}; + +struct rc_class { + enum rc_reg_class ID; + + unsigned int WritemaskCount; + + /** List of writemasks that belong to this class */ + unsigned int Writemasks[3]; +}; + +int rc_find_class( + const struct rc_class * classes, + unsigned int writemask, + unsigned int max_writemask_count); + +unsigned int rc_overlap_live_intervals_array( + struct live_intervals * a, + struct live_intervals * b); + +static inline unsigned int reg_get_index(int reg) +{ + return reg / RC_MASK_XYZW; +}; + +static inline unsigned int reg_get_writemask(int reg) +{ + return (reg % RC_MASK_XYZW) + 1; +}; + +static inline int get_reg_id(unsigned int index, unsigned int writemask) +{ + assert(writemask); + if (writemask == 0) { + return 0; + } + return (index * RC_MASK_XYZW) + (writemask - 1); +} + void rc_init_regalloc_state(struct rc_regalloc_state *s); void rc_destroy_regalloc_state(struct rc_regalloc_state *s); diff --git a/src/gallium/drivers/r300/meson.build b/src/gallium/drivers/r300/meson.build index 685f4a761c7..3d855dfb84b 100644 --- a/src/gallium/drivers/r300/meson.build +++ b/src/gallium/drivers/r300/meson.build @@ -105,6 +105,7 @@ files_r300 = files( 'compiler/radeon_program_print.c', 'compiler/radeon_program_tex.c', 'compiler/radeon_program_tex.h', + 'compiler/radeon_regalloc.c', 'compiler/radeon_regalloc.h', 'compiler/radeon_remove_constants.c', 'compiler/radeon_remove_constants.h',