r300/compiler: Use presubtract operations as much as possible

Previously, presubtract operations where only being used by instructions
with less than three source source registers.
This commit is contained in:
Tom Stellard
2010-11-08 18:49:44 -08:00
parent ddceededf8
commit bbe49bc585
8 changed files with 204 additions and 67 deletions
@@ -31,6 +31,8 @@
#include "radeon_compiler_util.h"
#include "radeon_compiler.h"
#include "radeon_dataflow.h"
/**
*/
unsigned int rc_swizzle_to_writemask(unsigned int swz)
@@ -59,3 +61,123 @@ unsigned int rc_src_reads_dst_mask(
}
return dst_mask & rc_swizzle_to_writemask(src_swz);
}
unsigned int rc_source_type_swz(unsigned int swizzle, unsigned int channels)
{
unsigned int chan;
unsigned int swz = RC_SWIZZLE_UNUSED;
unsigned int ret = RC_SOURCE_NONE;
for(chan = 0; chan < channels; chan++) {
swz = GET_SWZ(swizzle, chan);
if (swz == RC_SWIZZLE_W) {
ret |= RC_SOURCE_ALPHA;
} else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
|| swz == RC_SWIZZLE_Z) {
ret |= RC_SOURCE_RGB;
}
}
return ret;
}
unsigned int rc_source_type_mask(unsigned int mask)
{
unsigned int ret = RC_SOURCE_NONE;
if (mask & RC_MASK_XYZ)
ret |= RC_SOURCE_RGB;
if (mask & RC_MASK_W)
ret |= RC_SOURCE_ALPHA;
return ret;
}
struct can_use_presub_data {
struct rc_src_register RemoveSrcs[3];
unsigned int RGBCount;
unsigned int AlphaCount;
};
static void can_use_presub_read_cb(
void * userdata,
struct rc_instruction * inst,
rc_register_file file,
unsigned int index,
unsigned int mask)
{
struct can_use_presub_data * d = userdata;
unsigned int src_type = rc_source_type_mask(mask);
unsigned int i;
if (file == RC_FILE_NONE)
return;
for(i = 0; i < 3; i++) {
if (d->RemoveSrcs[i].File == file
&& d->RemoveSrcs[i].Index == index) {
src_type &=
~rc_source_type_swz(d->RemoveSrcs[i].Swizzle, 4);
}
}
if (src_type & RC_SOURCE_RGB)
d->RGBCount++;
if (src_type & RC_SOURCE_ALPHA)
d->AlphaCount++;
}
unsigned int rc_inst_can_use_presub(
struct rc_instruction * inst,
rc_presubtract_op presub_op,
unsigned int presub_writemask,
struct rc_src_register replace_reg,
struct rc_src_register presub_src0,
struct rc_src_register presub_src1)
{
struct can_use_presub_data d;
unsigned int num_presub_srcs;
unsigned int presub_src_type = rc_source_type_mask(presub_writemask);
const struct rc_opcode_info * info =
rc_get_opcode_info(inst->U.I.Opcode);
if (presub_op == RC_PRESUB_NONE) {
return 1;
}
if (info->HasTexture) {
return 0;
}
/* We can't use more than one presubtract value in an
* instruction, unless the two prsubtract operations
* are the same and read from the same registers.
* XXX For now we will limit instructions to only one presubtract
* value.*/
if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) {
return 0;
}
memset(&d, 0, sizeof(d));
d.RemoveSrcs[0] = replace_reg;
d.RemoveSrcs[1] = presub_src0;
d.RemoveSrcs[2] = presub_src1;
rc_for_all_reads_mask(inst, can_use_presub_read_cb, &d);
num_presub_srcs = rc_presubtract_src_reg_count(presub_op);
if ((presub_src_type & RC_SOURCE_RGB)
&& d.RGBCount + num_presub_srcs > 3) {
return 0;
}
if ((presub_src_type & RC_SOURCE_ALPHA)
&& d.AlphaCount + num_presub_srcs > 3) {
return 0;
}
return 1;
}
@@ -3,6 +3,9 @@
#ifndef RADEON_PROGRAM_UTIL_H
#define RADEON_PROGRAM_UTIL_H
struct rc_instruction;
struct rc_src_register;
unsigned int rc_swizzle_to_writemask(unsigned int swz);
unsigned int rc_src_reads_dst_mask(
@@ -13,4 +16,16 @@ unsigned int rc_src_reads_dst_mask(
unsigned int dst_idx,
unsigned int dst_mask);
unsigned int rc_source_type_swz(unsigned int swizzle, unsigned int channels);
unsigned int rc_source_type_mask(unsigned int mask);
unsigned int rc_inst_can_use_presub(
struct rc_instruction * inst,
rc_presubtract_op presub_op,
unsigned int presub_writemask,
struct rc_src_register replace_reg,
struct rc_src_register presub_src0,
struct rc_src_register presub_src1);
#endif /* RADEON_PROGRAM_UTIL_H */
@@ -139,9 +139,17 @@ static void pair_sub_for_all_args(
const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
for(i = 0; i < info->NumSrcRegs; i++) {
unsigned int src_type = rc_source_type_that_arg_reads(
sub->Arg[i].Source, sub->Arg[i].Swizzle);
if (src_type == RC_PAIR_SOURCE_NONE)
unsigned int src_type;
unsigned int channels = 0;
if (&fullinst->U.P.RGB == sub)
channels = 3;
else if (&fullinst->U.P.Alpha == sub)
channels = 1;
assert(channels > 0);
src_type = rc_source_type_swz(sub->Arg[i].Swizzle, channels);
if (src_type == RC_SOURCE_NONE)
continue;
if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) {
@@ -149,7 +157,7 @@ static void pair_sub_for_all_args(
unsigned int presub_src_count;
struct rc_pair_instruction_source * src_array;
unsigned int j;
if (src_type & RC_PAIR_SOURCE_RGB) {
if (src_type & RC_SOURCE_RGB) {
presub_type = fullinst->
U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index;
src_array = fullinst->U.P.RGB.Src;
@@ -71,12 +71,13 @@ static void copy_propagate_scan_read(void * data, struct rc_instruction * inst,
{
rc_register_file file = src->File;
struct rc_reader_data * reader_data = data;
const struct rc_opcode_info * info = rc_get_opcode_info(inst->U.I.Opcode);
/* It is possible to do copy propigation in this situation,
* just not right now, see peephole_add_presub_inv() */
if (reader_data->Writer->U.I.PreSub.Opcode != RC_PRESUB_NONE &&
(info->NumSrcRegs > 2 || info->HasTexture)) {
if(!rc_inst_can_use_presub(inst,
reader_data->Writer->U.I.PreSub.Opcode,
rc_swizzle_to_writemask(src->Swizzle),
*src,
reader_data->Writer->U.I.PreSub.SrcReg[0],
reader_data->Writer->U.I.PreSub.SrcReg[1])) {
reader_data->Abort = 1;
return;
}
@@ -424,24 +425,13 @@ static void presub_scan_read(
struct rc_src_register * src)
{
struct rc_reader_data * reader_data = data;
const struct rc_opcode_info * info =
rc_get_opcode_info(inst->U.I.Opcode);
/* XXX: There are some situations where instructions
* with more than 2 src registers can use the
* presubtract select, but to keep things simple we
* will disable presubtract on these instructions for
* now. */
if (info->NumSrcRegs > 2 || info->HasTexture) {
reader_data->Abort = 1;
return;
}
rc_presubtract_op * presub_opcode = reader_data->CbData;
/* We can't use more than one presubtract value in an
* instruction, unless the two prsubtract operations
* are the same and read from the same registers.
* XXX For now we will limit instructions to only one presubtract
* value.*/
if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) {
if (!rc_inst_can_use_presub(inst, *presub_opcode,
reader_data->Writer->U.I.DstReg.WriteMask,
*src,
reader_data->Writer->U.I.SrcReg[0],
reader_data->Writer->U.I.SrcReg[1])) {
reader_data->Abort = 1;
return;
}
@@ -455,7 +445,9 @@ static int presub_helper(
{
struct rc_reader_data reader_data;
unsigned int i;
rc_presubtract_op cb_op = presub_opcode;
reader_data.CbData = &cb_op;
rc_get_readers(c, inst_add, &reader_data, presub_scan_read, NULL,
is_src_clobbered_scan_write);
@@ -30,6 +30,7 @@
#include <stdio.h>
#include "radeon_compiler.h"
#include "radeon_compiler_util.h"
#include "radeon_dataflow.h"
@@ -301,12 +302,12 @@ static int merge_presub_sources(
assert(dst_full->Alpha.Opcode == RC_OPCODE_NOP);
switch(type) {
case RC_PAIR_SOURCE_RGB:
case RC_SOURCE_RGB:
is_rgb = 1;
is_alpha = 0;
dst_sub = &dst_full->RGB;
break;
case RC_PAIR_SOURCE_ALPHA:
case RC_SOURCE_ALPHA:
is_rgb = 0;
is_alpha = 1;
dst_sub = &dst_full->Alpha;
@@ -347,6 +348,8 @@ static int merge_presub_sources(
continue;
free_source = rc_pair_alloc_source(dst_full, is_rgb,
is_alpha, temp.File, temp.Index);
if (free_source < 0)
return 0;
one_way = 1;
} else {
dst_sub->Src[free_source] = temp;
@@ -362,11 +365,11 @@ static int merge_presub_sources(
for(arg = 0; arg < info->NumSrcRegs; arg++) {
/*If this arg does not read from an rgb source,
* do nothing. */
if (!(rc_source_type_that_arg_reads(
dst_full->RGB.Arg[arg].Source,
dst_full->RGB.Arg[arg].Swizzle) & type)) {
if (!(rc_source_type_swz(dst_full->RGB.Arg[arg].Swizzle,
3) & type)) {
continue;
}
if (dst_full->RGB.Arg[arg].Source == srcp_src)
dst_full->RGB.Arg[arg].Source = free_source;
/* We need to do this just in case register
@@ -398,13 +401,13 @@ static int destructive_merge_instructions(
/* Merge the rgb presubtract registers. */
if (alpha->RGB.Src[RC_PAIR_PRESUB_SRC].Used) {
if (!merge_presub_sources(rgb, alpha->RGB, RC_PAIR_SOURCE_RGB)) {
if (!merge_presub_sources(rgb, alpha->RGB, RC_SOURCE_RGB)) {
return 0;
}
}
/* Merge the alpha presubtract registers */
if (alpha->Alpha.Src[RC_PAIR_PRESUB_SRC].Used) {
if(!merge_presub_sources(rgb, alpha->Alpha, RC_PAIR_SOURCE_ALPHA)){
if(!merge_presub_sources(rgb, alpha->Alpha, RC_SOURCE_ALPHA)){
return 0;
}
}
@@ -181,4 +181,9 @@ static inline int rc_presubtract_src_reg_count(rc_presubtract_op op){
return 0;
}
}
#define RC_SOURCE_NONE 0x0
#define RC_SOURCE_RGB 0x1
#define RC_SOURCE_ALPHA 0x2
#endif /* RADEON_PROGRAM_CONSTANTS_H */
@@ -27,6 +27,8 @@
#include "radeon_program_pair.h"
#include "radeon_compiler_util.h"
#include <stdlib.h>
/**
@@ -205,37 +207,35 @@ void rc_pair_foreach_source_that_rgb_reads(
}
}
/*return 0 for rgb, 1 for alpha -1 for error. */
unsigned int rc_source_type_that_arg_reads(
unsigned int source,
unsigned int swizzle)
{
unsigned int chan;
unsigned int swz = RC_SWIZZLE_UNUSED;
unsigned int ret = RC_PAIR_SOURCE_NONE;
for(chan = 0; chan < 3; chan++) {
swz = GET_SWZ(swizzle, chan);
if (swz == RC_SWIZZLE_W) {
ret |= RC_PAIR_SOURCE_ALPHA;
} else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
|| swz == RC_SWIZZLE_Z) {
ret |= RC_PAIR_SOURCE_RGB;
}
}
return ret;
}
struct rc_pair_instruction_source * rc_pair_get_src(
struct rc_pair_instruction * pair_inst,
struct rc_pair_instruction_arg * arg)
{
unsigned int type = rc_source_type_that_arg_reads(arg->Source,
arg->Swizzle);
if (type & RC_PAIR_SOURCE_RGB) {
unsigned int i, type;
unsigned int channels = 0;
for(i = 0; i < 3; i++) {
if (arg == pair_inst->RGB.Arg + i) {
channels = 3;
break;
}
}
if (channels == 0) {
for (i = 0; i < 3; i++) {
if (arg == pair_inst->Alpha.Arg + i) {
channels = 1;
break;
}
}
}
assert(channels > 0);
type = rc_source_type_swz(arg->Swizzle, channels);
if (type & RC_SOURCE_RGB) {
return &pair_inst->RGB.Src[arg->Source];
} else if (type & RC_PAIR_SOURCE_ALPHA) {
} else if (type & RC_SOURCE_ALPHA) {
return &pair_inst->Alpha.Src[arg->Source];
} else {
return NULL;
@@ -55,10 +55,6 @@ struct radeon_compiler;
*/
#define RC_PAIR_PRESUB_SRC 3
#define RC_PAIR_SOURCE_NONE 0x0
#define RC_PAIR_SOURCE_RGB 0x1
#define RC_PAIR_SOURCE_ALPHA 0x2
struct rc_pair_instruction_source {
unsigned int Used:1;
unsigned int File:3;
@@ -115,10 +111,6 @@ void rc_pair_foreach_source_that_rgb_reads(
void * data,
rc_pair_foreach_src_fn cb);
unsigned int rc_source_type_that_arg_reads(
unsigned int source,
unsigned int swizzle);
struct rc_pair_instruction_source * rc_pair_get_src(
struct rc_pair_instruction * pair_inst,
struct rc_pair_instruction_arg * arg);