BRK instruction's BranchTarget field now used for efficiently breaking out of loops.
authorBrian <brian@yutani.localnet.net>
Tue, 6 Feb 2007 01:01:02 +0000 (18:01 -0700)
committerBrian <brian@yutani.localnet.net>
Tue, 6 Feb 2007 01:01:02 +0000 (18:01 -0700)
BRK's BranchTarget field actually points to the top of the loop, not the
bottom, since we don't know the later's location yet.  In the interpreter,
basically do an indirect jump to update the PC.

src/mesa/shader/prog_print.c
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/swrast/s_fragprog.c

index aea11da0db5b7c29c3a0264be58e81ce69f5b3d2..3d4a474b052a05fe191d3c1276def020c07e05b3 100644 (file)
@@ -332,17 +332,17 @@ _mesa_print_instruction(const struct prog_instruction *inst, GLint indent)
       _mesa_printf("ENDIF\n");
       break;
    case OPCODE_BGNLOOP:
-      _mesa_printf("BGNLOOP\n");
+      _mesa_printf("BGNLOOP (end at %d)\n", inst->BranchTarget);
       return indent + 3;
    case OPCODE_ENDLOOP:
       _mesa_printf("ENDLOOP (goto %d)\n", inst->BranchTarget);
       break;
    case OPCODE_BRK:
       /* XXX just like BRA */
-      _mesa_printf("BRK %u (%s%s)",
-                   inst->BranchTarget,
+      _mesa_printf("BRK (%s%s) (for loop beginning at %d)",
                    condcode_string(inst->DstReg.CondMask),
-                   swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
+                   swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
+                   inst->BranchTarget);
       print_comment(inst);
       break;
    case OPCODE_BGNSUB:
index 7a1881c68ee084c5eecd4b9e881b636a1d98201a..a5f033d91231c42ad026b56a3038837f787eb6ac 100644 (file)
@@ -590,6 +590,18 @@ new_end_loop(slang_ir_node *beginNode)
 }
 
 
+static slang_ir_node *
+new_break(slang_ir_node *beginNode)
+{
+   slang_ir_node *n = new_node(IR_BREAK, NULL, NULL);
+   assert(beginNode);
+   if (n) {
+      n->BranchNode = beginNode;
+   }
+   return n;
+}
+
+
 /**
  * Child[0] is the condition.
  * XXX we might re-design IR_IF so Children[1] is the "then" body and
@@ -1430,7 +1442,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
     *    IF !expr THEN
     *       BRK
     *    ENDIF
-    *    body code
+    *    body code (child[1])
     * ENDLOOP
     */
    slang_ir_node *beginLoop, *endLoop, *ifThen, *endif;
@@ -1445,7 +1457,7 @@ _slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
    ifThen = new_if(cond);
    tree = new_seq(beginLoop, ifThen);
 
-   brk = new_node(IR_BREAK, NULL, NULL);
+   brk = new_break(beginLoop);
    tree = new_seq(tree, brk);
 
    endif = new_endif(ifThen);
@@ -1571,6 +1583,73 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
 }
 
 
+/**
+ * Generate IR tree for a for-loop, using high-level BGNLOOP/ENDLOOP and
+ * IF/ENDIF instructions.
+ *
+ * XXX note done yet!
+ */
+static slang_ir_node *
+_slang_gen_hl_for(slang_assemble_ctx * A, const slang_operation *oper)
+{
+   /*
+    * init code (child[0])
+    * BGNLOOP
+    *    eval expr (child[1]), updating condcodes
+    *    IF !expr THEN
+    *       BRK
+    *    ENDIF
+    *    code body (child[3])
+    *    label "__continueFor"   // jump here for "continue"
+    *    incr code (child[2])
+    * ENDLOOP
+    */
+   slang_atom startAtom = slang_atom_pool_gen(A->atoms, "__startFor");
+   slang_atom contAtom = slang_atom_pool_gen(A->atoms, "__continueFor");
+   slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__endFor");
+   slang_ir_node *init, *startLab, *cond, *bra, *body, *contLab;
+   slang_ir_node *incr, *jump, *endLab, *tree;
+   slang_atom prevLoopBreak = A->CurLoopBreak;
+   slang_atom prevLoopCont = A->CurLoopCont;
+
+   /* Push this loop */
+   A->CurLoopBreak = endAtom;
+   A->CurLoopCont = contAtom;
+
+   init = _slang_gen_operation(A, &oper->children[0]);
+   startLab = new_label(startAtom);
+   tree = new_seq(init, startLab);
+
+   cond = _slang_gen_operation(A, &oper->children[1]);
+   cond = _slang_gen_cond(cond);
+   tree = new_seq(tree, cond);
+
+   bra = new_cjump(endAtom, 0);
+   tree = new_seq(tree, bra);
+
+   body = _slang_gen_operation(A, &oper->children[3]);
+   tree = new_seq(tree, body);
+
+   contLab = new_label(contAtom);
+   tree = new_seq(tree, contLab);
+
+   incr = _slang_gen_operation(A, &oper->children[2]);
+   tree = new_seq(tree, incr);
+
+   jump = new_jump(startAtom);
+   tree = new_seq(tree, jump);
+
+   endLab = new_label(endAtom);
+   tree = new_seq(tree, endLab);
+
+   /* Pop this loop */
+   A->CurLoopBreak = prevLoopBreak;
+   A->CurLoopCont = prevLoopCont;
+
+   return tree;
+}
+
+
 /**
  * Generate IR tree for an if/then/else conditional using BRAnch instructions.
  */
@@ -2378,16 +2457,21 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
    case slang_oper_do:
       return _slang_gen_do(A, oper);
    case slang_oper_for:
-      return _slang_gen_for(A, oper);
+      if (UseHighLevelInstructions)
+         return _slang_gen_hl_for(A, oper);
+      else
+         return _slang_gen_for(A, oper);
    case slang_oper_break:
       if (!A->CurLoopBreak) {
          RETURN_ERROR("'break' not in loop", 0);
       }
+      /* XXX emit IR_BREAK instruction */
       return new_jump(A->CurLoopBreak);
    case slang_oper_continue:
       if (!A->CurLoopCont) {
          RETURN_ERROR("'continue' not in loop", 0);
       }
+      /* XXX emit IR_CONT instruction */
       return new_jump(A->CurLoopCont);
    case slang_oper_discard:
       return new_node(IR_KILL, NULL, NULL);
index b890a6d93c29c5603aee748a6be2b6738f577ffa..3faacdd4cf84731cf3d9b9ae8e97862a9eef6689 100644 (file)
@@ -1265,24 +1265,29 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
       }
    case IR_ELSE:
       {
-         struct prog_instruction *inst;
+         struct prog_instruction *inst, *ifInst;
          n->InstLocation = prog->NumInstructions;
          inst = new_instruction(prog, OPCODE_ELSE);
          /* point IF's BranchTarget just after this instruction */
          assert(n->BranchNode);
          assert(n->BranchNode->InstLocation >= 0);
-         prog->Instructions[n->BranchNode->InstLocation].BranchTarget = prog->NumInstructions;
+         ifInst = prog->Instructions + n->BranchNode->InstLocation;
+         assert(ifInst->Opcode == OPCODE_IF);
+         ifInst->BranchTarget = prog->NumInstructions;
          return inst;
       }
    case IR_ENDIF:
       {
-         struct prog_instruction *inst;
+         struct prog_instruction *inst, *elseInst;
          n->InstLocation = prog->NumInstructions;
          inst = new_instruction(prog, OPCODE_ENDIF);
          /* point ELSE's BranchTarget to just after this inst */
          assert(n->BranchNode);
          assert(n->BranchNode->InstLocation >= 0);
-         prog->Instructions[n->BranchNode->InstLocation].BranchTarget = prog->NumInstructions;
+         elseInst = prog->Instructions + n->BranchNode->InstLocation;
+         assert(elseInst->Opcode == OPCODE_ELSE ||
+                elseInst->Opcode == OPCODE_IF);
+         elseInst->BranchTarget = prog->NumInstructions;
          return inst;
       }
 
@@ -1295,12 +1300,15 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
       break;
    case IR_END_LOOP:
       {
-         struct prog_instruction *inst;
+         struct prog_instruction *inst, *beginInst;
          inst = new_instruction(prog, OPCODE_ENDLOOP);
          assert(n->BranchNode);
          assert(n->BranchNode->InstLocation >= 0);
          /* The instruction BranchTarget points to top of loop */
          inst->BranchTarget = n->BranchNode->InstLocation;
+         /* Update BEGIN_LOOP's BranchTarget to point to this instruction */
+         beginInst = prog->Instructions + n->BranchNode->InstLocation;
+         beginInst->BranchTarget = prog->NumInstructions - 1;
          return inst;
       }
    case IR_CONT:
@@ -1310,6 +1318,12 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
          struct prog_instruction *inst;
          inst = new_instruction(prog, OPCODE_BRK);
          inst->DstReg.CondMask = COND_TR;  /* always true */
+         /* This instruction's branch target is top of loop, not bottom of
+          * loop because we don't know where it is yet!
+          */
+         assert(n->BranchNode);
+         assert(n->BranchNode->InstLocation >= 0);
+         inst->BranchTarget = n->BranchNode->InstLocation;
          return inst;
       }
    case IR_BEGIN_SUB:
index fbd25c0fbfe99d592f6a191885eac5f5e1270c35..12c8aee6ea0c5c38c8fb9991b2c95930081a7c98 100644 (file)
@@ -625,7 +625,7 @@ execute_program( GLcontext *ctx,
                  GLuint column )
 {
    const GLuint MAX_EXEC = 10000;
-   GLint pc, total = 0, loopDepth = 0;
+   GLint pc, total = 0;
 
    if (DEBUG_FRAG) {
       printf("execute fragment program --------------------\n");
@@ -676,11 +676,8 @@ execute_program( GLcontext *ctx,
             }
             break;
          case OPCODE_BGNLOOP: /* begin loop */
-            loopDepth++;
             break;
          case OPCODE_ENDLOOP: /* end loop */
-            loopDepth--;
-            assert(loopDepth >= 0);
             /* subtract 1 here since pc is incremented by for(pc) loop */
             pc = inst->BranchTarget - 1; /* go to matching BNGLOOP */
             break;
@@ -706,19 +703,18 @@ execute_program( GLcontext *ctx,
             }
             break;
          case OPCODE_BRK: /* break out of loop */
-            if (loopDepth == 0) {
-               _mesa_problem(ctx, "BRK not inside a loop");
-            }
-            /* search for OPCODE_ENDLOOP */
-            do {
-               pc++;
-               inst = program->Base.Instructions + pc;
-               if (inst->Opcode == OPCODE_ENDLOOP) {
-                  loopDepth--;
-                  assert(loopDepth >= 0);
-                  break;
-               }
-            } while (pc < maxInst);
+            {
+               /* The location of the ENDLOOP instruction is saved in the
+                * BGNLOOP instruction.  Get that instruction and jump to
+                * its BranchTarget + 1.
+                */
+               const struct prog_instruction *loopBeginInst
+                  = program->Base.Instructions + inst->BranchTarget;
+               ASSERT(loopBeginInst->Opcode == OPCODE_BGNLOOP);
+               ASSERT(loopBeginInst->BranchTarget >= 0);
+               /* we'll add one at bottom of for-loop */
+               pc = loopBeginInst->BranchTarget;
+            }
             break;
          case OPCODE_CAL: /* Call subroutine */
             {