r300: move some functions out of radeon_pair_regalloc

To prepare for a future sharing in vertex shader register allocator.

Signed-off-by: Pavel Ondračka <pavel.ondracka@gmail.com>
Reviewed-by: Filip Gawin <filip@gawin.net>
Tested-by: Filip Gawin <filip@gawin.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19618>
This commit is contained in:
Pavel Ondračka
2022-10-25 21:43:54 +02:00
committed by Marge Bot
parent 715e7172e8
commit e1b4ba1350
4 changed files with 401 additions and 358 deletions
@@ -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
@@ -0,0 +1,327 @@
/*
* Copyright (C) 2009 Nicolai Haehnle.
* Copyright 2011 Tom Stellard <tstellar@gmail.com>
*
* 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);
}
@@ -1,4 +1,6 @@
/*
* Copyright (C) 2009 Nicolai Haehnle.
* Copyright 2011 Tom Stellard <tstellar@gmail.com>
* 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);
+1
View File
@@ -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',