mesa: Branch 'glsl-compiler-1' - 5 commits

Brian Paul brianp at kemper.freedesktop.org
Fri Mar 23 23:49:30 UTC 2007


 docs/shading.html                     |   46 +++++++
 src/mesa/main/mtypes.h                |    6 -
 src/mesa/shader/prog_execute.c        |   53 +++++++--
 src/mesa/shader/prog_instruction.c    |    6 -
 src/mesa/shader/prog_instruction.h    |    4 
 src/mesa/shader/prog_print.c          |   37 ++++--
 src/mesa/shader/shader_api.c          |    1 
 src/mesa/shader/slang/slang_codegen.c |   90 ++++++++-------
 src/mesa/shader/slang/slang_emit.c    |  198 +++++++++++++++++++++++++---------
 src/mesa/shader/slang/slang_ir.h      |   11 +
 src/mesa/tnl/t_vb_arbprogram.c        |    4 
 11 files changed, 347 insertions(+), 109 deletions(-)

New commits:
diff-tree 8f9db0f81c13c3244f07333f33a15bfe098e0f31 (from d1934c2065751e2c594316c5abd2c49c47bfc1b8)
Author: Brian <brian at yutani.localnet.net>
Date:   Fri Mar 23 17:49:19 2007 -0600

    document internal compiler options

diff --git a/docs/shading.html b/docs/shading.html
index cb2c1c3..40a6d7a 100644
--- a/docs/shading.html
+++ b/docs/shading.html
@@ -67,7 +67,7 @@ All other major features of the shading 
 <li>The quality of generated code is pretty good, register usage is fair.
 <li>Shader error detection and reporting of errors (InfoLog) is not
     very good yet.
-<li>There are massive memory leaks in the compiler.
+<li>There are known memory leaks in the compiler.
 </ul>
 
 <p>
@@ -236,6 +236,50 @@ The final vertex and fragment programs m
 (see drivers/dri/i915/i915_fragprog.c for example).
 </p>
 
+<h3>Code Generation Options</h3>
+
+<p>
+Internally, there are several options that control the compiler's code
+generation and instruction selection.
+These options are seen in the gl_shader_state struct and may be set
+by the device driver to indicate its preferences:
+
+<pre>
+struct gl_shader_state
+{
+   ...
+   /** Driver-selectable options: */
+   GLboolean EmitHighLevelInstructions;
+   GLboolean EmitCondCodes;
+   GLboolean EmitComments;
+};
+</pre>
+
+<ul>
+<li>EmitHighLevelInstructions
+<br>
+This option controls instruction selection for loops and conditionals.
+If the option is set high-level IF/ELSE/ENDIF, LOOP/ENDLOOP, CONT/BRK
+instructions will be emitted.
+Otherwise, those constructs will be implemented with BRA instructions.
+</li>
+
+<li>EmitCondCodes
+<br>
+If set, condition codes (ala GL_NV_fragment_program) will be used for
+branching and looping.
+Otherwise, ordinary registers will be used (the IF instruction will
+examine the first operand's X component and do the if-part if non-zero).
+This option is only relevant if EmitHighLevelInstructions is set.
+</li>
+
+<li>EmitComments
+<br>
+If set, instructions will be annoted with comments to help with debugging.
+Extra NOP instructions will also be inserted.
+</br>
+
+</ul>
 
 
 </BODY>
diff-tree d1934c2065751e2c594316c5abd2c49c47bfc1b8 (from 81767eead9e1b1b5d5dfd274c0875fa1332a5983)
Author: Brian <brian at yutani.localnet.net>
Date:   Fri Mar 23 17:48:42 2007 -0600

    Fix issues related to the 'continue' statement.
    
    IR_LOOP now has two children: the body code, and the tail code.
    Tail code is the "i++" part of a for-loop, or the expression at the end
    of a "do {} while(expr);" loop.
    "continue" translates into: "execute tail code; CONT;"
    Also, the test for infinite do/while loops was incorrect.

diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 4e41aa8..2eb509b 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -414,7 +414,7 @@ _slang_free_ir_tree(slang_ir_node *n)
       return;
    for (i = 0; i < 3; i++)
       _slang_free_ir_tree(n->Children[i]);
-   /* Do not free n->BranchNode since it's a child elsewhere */
+   /* Do not free n->List since it's a child elsewhere */
    free(n);
 #endif
 }
@@ -515,8 +515,8 @@ new_break(slang_ir_node *loopNode)
    assert(loopNode->Opcode == IR_LOOP);
    if (n) {
       /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
+      n->List = loopNode->List;
+      loopNode->List = n;
    }
    return n;
 }
@@ -534,8 +534,8 @@ new_break_if(slang_ir_node *loopNode, sl
    n = new_node1(breakTrue ? IR_BREAK_IF_TRUE : IR_BREAK_IF_FALSE, cond);
    if (n) {
       /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
+      n->List = loopNode->List;
+      loopNode->List = n;
    }
    return n;
 }
@@ -553,23 +553,8 @@ new_cont_if(slang_ir_node *loopNode, sla
    n = new_node1(contTrue ? IR_CONT_IF_TRUE : IR_CONT_IF_FALSE, cond);
    if (n) {
       /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
-   }
-   return n;
-}
-
-
-static slang_ir_node *
-new_cont(slang_ir_node *loopNode)
-{
-   slang_ir_node *n = new_node0(IR_CONT);
-   assert(loopNode);
-   assert(loopNode->Opcode == IR_LOOP);
-   if (n) {
-      /* insert this node at head of linked list */
-      n->BranchNode = loopNode->BranchNode;
-      loopNode->BranchNode = n;
+      n->List = loopNode->List;
+      loopNode->List = n;
    }
    return n;
 }
@@ -1369,7 +1354,8 @@ _slang_gen_while(slang_assemble_ctx * A,
    loop->Children[0] = new_seq(breakIf, body);
 
    /* Do infinite loop detection */
-   if (!loop->BranchNode && isConst && constTrue) {
+   /* loop->List is head of linked list of break/continue nodes */
+   if (!loop->List && isConst && constTrue) {
       /* infinite loop detected */
       A->CurLoop = prevLoop; /* clean-up */
       slang_info_log_error(A->log, "Infinite loop detected!");
@@ -1392,30 +1378,33 @@ _slang_gen_do(slang_assemble_ctx * A, co
    /*
     * LOOP:
     *    body code (child[0])
-    *    BREAK if !expr (child[1])
+    *    tail code:
+    *       BREAK if !expr (child[1])
     */
-   slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+   slang_ir_node *prevLoop, *loop, *cond;
    GLboolean isConst, constTrue;
 
-   /* Check if loop condition is a constant */
-   isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
-
    loop = new_loop(NULL);
 
    /* save old, push new loop */
    prevLoop = A->CurLoop;
    A->CurLoop = loop;
 
-   body = _slang_gen_operation(A, &oper->children[0]);
-   cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
+   /* loop body: */
+   loop->Children[0] = _slang_gen_operation(A, &oper->children[0]);
+
+   /* Check if loop condition is a constant */
+   isConst = _slang_is_constant_cond(&oper->children[1], &constTrue);
    if (isConst && constTrue) {
-      /* while(nonzero constant), no conditional break */
-      breakIf = NULL;
+      /* do { } while(1)   ==> no conditional break */
+      loop->Children[1] = NULL; /* no tail code */
    }
    else {
-      breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+      cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
+      loop->Children[1] = new_break_if(A->CurLoop, cond, GL_FALSE);
    }
-   loop->Children[0] = new_seq(body, breakIf);
+
+   /* XXX we should do infinite loop detection, as above */
 
    /* pop loop, restore prev */
    A->CurLoop = prevLoop;
@@ -1431,11 +1420,12 @@ static slang_ir_node *
 _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
 {
    /*
-    * init (child[0])
+    * init code (child[0])
     * LOOP:
     *    BREAK if !expr (child[1])
     *    body code (child[3])
-    *    incr code (child[2])   // XXX continue here
+    *    tail code:
+    *       incr code (child[2])   // XXX continue here
     */
    slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
 
@@ -1450,8 +1440,9 @@ _slang_gen_for(slang_assemble_ctx * A, c
    breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
    body = _slang_gen_operation(A, &oper->children[3]);
    incr = _slang_gen_operation(A, &oper->children[2]);
-   loop->Children[0] = new_seq(breakIf,
-                               new_seq(body, incr));
+
+   loop->Children[0] = new_seq(breakIf, body);
+   loop->Children[1] = incr;  /* tail code */
 
    /* pop loop, restore prev */
    A->CurLoop = prevLoop;
@@ -1460,6 +1451,25 @@ _slang_gen_for(slang_assemble_ctx * A, c
 }
 
 
+static slang_ir_node *
+_slang_gen_continue(slang_assemble_ctx * A, const slang_operation *oper)
+{
+   slang_ir_node *n, *loopNode;
+   assert(oper->type == SLANG_OPER_CONTINUE);
+   loopNode = A->CurLoop;
+   assert(loopNode);
+   assert(loopNode->Opcode == IR_LOOP);
+   n = new_node0(IR_CONT);
+   if (n) {
+      n->Parent = loopNode;
+      /* insert this node at head of linked list */
+      n->List = loopNode->List;
+      loopNode->List = n;
+   }
+   return n;
+}
+
+
 /**
  * Determine if the given operation is of a specific type.
  */
@@ -2364,7 +2374,7 @@ _slang_gen_operation(slang_assemble_ctx 
       if (!A->CurLoop) {
          slang_info_log_error(A->log, "'continue' not in loop");
       }
-      return new_cont(A->CurLoop);
+      return _slang_gen_continue(A, oper);
    case SLANG_OPER_DISCARD:
       return new_node0(IR_KILL);
 
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index 9e476b8..6ec20da 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -316,6 +316,7 @@ slang_print_ir(const slang_ir_node *n, i
          printf("ELSE\n");
          slang_print_ir(n->Children[2], indent+3);
       }
+      spaces(indent);
       printf("ENDIF\n");
       break;
 
@@ -335,6 +336,11 @@ slang_print_ir(const slang_ir_node *n, i
    case IR_LOOP:
       printf("LOOP\n");
       slang_print_ir(n->Children[0], indent+3);
+      if (n->Children[1]) {
+         spaces(indent);
+         printf("TAIL:\n");
+         slang_print_ir(n->Children[1], indent+3);
+      }
       spaces(indent);
       printf("ENDLOOP\n");
       break;
@@ -685,6 +691,19 @@ instruction_annotation(gl_inst_opcode op
 }
 
 
+/**
+ * Emit an instruction that's just a comment.
+ */
+static struct prog_instruction *
+emit_comment(slang_emit_info *emitInfo, const char *s)
+{
+   struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP);
+   if (inst) {
+      inst->Comment = _mesa_strdup(s);
+   }
+   return inst;
+}
+
 
 /**
  * Generate code for a simple arithmetic instruction.
@@ -1005,9 +1024,16 @@ static struct prog_instruction *
 emit_label(slang_emit_info *emitInfo, const slang_ir_node *n)
 {
    assert(n->Label);
+#if 0
+   /* XXX this fails in loop tail code - investigate someday */
    assert(_slang_label_get_location(n->Label) < 0);
    _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions,
                              emitInfo->prog);
+#else
+   if (_slang_label_get_location(n->Label) < 0)
+      _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions,
+                                emitInfo->prog);
+#endif
    return NULL;
 }
 
@@ -1097,7 +1123,9 @@ emit_move(slang_emit_info *emitInfo, sla
 
    assert(n->Children[1]->Store->Index >= 0);
 
+#if 0
    assert(!n->Store);
+#endif
    n->Store = n->Children[0]->Store;
 
 #if PEEPHOLE_OPTIMIZATIONS
@@ -1316,9 +1344,11 @@ emit_loop(slang_emit_info *emitInfo, sla
 {
    struct gl_program *prog = emitInfo->prog;
    struct prog_instruction *beginInst, *endInst;
-   GLuint beginInstLoc, endInstLoc;
+   GLuint beginInstLoc, tailInstLoc, endInstLoc;
    slang_ir_node *ir;
 
+   slang_print_ir(n, 10);
+
    /* emit OPCODE_BGNLOOP */
    beginInstLoc = prog->NumInstructions;
    if (emitInfo->EmitHighLevelInstructions) {
@@ -1328,6 +1358,14 @@ emit_loop(slang_emit_info *emitInfo, sla
    /* body */
    emit(emitInfo, n->Children[0]);
 
+   /* tail */
+   tailInstLoc = prog->NumInstructions;
+   if (n->Children[1]) {
+      if (emitInfo->EmitComments)
+         emit_comment(emitInfo, "Loop tail code:");
+      emit(emitInfo, n->Children[1]);
+   }
+
    endInstLoc = prog->NumInstructions;
    if (emitInfo->EmitHighLevelInstructions) {
       /* emit OPCODE_ENDLOOP */
@@ -1338,7 +1376,7 @@ emit_loop(slang_emit_info *emitInfo, sla
       endInst = new_instruction(emitInfo, OPCODE_BRA);
       endInst->DstReg.CondMask = COND_TR;  /* always true */
    }
-   /* end instruction's BranchTarget points to top of loop */
+   /* ENDLOOP's BranchTarget points to the BGNLOOP inst */
    endInst->BranchTarget = beginInstLoc;
 
    if (emitInfo->EmitHighLevelInstructions) {
@@ -1351,7 +1389,7 @@ emit_loop(slang_emit_info *emitInfo, sla
     * BREAK and CONT nodes, filling in their BranchTarget fields (which
     * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively).
     */
-   for (ir = n->BranchNode; ir; ir = ir->BranchNode) {
+   for (ir = n->List; ir; ir = ir->List) {
       struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
       assert(inst->BranchTarget < 0);
       if (ir->Opcode == IR_BREAK ||
@@ -1372,8 +1410,8 @@ emit_loop(slang_emit_info *emitInfo, sla
                 inst->Opcode == OPCODE_CONT0 ||
                 inst->Opcode == OPCODE_CONT1 ||
                 inst->Opcode == OPCODE_BRA);
-         /* to go instruction at top of loop */
-         inst->BranchTarget = beginInstLoc;
+         /* go to instruction at tail of loop */
+         inst->BranchTarget = endInstLoc;
       }
    }
    return NULL;
@@ -1389,13 +1427,28 @@ emit_cont_break(slang_emit_info *emitInf
 {
    gl_inst_opcode opcode;
    struct prog_instruction *inst;
-   n->InstLocation = emitInfo->prog->NumInstructions;
+
+   if (n->Opcode == IR_CONT) {
+      /* we need to execute the loop's tail code before doing CONT */
+      assert(n->Parent);
+      assert(n->Parent->Opcode == IR_LOOP);
+      if (n->Parent->Children[1]) {
+         /* emit tail code */
+         if (emitInfo->EmitComments) {
+            emit_comment(emitInfo, "continue - tail code:");
+         }
+         emit(emitInfo, n->Parent->Children[1]);
+      }
+   }
+
+   /* opcode selection */
    if (emitInfo->EmitHighLevelInstructions) {
       opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
    }
    else {
       opcode = OPCODE_BRA;
    }
+   n->InstLocation = emitInfo->prog->NumInstructions;
    inst = new_instruction(emitInfo, opcode);
    inst->DstReg.CondMask = COND_TR;  /* always true */
    return inst;
@@ -1456,7 +1509,7 @@ emit_cont_break_if(slang_emit_info *emit
       inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
    }
    else {
-      /* BRK0, BRK1, CONT0, CONT1 */
+      /* BRK0, BRK1, CONT0, CONT1 uses SrcReg[0] as the condition */
       storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
    }
    return inst;
@@ -1607,7 +1660,9 @@ emit(slang_emit_info *emitInfo, slang_ir
       assert(n->Children[1]);
       emit(emitInfo, n->Children[0]);
       inst = emit(emitInfo, n->Children[1]);
+#if 0
       assert(!n->Store);
+#endif
       n->Store = n->Children[1]->Store;
       return inst;
 
@@ -1623,10 +1678,11 @@ emit(slang_emit_info *emitInfo, slang_ir
       assert(n->Store);
       assert(n->Store->File != PROGRAM_UNDEFINED);
       assert(n->Store->Size > 0);
-      assert(n->Store->Index < 0);
+      /*assert(n->Store->Index < 0);*/
       if (!n->Var || n->Var->isTemp) {
          /* a nameless/temporary variable, will be freed after first use */
-         if (!_slang_alloc_temp(emitInfo->vt, n->Store)) {
+         /*NEW*/
+         if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) {
             slang_info_log_error(emitInfo->log,
                                  "Ran out of registers, too many temporaries");
             return NULL;
@@ -1654,8 +1710,7 @@ emit(slang_emit_info *emitInfo, slang_ir
                  _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), 
                  (n->Var ? (char *) n->Var->a_name : "anonymous"),
                  n->Store->Size);
-         inst = new_instruction(emitInfo, OPCODE_NOP);
-         inst->Comment = _mesa_strdup(s);
+         inst = emit_comment(emitInfo, s);
          return inst;
       }
       return NULL;
@@ -1828,7 +1883,7 @@ _slang_emit_code(slang_ir_node *n, slang
 
    emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
    emitInfo.EmitCondCodes = 0; /* XXX temporary! */
-   emitInfo.EmitComments = ctx->Shader.EmitComments;
+   emitInfo.EmitComments = 1 + ctx->Shader.EmitComments;
 
    (void) emit(&emitInfo, n);
 
diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h
index cc9df69..37dd38e 100644
--- a/src/mesa/shader/slang/slang_ir.h
+++ b/src/mesa/shader/slang/slang_ir.h
@@ -53,6 +53,9 @@ typedef enum
    IR_COND,    /* conditional expression/predicate */
 
    IR_IF,      /* high-level IF/then/else */
+               /* Children[0] = conditional expression */
+               /* Children[1] = if-true part */
+               /* Children[2] = if-else part, or NULL */
 
    IR_BEGIN_SUB, /* begin subroutine */
    IR_END_SUB,   /* end subroutine */
@@ -60,13 +63,18 @@ typedef enum
    IR_CALL,      /* call subroutine */
 
    IR_LOOP,      /* high-level loop-begin / loop-end */
+                 /* Children[0] = loop body */
+                 /* Children[1] = loop tail code, or NULL */
+
    IR_CONT,      /* continue loop */
+                 /* n->Parent = ptr to parent IR_LOOP Node */
    IR_BREAK,     /* break loop */
 
    IR_BREAK_IF_TRUE,
    IR_BREAK_IF_FALSE,
    IR_CONT_IF_TRUE,
    IR_CONT_IF_FALSE,
+                 /* Children[0] = the condition expression */
 
    IR_MOVE,
 
@@ -161,7 +169,8 @@ typedef struct slang_ir_node_
    GLuint Writemask;  /**< If Opcode == IR_MOVE */
    GLfloat Value[4];    /**< If Opcode == IR_FLOAT */
    slang_variable *Var;  /**< If Opcode == IR_VAR or IR_VAR_DECL */
-   struct slang_ir_node_ *BranchNode;  /**< Used for branching instructions */
+   struct slang_ir_node_ *List;  /**< For various linked lists */
+   struct slang_ir_node_ *Parent;  /**< Pointer to logical parent (ie. loop) */
    slang_label *Label;  /**< Used for branches */
 } slang_ir_node;
 
diff-tree 81767eead9e1b1b5d5dfd274c0875fa1332a5983 (from 63556fa9949f543a8134b6b5ff3d216acb71dd9f)
Author: Brian <brian at yutani.localnet.net>
Date:   Fri Mar 23 17:45:53 2007 -0600

    consolidate some code

diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c
index 39d2a07..3f7ad47 100644
--- a/src/mesa/shader/prog_print.c
+++ b/src/mesa/shader/prog_print.c
@@ -601,14 +601,9 @@ _mesa_print_instruction_opt(const struct
       _mesa_printf("ENDLOOP; # (goto %d)\n", inst->BranchTarget);
       break;
    case OPCODE_BRK:
-      _mesa_printf("BRK (%s%s); #(goto %d)",
-                   condcode_string(inst->DstReg.CondMask),
-                   _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
-                   inst->BranchTarget);
-      print_comment(inst);
-      break;
    case OPCODE_CONT:
-      _mesa_printf("CONT (%s%s); #(goto %d)",
+      _mesa_printf("%s (%s%s); # (goto %d)",
+                   _mesa_opcode_string(inst->Opcode),
                    condcode_string(inst->DstReg.CondMask),
                    _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
                    inst->BranchTarget);
diff-tree 63556fa9949f543a8134b6b5ff3d216acb71dd9f (from bf020d8d7f719dfea7ea3c65bd2833df6439b59e)
Author: Brian <brian at yutani.localnet.net>
Date:   Fri Mar 23 14:47:46 2007 -0600

    Add the ability to generate programs that doesn't use condition codes.
    
    ctx->Shader.EmitCondCodes determines if we use condition codes.
    If not, IF statement uses first operand's X component as the condition.
    Added OPCODE_BRK0, OPCODE_BRK1, OPCODE_CONT0, OPCODE_CONT1 to handle
    the common cases of conditional break/continue.

diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 0c9bf20..828b0f2 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2127,8 +2127,10 @@ struct gl_shader_program
 struct gl_shader_state
 {
    struct gl_shader_program *CurrentProgram; /**< The user-bound program */
-   GLboolean EmitHighLevelInstructions; /**< Driver-selectable */
-   GLboolean EmitComments;              /**< Driver-selectable */
+   /** Driver-selectable options: */
+   GLboolean EmitHighLevelInstructions; /**< IF/ELSE/ENDIF vs. BRA, etc. */
+   GLboolean EmitCondCodes;             /**< Use condition codes? */
+   GLboolean EmitComments;              /**< Annotated instructions */
 };
 
 
diff --git a/src/mesa/shader/prog_execute.c b/src/mesa/shader/prog_execute.c
index 092c07f..f881d47 100644
--- a/src/mesa/shader/prog_execute.c
+++ b/src/mesa/shader/prog_execute.c
@@ -720,6 +720,32 @@ _mesa_execute_program(GLcontext * ctx,
             pc = inst->BranchTarget - 1;
          }
          break;
+      case OPCODE_BRK0:   /* Break if zero */
+         /* fall-through */
+      case OPCODE_CONT0:  /* Continue if zero */
+         {
+            GLfloat a[4];
+            fetch_vector1(&inst->SrcReg[0], machine, a);
+            if (a[0] == 0.0) {
+               /* take branch */
+               /* Subtract 1 here since we'll do pc++ at end of for-loop */
+               pc = inst->BranchTarget - 1;
+            }
+         }
+         break;
+      case OPCODE_BRK1:   /* Break if non-zero */
+         /* fall-through */
+      case OPCODE_CONT1:  /* Continue if non-zero */
+         {
+            GLfloat a[4];
+            fetch_vector1(&inst->SrcReg[0], machine, a);
+            if (a[0] != 0.0) {
+               /* take branch */
+               /* Subtract 1 here since we'll do pc++ at end of for-loop */
+               pc = inst->BranchTarget - 1;
+            }
+         }
+         break;
       case OPCODE_CAL:         /* Call subroutine (conditional) */
          if (eval_condition(machine, inst)) {
             /* call the subroutine */
@@ -914,13 +940,26 @@ _mesa_execute_program(GLcontext * ctx,
          }
          break;
       case OPCODE_IF:
-         if (eval_condition(machine, inst)) {
-            /* do if-clause (just continue execution) */
-         }
-         else {
-            /* go to the instruction after ELSE or ENDIF */
-            assert(inst->BranchTarget >= 0);
-            pc = inst->BranchTarget - 1;
+         {
+            GLboolean cond;
+            /* eval condition */
+            if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+               GLfloat a[4];
+               fetch_vector1(&inst->SrcReg[0], machine, a);
+               cond = (a[0] != 0.0);
+            }
+            else {
+               cond = eval_condition(machine, inst);
+            }
+            /* do if/else */
+            if (cond) {
+               /* do if-clause (just continue execution) */
+            }
+            else {
+               /* go to the instruction after ELSE or ENDIF */
+               assert(inst->BranchTarget >= 0);
+               pc = inst->BranchTarget - 1;
+            }
          }
          break;
       case OPCODE_ELSE:
diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c
index ed479a7..272caf6 100644
--- a/src/mesa/shader/prog_instruction.c
+++ b/src/mesa/shader/prog_instruction.c
@@ -138,9 +138,13 @@ static const struct instruction_info Ins
    { OPCODE_BGNSUB, "BGNSUB", 0 },
    { OPCODE_BRA,    "BRA",   0 },
    { OPCODE_BRK,    "BRK",   0 },
+   { OPCODE_BRK0,   "BRK0",  1 },
+   { OPCODE_BRK1,   "BRK1",  1 },
    { OPCODE_CAL,    "CAL",   0 },
    { OPCODE_CMP,    "CMP",   3 },
-   { OPCODE_CONT,   "CONT",  1 },
+   { OPCODE_CONT,   "CONT",  0 },
+   { OPCODE_CONT0,  "CONT0", 1 },
+   { OPCODE_CONT1,  "CONT1", 1 },
    { OPCODE_COS,    "COS",   1 },
    { OPCODE_DDX,    "DDX",   1 },
    { OPCODE_DDY,    "DDY",   1 },
diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h
index c800757..dc2d2dc 100644
--- a/src/mesa/shader/prog_instruction.h
+++ b/src/mesa/shader/prog_instruction.h
@@ -153,9 +153,13 @@ typedef enum prog_opcode {
    OPCODE_BGNSUB,    /*                                     opt  */
    OPCODE_BRA,       /*                    2                 X   */
    OPCODE_BRK,       /*                    2                opt  */
+   OPCODE_BRK0,      /*                                     opt  */
+   OPCODE_BRK1,      /*                                     opt  */
    OPCODE_CAL,       /*                    2       2             */
    OPCODE_CMP,       /*            X                             */
    OPCODE_CONT,      /*                                     opt  */
+   OPCODE_CONT0,     /*                                     opt  */
+   OPCODE_CONT1,     /*                                     opt  */
    OPCODE_COS,       /*            X       2       X         X   */
    OPCODE_DDX,       /*                            X         X   */
    OPCODE_DDY,       /*                            X         X   */
diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c
index d290ce0..39d2a07 100644
--- a/src/mesa/shader/prog_print.c
+++ b/src/mesa/shader/prog_print.c
@@ -572,10 +572,20 @@ _mesa_print_instruction_opt(const struct
       print_comment(inst);
       break;
    case OPCODE_IF:
-      _mesa_printf("IF (%s%s); # (if false, goto %d)",
-                   condcode_string(inst->DstReg.CondMask),
-                   _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
-                   inst->BranchTarget);
+      if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+         /* Use ordinary register */
+         _mesa_printf("IF ");
+         print_src_reg(&inst->SrcReg[0], mode, prog);
+         _mesa_printf("; ");
+      }
+      else {
+         /* Use cond codes */
+         _mesa_printf("IF (%s%s);",
+                      condcode_string(inst->DstReg.CondMask),
+                      _mesa_swizzle_string(inst->DstReg.CondSwizzle,
+                                           0, GL_FALSE));
+      }
+      _mesa_printf(" # (if false, goto %d)", inst->BranchTarget);
       print_comment(inst);
       return indent + 3;
    case OPCODE_ELSE:
@@ -604,6 +614,18 @@ _mesa_print_instruction_opt(const struct
                    inst->BranchTarget);
       print_comment(inst);
       break;
+
+   case OPCODE_BRK0:
+   case OPCODE_BRK1:
+   case OPCODE_CONT0:
+   case OPCODE_CONT1:
+      _mesa_printf("%s ", _mesa_opcode_string(inst->Opcode));
+      print_src_reg(&inst->SrcReg[0], mode, prog);
+      _mesa_printf("; ");
+      _mesa_printf(" # (goto %d)", inst->BranchTarget);
+      print_comment(inst);
+      break;
+
    case OPCODE_BGNSUB:
       _mesa_printf("SUB");
       print_comment(inst);
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index aab522e..88aa8c5 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -206,6 +206,7 @@ _mesa_init_shader_state(GLcontext * ctx)
     * are generated by the GLSL compiler.
     */
    ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
+   ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
    ctx->Shader.EmitComments = GL_FALSE;
 }
 
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index 16a054b..9e476b8 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -61,6 +61,7 @@ typedef struct
    struct gl_program *prog;
    /* code-gen options */
    GLboolean EmitHighLevelInstructions;
+   GLboolean EmitCondCodes;
    GLboolean EmitComments;
 } slang_emit_info;
 
@@ -1155,10 +1156,6 @@ emit_move(slang_emit_info *emitInfo, sla
 static struct prog_instruction *
 emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
 {
-   /* Conditional expression (in if/while/for stmts).
-    * Need to update condition code register.
-    * Next instruction is typically an IR_IF.
-    */
    struct prog_instruction *inst;
 
    if (!n->Children[0])
@@ -1166,28 +1163,39 @@ emit_cond(slang_emit_info *emitInfo, sla
 
    inst = emit(emitInfo, n->Children[0]);
 
-   if (inst) {
-      /* set inst's CondUpdate flag */
-      inst->CondUpdate = GL_TRUE;
-      n->Store = n->Children[0]->Store;
-      return inst; /* XXX or null? */
+   if (emitInfo->EmitCondCodes) {
+      /* Conditional expression (in if/while/for stmts).
+       * Need to update condition code register.
+       * Next instruction is typically an IR_IF.
+       */
+      if (inst) {
+         /* set inst's CondUpdate flag */
+         inst->CondUpdate = GL_TRUE;
+         n->Store = n->Children[0]->Store;
+         return inst; /* XXX or null? */
+      }
+      else {
+         /* This'll happen for things like "if (i) ..." where no code
+          * is normally generated for the expression "i".
+          * Generate a move instruction just to set condition codes.
+          * Note: must use full 4-component vector since all four
+          * condition codes must be set identically.
+          */
+         if (!alloc_temp_storage(emitInfo, n, 4))
+            return NULL;
+         inst = new_instruction(emitInfo, OPCODE_MOV);
+         inst->CondUpdate = GL_TRUE;
+         storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+         storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+         _slang_free_temp(emitInfo->vt, n->Store);
+         inst->Comment = _mesa_strdup("COND expr");
+         return inst; /* XXX or null? */
+      }
    }
    else {
-      /* This'll happen for things like "if (i) ..." where no code
-       * is normally generated for the expression "i".
-       * Generate a move instruction just to set condition codes.
-       * Note: must use full 4-component vector since all four
-       * condition codes must be set identically.
-       */
-      if (!alloc_temp_storage(emitInfo, n, 4))
-         return NULL;
-      inst = new_instruction(emitInfo, OPCODE_MOV);
-      inst->CondUpdate = GL_TRUE;
-      storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
-      storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
-      _slang_free_temp(emitInfo->vt, n->Store);
-      inst->Comment = _mesa_strdup("COND expr");
-      return inst; /* XXX or null? */
+      /* No-op */
+      n->Store = n->Children[0]->Store;
+      return NULL;
    }
 }
 
@@ -1244,7 +1252,13 @@ emit_if(slang_emit_info *emitInfo, slang
    ifInstLoc = prog->NumInstructions;
    if (emitInfo->EmitHighLevelInstructions) {
       ifInst = new_instruction(emitInfo, OPCODE_IF);
-      ifInst->DstReg.CondMask = COND_NE;  /* if cond is non-zero */
+      if (emitInfo->EmitCondCodes) {
+         ifInst->DstReg.CondMask = COND_NE;  /* if cond is non-zero */
+      }
+      else {
+         /* test reg.x */
+         storage_to_src_reg(&ifInst->SrcReg[0], n->Children[0]->Store);
+      }
    }
    else {
       /* conditional jump to else, or endif */
@@ -1252,8 +1266,10 @@ emit_if(slang_emit_info *emitInfo, slang
       ifInst->DstReg.CondMask = COND_EQ;  /* BRA if cond is zero */
       ifInst->Comment = _mesa_strdup("if zero");
    }
-   /* which condition code to use: */
-   ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle;
+   if (emitInfo->EmitCondCodes) {
+      /* which condition code to use: */
+      ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle;
+   }
 
    /* if body */
    emit(emitInfo, n->Children[1]);
@@ -1342,6 +1358,8 @@ emit_loop(slang_emit_info *emitInfo, sla
           ir->Opcode == IR_BREAK_IF_FALSE ||
           ir->Opcode == IR_BREAK_IF_TRUE) {
          assert(inst->Opcode == OPCODE_BRK ||
+                inst->Opcode == OPCODE_BRK0 ||
+                inst->Opcode == OPCODE_BRK1 ||
                 inst->Opcode == OPCODE_BRA);
          /* go to instruction after end of loop */
          inst->BranchTarget = endInstLoc + 1;
@@ -1351,6 +1369,8 @@ emit_loop(slang_emit_info *emitInfo, sla
                 ir->Opcode == IR_CONT_IF_FALSE ||
                 ir->Opcode == IR_CONT_IF_TRUE);
          assert(inst->Opcode == OPCODE_CONT ||
+                inst->Opcode == OPCODE_CONT0 ||
+                inst->Opcode == OPCODE_CONT1 ||
                 inst->Opcode == OPCODE_BRA);
          /* to go instruction at top of loop */
          inst->BranchTarget = beginInstLoc;
@@ -1361,7 +1381,7 @@ emit_loop(slang_emit_info *emitInfo, sla
 
 
 /**
- * "Continue" or "break" statement.
+ * Unconditional "continue" or "break" statement.
  * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
  */
 static struct prog_instruction *
@@ -1393,24 +1413,52 @@ emit_cont_break_if(slang_emit_info *emit
    gl_inst_opcode opcode;
    struct prog_instruction *inst;
 
+   assert(n->Opcode == IR_CONT_IF_TRUE ||
+          n->Opcode == IR_CONT_IF_FALSE ||
+          n->Opcode == IR_BREAK_IF_TRUE ||
+          n->Opcode == IR_BREAK_IF_FALSE);
+
    /* evaluate condition expr, setting cond codes */
    inst = emit(emitInfo, n->Children[0]);
-   assert(inst);
-   inst->CondUpdate = GL_TRUE;
+   if (emitInfo->EmitCondCodes) {
+      assert(inst);
+      inst->CondUpdate = GL_TRUE;
+   }
 
    n->InstLocation = emitInfo->prog->NumInstructions;
+
+   /* opcode selection */
    if (emitInfo->EmitHighLevelInstructions) {
-      if (n->Opcode == IR_CONT_IF_TRUE ||
-          n->Opcode == IR_CONT_IF_FALSE)
-         opcode = OPCODE_CONT;
-      else
-         opcode = OPCODE_BRK;
+      if (emitInfo->EmitCondCodes) {
+         if (n->Opcode == IR_CONT_IF_TRUE ||
+             n->Opcode == IR_CONT_IF_FALSE)
+            opcode = OPCODE_CONT;
+         else
+            opcode = OPCODE_BRK;
+      }
+      else {
+         if (n->Opcode == IR_CONT_IF_TRUE)
+            opcode = OPCODE_CONT1;
+         else if (n->Opcode == IR_CONT_IF_FALSE)
+            opcode = OPCODE_CONT0;
+         else if (n->Opcode == IR_BREAK_IF_TRUE)
+            opcode = OPCODE_BRK1;
+         else if (n->Opcode == IR_BREAK_IF_FALSE)
+            opcode = OPCODE_BRK0;
+      }
    }
    else {
       opcode = OPCODE_BRA;
    }
+
    inst = new_instruction(emitInfo, opcode);
-   inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
+   if (emitInfo->EmitCondCodes) {
+      inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
+   }
+   else {
+      /* BRK0, BRK1, CONT0, CONT1 */
+      storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+   }
    return inst;
 }
 
@@ -1779,7 +1827,8 @@ _slang_emit_code(slang_ir_node *n, slang
    emitInfo.prog = prog;
 
    emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
-   emitInfo.EmitComments = 1+ctx->Shader.EmitComments;
+   emitInfo.EmitCondCodes = 0; /* XXX temporary! */
+   emitInfo.EmitComments = ctx->Shader.EmitComments;
 
    (void) emit(&emitInfo, n);
 
diff --git a/src/mesa/tnl/t_vb_arbprogram.c b/src/mesa/tnl/t_vb_arbprogram.c
index b322d48..425a866 100644
--- a/src/mesa/tnl/t_vb_arbprogram.c
+++ b/src/mesa/tnl/t_vb_arbprogram.c
@@ -741,9 +741,13 @@ static gpu_function opcode_func[MAX_OPCO
    do_NOP,/*BGNSUB*/
    do_NOP,/*BRA*/
    do_NOP,/*BRK*/
+   do_NOP,/*BRK0*/
+   do_NOP,/*BRK1*/
    do_NOP,/*CAL*/
    do_NOP,/*CMP*/
    do_NOP,/*CONT*/
+   do_NOP,/*CONT0*/
+   do_NOP,/*CONT1*/
    do_NOP,/*COS*/
    do_NOP,/*DDX*/
    do_NOP,/*DDY*/
diff-tree bf020d8d7f719dfea7ea3c65bd2833df6439b59e (from 2bdac09d16904334424a53d4c7436408a5cc3ca5)
Author: Brian <brian at yutani.localnet.net>
Date:   Fri Mar 23 14:44:34 2007 -0600

    minor tweaks

diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index f1be713..4e41aa8 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -1369,7 +1369,7 @@ _slang_gen_while(slang_assemble_ctx * A,
    loop->Children[0] = new_seq(breakIf, body);
 
    /* Do infinite loop detection */
-   if (loop->BranchNode == 0 && isConst && constTrue) {
+   if (!loop->BranchNode && isConst && constTrue) {
       /* infinite loop detected */
       A->CurLoop = prevLoop; /* clean-up */
       slang_info_log_error(A->log, "Infinite loop detected!");
@@ -1485,7 +1485,7 @@ static slang_ir_node *
 _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
 {
    /*
-    * eval expr (child[0]), updating condcodes
+    * eval expr (child[0])
     * IF expr THEN
     *    if-body code
     * ELSE



More information about the mesa-commit mailing list