}
+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;
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(
/* 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;
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)
d->DstIndex = dst_index;
d->DstMask = dst_mask;
d->AliveWriteMask = dst_mask;
+ memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
if (!dst_mask)
return;
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;
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;
}
}