r300/compiler: Track readers through branches in rc_get_readers()

This commit is contained in:
Tom Stellard
2010-11-06 11:30:27 -07:00
parent 255860113f
commit 681f56af80
4 changed files with 65 additions and 38 deletions
@@ -45,9 +45,6 @@
#include "radeon_program_pair.h"
#define MAX_BRANCH_DEPTH_FULL 32
#define MAX_BRANCH_DEPTH_PARTIAL 4
#define PROG_CODE \
struct r500_fragment_program_code *code = &c->code->code.r500
@@ -509,7 +506,7 @@ static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst
break;
}
case RC_OPCODE_IF:
if ( s->CurrentBranchDepth >= MAX_BRANCH_DEPTH_FULL) {
if ( s->CurrentBranchDepth >= R500_PFS_MAX_BRANCH_DEPTH_FULL) {
rc_error(s->C, "Branch depth exceeds hardware limit");
return;
}
@@ -34,6 +34,8 @@
#define R500_PFS_MAX_INST 512
#define R500_PFS_NUM_TEMP_REGS 128
#define R500_PFS_NUM_CONST_REGS 256
#define R500_PFS_MAX_BRANCH_DEPTH_FULL 32
#define R500_PFS_MAX_BRANCH_DEPTH_PARTIAL 4
#define STATE_R300_WINDOW_DIMENSION (STATE_INTERNAL_DRIVER+0)
@@ -461,6 +461,12 @@ static rc_opcode get_flow_control_inst(struct rc_instruction * inst)
}
struct branch_write_mask {
unsigned int IfWriteMask:4;
unsigned int ElseWriteMask:4;
unsigned int HasElse:1;
};
union get_readers_read_cb {
rc_read_src_fn I;
rc_pair_read_arg_fn P;
@@ -476,6 +482,8 @@ struct get_readers_callback_data {
unsigned int DstIndex;
unsigned int DstMask;
unsigned int AliveWriteMask;
/* For convenience, this is indexed starting at 1 */
struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1];
};
static void add_reader(
@@ -521,12 +529,12 @@ static unsigned int get_readers_read_callback(
/* If we make it this far, it means that this source reads from the
* same register written to by d->ReaderData->Writer. */
if (cb_data->ReaderData->AbortOnRead) {
read_mask = rc_swizzle_to_writemask(swizzle);
if (cb_data->ReaderData->AbortOnRead & read_mask) {
cb_data->ReaderData->Abort = 1;
return shared_mask;
}
read_mask = rc_swizzle_to_writemask(swizzle);
/* XXX The behavior in this case should be configurable. */
if ((read_mask & cb_data->AliveWriteMask) != read_mask) {
cb_data->ReaderData->Abort = 1;
@@ -605,22 +613,8 @@ static void get_readers_write_callback(
if (index == d->DstIndex && file == d->DstFile) {
unsigned int shared_mask = mask & d->DstMask;
if (d->ReaderData->InElse) {
if (shared_mask & d->AliveWriteMask) {
/* We set AbortOnRead here because the
* destination register of d->ReaderData->Writer
* is written to in both the IF and the
* ELSE block of this IF/ELSE statement.
* This means that readers of this
* destination register that follow this IF/ELSE
* statement use the value of different
* instructions depending on the control flow
* decisions made by the program. */
d->ReaderData->AbortOnRead = 1;
}
} else {
d->AliveWriteMask &= ~shared_mask;
}
d->ReaderData->AbortOnRead &= ~shared_mask;
d->AliveWriteMask &= ~shared_mask;
}
if(d->WriteCB)
@@ -645,6 +639,7 @@ static void get_readers_for_single_write(
d->DstIndex = dst_index;
d->DstMask = dst_mask;
d->AliveWriteMask = dst_mask;
memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
if (!dst_mask)
return;
@@ -670,21 +665,53 @@ static void get_readers_for_single_write(
d->ReaderData->Abort = 1;
return;
case RC_OPCODE_IF:
/* XXX We can do better here, but this will have to
* do until this dataflow analysis is more mature. */
d->ReaderData->Abort = 1;
branch_depth++;
if (branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
d->ReaderData->Abort = 1;
return;
}
d->BranchMasks[branch_depth].IfWriteMask =
d->AliveWriteMask;
break;
case RC_OPCODE_ELSE:
if (branch_depth == 0)
if (branch_depth == 0) {
d->ReaderData->InElse = 1;
} else {
unsigned int temp_mask = d->AliveWriteMask;
d->AliveWriteMask =
d->BranchMasks[branch_depth].IfWriteMask;
d->BranchMasks[branch_depth].ElseWriteMask =
temp_mask;
d->BranchMasks[branch_depth].HasElse = 1;
}
break;
case RC_OPCODE_ENDIF:
if (branch_depth == 0) {
d->ReaderData->AbortOnRead = 1;
d->ReaderData->AbortOnRead = d->AliveWriteMask;
d->ReaderData->InElse = 0;
}
else {
struct branch_write_mask * masks =
&d->BranchMasks[branch_depth];
if (masks->HasElse) {
d->ReaderData->AbortOnRead |=
masks->IfWriteMask
& ~masks->ElseWriteMask;
d->AliveWriteMask = masks->IfWriteMask
^ ((masks->IfWriteMask ^
masks->ElseWriteMask)
& (masks->IfWriteMask
^ d->AliveWriteMask));
} else {
d->ReaderData->AbortOnRead |=
masks->IfWriteMask
& ~d->AliveWriteMask;
d->AliveWriteMask = masks->IfWriteMask;
}
memset(masks, 0,
sizeof(struct branch_write_mask));
branch_depth--;
}
break;
@@ -692,21 +719,22 @@ static void get_readers_for_single_write(
break;
}
if (!d->ReaderData->InElse) {
if (tmp->Type == RC_INSTRUCTION_NORMAL) {
rc_for_all_reads_src(tmp,
get_readers_normal_read_callback, d);
} else {
rc_pair_for_all_reads_arg(tmp,
get_readers_pair_read_callback, d);
}
if (d->ReaderData->InElse)
continue;
if (tmp->Type == RC_INSTRUCTION_NORMAL) {
rc_for_all_reads_src(tmp,
get_readers_normal_read_callback, d);
} else {
rc_pair_for_all_reads_arg(tmp,
get_readers_pair_read_callback, d);
}
rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
if (d->ReaderData->Abort)
return;
if (!d->AliveWriteMask)
if (branch_depth == 0 && !d->AliveWriteMask)
return;
}
}
@@ -112,11 +112,11 @@ static void src_clobbered_reads_cb(
&& src->Index == sc_data->Index
&& (rc_swizzle_to_writemask(src->Swizzle) & sc_data->Mask)) {
sc_data->ReaderData->AbortOnRead = 1;
sc_data->ReaderData->AbortOnRead = RC_MASK_XYZW;
}
if (src->RelAddr && sc_data->File == RC_FILE_ADDRESS) {
sc_data->ReaderData->AbortOnRead = 1;
sc_data->ReaderData->AbortOnRead = RC_MASK_XYZW;
}
}