Fix issues related to the 'continue' statement.
authorBrian <brian@yutani.localnet.net>
Fri, 23 Mar 2007 23:48:42 +0000 (17:48 -0600)
committerBrian <brian@yutani.localnet.net>
Fri, 23 Mar 2007 23:48:42 +0000 (17:48 -0600)
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.

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_ir.h

index 4e41aa87002d0e97b21f17d705184e25dcca3378..2eb509b4d1bb016f8fb765b028c76ab69d730a98 100644 (file)
@@ -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, slang_ir_node *cond, GLboolean breakTrue)
    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, slang_ir_node *cond, GLboolean contTrue)
    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, const slang_operation *oper)
    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, const slang_operation *oper)
    /*
     * 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, const slang_operation *oper)
    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, const slang_operation *oper)
 }
 
 
+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 * A, slang_operation *oper)
       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);
 
index 9e476b8a0fae89bef69c42104f4df519085ed3c9..6ec20daabb6e46235c55b1642066bbf85e69eb3d 100644 (file)
@@ -316,6 +316,7 @@ slang_print_ir(const slang_ir_node *n, int indent)
          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, int indent)
    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 opcode, char *dstAnnot,
 }
 
 
+/**
+ * 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, slang_ir_node *n)
 
    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, slang_ir_node *n)
 {
    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, slang_ir_node *n)
    /* 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, slang_ir_node *n)
       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, slang_ir_node *n)
     * 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, slang_ir_node *n)
                 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 *emitInfo, slang_ir_node *n)
 {
    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 *emitInfo, slang_ir_node *n,
       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_node *n)
       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_node *n)
       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_node *n)
                  _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_var_table *vt,
 
    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);
 
index cc9df69e722edf5ad5ffbdc4a78cc6b0fe4b232a..37dd38eaa5dc1289e2313204b8464c1f9c33b6a9 100644 (file)
@@ -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;