optimize conditional breaks/continues
authorBrian <brian@nostromo.localnet.net>
Fri, 9 Feb 2007 00:11:18 +0000 (17:11 -0700)
committerBrian <brian@nostromo.localnet.net>
Fri, 9 Feb 2007 00:11:18 +0000 (17:11 -0700)
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_emit.c

index 2da53171edec741ea2abd70aad3f58967b87e8d1..7566ad2e9f844954e5c904e642337071e2de3965 100644 (file)
@@ -614,12 +614,35 @@ new_break(slang_ir_node *loopNode)
 }
 
 
+/**
+ * Make new IR_BREAK_IF_TRUE or IR_BREAK_IF_FALSE node.
+ */
 static slang_ir_node *
-new_break_if_false(slang_ir_node *loopNode, slang_ir_node *cond)
+new_break_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean breakTrue)
 {
-   slang_ir_node *n = new_node1(IR_BREAK_IF_FALSE, cond);
+   slang_ir_node *n;
+   assert(loopNode);
+   assert(loopNode->Opcode == IR_LOOP);
+   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;
+   }
+   return n;
+}
+
+
+/**
+ * Make new IR_CONT_IF_TRUE or IR_CONT_IF_FALSE node.
+ */
+static slang_ir_node *
+new_cont_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean contTrue)
+{
+   slang_ir_node *n;
    assert(loopNode);
    assert(loopNode->Opcode == IR_LOOP);
+   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;
@@ -1406,7 +1429,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
    A->CurLoop = loop;
 
    cond = new_cond(_slang_gen_operation(A, &oper->children[0]));
-   breakIf = new_break_if_false(A->CurLoop, cond);
+   breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
    body = _slang_gen_operation(A, &oper->children[1]);
    loop->Children[0] = new_seq(breakIf, body);
 
@@ -1439,7 +1462,7 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
 
    body = _slang_gen_operation(A, &oper->children[0]);
    cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
-   breakIf = new_break_if_false(A->CurLoop, cond);
+   breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
    loop->Children[0] = new_seq(body, breakIf);
 
    /* pop loop, restore prev */
@@ -1473,7 +1496,7 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
    A->CurLoop = loop;
 
    cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
-   breakIf = new_break_if_false(A->CurLoop, cond);
+   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,
@@ -1536,6 +1559,23 @@ _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
 }
 
 
+/**
+ * Determine if the given operation is of a specific type.
+ */
+static GLboolean
+is_operation_type(const const slang_operation *oper, slang_operation_type type)
+{
+   if (oper->type == type)
+      return GL_TRUE;
+   else if ((oper->type == slang_oper_block_new_scope ||
+             oper->type == slang_oper_block_no_new_scope) &&
+            oper->num_children == 1)
+      return is_operation_type(&oper->children[0], type);
+   else
+      return GL_FALSE;
+}
+
+
 /**
  * Generate IR tree for an if/then/else conditional using high-level
  * IR_IF instruction.
@@ -1551,24 +1591,40 @@ _slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper)
     *    else-body code
     * 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, *ifBody, *elseBody;
 
    cond = _slang_gen_operation(A, &oper->children[0]);
    cond = new_cond(cond);
-   ifBody = _slang_gen_operation(A, &oper->children[1]);
-   if (haveElseClause)
-      elseBody = _slang_gen_operation(A, &oper->children[2]);
-   else
-      elseBody = NULL;
-
-   ifNode = new_if(cond, ifBody, elseBody);
 
-   return ifNode;
+   if (is_operation_type(&oper->children[1], slang_oper_break)) {
+      /* Special case: generate a conditional break */
+      ifBody = new_break_if(A->CurLoop, cond, GL_TRUE);
+      if (haveElseClause) {
+         elseBody = _slang_gen_operation(A, &oper->children[2]);
+         return new_seq(ifBody, elseBody);
+      }
+      return ifBody;
+   }
+   else if (is_operation_type(&oper->children[1], slang_oper_continue)) {
+      /* Special case: generate a conditional break */
+      ifBody = new_cont_if(A->CurLoop, cond, GL_TRUE);
+      if (haveElseClause) {
+         elseBody = _slang_gen_operation(A, &oper->children[2]);
+         return new_seq(ifBody, elseBody);
+      }
+      return ifBody;
+   }
+   else {
+      /* general case */
+      ifBody = _slang_gen_operation(A, &oper->children[1]);
+      if (haveElseClause)
+         elseBody = _slang_gen_operation(A, &oper->children[2]);
+      else
+         elseBody = NULL;
+      ifNode = new_if(cond, ifBody, elseBody);
+      return ifNode;
+   }
 }
 
 
index c43f79cc72730ba2aa2acc39f3252dd921e0d8cb..1b43042e2d9a24e5deb677e950692ff528390ce3 100644 (file)
@@ -1156,9 +1156,9 @@ emit_loop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
       beginInst->BranchTarget = prog->NumInstructions - 1;
    }
 
-   /* Done emitting loop code.  Now walk over the loop's linked list
-    * of BREAK and CONT nodes, filling in their BranchTarget fields
-    * (which will point to the ENDLOOP or ENDLOOP+1 instructions).
+   /* Done emitting loop code.  Now walk over the loop's linked list of
+    * 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) {
       struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
@@ -1186,7 +1186,8 @@ emit_loop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
 
 
 /**
- * Emit code for IR_CONT or IR_BREAK.
+ * "Continue" or "break" statement.
+ * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
  */
 static struct prog_instruction *
 emit_cont_break(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
@@ -1207,7 +1208,8 @@ emit_cont_break(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
 
 
 /**
- * Conditional loop continue/break.
+ * Conditional "continue" or "break" statement.
+ * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
  */
 static struct prog_instruction *
 emit_cont_break_if(slang_var_table *vt, slang_ir_node *n,
@@ -1223,7 +1225,11 @@ emit_cont_break_if(slang_var_table *vt, slang_ir_node *n,
 
    n->InstLocation = prog->NumInstructions;
    if (EmitHighLevelInstructions) {
-      opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
+      if (n->Opcode == IR_CONT_IF_TRUE ||
+          n->Opcode == IR_CONT_IF_FALSE)
+         opcode = OPCODE_CONT;
+      else
+         opcode = OPCODE_BRK;
    }
    else {
       opcode = OPCODE_BRA;
@@ -1452,8 +1458,10 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
    case IR_LOOP:
       return emit_loop(vt, n, prog);
    case IR_BREAK_IF_FALSE:
+   case IR_CONT_IF_FALSE:
       return emit_cont_break_if(vt, n, prog, GL_FALSE);
    case IR_BREAK_IF_TRUE:
+   case IR_CONT_IF_TRUE:
       return emit_cont_break_if(vt, n, prog, GL_TRUE);
    case IR_BREAK:
       /* fall-through */