Commit 574ba4b5 authored by Marek Olšák's avatar Marek Olšák

r300/compiler: implement elimination of unused constants

Wine likes to create a *lot* of constants, exceeding the size of the constant
file in hw.
parent 4b9b2a3c
......@@ -23,6 +23,7 @@ C_SOURCES = \
radeon_dataflow_deadcode.c \
radeon_dataflow_swizzles.c \
radeon_optimize.c \
radeon_remove_constants.c \
radeon_rename_regs.c \
r3xx_fragprog.c \
r300_fragprog.c \
......
......@@ -22,6 +22,7 @@ r300compiler = env.ConvenienceLibrary(
'radeon_pair_schedule.c',
'radeon_pair_regalloc.c',
'radeon_optimize.c',
'radeon_remove_constants.c'
'radeon_rename_regs.c',
'radeon_emulate_branches.c',
'radeon_emulate_loops.c',
......
......@@ -30,6 +30,7 @@
#include "radeon_program_alu.h"
#include "radeon_program_tex.h"
#include "radeon_rename_regs.h"
#include "radeon_remove_constants.h"
#include "r300_fragprog.h"
#include "r300_fragprog_swizzle.h"
#include "r500_fragprog.h"
......@@ -180,6 +181,13 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
debug_program_log(c, "after dataflow passes");
if (c->Base.remove_unused_constants) {
rc_remove_unused_constants(&c->Base,
&c->code->constants_remap_table);
debug_program_log(c, "after constants cleanup");
}
if(!c->Base.is_r500) {
/* This pass makes it easier for the scheduler to group TEX
* instructions and reduces the chances of creating too
......
......@@ -31,6 +31,7 @@
#include "radeon_swizzle.h"
#include "radeon_emulate_branches.h"
#include "radeon_emulate_loops.h"
#include "radeon_remove_constants.h"
struct loop {
int BgnLoop;
......@@ -993,6 +994,14 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler *c)
debug_program_log(c, "after register allocation");
if (c->Base.remove_unused_constants) {
rc_remove_unused_constants(&c->Base,
&c->code->constants_remap_table);
if (c->Base.Error)
return;
debug_program_log(c, "after constants cleanup");
}
translate_vertex_program(c);
if (c->Base.Error)
......
......@@ -235,6 +235,7 @@ struct rX00_fragment_program_code {
unsigned writes_depth:1;
struct rc_constant_list constants;
unsigned *constants_remap_table;
};
......@@ -266,6 +267,7 @@ struct r300_vertex_program_code {
int outputs[VSF_MAX_OUTPUTS];
struct rc_constant_list constants;
unsigned *constants_remap_table;
uint32_t InputsRead;
uint32_t OutputsWritten;
......
......@@ -39,9 +39,12 @@ struct radeon_compiler {
char * ErrorMsg;
/* Hardware specification. */
unsigned is_r500;
unsigned is_r500:1;
unsigned max_temp_regs;
/* Whether to remove unused constants and empty holes in constant space. */
unsigned remove_unused_constants:1;
/**
* Variables used internally, not be touched by callers
* of the compiler
......
/*
* Copyright (C) 2010 Marek Olšák <maraeo@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_remove_constants.h"
void rc_remove_unused_constants(struct radeon_compiler *c,
unsigned **out_remap_table)
{
unsigned char *const_used;
unsigned *remap_table;
unsigned *inv_remap_table;
unsigned has_rel_addr = 0;
unsigned is_identity = 1;
unsigned are_externals_remapped = 0;
struct rc_constant *constants = c->Program.Constants.Constants;
if (!c->Program.Constants.Count) {
*out_remap_table = NULL;
return;
}
const_used = malloc(c->Program.Constants.Count);
memset(const_used, 0, c->Program.Constants.Count);
/* Pass 1: Mark used constants. */
for (struct rc_instruction *inst = c->Program.Instructions.Next;
inst != &c->Program.Instructions; inst = inst->Next) {
const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode);
for (unsigned i = 0; i < opcode->NumSrcRegs; i++) {
if (inst->U.I.SrcReg[i].File == RC_FILE_CONSTANT) {
if (inst->U.I.SrcReg[i].RelAddr) {
has_rel_addr = 1;
} else {
const_used[inst->U.I.SrcReg[i].Index] = 1;
}
}
}
}
/* Pass 2: If there is relative addressing, mark all externals as used. */
if (has_rel_addr) {
for (unsigned i = 0; i < c->Program.Constants.Count; i++)
if (constants[i].Type == RC_CONSTANT_EXTERNAL)
const_used[i] = 1;
}
/* Pass 3: Make the remapping table and remap constants.
* This pass removes unused constants simply by overwriting them by other constants. */
remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned));
inv_remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned));
unsigned new_count = 0;
for (unsigned i = 0; i < c->Program.Constants.Count; i++) {
if (const_used[i]) {
remap_table[new_count] = i;
inv_remap_table[i] = new_count;
if (i != new_count) {
if (constants[i].Type == RC_CONSTANT_EXTERNAL)
are_externals_remapped = 1;
constants[new_count] = constants[i];
is_identity = 0;
}
new_count++;
}
}
/* is_identity ==> new_count == old_count
* !is_identity ==> new_count < old_count */
assert( is_identity || new_count < c->Program.Constants.Count);
assert(!(has_rel_addr && are_externals_remapped));
/* Pass 4: Redirect reads of all constants to their new locations. */
if (!is_identity) {
for (struct rc_instruction *inst = c->Program.Instructions.Next;
inst != &c->Program.Instructions; inst = inst->Next) {
const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode);
for (unsigned i = 0; i < opcode->NumSrcRegs; i++) {
if (inst->U.I.SrcReg[i].File == RC_FILE_CONSTANT) {
inst->U.I.SrcReg[i].Index = inv_remap_table[inst->U.I.SrcReg[i].Index];
}
}
}
}
/* Set the new constant count. Note that new_count may be less than
* Count even though the remapping function is identity. In that case,
* the constants have been removed at the end of the array. */
c->Program.Constants.Count = new_count;
if (are_externals_remapped) {
*out_remap_table = remap_table;
} else {
*out_remap_table = NULL;
free(remap_table);
}
free(const_used);
free(inv_remap_table);
}
/*
* Copyright (C) 2010 Marek Olšák <maraeo@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.
*
*/
#ifndef RADEON_REMOVE_CONSTANTS_H
#define RADEON_REMOVE_CONSTANTS_H
#include "radeon_compiler.h"
void rc_remove_unused_constants(struct radeon_compiler *c,
unsigned **out_remap_table);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment