glsl: fix assorted regressions related to early-return-removal
authorBrian Paul <brianp@vmware.com>
Thu, 25 Jun 2009 17:12:26 +0000 (11:12 -0600)
committerBrian Paul <brianp@vmware.com>
Fri, 26 Jun 2009 19:16:34 +0000 (13:16 -0600)
src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_codegen.h

index b918e03aa594d4ff6f63756af10286cfe3c68f1d..bb1ae0356905c2cd1ab4acda5ceb73863761b9fc 100644 (file)
@@ -832,7 +832,7 @@ _slang_find_node_type(slang_operation *oper, slang_operation_type type)
  * Count the number of operations of the given time rooted at 'oper'.
  */
 static GLuint
-_slang_count_node_type(slang_operation *oper, slang_operation_type type)
+_slang_count_node_type(const slang_operation *oper, slang_operation_type type)
 {
    GLuint i, count = 0;
    if (oper->type == type) {
@@ -1025,7 +1025,7 @@ slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
          {
             slang_operation *assignOper;
 
-            if (!A->EmitContReturn) {
+            if (A->UseReturnFlag) {
                slang_operation *ifOper = slang_oper_child(blockOper, 0);
                ifOper->type = SLANG_OPER_IF;
                slang_operation_add_children(ifOper, 3);
@@ -1493,7 +1493,7 @@ declare_return_flag(slang_assemble_ctx *A, slang_operation *oper)
    slang_generate_declaration(A, oper->locals, decl,
                               SLANG_SPEC_BOOL, "__returnFlag", GL_TRUE);
 
-   slang_print_tree(oper, 0);
+   /*slang_print_tree(oper, 0);*/
 }
 
 
@@ -1526,10 +1526,31 @@ replace_return_with_flag_set(slang_assemble_ctx *A, slang_operation *oper)
       var = _slang_variable_locate(oper->locals, id, GL_TRUE);
       assert(var);
    }
+}
+
 
+/**
+ * Test if the given function body has an "early return".  That is, there's
+ * a 'return' statement that's not the very last instruction in the body.
+ */
+static GLboolean
+has_early_return(const slang_operation *funcBody)
+{
+   GLuint retCount = _slang_count_node_type(funcBody, SLANG_OPER_RETURN);
+   if (retCount == 0)
+      return GL_FALSE;
+   else if (retCount == 1 && _slang_is_tail_return(funcBody))
+      return GL_FALSE;
+   else
+      return GL_TRUE;
 }
 
 
+/**
+ * Emit IR code for a function call.  This does one of two things:
+ * 1. Inline the function's code
+ * 2. Create an IR for the function's body and create a real call to it.
+ */
 static slang_ir_node *
 _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
                          slang_operation *oper, slang_operation *dest)
@@ -1555,10 +1576,13 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
        *  1. insert the inline code
        *  2. Generate a call to the "inline" code as a subroutine
        */
-
-
+      const GLboolean earlyReturn = has_early_return(fun->body);
       slang_operation *ret = NULL;
 
+      if (earlyReturn && !A->EmitContReturn) {
+         A->UseReturnFlag = GL_TRUE;
+      }
+
       inlined = slang_inline_function_call(A, fun, oper, dest);
       if (!inlined)
          return NULL;
@@ -1566,8 +1590,7 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
       ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN);
       if (ret) {
          /* check if this is a "tail" return */
-         if (_slang_count_node_type(inlined, SLANG_OPER_RETURN) == 1 &&
-             _slang_is_tail_return(inlined)) {
+         if (!earlyReturn) {
             /* The only RETURN is the last stmt in the function, no-op it
              * and inline the function body.
              */
@@ -1593,7 +1616,7 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
                callOper = inlined;
             }
 
-            if (!A->EmitContReturn) {
+            if (A->UseReturnFlag) {
                /* Early returns not supported.  Create a _returnFlag variable
                 * that's set upon 'return' and tested elsewhere to no-op any
                 * remaining instructions in the subroutine.
@@ -4030,7 +4053,7 @@ _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
          n = new_seq(_slang_gen_operation(A, assign),
                      new_return(A->curFuncEndLabel));
       }
-      else {
+      else if (A->UseReturnFlag) {
          /* set __returnFlag = false; */
          slang_operation *setFlag = slang_operation_new(1);
          setFlag->type = SLANG_OPER_ASSIGN;
@@ -5301,12 +5324,9 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
    assert(A->program->Parameters );
    assert(A->program->Varying);
    assert(A->vartable);
-#if 0
-   A->CurLoop = NULL;
-   A->CurLoopOper = NULL;
-#else
+
    A->LoopDepth = 0;
-#endif
+   A->UseReturnFlag = GL_FALSE;
    A->CurFunction = fun;
 
    /* fold constant expressions, etc. */
index 2b55b521219e26d264bab3e590fc3d8ae3b5b047..ee3be55a459a8e47c05686b0b7eeb131d3e4dff8 100644 (file)
@@ -51,6 +51,7 @@ typedef struct slang_assemble_ctx_
    /* current function */
    struct slang_function_ *CurFunction;
    struct slang_label_ *curFuncEndLabel;
+   GLboolean UseReturnFlag;
 
    GLboolean UnresolvedRefs;
    GLboolean EmitContReturn;