mesa: Branch 'glsl-compiler-1'

Brian Paul brianp at kemper.freedesktop.org
Tue Feb 6 01:01:12 UTC 2007


 src/mesa/shader/prog_print.c          |    8 +--
 src/mesa/shader/slang/slang_codegen.c |   90 ++++++++++++++++++++++++++++++++--
 src/mesa/shader/slang/slang_emit.c    |   24 +++++++--
 src/mesa/swrast/s_fragprog.c          |   28 ++++------
 4 files changed, 122 insertions(+), 28 deletions(-)

New commits:
diff-tree 2755c798f3cb89fcd4ece16cd740af1cd86a6b99 (from 86080796471df6a9e126fd536b21c3b10cb5310c)
Author: Brian <brian at yutani.localnet.net>
Date:   Mon Feb 5 18:01:02 2007 -0700

    BRK instruction's BranchTarget field now used for efficiently breaking out of loops.
    
    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.

diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c
index aea11da..3d4a474 100644
--- a/src/mesa/shader/prog_print.c
+++ b/src/mesa/shader/prog_print.c
@@ -332,17 +332,17 @@ _mesa_print_instruction(const struct pro
       _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:
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 7a1881c..a5f033d 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -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 *
     *    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 *
    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);
@@ -1572,6 +1584,73 @@ _slang_gen_for(slang_assemble_ctx * A, c
 
 
 /**
+ * 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.
  */
 static slang_ir_node *
@@ -2378,16 +2457,21 @@ _slang_gen_operation(slang_assemble_ctx 
    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);
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index b890a6d..3faacdd 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -1265,24 +1265,29 @@ emit(slang_var_table *vt, slang_ir_node 
       }
    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 
       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 
          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:
diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c
index fbd25c0..12c8aee 100644
--- a/src/mesa/swrast/s_fragprog.c
+++ b/src/mesa/swrast/s_fragprog.c
@@ -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");
+            {
+               /* 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;
             }
-            /* search for OPCODE_ENDLOOP */
-            do {
-               pc++;
-               inst = program->Base.Instructions + pc;
-               if (inst->Opcode == OPCODE_ENDLOOP) {
-                  loopDepth--;
-                  assert(loopDepth >= 0);
-                  break;
-               }
-            } while (pc < maxInst);
             break;
          case OPCODE_CAL: /* Call subroutine */
             {



More information about the mesa-commit mailing list