r300/compiler: Handle loops in rc_get_readers()

This commit is contained in:
Tom Stellard 2011-04-12 16:08:25 -07:00
parent fe622bac0c
commit ac952a11df
4 changed files with 150 additions and 75 deletions

View file

@ -537,3 +537,49 @@ unsigned int rc_pair_remove_src(
return 1;
}
/**
* @return RC_OPCODE_NOOP if inst is not a flow control instruction.
* @return The opcode of inst if it is a flow control instruction.
*/
rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst)
{
const struct rc_opcode_info * info;
if (inst->Type == RC_INSTRUCTION_NORMAL) {
info = rc_get_opcode_info(inst->U.I.Opcode);
} else {
info = rc_get_opcode_info(inst->U.P.RGB.Opcode);
/*A flow control instruction shouldn't have an alpha
* instruction.*/
assert(!info->IsFlowControl ||
inst->U.P.Alpha.Opcode == RC_OPCODE_NOP);
}
if (info->IsFlowControl)
return info->Opcode;
else
return RC_OPCODE_NOP;
}
/**
* @return The BGNLOOP instruction that starts the loop ended by endloop.
*/
struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop)
{
unsigned int endloop_count = 0;
struct rc_instruction * inst;
for (inst = endloop->Prev; inst != endloop; inst = inst->Prev) {
rc_opcode op = rc_get_flow_control_inst(inst);
if (op == RC_OPCODE_ENDLOOP) {
endloop_count++;
} else if (op == RC_OPCODE_BGNLOOP) {
if (endloop_count == 0) {
return inst;
} else {
endloop_count--;
}
}
}
return NULL;
}

View file

@ -3,6 +3,8 @@
#ifndef RADEON_PROGRAM_UTIL_H
#define RADEON_PROGRAM_UTIL_H
#include "radeon_opcodes.h"
struct radeon_compiler;
struct rc_instruction;
struct rc_pair_instruction;
@ -71,4 +73,8 @@ unsigned int rc_pair_remove_src(
unsigned int source,
unsigned int new_readmask);
rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst);
struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop);
#endif /* RADEON_PROGRAM_UTIL_H */

View file

@ -449,30 +449,6 @@ void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, v
remap_pair_instruction(inst, cb, userdata);
}
/**
* @return RC_OPCODE_NOOP if inst is not a flow control instruction.
* @return The opcode of inst if it is a flow control instruction.
*/
static rc_opcode get_flow_control_inst(struct rc_instruction * inst)
{
const struct rc_opcode_info * info;
if (inst->Type == RC_INSTRUCTION_NORMAL) {
info = rc_get_opcode_info(inst->U.I.Opcode);
} else {
info = rc_get_opcode_info(inst->U.P.RGB.Opcode);
/*A flow control instruction shouldn't have an alpha
* instruction.*/
assert(!info->IsFlowControl ||
inst->U.P.Alpha.Opcode == RC_OPCODE_NOP);
}
if (info->IsFlowControl)
return info->Opcode;
else
return RC_OPCODE_NOP;
}
struct branch_write_mask {
unsigned int IfWriteMask:4;
unsigned int ElseWriteMask:4;
@ -567,6 +543,11 @@ static unsigned int get_readers_read_callback(
return shared_mask;
}
if (cb_data->ReaderData->LoopDepth > 0) {
cb_data->ReaderData->AbortOnWrite |=
(read_mask & cb_data->AliveWriteMask);
}
/* XXX The behavior in this case should be configurable. */
if ((read_mask & cb_data->AliveWriteMask) != read_mask) {
cb_data->ReaderData->Abort = 1;
@ -649,12 +630,57 @@ static void get_readers_write_callback(
unsigned int shared_mask = mask & d->DstMask;
d->ReaderData->AbortOnRead &= ~shared_mask;
d->AliveWriteMask &= ~shared_mask;
if (d->ReaderData->AbortOnWrite & shared_mask) {
d->ReaderData->Abort = 1;
}
}
if(d->WriteCB)
d->WriteCB(d->ReaderData, inst, file, index, mask);
}
static void push_branch_mask(
struct get_readers_callback_data * d,
unsigned int * branch_depth)
{
(*branch_depth)++;
if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
d->ReaderData->Abort = 1;
return;
}
d->BranchMasks[*branch_depth].IfWriteMask =
d->AliveWriteMask;
}
static void pop_branch_mask(
struct get_readers_callback_data * d,
unsigned int * branch_depth)
{
struct branch_write_mask * masks = &d->BranchMasks[*branch_depth];
if (masks->HasElse) {
/* Abort on read for components that were written in the IF
* block. */
d->ReaderData->AbortOnRead |=
masks->IfWriteMask & ~masks->ElseWriteMask;
/* Abort on read for components that were written in the ELSE
* block. */
d->ReaderData->AbortOnRead |=
masks->ElseWriteMask & ~d->AliveWriteMask;
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)--;
}
static void get_readers_for_single_write(
void * userdata,
struct rc_instruction * writer,
@ -664,10 +690,14 @@ static void get_readers_for_single_write(
{
struct rc_instruction * tmp;
unsigned int branch_depth = 0;
struct rc_instruction * endloop = NULL;
unsigned int abort_on_read_at_endloop;
struct get_readers_callback_data * d = userdata;
d->ReaderData->Writer = writer;
d->ReaderData->AbortOnRead = 0;
d->ReaderData->AbortOnWrite = 0;
d->ReaderData->LoopDepth = 0;
d->ReaderData->InElse = 0;
d->DstFile = dst_file;
d->DstIndex = dst_index;
@ -680,32 +710,43 @@ static void get_readers_for_single_write(
for(tmp = writer->Next; tmp != &d->C->Program.Instructions;
tmp = tmp->Next){
rc_opcode opcode = get_flow_control_inst(tmp);
rc_opcode opcode = rc_get_flow_control_inst(tmp);
switch(opcode) {
case RC_OPCODE_BGNLOOP:
/* XXX We can do better when we see a BGNLOOP if we
* add a flag called AbortOnWrite to struct
* rc_reader_data and leave it set until the next
* ENDLOOP. */
d->ReaderData->LoopDepth++;
push_branch_mask(d, &branch_depth);
break;
case RC_OPCODE_ENDLOOP:
/* XXX We can do better when we see an ENDLOOP by
* searching backwards from writer and looking for
* readers of writer's destination index. If we find a
* reader before we get to the BGNLOOP, we must abort
* unless there is another writer between that reader
* and the BGNLOOP. */
case RC_OPCODE_BRK:
case RC_OPCODE_CONT:
d->ReaderData->Abort = 1;
return;
case RC_OPCODE_IF:
branch_depth++;
if (branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
d->ReaderData->Abort = 1;
return;
if (d->ReaderData->LoopDepth > 0) {
d->ReaderData->LoopDepth--;
if (d->ReaderData->LoopDepth == 0) {
d->ReaderData->AbortOnWrite = 0;
}
pop_branch_mask(d, &branch_depth);
} else {
/* Here we have reached an ENDLOOP without
* seeing its BGNLOOP. These means that
* the writer was written inside of a loop,
* so it could have readers that are above it
* (i.e. they have a lower IP). To find these
* readers we jump to the BGNLOOP instruction
* and check each instruction until we get
* back to the writer.
*/
endloop = tmp;
tmp = rc_match_endloop(tmp);
if (!tmp) {
rc_error(d->C, "Failed to match endloop.\n");
d->ReaderData->Abort = 1;
return;
}
abort_on_read_at_endloop = d->ReaderData->AbortOnRead;
d->ReaderData->AbortOnRead |= d->AliveWriteMask;
continue;
}
d->BranchMasks[branch_depth].IfWriteMask =
d->AliveWriteMask;
break;
case RC_OPCODE_IF:
push_branch_mask(d, &branch_depth);
break;
case RC_OPCODE_ELSE:
if (branch_depth == 0) {
@ -725,35 +766,7 @@ static void get_readers_for_single_write(
d->ReaderData->InElse = 0;
}
else {
struct branch_write_mask * masks =
&d->BranchMasks[branch_depth];
if (masks->HasElse) {
/* Abort on read for components that
* were written in the IF block. */
d->ReaderData->AbortOnRead |=
masks->IfWriteMask
& ~masks->ElseWriteMask;
/* Abort on read for components that
* were written in the ELSE block. */
d->ReaderData->AbortOnRead |=
masks->ElseWriteMask
& ~d->AliveWriteMask;
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--;
pop_branch_mask(d, &branch_depth);
}
break;
default:
@ -770,6 +783,14 @@ static void get_readers_for_single_write(
rc_pair_for_all_reads_arg(tmp,
get_readers_pair_read_callback, d);
}
/* This can happen when we jump from an ENDLOOP to BGNLOOP */
if (tmp == writer) {
tmp = endloop;
endloop = NULL;
d->ReaderData->AbortOnRead = abort_on_read_at_endloop;
continue;
}
rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)

View file

@ -88,6 +88,8 @@ struct rc_reader {
struct rc_reader_data {
unsigned int Abort;
unsigned int AbortOnRead;
unsigned int AbortOnWrite;
unsigned int LoopDepth;
unsigned int InElse;
struct rc_instruction * Writer;