glsl/tests: Convert optimization-test.sh to pure python
authorDylan Baker <dylan@pnwbakers.com>
Sat, 9 Dec 2017 01:45:03 +0000 (17:45 -0800)
committerDylan Baker <dylan@pnwbakers.com>
Wed, 18 Apr 2018 16:03:57 +0000 (09:03 -0700)
This patch converts optimization-test.sh to python, in this process it
removes external shell dependencies including diff. It replaces the
python script that generates shell scripts with a python library that
generates test cases and runs them using subprocess.

v2: - use $PYTHON2 to be consistent with other tests in mesa

Signed-off-by: Dylan Baker <dylan.c.baker@intel.com>
src/compiler/glsl/tests/lower_jump_cases.py [new file with mode: 0644]
src/compiler/glsl/tests/lower_jumps/.gitignore [deleted file]
src/compiler/glsl/tests/lower_jumps/create_test_cases.py [deleted file]
src/compiler/glsl/tests/optimization-test.sh
src/compiler/glsl/tests/optimization_test.py [new file with mode: 0755]

diff --git a/src/compiler/glsl/tests/lower_jump_cases.py b/src/compiler/glsl/tests/lower_jump_cases.py
new file mode 100644 (file)
index 0000000..b50ab73
--- /dev/null
@@ -0,0 +1,643 @@
+# coding=utf-8
+#
+# Copyright © 2011, 2018 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+from sexps import *
+
+def make_test_case(f_name, ret_type, body):
+    """Create a simple optimization test case consisting of a single
+    function with the given name, return type, and body.
+
+    Global declarations are automatically created for any undeclared
+    variables that are referenced by the function.  All undeclared
+    variables are assumed to be floats.
+    """
+    check_sexp(body)
+    declarations = {}
+    def make_declarations(sexp, already_declared = ()):
+        if isinstance(sexp, list):
+            if len(sexp) == 2 and sexp[0] == 'var_ref':
+                if sexp[1] not in already_declared:
+                    declarations[sexp[1]] = [
+                        'declare', ['in'], 'float', sexp[1]]
+            elif len(sexp) == 4 and sexp[0] == 'assign':
+                assert sexp[2][0] == 'var_ref'
+                if sexp[2][1] not in already_declared:
+                    declarations[sexp[2][1]] = [
+                        'declare', ['out'], 'float', sexp[2][1]]
+                make_declarations(sexp[3], already_declared)
+            else:
+                already_declared = set(already_declared)
+                for s in sexp:
+                    if isinstance(s, list) and len(s) >= 4 and \
+                            s[0] == 'declare':
+                        already_declared.add(s[3])
+                    else:
+                        make_declarations(s, already_declared)
+    make_declarations(body)
+    return declarations.values() + \
+        [['function', f_name, ['signature', ret_type, ['parameters'], body]]]
+
+
+# The following functions can be used to build expressions.
+
+def const_float(value):
+    """Create an expression representing the given floating point value."""
+    return ['constant', 'float', ['{0:.6f}'.format(value)]]
+
+def const_bool(value):
+    """Create an expression representing the given boolean value.
+
+    If value is not a boolean, it is converted to a boolean.  So, for
+    instance, const_bool(1) is equivalent to const_bool(True).
+    """
+    return ['constant', 'bool', ['{0}'.format(1 if value else 0)]]
+
+def gt_zero(var_name):
+    """Create Construct the expression var_name > 0"""
+    return ['expression', 'bool', '<', const_float(0), ['var_ref', var_name]]
+
+
+# The following functions can be used to build complex control flow
+# statements.  All of these functions return statement lists (even
+# those which only create a single statement), so that statements can
+# be sequenced together using the '+' operator.
+
+def return_(value = None):
+    """Create a return statement."""
+    if value is not None:
+        return [['return', value]]
+    else:
+        return [['return']]
+
+def break_():
+    """Create a break statement."""
+    return ['break']
+
+def continue_():
+    """Create a continue statement."""
+    return ['continue']
+
+def simple_if(var_name, then_statements, else_statements = None):
+    """Create a statement of the form
+
+    if (var_name > 0.0) {
+       <then_statements>
+    } else {
+       <else_statements>
+    }
+
+    else_statements may be omitted.
+    """
+    if else_statements is None:
+        else_statements = []
+    check_sexp(then_statements)
+    check_sexp(else_statements)
+    return [['if', gt_zero(var_name), then_statements, else_statements]]
+
+def loop(statements):
+    """Create a loop containing the given statements as its loop
+    body.
+    """
+    check_sexp(statements)
+    return [['loop', statements]]
+
+def declare_temp(var_type, var_name):
+    """Create a declaration of the form
+
+    (declare (temporary) <var_type> <var_name)
+    """
+    return [['declare', ['temporary'], var_type, var_name]]
+
+def assign_x(var_name, value):
+    """Create a statement that assigns <value> to the variable
+    <var_name>.  The assignment uses the mask (x).
+    """
+    check_sexp(value)
+    return [['assign', ['x'], ['var_ref', var_name], value]]
+
+def complex_if(var_prefix, statements):
+    """Create a statement of the form
+
+    if (<var_prefix>a > 0.0) {
+       if (<var_prefix>b > 0.0) {
+          <statements>
+       }
+    }
+
+    This is useful in testing jump lowering, because if <statements>
+    ends in a jump, lower_jumps.cpp won't try to combine this
+    construct with the code that follows it, as it might do for a
+    simple if.
+
+    All variables used in the if statement are prefixed with
+    var_prefix.  This can be used to ensure uniqueness.
+    """
+    check_sexp(statements)
+    return simple_if(var_prefix + 'a', simple_if(var_prefix + 'b', statements))
+
+def declare_execute_flag():
+    """Create the statements that lower_jumps.cpp uses to declare and
+    initialize the temporary boolean execute_flag.
+    """
+    return declare_temp('bool', 'execute_flag') + \
+        assign_x('execute_flag', const_bool(True))
+
+def declare_return_flag():
+    """Create the statements that lower_jumps.cpp uses to declare and
+    initialize the temporary boolean return_flag.
+    """
+    return declare_temp('bool', 'return_flag') + \
+        assign_x('return_flag', const_bool(False))
+
+def declare_return_value():
+    """Create the statements that lower_jumps.cpp uses to declare and
+    initialize the temporary variable return_value.  Assume that
+    return_value is a float.
+    """
+    return declare_temp('float', 'return_value')
+
+def declare_break_flag():
+    """Create the statements that lower_jumps.cpp uses to declare and
+    initialize the temporary boolean break_flag.
+    """
+    return declare_temp('bool', 'break_flag') + \
+        assign_x('break_flag', const_bool(False))
+
+def lowered_return_simple(value = None):
+    """Create the statements that lower_jumps.cpp lowers a return
+    statement to, in situations where it does not need to clear the
+    execute flag.
+    """
+    if value:
+        result = assign_x('return_value', value)
+    else:
+        result = []
+    return result + assign_x('return_flag', const_bool(True))
+
+def lowered_return(value = None):
+    """Create the statements that lower_jumps.cpp lowers a return
+    statement to, in situations where it needs to clear the execute
+    flag.
+    """
+    return lowered_return_simple(value) + \
+        assign_x('execute_flag', const_bool(False))
+
+def lowered_continue():
+    """Create the statement that lower_jumps.cpp lowers a continue
+    statement to.
+    """
+    return assign_x('execute_flag', const_bool(False))
+
+def lowered_break_simple():
+    """Create the statement that lower_jumps.cpp lowers a break
+    statement to, in situations where it does not need to clear the
+    execute flag.
+    """
+    return assign_x('break_flag', const_bool(True))
+
+def lowered_break():
+    """Create the statement that lower_jumps.cpp lowers a break
+    statement to, in situations where it needs to clear the execute
+    flag.
+    """
+    return lowered_break_simple() + assign_x('execute_flag', const_bool(False))
+
+def if_execute_flag(statements):
+    """Wrap statements in an if test so that they will only execute if
+    execute_flag is True.
+    """
+    check_sexp(statements)
+    return [['if', ['var_ref', 'execute_flag'], statements, []]]
+
+def if_return_flag(then_statements, else_statements):
+    """Wrap statements in an if test with return_flag as the condition.
+    """
+    check_sexp(then_statements)
+    check_sexp(else_statements)
+    return [['if', ['var_ref', 'return_flag'], then_statements, else_statements]]
+
+def if_not_return_flag(statements):
+    """Wrap statements in an if test so that they will only execute if
+    return_flag is False.
+    """
+    check_sexp(statements)
+    return [['if', ['var_ref', 'return_flag'], [], statements]]
+
+def final_return():
+    """Create the return statement that lower_jumps.cpp places at the
+    end of a function when lowering returns.
+    """
+    return [['return', ['var_ref', 'return_value']]]
+
+def final_break():
+    """Create the conditional break statement that lower_jumps.cpp
+    places at the end of a function when lowering breaks.
+    """
+    return [['if', ['var_ref', 'break_flag'], break_(), []]]
+
+def bash_quote(*args):
+    """Quote the arguments appropriately so that bash will understand
+    each argument as a single word.
+    """
+    def quote_word(word):
+        for c in word:
+            if not (c.isalpha() or c.isdigit() or c in '@%_-+=:,./'):
+                break
+        else:
+            if not word:
+                return "''"
+            return word
+        return "'{0}'".format(word.replace("'", "'\"'\"'"))
+    return ' '.join(quote_word(word) for word in args)
+
+def create_test_case(input_sexp, expected_sexp, test_name,
+                     pull_out_jumps=False, lower_sub_return=False,
+                     lower_main_return=False, lower_continue=False,
+                     lower_break=False):
+    """Create a test case that verifies that do_lower_jumps transforms
+    the given code in the expected way.
+    """
+    check_sexp(input_sexp)
+    check_sexp(expected_sexp)
+    input_str = sexp_to_string(sort_decls(input_sexp))
+    expected_output = sexp_to_string(sort_decls(expected_sexp)) # XXX: don't stringify this
+    optimization = (
+        'do_lower_jumps({0:d}, {1:d}, {2:d}, {3:d}, {4:d})'.format(
+            pull_out_jumps, lower_sub_return, lower_main_return,
+            lower_continue, lower_break))
+
+    return (test_name, optimization, input_str, expected_output)
+
+def test_lower_returns_main():
+    """Test that do_lower_jumps respects the lower_main_return flag in deciding
+    whether to lower returns in the main function.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            complex_if('', return_())
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            declare_execute_flag() +
+            declare_return_flag() +
+            complex_if('', lowered_return())
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_returns_main_true',
+        lower_main_return=True)
+    yield create_test_case(
+        input_sexp, input_sexp, 'lower_returns_main_false',
+        lower_main_return=False)
+
+def test_lower_returns_sub():
+    """Test that do_lower_jumps respects the lower_sub_return flag in deciding
+    whether to lower returns in subroutines.
+    """
+    input_sexp = make_test_case('sub', 'void', (
+            complex_if('', return_())
+            ))
+    expected_sexp = make_test_case('sub', 'void', (
+            declare_execute_flag() +
+            declare_return_flag() +
+            complex_if('', lowered_return())
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_returns_sub_true',
+        lower_sub_return=True)
+    yield create_test_case(
+        input_sexp, input_sexp, 'lower_returns_sub_false',
+        lower_sub_return=False)
+
+def test_lower_returns_1():
+    """Test that a void return at the end of a function is eliminated."""
+    input_sexp = make_test_case('main', 'void', (
+            assign_x('a', const_float(1)) +
+            return_()
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            assign_x('a', const_float(1))
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_returns_1', lower_main_return=True)
+
+def test_lower_returns_2():
+    """Test that lowering is not performed on a non-void return at the end of
+    subroutine.
+    """
+    input_sexp = make_test_case('sub', 'float', (
+            assign_x('a', const_float(1)) +
+            return_(const_float(1))
+            ))
+    yield create_test_case(
+        input_sexp, input_sexp, 'lower_returns_2', lower_sub_return=True)
+
+def test_lower_returns_3():
+    """Test lowering of returns when there is one nested inside a complex
+    structure of ifs, and one at the end of a function.
+
+    In this case, the latter return needs to be lowered because it will not be
+    at the end of the function once the final return is inserted.
+    """
+    input_sexp = make_test_case('sub', 'float', (
+            complex_if('', return_(const_float(1))) +
+            return_(const_float(2))
+            ))
+    expected_sexp = make_test_case('sub', 'float', (
+            declare_execute_flag() +
+            declare_return_value() +
+            declare_return_flag() +
+            complex_if('', lowered_return(const_float(1))) +
+            if_execute_flag(lowered_return(const_float(2))) +
+            final_return()
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_returns_3', lower_sub_return=True)
+
+def test_lower_returns_4():
+    """Test that returns are properly lowered when they occur in both branches
+    of an if-statement.
+    """
+    input_sexp = make_test_case('sub', 'float', (
+            simple_if('a', return_(const_float(1)),
+                      return_(const_float(2)))
+            ))
+    expected_sexp = make_test_case('sub', 'float', (
+            declare_execute_flag() +
+            declare_return_value() +
+            declare_return_flag() +
+            simple_if('a', lowered_return(const_float(1)),
+                      lowered_return(const_float(2))) +
+            final_return()
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_returns_4', lower_sub_return=True)
+
+def test_lower_unified_returns():
+    """If both branches of an if statement end in a return, and pull_out_jumps
+    is True, then those returns should be lifted outside the if and then
+    properly lowered.
+
+    Verify that this lowering occurs during the same pass as the lowering of
+    other returns by checking that extra temporary variables aren't generated.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            complex_if('a', return_()) +
+            simple_if('b', simple_if('c', return_(), return_()))
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            declare_execute_flag() +
+            declare_return_flag() +
+            complex_if('a', lowered_return()) +
+            if_execute_flag(simple_if('b', (simple_if('c', [], []) +
+                                            lowered_return())))
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_unified_returns',
+        lower_main_return=True, pull_out_jumps=True)
+
+def test_lower_pulled_out_jump():
+    doc_string = """If one branch of an if ends in a jump, and control cannot
+    fall out the bottom of the other branch, and pull_out_jumps is
+    True, then the jump is lifted outside the if.
+
+    Verify that this lowering occurs during the same pass as the
+    lowering of other jumps by checking that extra temporary
+    variables aren't generated.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            complex_if('a', return_()) +
+            loop(simple_if('b', simple_if('c', break_(), continue_()),
+                           return_())) +
+            assign_x('d', const_float(1))
+            ))
+    # Note: optimization produces two other effects: the break
+    # gets lifted out of the if statements, and the code after the
+    # loop gets guarded so that it only executes if the return
+    # flag is clear.
+    expected_sexp = make_test_case('main', 'void', (
+            declare_execute_flag() +
+            declare_return_flag() +
+            complex_if('a', lowered_return()) +
+            if_execute_flag(
+                loop(simple_if('b', simple_if('c', [], continue_()),
+                               lowered_return_simple()) +
+                     break_()) +
+
+                if_return_flag(assign_x('return_flag', const_bool(1)) +
+                               assign_x('execute_flag', const_bool(0)),
+                               assign_x('d', const_float(1))))
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_pulled_out_jump',
+        lower_main_return=True, pull_out_jumps=True)
+
+def test_lower_breaks_1():
+    """If a loop contains an unconditional break at the bottom of it, it should
+    not be lowered.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 break_())
+            ))
+    expected_sexp = input_sexp
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_breaks_1', lower_break=True)
+
+def test_lower_breaks_2():
+    """If a loop contains a conditional break at the bottom of it, it should
+    not be lowered if it is in the then-clause.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 simple_if('b', break_()))
+            ))
+    expected_sexp = input_sexp
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_breaks_2', lower_break=True)
+
+def test_lower_breaks_3():
+    """If a loop contains a conditional break at the bottom of it, it should
+    not be lowered if it is in the then-clause, even if there are statements
+    preceding the break.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 simple_if('b', (assign_x('c', const_float(1)) +
+                                 break_())))
+            ))
+    expected_sexp = input_sexp
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_breaks_3', lower_break=True)
+
+def test_lower_breaks_4():
+    """If a loop contains a conditional break at the bottom of it, it should
+    not be lowered if it is in the else-clause.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 simple_if('b', [], break_()))
+            ))
+    expected_sexp = input_sexp
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_breaks_4', lower_break=True)
+
+def test_lower_breaks_5():
+    """If a loop contains a conditional break at the bottom of it, it should
+    not be lowered if it is in the else-clause, even if there are statements
+    preceding the break.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 simple_if('b', [], (assign_x('c', const_float(1)) +
+                                     break_())))
+            ))
+    expected_sexp = input_sexp
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_breaks_5', lower_break=True)
+
+def test_lower_breaks_6():
+    """If a loop contains conditional breaks and continues, and ends in an
+    unconditional break, then the unconditional break needs to be lowered,
+    because it will no longer be at the end of the loop after the final break
+    is added.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(simple_if('a', (complex_if('b', continue_()) +
+                                 complex_if('c', break_()))) +
+                 break_())
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            declare_break_flag() +
+            loop(declare_execute_flag() +
+                 simple_if(
+                    'a',
+                    (complex_if('b', lowered_continue()) +
+                     if_execute_flag(
+                            complex_if('c', lowered_break())))) +
+                 if_execute_flag(lowered_break_simple()) +
+                 final_break())
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_breaks_6', lower_break=True,
+        lower_continue=True)
+
+def test_lower_guarded_conditional_break():
+    """Normally a conditional break at the end of a loop isn't lowered, however
+    if the conditional break gets placed inside an if(execute_flag) because of
+    earlier lowering of continues, then the break needs to be lowered.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(complex_if('a', continue_()) +
+                 simple_if('b', break_()))
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            declare_break_flag() +
+            loop(declare_execute_flag() +
+                 complex_if('a', lowered_continue()) +
+                 if_execute_flag(simple_if('b', lowered_break())) +
+                 final_break())
+            ))
+    yield create_test_case(
+        input_sexp, expected_sexp, 'lower_guarded_conditional_break',
+        lower_break=True, lower_continue=True)
+
+def test_remove_continue_at_end_of_loop():
+    """Test that a redundant continue-statement at the end of a loop is
+    removed.
+    """
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 continue_())
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)))
+            ))
+    yield create_test_case(input_sexp, expected_sexp, 'remove_continue_at_end_of_loop')
+
+def test_lower_return_void_at_end_of_loop():
+    """Test that a return of void at the end of a loop is properly lowered."""
+    input_sexp = make_test_case('main', 'void', (
+            loop(assign_x('a', const_float(1)) +
+                 return_()) +
+            assign_x('b', const_float(2))
+            ))
+    expected_sexp = make_test_case('main', 'void', (
+            declare_execute_flag() +
+            declare_return_flag() +
+            loop(assign_x('a', const_float(1)) +
+                 lowered_return_simple() +
+                 break_()) +
+            if_return_flag(assign_x('return_flag', const_bool(1)) +
+                           assign_x('execute_flag', const_bool(0)),
+                           assign_x('b', const_float(2)))
+            ))
+    yield create_test_case(
+        input_sexp, input_sexp, 'return_void_at_end_of_loop_lower_nothing')
+    yield create_test_case(
+        input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return',
+        lower_main_return=True)
+    yield create_test_case(
+        input_sexp, expected_sexp,
+        'return_void_at_end_of_loop_lower_return_and_break',
+        lower_main_return=True, lower_break=True)
+
+def test_lower_return_non_void_at_end_of_loop():
+    """Test that a non-void return at the end of a loop is properly lowered."""
+    input_sexp = make_test_case('sub', 'float', (
+            loop(assign_x('a', const_float(1)) +
+                 return_(const_float(2))) +
+            assign_x('b', const_float(3)) +
+            return_(const_float(4))
+            ))
+    expected_sexp = make_test_case('sub', 'float', (
+            declare_execute_flag() +
+            declare_return_value() +
+            declare_return_flag() +
+            loop(assign_x('a', const_float(1)) +
+                 lowered_return_simple(const_float(2)) +
+                 break_()) +
+            if_return_flag(assign_x('return_value', '(var_ref return_value)') +
+                           assign_x('return_flag', const_bool(1)) +
+                           assign_x('execute_flag', const_bool(0)),
+                           assign_x('b', const_float(3)) +
+                               lowered_return(const_float(4))) +
+            final_return()
+            ))
+    yield create_test_case(
+        input_sexp, input_sexp, 'return_non_void_at_end_of_loop_lower_nothing')
+    yield create_test_case(
+        input_sexp, expected_sexp,
+        'return_non_void_at_end_of_loop_lower_return', lower_sub_return=True)
+    yield create_test_case(
+        input_sexp, expected_sexp,
+        'return_non_void_at_end_of_loop_lower_return_and_break',
+        lower_sub_return=True, lower_break=True)
+
+CASES = [
+    test_lower_breaks_1, test_lower_breaks_2, test_lower_breaks_3,
+    test_lower_breaks_4, test_lower_breaks_5, test_lower_breaks_6,
+    test_lower_guarded_conditional_break, test_lower_pulled_out_jump,
+    test_lower_return_non_void_at_end_of_loop,
+    test_lower_return_void_at_end_of_loop,
+    test_lower_returns_1, test_lower_returns_2, test_lower_returns_3,
+    test_lower_returns_4, test_lower_returns_main, test_lower_returns_sub,
+    test_lower_unified_returns, test_remove_continue_at_end_of_loop,
+]
diff --git a/src/compiler/glsl/tests/lower_jumps/.gitignore b/src/compiler/glsl/tests/lower_jumps/.gitignore
deleted file mode 100644 (file)
index e98df62..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-*.opt_test
-*.expected
-*.out
diff --git a/src/compiler/glsl/tests/lower_jumps/create_test_cases.py b/src/compiler/glsl/tests/lower_jumps/create_test_cases.py
deleted file mode 100644 (file)
index 88a74a3..0000000
+++ /dev/null
@@ -1,673 +0,0 @@
-# coding=utf-8
-#
-# Copyright © 2011 Intel Corporation
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice (including the next
-# paragraph) shall be included in all copies or substantial portions of the
-# Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-import argparse
-import os
-import os.path
-import re
-import subprocess
-import sys
-
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) # For access to sexps.py, which is in parent dir
-from sexps import *
-
-runner = ":"
-outdir = "."
-def make_test_case(f_name, ret_type, body):
-    """Create a simple optimization test case consisting of a single
-    function with the given name, return type, and body.
-
-    Global declarations are automatically created for any undeclared
-    variables that are referenced by the function.  All undeclared
-    variables are assumed to be floats.
-    """
-    check_sexp(body)
-    declarations = {}
-    def make_declarations(sexp, already_declared = ()):
-        if isinstance(sexp, list):
-            if len(sexp) == 2 and sexp[0] == 'var_ref':
-                if sexp[1] not in already_declared:
-                    declarations[sexp[1]] = [
-                        'declare', ['in'], 'float', sexp[1]]
-            elif len(sexp) == 4 and sexp[0] == 'assign':
-                assert sexp[2][0] == 'var_ref'
-                if sexp[2][1] not in already_declared:
-                    declarations[sexp[2][1]] = [
-                        'declare', ['out'], 'float', sexp[2][1]]
-                make_declarations(sexp[3], already_declared)
-            else:
-                already_declared = set(already_declared)
-                for s in sexp:
-                    if isinstance(s, list) and len(s) >= 4 and \
-                            s[0] == 'declare':
-                        already_declared.add(s[3])
-                    else:
-                        make_declarations(s, already_declared)
-    make_declarations(body)
-    return declarations.values() + \
-        [['function', f_name, ['signature', ret_type, ['parameters'], body]]]
-
-
-# The following functions can be used to build expressions.
-
-def const_float(value):
-    """Create an expression representing the given floating point value."""
-    return ['constant', 'float', ['{0:.6f}'.format(value)]]
-
-def const_bool(value):
-    """Create an expression representing the given boolean value.
-
-    If value is not a boolean, it is converted to a boolean.  So, for
-    instance, const_bool(1) is equivalent to const_bool(True).
-    """
-    return ['constant', 'bool', ['{0}'.format(1 if value else 0)]]
-
-def gt_zero(var_name):
-    """Create Construct the expression var_name > 0"""
-    return ['expression', 'bool', '<', const_float(0), ['var_ref', var_name]]
-
-
-# The following functions can be used to build complex control flow
-# statements.  All of these functions return statement lists (even
-# those which only create a single statement), so that statements can
-# be sequenced together using the '+' operator.
-
-def return_(value = None):
-    """Create a return statement."""
-    if value is not None:
-        return [['return', value]]
-    else:
-        return [['return']]
-
-def break_():
-    """Create a break statement."""
-    return ['break']
-
-def continue_():
-    """Create a continue statement."""
-    return ['continue']
-
-def simple_if(var_name, then_statements, else_statements = None):
-    """Create a statement of the form
-
-    if (var_name > 0.0) {
-       <then_statements>
-    } else {
-       <else_statements>
-    }
-
-    else_statements may be omitted.
-    """
-    if else_statements is None:
-        else_statements = []
-    check_sexp(then_statements)
-    check_sexp(else_statements)
-    return [['if', gt_zero(var_name), then_statements, else_statements]]
-
-def loop(statements):
-    """Create a loop containing the given statements as its loop
-    body.
-    """
-    check_sexp(statements)
-    return [['loop', statements]]
-
-def declare_temp(var_type, var_name):
-    """Create a declaration of the form
-
-    (declare (temporary) <var_type> <var_name)
-    """
-    return [['declare', ['temporary'], var_type, var_name]]
-
-def assign_x(var_name, value):
-    """Create a statement that assigns <value> to the variable
-    <var_name>.  The assignment uses the mask (x).
-    """
-    check_sexp(value)
-    return [['assign', ['x'], ['var_ref', var_name], value]]
-
-def complex_if(var_prefix, statements):
-    """Create a statement of the form
-
-    if (<var_prefix>a > 0.0) {
-       if (<var_prefix>b > 0.0) {
-          <statements>
-       }
-    }
-
-    This is useful in testing jump lowering, because if <statements>
-    ends in a jump, lower_jumps.cpp won't try to combine this
-    construct with the code that follows it, as it might do for a
-    simple if.
-
-    All variables used in the if statement are prefixed with
-    var_prefix.  This can be used to ensure uniqueness.
-    """
-    check_sexp(statements)
-    return simple_if(var_prefix + 'a', simple_if(var_prefix + 'b', statements))
-
-def declare_execute_flag():
-    """Create the statements that lower_jumps.cpp uses to declare and
-    initialize the temporary boolean execute_flag.
-    """
-    return declare_temp('bool', 'execute_flag') + \
-        assign_x('execute_flag', const_bool(True))
-
-def declare_return_flag():
-    """Create the statements that lower_jumps.cpp uses to declare and
-    initialize the temporary boolean return_flag.
-    """
-    return declare_temp('bool', 'return_flag') + \
-        assign_x('return_flag', const_bool(False))
-
-def declare_return_value():
-    """Create the statements that lower_jumps.cpp uses to declare and
-    initialize the temporary variable return_value.  Assume that
-    return_value is a float.
-    """
-    return declare_temp('float', 'return_value')
-
-def declare_break_flag():
-    """Create the statements that lower_jumps.cpp uses to declare and
-    initialize the temporary boolean break_flag.
-    """
-    return declare_temp('bool', 'break_flag') + \
-        assign_x('break_flag', const_bool(False))
-
-def lowered_return_simple(value = None):
-    """Create the statements that lower_jumps.cpp lowers a return
-    statement to, in situations where it does not need to clear the
-    execute flag.
-    """
-    if value:
-        result = assign_x('return_value', value)
-    else:
-        result = []
-    return result + assign_x('return_flag', const_bool(True))
-
-def lowered_return(value = None):
-    """Create the statements that lower_jumps.cpp lowers a return
-    statement to, in situations where it needs to clear the execute
-    flag.
-    """
-    return lowered_return_simple(value) + \
-        assign_x('execute_flag', const_bool(False))
-
-def lowered_continue():
-    """Create the statement that lower_jumps.cpp lowers a continue
-    statement to.
-    """
-    return assign_x('execute_flag', const_bool(False))
-
-def lowered_break_simple():
-    """Create the statement that lower_jumps.cpp lowers a break
-    statement to, in situations where it does not need to clear the
-    execute flag.
-    """
-    return assign_x('break_flag', const_bool(True))
-
-def lowered_break():
-    """Create the statement that lower_jumps.cpp lowers a break
-    statement to, in situations where it needs to clear the execute
-    flag.
-    """
-    return lowered_break_simple() + assign_x('execute_flag', const_bool(False))
-
-def if_execute_flag(statements):
-    """Wrap statements in an if test so that they will only execute if
-    execute_flag is True.
-    """
-    check_sexp(statements)
-    return [['if', ['var_ref', 'execute_flag'], statements, []]]
-
-def if_return_flag(then_statements, else_statements):
-    """Wrap statements in an if test with return_flag as the condition.
-    """
-    check_sexp(then_statements)
-    check_sexp(else_statements)
-    return [['if', ['var_ref', 'return_flag'], then_statements, else_statements]]
-
-def if_not_return_flag(statements):
-    """Wrap statements in an if test so that they will only execute if
-    return_flag is False.
-    """
-    check_sexp(statements)
-    return [['if', ['var_ref', 'return_flag'], [], statements]]
-
-def final_return():
-    """Create the return statement that lower_jumps.cpp places at the
-    end of a function when lowering returns.
-    """
-    return [['return', ['var_ref', 'return_value']]]
-
-def final_break():
-    """Create the conditional break statement that lower_jumps.cpp
-    places at the end of a function when lowering breaks.
-    """
-    return [['if', ['var_ref', 'break_flag'], break_(), []]]
-
-def bash_quote(*args):
-    """Quote the arguments appropriately so that bash will understand
-    each argument as a single word.
-    """
-    def quote_word(word):
-        for c in word:
-            if not (c.isalpha() or c.isdigit() or c in '@%_-+=:,./'):
-                break
-        else:
-            if not word:
-                return "''"
-            return word
-        return "'{0}'".format(word.replace("'", "'\"'\"'"))
-    return ' '.join(quote_word(word) for word in args)
-
-def create_test_case(doc_string, input_sexp, expected_sexp, test_name,
-                     pull_out_jumps=False, lower_sub_return=False,
-                     lower_main_return=False, lower_continue=False,
-                     lower_break=False):
-    """Create a test case that verifies that do_lower_jumps transforms
-    the given code in the expected way.
-    """
-    doc_lines = [line.strip() for line in doc_string.splitlines()]
-    doc_string = ''.join('# {0}\n'.format(line) for line in doc_lines if line != '')
-    check_sexp(input_sexp)
-    check_sexp(expected_sexp)
-    input_str = sexp_to_string(sort_decls(input_sexp))
-    expected_output = sexp_to_string(sort_decls(expected_sexp))
-
-    optimization = (
-        'do_lower_jumps({0:d}, {1:d}, {2:d}, {3:d}, {4:d})'.format(
-            pull_out_jumps, lower_sub_return, lower_main_return,
-            lower_continue, lower_break))
-    args = [runner, 'optpass', '--quiet', '--input-ir', optimization]
-    test_file = os.path.join(outdir, '{0}.opt_test'.format(test_name))
-    with open(test_file, 'w') as f:
-        f.write('#!/usr/bin/env bash\n#\n# This file was generated by create_test_cases.py.\n#\n')
-        f.write(doc_string)
-        f.write('{0} <<EOF\n'.format(bash_quote(*args)))
-        f.write('{0}\nEOF\n'.format(input_str))
-    os.chmod(test_file, 0774)
-    expected_file = os.path.join(outdir, '{0}.opt_test.expected'.format(test_name))
-    with open(expected_file, 'w') as f:
-        f.write('{0}\n'.format(expected_output))
-
-def test_lower_returns_main():
-    doc_string = """Test that do_lower_jumps respects the lower_main_return
-    flag in deciding whether to lower returns in the main
-    function.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            complex_if('', return_())
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            declare_execute_flag() +
-            declare_return_flag() +
-            complex_if('', lowered_return())
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_main_true',
-                     lower_main_return=True)
-    create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_main_false',
-                     lower_main_return=False)
-
-def test_lower_returns_sub():
-    doc_string = """Test that do_lower_jumps respects the lower_sub_return flag
-    in deciding whether to lower returns in subroutines.
-    """
-    input_sexp = make_test_case('sub', 'void', (
-            complex_if('', return_())
-            ))
-    expected_sexp = make_test_case('sub', 'void', (
-            declare_execute_flag() +
-            declare_return_flag() +
-            complex_if('', lowered_return())
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_sub_true',
-                     lower_sub_return=True)
-    create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_sub_false',
-                     lower_sub_return=False)
-
-def test_lower_returns_1():
-    doc_string = """Test that a void return at the end of a function is
-    eliminated.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            assign_x('a', const_float(1)) +
-            return_()
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            assign_x('a', const_float(1))
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_1',
-                     lower_main_return=True)
-
-def test_lower_returns_2():
-    doc_string = """Test that lowering is not performed on a non-void return at
-    the end of subroutine.
-    """
-    input_sexp = make_test_case('sub', 'float', (
-            assign_x('a', const_float(1)) +
-            return_(const_float(1))
-            ))
-    create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_2',
-                     lower_sub_return=True)
-
-def test_lower_returns_3():
-    doc_string = """Test lowering of returns when there is one nested inside a
-    complex structure of ifs, and one at the end of a function.
-
-    In this case, the latter return needs to be lowered because it
-    will not be at the end of the function once the final return
-    is inserted.
-    """
-    input_sexp = make_test_case('sub', 'float', (
-            complex_if('', return_(const_float(1))) +
-            return_(const_float(2))
-            ))
-    expected_sexp = make_test_case('sub', 'float', (
-            declare_execute_flag() +
-            declare_return_value() +
-            declare_return_flag() +
-            complex_if('', lowered_return(const_float(1))) +
-            if_execute_flag(lowered_return(const_float(2))) +
-            final_return()
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_3',
-                     lower_sub_return=True)
-
-def test_lower_returns_4():
-    doc_string = """Test that returns are properly lowered when they occur in
-    both branches of an if-statement.
-    """
-    input_sexp = make_test_case('sub', 'float', (
-            simple_if('a', return_(const_float(1)),
-                      return_(const_float(2)))
-            ))
-    expected_sexp = make_test_case('sub', 'float', (
-            declare_execute_flag() +
-            declare_return_value() +
-            declare_return_flag() +
-            simple_if('a', lowered_return(const_float(1)),
-                      lowered_return(const_float(2))) +
-            final_return()
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_4',
-                     lower_sub_return=True)
-
-def test_lower_unified_returns():
-    doc_string = """If both branches of an if statement end in a return, and
-    pull_out_jumps is True, then those returns should be lifted
-    outside the if and then properly lowered.
-
-    Verify that this lowering occurs during the same pass as the
-    lowering of other returns by checking that extra temporary
-    variables aren't generated.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            complex_if('a', return_()) +
-            simple_if('b', simple_if('c', return_(), return_()))
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            declare_execute_flag() +
-            declare_return_flag() +
-            complex_if('a', lowered_return()) +
-            if_execute_flag(simple_if('b', (simple_if('c', [], []) +
-                                            lowered_return())))
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_unified_returns',
-                     lower_main_return=True, pull_out_jumps=True)
-
-def test_lower_pulled_out_jump():
-    doc_string = """If one branch of an if ends in a jump, and control cannot
-    fall out the bottom of the other branch, and pull_out_jumps is
-    True, then the jump is lifted outside the if.
-
-    Verify that this lowering occurs during the same pass as the
-    lowering of other jumps by checking that extra temporary
-    variables aren't generated.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            complex_if('a', return_()) +
-            loop(simple_if('b', simple_if('c', break_(), continue_()),
-                           return_())) +
-            assign_x('d', const_float(1))
-            ))
-    # Note: optimization produces two other effects: the break
-    # gets lifted out of the if statements, and the code after the
-    # loop gets guarded so that it only executes if the return
-    # flag is clear.
-    expected_sexp = make_test_case('main', 'void', (
-            declare_execute_flag() +
-            declare_return_flag() +
-            complex_if('a', lowered_return()) +
-            if_execute_flag(
-                loop(simple_if('b', simple_if('c', [], continue_()),
-                               lowered_return_simple()) +
-                     break_()) +
-
-                if_return_flag(assign_x('return_flag', const_bool(1)) +
-                               assign_x('execute_flag', const_bool(0)),
-                               assign_x('d', const_float(1))))
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_pulled_out_jump',
-                     lower_main_return=True, pull_out_jumps=True)
-
-def test_lower_breaks_1():
-    doc_string = """If a loop contains an unconditional break at the bottom of
-    it, it should not be lowered."""
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 break_())
-            ))
-    expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_1', lower_break=True)
-
-def test_lower_breaks_2():
-    doc_string = """If a loop contains a conditional break at the bottom of it,
-    it should not be lowered if it is in the then-clause.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 simple_if('b', break_()))
-            ))
-    expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_2', lower_break=True)
-
-def test_lower_breaks_3():
-    doc_string = """If a loop contains a conditional break at the bottom of it,
-    it should not be lowered if it is in the then-clause, even if
-    there are statements preceding the break.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 simple_if('b', (assign_x('c', const_float(1)) +
-                                 break_())))
-            ))
-    expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_3', lower_break=True)
-
-def test_lower_breaks_4():
-    doc_string = """If a loop contains a conditional break at the bottom of it,
-    it should not be lowered if it is in the else-clause.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 simple_if('b', [], break_()))
-            ))
-    expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_4', lower_break=True)
-
-def test_lower_breaks_5():
-    doc_string = """If a loop contains a conditional break at the bottom of it,
-    it should not be lowered if it is in the else-clause, even if
-    there are statements preceding the break.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 simple_if('b', [], (assign_x('c', const_float(1)) +
-                                     break_())))
-            ))
-    expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_5', lower_break=True)
-
-def test_lower_breaks_6():
-    doc_string = """If a loop contains conditional breaks and continues, and
-    ends in an unconditional break, then the unconditional break
-    needs to be lowered, because it will no longer be at the end
-    of the loop after the final break is added.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(simple_if('a', (complex_if('b', continue_()) +
-                                 complex_if('c', break_()))) +
-                 break_())
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            declare_break_flag() +
-            loop(declare_execute_flag() +
-                 simple_if(
-                    'a',
-                    (complex_if('b', lowered_continue()) +
-                     if_execute_flag(
-                            complex_if('c', lowered_break())))) +
-                 if_execute_flag(lowered_break_simple()) +
-                 final_break())
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_6',
-                     lower_break=True, lower_continue=True)
-
-def test_lower_guarded_conditional_break():
-    doc_string = """Normally a conditional break at the end of a loop isn't
-    lowered, however if the conditional break gets placed inside
-    an if(execute_flag) because of earlier lowering of continues,
-    then the break needs to be lowered.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(complex_if('a', continue_()) +
-                 simple_if('b', break_()))
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            declare_break_flag() +
-            loop(declare_execute_flag() +
-                 complex_if('a', lowered_continue()) +
-                 if_execute_flag(simple_if('b', lowered_break())) +
-                 final_break())
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_guarded_conditional_break',
-                     lower_break=True, lower_continue=True)
-
-def test_remove_continue_at_end_of_loop():
-    doc_string = """Test that a redundant continue-statement at the end of a
-    loop is removed.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 continue_())
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)))
-            ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'remove_continue_at_end_of_loop')
-
-def test_lower_return_void_at_end_of_loop():
-    doc_string = """Test that a return of void at the end of a loop is properly
-    lowered.
-    """
-    input_sexp = make_test_case('main', 'void', (
-            loop(assign_x('a', const_float(1)) +
-                 return_()) +
-            assign_x('b', const_float(2))
-            ))
-    expected_sexp = make_test_case('main', 'void', (
-            declare_execute_flag() +
-            declare_return_flag() +
-            loop(assign_x('a', const_float(1)) +
-                 lowered_return_simple() +
-                 break_()) +
-            if_return_flag(assign_x('return_flag', const_bool(1)) +
-                           assign_x('execute_flag', const_bool(0)),
-                           assign_x('b', const_float(2)))
-            ))
-    create_test_case(doc_string, input_sexp, input_sexp, 'return_void_at_end_of_loop_lower_nothing')
-    create_test_case(doc_string, input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return',
-                     lower_main_return=True)
-    create_test_case(doc_string, input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return_and_break',
-                     lower_main_return=True, lower_break=True)
-
-def test_lower_return_non_void_at_end_of_loop():
-    doc_string = """Test that a non-void return at the end of a loop is
-    properly lowered.
-    """
-    input_sexp = make_test_case('sub', 'float', (
-            loop(assign_x('a', const_float(1)) +
-                 return_(const_float(2))) +
-            assign_x('b', const_float(3)) +
-            return_(const_float(4))
-            ))
-    expected_sexp = make_test_case('sub', 'float', (
-            declare_execute_flag() +
-            declare_return_value() +
-            declare_return_flag() +
-            loop(assign_x('a', const_float(1)) +
-                 lowered_return_simple(const_float(2)) +
-                 break_()) +
-            if_return_flag(assign_x('return_value', '(var_ref return_value)') +
-                           assign_x('return_flag', const_bool(1)) +
-                           assign_x('execute_flag', const_bool(0)),
-                           assign_x('b', const_float(3)) +
-                               lowered_return(const_float(4))) +
-            final_return()
-            ))
-    create_test_case(doc_string, input_sexp, input_sexp, 'return_non_void_at_end_of_loop_lower_nothing')
-    create_test_case(doc_string, input_sexp, expected_sexp, 'return_non_void_at_end_of_loop_lower_return',
-                     lower_sub_return=True)
-    create_test_case(doc_string, input_sexp, expected_sexp, 'return_non_void_at_end_of_loop_lower_return_and_break',
-                     lower_sub_return=True, lower_break=True)
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--runner',
-                        help='The glsl_test runner',
-                        required=True)
-    parser.add_argument('--outdir',
-                        help='Directory to put the generated files in',
-                        required=True)
-    args = parser.parse_args()
-    runner = args.runner
-    outdir = args.outdir
-
-    test_lower_returns_main()
-    test_lower_returns_sub()
-    test_lower_returns_1()
-    test_lower_returns_2()
-    test_lower_returns_3()
-    test_lower_returns_4()
-    test_lower_unified_returns()
-    test_lower_pulled_out_jump()
-    test_lower_breaks_1()
-    test_lower_breaks_2()
-    test_lower_breaks_3()
-    test_lower_breaks_4()
-    test_lower_breaks_5()
-    test_lower_breaks_6()
-    test_lower_guarded_conditional_break()
-    test_remove_continue_at_end_of_loop()
-    test_lower_return_void_at_end_of_loop()
-    test_lower_return_non_void_at_end_of_loop()
index e54edc7fb01d209f33f4bd49afec81a8a1c91e04..410ed262ef028caaaaecb14b69c63ba6d73c1ba8 100755 (executable)
@@ -1,88 +1,3 @@
 #!/bin/sh
 
-if [ -z "$PYTHON2" ]; then
-    PYTHON2=python2
-fi
-
-which $PYTHON2 >/dev/null
-if [ $? -ne 0 ]; then
-    echo "Could not find python2. Make sure that PYTHON2 variable is correctly set."
-    exit 1
-fi
-
-if [ -z "$srcdir" -o -z "$abs_builddir" ]; then
-    echo ""
-    echo "Warning: you're invoking the script manually and things may fail."
-    echo "Attempting to determine/set srcdir and abs_builddir variables."
-    echo ""
-
-    # Variable should point to the Makefile.glsl.am
-    srcdir=./../../
-    cd `dirname "$0"`
-    # Variable should point to the folder two levels above glsl_test
-    abs_builddir=`pwd`/../../
-fi
-
-compare_ir=$srcdir/glsl/tests/compare_ir.py
-
-total=0
-pass=0
-has_tests=0
-
-# Store our location before we start diving into subdirectories.
-ORIGDIR=`pwd`
-echo "======       Generating tests      ======"
-for dir in $srcdir/glsl/tests/*/; do
-    if [ -e "${dir}create_test_cases.py" ]; then
-        echo "$dir"
-        # construct the correct builddir
-        completedir="$abs_builddir/glsl/tests/`echo ${dir} | sed 's|.*/glsl/tests/||g'`"
-        mkdir -p $completedir
-        cd $dir;
-        $PYTHON2 create_test_cases.py --runner $abs_builddir/glsl/glsl_test --outdir $completedir;
-        if [ $? -eq 0 ]; then
-            has_tests=1
-        fi
-        cd ..
-    fi
-done
-cd "$ORIGDIR"
-
-if [ $has_tests -eq 0 ]; then
-    echo "Could not generate any tests."
-    exit 1
-fi
-
-if [ ! -f "$compare_ir" ]; then
-    echo "Could not find compare_ir. Make sure that srcdir variable is correctly set."
-    exit 1
-fi
-
-echo "====== Testing optimization passes ======"
-for test in `find . -iname '*.opt_test'`; do
-    echo -n "Testing `echo $test| sed 's|.*/glsl/tests/||g'`..."
-    ./$test > "$test.out" 2>&1
-    total=$((total+1))
-    if $PYTHON2 $PYTHON_FLAGS $compare_ir "$test.expected" "$test.out" >/dev/null 2>&1; then
-        echo "PASS"
-        pass=$((pass+1))
-    else
-        echo "FAIL"
-        $PYTHON2 $PYTHON_FLAGS $compare_ir "$test.expected" "$test.out"
-    fi
-done
-
-if [ $total -eq 0 ]; then
-    echo "Could not find any tests."
-    exit 1
-fi
-
-echo ""
-echo "$pass/$total tests returned correct results"
-echo ""
-
-if [ $pass = $total ]; then
-    exit 0
-else
-    exit 1
-fi
+$PYTHON2 $srcdir/glsl/tests/optimization_test.py --test-runner $abs_builddir/glsl/glsl_test
diff --git a/src/compiler/glsl/tests/optimization_test.py b/src/compiler/glsl/tests/optimization_test.py
new file mode 100755 (executable)
index 0000000..577d2df
--- /dev/null
@@ -0,0 +1,95 @@
+#!/usr/bin/env python2
+# encoding=utf-8
+# Copyright © 2018 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""Script to generate and run glsl optimization tests."""
+
+from __future__ import print_function
+import argparse
+import difflib
+import subprocess
+import sys
+
+import sexps
+import lower_jump_cases
+
+
+def arg_parser():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        '--test-runner',
+        required=True,
+        help='The glsl_test binary.')
+    return parser.parse_args()
+
+
+def compare(actual, expected):
+    """Compare the s-expresions and return a diff if they are different."""
+    actual = sexps.sort_decls(sexps.parse_sexp(actual))
+    expected = sexps.sort_decls(sexps.parse_sexp(expected))
+
+    if actual == expected:
+        return None
+
+    actual = sexps.sexp_to_string(actual)
+    expected = sexps.sexp_to_string(expected)
+
+    return difflib.unified_diff(expected.splitlines(), actual.splitlines())
+
+
+def main():
+    """Generate each test and report pass or fail."""
+    args = arg_parser()
+
+    total = 0
+    passes = 0
+
+    for gen in lower_jump_cases.CASES:
+        for name, opt, source, expected in gen():
+            total += 1
+            print('{}: '.format(name), end='')
+            proc = subprocess.Popen(
+                [args.test_runner, 'optpass', '--quiet', '--input-ir', opt],
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                stdin=subprocess.PIPE)
+            out, err = proc.communicate(source)
+            if err:
+                print('FAIL')
+                print('Unexpected output on stderr: {}'.format(err),
+                      file=sys.stdout)
+                continue
+
+            result = compare(out, expected)
+            if result is not None:
+                print('FAIL')
+                for l in result:
+                    print(l, file=sys.stderr)
+            else:
+                print('PASS')
+                passes += 1
+
+    print('{}/{} tests returned correct results'.format(passes, total))
+    exit(0 if passes == total else 1)
+
+
+if __name__ == '__main__':
+    main()