Initial implementation of high-level flow-control instructions.
authorBrian <brian@yutani.localnet.net>
Mon, 5 Feb 2007 22:00:07 +0000 (15:00 -0700)
committerBrian <brian@yutani.localnet.net>
Mon, 5 Feb 2007 22:00:07 +0000 (15:00 -0700)
IF/ELSE/ENDIF and BEGIN_LOOP/END_LOOP/BREAK instructions seem to work.
Disabled by default though until better tested.
Implemented IR_NOT, but needs optimization.

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_ir.h
src/mesa/swrast/s_fragprog.c
src/mesa/tnl/t_vp_build.c

index 72f58a9ebd172985edaa51da6fb514591ba7b277..2dd9ccc6fdc481a18225a0dbb088c3e81df0edd7 100644 (file)
@@ -47,6 +47,8 @@
 #include "slang_print.h"
 
 
+static GLboolean UseHighLevelInstructions = GL_TRUE;
+
 static slang_ir_node *
 _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
 
@@ -506,6 +508,7 @@ new_node(slang_ir_opcode op, slang_ir_node *left, slang_ir_node *right)
       n->Children[0] = left;
       n->Children[1] = right;
       n->Writemask = WRITEMASK_XYZW;
+      n->InstLocation = -1;
    }
    return n;
 }
@@ -567,6 +570,26 @@ new_jump(slang_atom target)
 }
 
 
+static slang_ir_node *
+new_begin_loop(void)
+{
+   slang_ir_node *n = new_node(IR_BEGIN_LOOP, NULL, NULL);
+   return n;
+}
+
+
+static slang_ir_node *
+new_end_loop(slang_ir_node *beginNode)
+{
+   slang_ir_node *n = new_node(IR_END_LOOP, NULL, NULL);
+   assert(beginNode);
+   if (n) {
+      n->BranchNode = beginNode;
+   }
+   return n;
+}
+
+
 /**
  * New IR_VAR node - a reference to a previously declared variable.
  */
@@ -1304,7 +1327,7 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
 
 
 /**
- * Generate IR tree for a while-loop.
+ * Generate IR tree for a while-loop.  Use BRA-nch instruction.
  */
 static slang_ir_node *
 _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
@@ -1313,7 +1336,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
     * label "__startWhile"
     * eval expr (child[0]), updating condcodes
     * branch if false to "__endWhile"
-    * code body
+    * body code
     * jump "__startWhile"
     * label "__endWhile"
     */
@@ -1353,6 +1376,51 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
 }
 
 
+/**
+ * Generate IR tree for a while-loop using high-level BGNLOOP/ENDLOOP,
+ * IF/ENDIF instructions.
+ */
+static slang_ir_node *
+_slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
+{
+   /*
+    * BGNLOOP
+    *    eval expr (child[0]), updating condcodes
+    *    IF !expr THEN
+    *       BRK
+    *    ENDIF
+    *    body code
+    * ENDLOOP
+    */
+   slang_ir_node *beginLoop, *endLoop, *ifThen, *endif;
+   slang_ir_node *brk, *cond, *body, *tree;
+
+   beginLoop = new_begin_loop();
+
+   cond = _slang_gen_operation(A, &oper->children[0]);
+   cond = new_node(IR_NOT, cond, NULL);
+   cond = _slang_gen_cond(cond);
+
+   ifThen = new_node(IR_IF, cond, NULL);
+   tree = new_seq(beginLoop, ifThen);
+
+   brk = new_node(IR_BREAK, NULL, NULL);
+   tree = new_seq(tree, brk);
+
+   endif = new_node(IR_ENDIF, NULL, NULL);
+   tree = new_seq(tree, endif);
+
+   body = _slang_gen_operation(A, &oper->children[1]);
+   if (body)
+      tree = new_seq(tree, body);
+
+   endLoop = new_end_loop(beginLoop);
+   tree = new_seq(tree, endLoop);
+
+   return tree;
+}
+
+
 /**
  * Generate IR tree for a do-while-loop.
  */
@@ -1517,7 +1585,7 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
  * IF/ELSE/ENDIF instructions
  */
 static slang_ir_node *
-_slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper)
 {
    /*
     * eval expr (child[0]), updating condcodes
@@ -1529,6 +1597,10 @@ _slang_gen_if2(slang_assemble_ctx * A, const slang_operation *oper)
     *    "false" code block
     * label "__endif"
     */
+   /* XXX special cases to check for:
+    * if body of conditiona is just a "break", emit a conditional break
+    * instruction.
+    */
    const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
    slang_ir_node *ifNode, *cond, *trueBody, *elseNode, *falseBody, *endifNode;
    slang_ir_node *tree;
@@ -2261,7 +2333,10 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
       return _slang_gen_operation(A, &oper->children[0]);
       break;
    case slang_oper_while:
-      return _slang_gen_while(A, oper);
+      if (UseHighLevelInstructions)
+         return _slang_gen_hl_while(A, oper);
+      else
+         return _slang_gen_while(A, oper);
    case slang_oper_do:
       return _slang_gen_do(A, oper);
    case slang_oper_for:
@@ -2427,8 +2502,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
    case slang_oper_identifier:
       return _slang_gen_variable(A, oper);
    case slang_oper_if:
-      if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) {
-         return _slang_gen_if(A, oper);
+      if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB
+          && UseHighLevelInstructions) {
+         return _slang_gen_hl_if(A, oper);
       }
       else {
          /* XXX update tnl executor */
index 756bbe95879d7d1ebcbb70832bd80075f36a8f0d..311eea1e6ad725cfcd6c003d8a16b4bd0a62d956 100644 (file)
@@ -1005,6 +1005,42 @@ emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
 }
 
 
+/**
+ * Logical-NOT
+ */
+static struct prog_instruction *
+emit_not(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
+{
+   GLfloat zero = 0.0;
+   slang_ir_storage st;
+   struct prog_instruction *inst;
+
+   /* need zero constant */
+   st.File = PROGRAM_CONSTANT;
+   st.Size = 1;
+   st.Index = _mesa_add_unnamed_constant(prog->Parameters, &zero,
+                                         1, &st.Swizzle);
+
+   /* child expr */
+   (void) emit(vt, n->Children[0], prog);
+   /* XXXX if child instr is SGT convert to SLE, if SEQ, SNE, etc */
+
+   if (!n->Store)
+      if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
+         return NULL;
+
+   inst = new_instruction(prog, OPCODE_SEQ);
+   storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
+   storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+   storage_to_src_reg(&inst->SrcReg[1], &st);
+
+   free_temp_storage(vt, n->Children[0]);
+
+   return inst;
+}
+
+
+
 /**
  * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
  * Ex: fix_swizzle("zyNN") -> "zyyy"
@@ -1202,6 +1238,9 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
    case IR_COND:
       return emit_cond(vt, n, prog);
 
+   case IR_NOT:
+      return emit_not(vt, n, prog);
+
    case IR_LABEL:
       return emit_label(n->Target, prog);
    case IR_JUMP:
@@ -1235,6 +1274,39 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
          return inst;
       }
 
+   case IR_BEGIN_LOOP:
+      {
+         /* save location of this instruction, used by OPCODE_ENDLOOP */
+         n->InstLocation = prog->NumInstructions;
+         (void) new_instruction(prog, OPCODE_BGNLOOP);
+      }
+      break;
+   case IR_END_LOOP:
+      {
+         struct prog_instruction *inst;
+         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;
+         return inst;
+      }
+   case IR_CONT:
+      return new_instruction(prog, OPCODE_CONT);
+   case IR_BREAK:
+      {
+         struct prog_instruction *inst;
+         inst = new_instruction(prog, OPCODE_BRK);
+         inst->DstReg.CondMask = COND_TR;  /* always true */
+         return inst;
+      }
+   case IR_BEGIN_SUB:
+      return new_instruction(prog, OPCODE_BGNSUB);
+   case IR_END_SUB:
+      return new_instruction(prog, OPCODE_ENDSUB);
+   case IR_RETURN:
+      return new_instruction(prog, OPCODE_RET);
+
    default:
       _mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
       abort();
index ac1ea4dbb4ab3fcde61f4b412a776479432fc99c..df5fc067790d69e4044e4e8b3359344b53db945f 100644 (file)
@@ -150,6 +150,8 @@ typedef struct slang_ir_node_
    GLfloat Value[4];    /**< If Opcode == IR_FLOAT */
    slang_variable *Var;  /**< If Opcode == IR_VAR or IR_VAR_DECL */
    slang_ir_storage *Store;  /**< location of result of this operation */
+   GLint InstLocation;  /**< Location of instruction emitted for this node */
+   struct slang_ir_node_ *BranchNode;  /**< Used for branch instructions */
 } slang_ir_node;
 
 
index 00231aeae8b773803c6c6da8879b8adb61ec110e..287dd9b1dbe5238b62e249177ec04c6e5de90e3e 100644 (file)
@@ -625,7 +625,7 @@ execute_program( GLcontext *ctx,
                  GLuint column )
 {
    const GLuint MAX_EXEC = 10000;
-   GLuint pc, total = 0;
+   GLint pc, total = 0, loopDepth = 0;
 
    if (DEBUG_FRAG) {
       printf("execute fragment program --------------------\n");
@@ -642,7 +642,7 @@ execute_program( GLcontext *ctx,
       }
 
       if (DEBUG_FRAG) {
-         _mesa_print_instruction(inst);
+         _mesa_print_instruction(inst, 0);
       }
 
       switch (inst->Opcode) {
@@ -676,8 +676,13 @@ 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;
          case OPCODE_BGNSUB: /* begin subroutine */
             break;
@@ -701,7 +706,19 @@ execute_program( GLcontext *ctx,
             }
             break;
          case OPCODE_BRK: /* break out of loop */
-            /* assert inside 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);
             break;
          case OPCODE_CAL: /* Call subroutine */
             {
@@ -880,20 +897,25 @@ execute_program( GLcontext *ctx,
                   /* do if-clause (just continue execution) */
                }
                else {
-                  /* do else-clause, or go to endif */
+                  /* search for else-clause or endif */
+                  /* XXX could encode location of the else/endif statement
+                   * in the IF instruction to avoid searching...
+                   */
                   GLint ifDepth = 1;
                   do {
                      pc++;
                      inst = program->Base.Instructions + pc;
                      if (inst->Opcode == OPCODE_END) {
                         /* mal-formed program! */
-                        abort();
+                        _mesa_problem(ctx, "END found before ELSE/ENDIF");
+                        return GL_FALSE;
                      }
                      else if (inst->Opcode == OPCODE_IF) {
+                        /* nested if */
                         ifDepth++;
                      }
                      else if (inst->Opcode == OPCODE_ELSE) {
-                        if (ifDepth == 0) {
+                        if (ifDepth == 1) {
                            /* ok, continue normal execution */
                            break;
                         }
@@ -1335,6 +1357,10 @@ execute_program( GLcontext *ctx,
                result[2] = (a[2] > b[2]) ? 1.0F : 0.0F;
                result[3] = (a[3] > b[3]) ? 1.0F : 0.0F;
                store_vector4( inst, machine, result );
+               if (DEBUG_FRAG) {
+                  printf("SGT %g %g %g %g\n",
+                         result[0], result[1], result[2], result[3]);
+               }
             }
             break;
          case OPCODE_SIN:
index 47fed32904dd2d33bba4bfdce8f53625a5b263e1..6fb14e7caa8479fcbda0f73fc513f9a5ae972442 100644 (file)
@@ -497,7 +497,7 @@ static void debug_insn( struct prog_instruction *inst, const char *fn,
       }
         
       _mesa_printf("%d:\t", line);
-      _mesa_print_instruction(inst);
+      _mesa_print_instruction(inst, 0);
    }
 }