glsl: use new _slang_loop_contains_continue() helper function
authorBrian Paul <brianp@vmware.com>
Thu, 18 Jun 2009 23:25:47 +0000 (17:25 -0600)
committerBrian Paul <brianp@vmware.com>
Fri, 26 Jun 2009 19:16:32 +0000 (13:16 -0600)
src/mesa/shader/slang/slang_codegen.c

index 5f40ddda20d552047d42662abea2d66fd6cb1844..64dfdaff7ee3e6b79a15ec52e30007feb6e1bf2f 100644 (file)
@@ -2347,11 +2347,123 @@ _slang_is_boolean(slang_assemble_ctx *A, slang_operation *oper)
 }
 
 
+/**
+ * Check if a loop contains a 'continue' statement.
+ * Stop looking if we find a nested loop.
+ */
+static GLboolean
+_slang_loop_contains_continue(const slang_operation *oper)
+{
+   switch (oper->type) {
+   case SLANG_OPER_CONTINUE:
+      return GL_TRUE;
+   case SLANG_OPER_FOR:
+   case SLANG_OPER_DO:
+   case SLANG_OPER_WHILE:
+      /* stop upon finding a nested loop */
+      return GL_FALSE;
+   default:
+       /* recurse */
+      {
+         GLuint i;
+         for (i = 0; i < oper->num_children; i++) {
+            if (_slang_loop_contains_continue(slang_oper_child((slang_operation *) oper, i)))
+               return GL_TRUE;
+         }
+      }
+      return GL_FALSE;
+   }
+}
+
+
+static slang_ir_node *
+_slang_gen_while_without_continue(slang_assemble_ctx *A, slang_operation *oper)
+{
+#if 0
+   slang_operation *top;
+   slang_operation *innerBody;
+
+   assert(oper->type == SLANG_OPER_DO);
+
+   top = slang_operation_new(1);
+   top->type = SLANG_OPER_BLOCK_NEW_SCOPE;
+   top->locals->outer_scope = oper->locals->outer_scope;
+   slang_operation_add_children(top, 2);
+
+   /* declare: bool _notBreakFlag = true */
+   {
+      slang_operation *condDecl = slang_oper_child(top, 0);
+      slang_variable *var;
+
+      condDecl->type = SLANG_OPER_VARIABLE_DECL;
+      var = slang_variable_scope_grow(top->locals);
+      slang_fully_specified_type_construct(&var->type);
+      var->type.specifier.type = SLANG_SPEC_BOOL;
+      var->a_name = slang_atom_pool_atom(A->atoms, "_notBreakFlag");
+      condDecl->a_id = var->a_name;
+      var->initializer = slang_operation_new(1);
+      slang_operation_literal_bool(var->initializer, GL_TRUE);
+   }
+
+   /* build outer do-loop:  do { ... } while (_notBreakFlag && LOOPCOND) */
+   {
+      slang_operation *outerDo = slang_oper_child(top, 1);
+      outerDo->type = SLANG_OPER_DO;
+      slang_operation_add_children(outerDo, 2);
+
+      /* inner do-loop */
+      {
+         slang_operation *innerDo = slang_oper_child(outerDo, 0);
+         innerDo->type = SLANG_OPER_DO;
+         slang_operation_add_children(innerDo, 2);
+
+         /* copy original do-loop body into inner do-loop's body */
+         innerBody = slang_oper_child(innerDo, 0);
+         slang_operation_copy(innerBody, slang_oper_child(oper, 0));
+         innerBody->locals->outer_scope = innerDo->locals;
+
+         /* inner do-loop's condition is constant/false */
+         {
+            slang_operation *constFalse = slang_oper_child(innerDo, 1);
+            slang_operation_literal_bool(constFalse, GL_FALSE);
+         }
+      }
+
+      /* _notBreakFlag && LOOPCOND */
+      {
+         slang_operation *cond = slang_oper_child(outerDo, 1);
+         cond->type = SLANG_OPER_LOGICALAND;
+         slang_operation_add_children(cond, 2);
+         {
+            slang_operation *notBreak = slang_oper_child(cond, 0);
+            slang_operation_identifier(notBreak, A, "_notBreakFlag");
+         }
+         {
+            slang_operation *origCond = slang_oper_child(cond, 1);
+            slang_operation_copy(origCond, slang_oper_child(oper, 1));
+         }
+      }
+   }
+
+   /* Finally, in innerBody,
+    *   replace "break" with "_notBreakFlag = 0; break"
+    *   replace "continue" with "break"
+    */
+   replace_break_and_cont(A, innerBody);
+
+   slang_print_tree(top, 0);
+
+   return _slang_gen_operation(A, top);
+#endif
+   return NULL;
+}
+
+
 /**
  * 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_gen_while(slang_assemble_ctx * A, slang_operation *oper)
 {
    /*
     * LOOP:
@@ -2361,6 +2473,15 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
    slang_ir_node *prevLoop, *loop, *breakIf, *body;
    GLboolean isConst, constTrue;
 
+   if (!A->EmitContReturn) {
+      /* We don't want to emit CONT instructions.  If this while-loop has
+       * a continue, translate it away.
+       */
+      if (_slang_loop_contains_continue(slang_oper_child(oper, 1))) {
+         return _slang_gen_while_without_continue(A, oper);
+      }
+   }
+
    /* type-check expression */
    if (!_slang_is_boolean(A, &oper->children[0])) {
       slang_info_log_error(A->log, "scalar/boolean expression expected for 'while'");
@@ -2581,7 +2702,7 @@ _slang_gen_do_without_continue(slang_assemble_ctx *A, slang_operation *oper)
  * Generate IR tree for a do-while loop using high-level LOOP, IF instructions.
  */
 static slang_ir_node *
-_slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
+_slang_gen_do(slang_assemble_ctx * A, slang_operation *oper)
 {
    /*
     * LOOP:
@@ -2596,8 +2717,8 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
       /* We don't want to emit CONT instructions.  If this do-loop has
        * a continue, translate it away.
        */
-      if (_slang_find_node_type((slang_operation *) oper, SLANG_OPER_CONTINUE)) {
-         return _slang_gen_do_without_continue(A, (slang_operation *) oper);
+      if (_slang_loop_contains_continue(slang_oper_child(oper, 0))) {
+         return _slang_gen_do_without_continue(A, oper);
       }
    }
 
@@ -3029,7 +3150,7 @@ _slang_gen_for(slang_assemble_ctx * A, slang_operation *oper)
       /* We don't want to emit CONT instructions.  If this for-loop has
        * a continue, translate it away.
        */
-      if (_slang_find_node_type(oper, SLANG_OPER_CONTINUE)) {
+      if (_slang_loop_contains_continue(slang_oper_child(oper, 3))) {
          return _slang_gen_for_without_continue(A, oper);
       }
    }