r300/compiler: Handle loops in rc_get_readers()
authorTom Stellard <tstellar@gmail.com>
Tue, 12 Apr 2011 23:08:25 +0000 (16:08 -0700)
committerTom Stellard <tstellar@gmail.com>
Sat, 30 Apr 2011 18:00:16 +0000 (11:00 -0700)
src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c
src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h

index ae61d20fb9bdc5b59a2ab29bf0b9e603db335cc0..ce7b008e7f10edc17b11d0b5f640a4eac58049ef 100644 (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;
+}
index 43ef87720920ddb53d072bbafd66a5403c06c835..0ba25aa96278d4628ffa5df3d5e4e199069dfaac 100644 (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 */
index 966b7f825f898aad137ede8e2478e116cd56081c..b94838e6c935703bed2b65c8183580a8bf2308e8 100644 (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)
index 6667ae1c4f3e9bec380da20b7575b087b8e22996..d8a627258ea3d81195d8d96bf73e2f10c81a1c48 100644 (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;