Check for constant-valued while/do loop conditions.
authorBrian <brian@nostromo.localnet.net>
Fri, 9 Feb 2007 00:40:29 +0000 (17:40 -0700)
committerBrian <brian@nostromo.localnet.net>
Fri, 9 Feb 2007 00:40:29 +0000 (17:40 -0700)
Allows us to:
1. avoid generating constant-valued BRK test for while(1)..
2. discard entire loop for while(0).
3. detection infinite loops at compile-time.

src/mesa/shader/slang/slang_codegen.c

index 7566ad2e9f844954e5c904e642337071e2de3965..62854548608d8316dda38cd24a2c5d12640005f8 100644 (file)
@@ -1408,19 +1408,48 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
 }
 
 
+static GLboolean
+_slang_is_constant_cond(const slang_operation *oper, GLboolean *value)
+{
+   if (oper->type == slang_oper_literal_float ||
+       oper->type == slang_oper_literal_int ||
+       oper->type == slang_oper_literal_bool) {
+      if (oper->literal[0])
+         *value = GL_TRUE;
+      else
+         *value = GL_FALSE;
+      return GL_TRUE;
+   }
+   else if (oper->type == slang_oper_expression &&
+            oper->num_children == 1) {
+      return _slang_is_constant_cond(&oper->children[0], value);
+   }
+   return GL_FALSE;
+}
+
+
+
 /**
  * Generate loop code using high-level IR_LOOP instruction
  */
 static slang_ir_node *
 _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
 {
-   slang_ir_node *prevLoop;
    /*
     * LOOP:
     *    BREAK if !expr (child[0])
     *    body code (child[1])
     */
-   slang_ir_node *loop, *cond, *breakIf, *body;
+   slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+   GLboolean isConst, constTrue;
+
+   /* Check if loop condition is a constant */
+   isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
+
+   if (isConst && !constTrue) {
+      /* loop is never executed! */
+      return new_node0(IR_NOP);
+   }
 
    loop = new_loop(NULL);
 
@@ -1429,10 +1458,23 @@ _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(A->CurLoop, cond, GL_FALSE);
+   if (isConst && constTrue) {
+      /* while(nonzero constant), no conditional break */
+      breakIf = NULL;
+   }
+   else {
+      breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+   }
    body = _slang_gen_operation(A, &oper->children[1]);
    loop->Children[0] = new_seq(breakIf, body);
 
+   /* Do infinite loop detection */
+   if (loop->BranchNode == 0 && isConst && constTrue) {
+      /* infinite loop detected */
+      A->CurLoop = prevLoop; /* clean-up */
+      RETURN_ERROR("Infinite loop detected!", 0);
+   }
+
    /* pop loop, restore prev */
    A->CurLoop = prevLoop;
 
@@ -1446,13 +1488,16 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
 static slang_ir_node *
 _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
 {
-   slang_ir_node *prevLoop;
    /*
     * LOOP:
     *    body code (child[0])
     *    BREAK if !expr (child[1])
     */
-   slang_ir_node *loop, *cond, *breakIf, *body;
+   slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
+   GLboolean isConst, constTrue;
+
+   /* Check if loop condition is a constant */
+   isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
 
    loop = new_loop(NULL);
 
@@ -1462,7 +1507,13 @@ _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(A->CurLoop, cond, GL_FALSE);
+   if (isConst && constTrue) {
+      /* while(nonzero constant), no conditional break */
+      breakIf = NULL;
+   }
+   else {
+      breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
+   }
    loop->Children[0] = new_seq(body, breakIf);
 
    /* pop loop, restore prev */
@@ -1478,7 +1529,6 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
 static slang_ir_node *
 _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
 {
-   slang_ir_node *prevLoop;
    /*
     * init (child[0])
     * LOOP:
@@ -1486,7 +1536,7 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
     *    body code (child[3])
     *    incr code (child[2])   // XXX continue here
     */
-   slang_ir_node *loop, *cond, *breakIf, *body, *init, *incr;
+   slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
 
    init = _slang_gen_operation(A, &oper->children[0]);
    loop = new_loop(NULL);