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 [moved from src/compiler/glsl/tests/lower_jumps/create_test_cases.py with 70% similarity]
src/compiler/glsl/tests/lower_jumps/.gitignore [deleted file]
src/compiler/glsl/tests/optimization-test.sh
src/compiler/glsl/tests/optimization_test.py [new file with mode: 0755]

@@ -1,6 +1,6 @@
 # coding=utf-8
 #
-# Copyright © 2011 Intel Corporation
+# 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"),
 # 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.
@@ -280,40 +270,27 @@ def bash_quote(*args):
         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,
+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.
     """
-    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))
-
+    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))
-    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))
+
+    return (test_name, optimization, input_str, 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.
+    """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_())
@@ -323,14 +300,16 @@ def test_lower_returns_main():
             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)
+    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():
-    doc_string = """Test that do_lower_jumps respects the lower_sub_return flag
-    in deciding whether to lower returns in subroutines.
+    """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_())
@@ -340,15 +319,15 @@ def test_lower_returns_sub():
             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)
+    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():
-    doc_string = """Test that a void return at the end of a function is
-    eliminated.
-    """
+    """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_()
@@ -356,27 +335,26 @@ def test_lower_returns_1():
     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)
+    yield create_test_case(
+        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.
+    """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)
+    yield create_test_case(
+        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.
+    """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.
+    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))) +
@@ -390,12 +368,12 @@ def test_lower_returns_3():
             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)
+    yield create_test_case(
+        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.
+    """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)),
@@ -409,17 +387,16 @@ def test_lower_returns_4():
                       lowered_return(const_float(2))) +
             final_return()
             ))
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_4',
-                     lower_sub_return=True)
+    yield create_test_case(
+        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.
+    """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.
+    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_()) +
@@ -432,8 +409,9 @@ def test_lower_unified_returns():
             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)
+    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
@@ -467,34 +445,38 @@ def test_lower_pulled_out_jump():
                                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)
+    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():
-    doc_string = """If a loop contains an unconditional break at the bottom of
-    it, it should not be lowered."""
+    """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)
+    yield create_test_case(
+        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.
+    """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)
+    yield create_test_case(
+        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.
+    """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)) +
@@ -502,23 +484,25 @@ def test_lower_breaks_3():
                                  break_())))
             ))
     expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_3', lower_break=True)
+    yield create_test_case(
+        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.
+    """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)
+    yield create_test_case(
+        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.
+    """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)) +
@@ -526,13 +510,14 @@ def test_lower_breaks_5():
                                      break_())))
             ))
     expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_5', lower_break=True)
+    yield create_test_case(
+        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.
+    """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_()) +
@@ -550,14 +535,14 @@ def test_lower_breaks_6():
                  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)
+    yield create_test_case(
+        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.
+    """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_()) +
@@ -570,12 +555,13 @@ def test_lower_guarded_conditional_break():
                  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)
+    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():
-    doc_string = """Test that a redundant continue-statement at the end of a
-    loop is removed.
+    """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)) +
@@ -584,12 +570,10 @@ def test_remove_continue_at_end_of_loop():
     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')
+    yield create_test_case(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.
-    """
+    """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_()) +
@@ -605,16 +589,18 @@ def test_lower_return_void_at_end_of_loop():
                            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)
+    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():
-    doc_string = """Test that a non-void return at the end of a loop is
-    properly lowered.
-    """
+    """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))) +
@@ -635,39 +621,23 @@ def test_lower_return_non_void_at_end_of_loop():
                                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()
+    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
index e54edc7..410ed26 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()