summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl')
-rwxr-xr-xsrc/glsl/tests/compare_ir59
-rw-r--r--src/glsl/tests/lower_jumps/.gitignore1
-rw-r--r--src/glsl/tests/lower_jumps/create_test_cases.py643
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_breaks_1.opt_test13
-rw-r--r--src/glsl/tests/lower_jumps/lower_breaks_1.opt_test.expected5
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_breaks_2.opt_test15
-rw-r--r--src/glsl/tests/lower_jumps/lower_breaks_2.opt_test.expected7
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_breaks_3.opt_test17
-rw-r--r--src/glsl/tests/lower_jumps/lower_breaks_3.opt_test.expected8
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_breaks_4.opt_test15
-rw-r--r--src/glsl/tests/lower_jumps/lower_breaks_4.opt_test.expected7
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_breaks_5.opt_test16
-rw-r--r--src/glsl/tests/lower_jumps/lower_breaks_5.opt_test.expected7
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_breaks_6.opt_test29
-rw-r--r--src/glsl/tests/lower_jumps/lower_breaks_6.opt_test.expected29
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test21
-rw-r--r--src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test.expected20
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test28
-rw-r--r--src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test.expected25
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_1.opt_test12
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_1.opt_test.expected4
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_2.opt_test13
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_2.opt_test.expected5
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_3.opt_test20
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_3.opt_test.expected21
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_4.opt_test14
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_4.opt_test.expected16
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_main_false.opt_test17
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test.expected8
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_main_true.opt_test17
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test.expected13
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test16
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test.expected8
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test16
-rw-r--r--src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test.expected13
-rwxr-xr-xsrc/glsl/tests/lower_jumps/lower_unified_returns.opt_test26
-rw-r--r--src/glsl/tests/lower_jumps/lower_unified_returns.opt_test.expected21
-rwxr-xr-xsrc/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test13
-rw-r--r--src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test.expected5
-rwxr-xr-xsrc/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test16
-rw-r--r--src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test.expected8
-rwxr-xr-xsrc/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test16
-rw-r--r--src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test.expected19
-rwxr-xr-xsrc/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test16
-rw-r--r--src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test.expected19
-rwxr-xr-xsrc/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test14
-rw-r--r--src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test.expected6
-rwxr-xr-xsrc/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test14
-rw-r--r--src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test.expected11
-rwxr-xr-xsrc/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test14
-rw-r--r--src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test.expected11
-rwxr-xr-xsrc/glsl/tests/optimization-test28
-rw-r--r--src/glsl/tests/sexps.py103
53 files changed, 1538 insertions, 0 deletions
diff --git a/src/glsl/tests/compare_ir b/src/glsl/tests/compare_ir
new file mode 100755
index 00000000000..a40fc810cf3
--- /dev/null
+++ b/src/glsl/tests/compare_ir
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# 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.
+
+# Compare two files containing IR code. Ignore formatting differences
+# and declaration order.
+
+import os
+import os.path
+import subprocess
+import sys
+import tempfile
+
+from sexps import *
+
+if len(sys.argv) != 3:
+ print 'Usage: compare_ir <file1> <file2>'
+ exit(1)
+
+with open(sys.argv[1]) as f:
+ ir1 = sort_decls(parse_sexp(f.read()))
+with open(sys.argv[2]) as f:
+ ir2 = sort_decls(parse_sexp(f.read()))
+
+if ir1 == ir2:
+ exit(0)
+else:
+ file1, path1 = tempfile.mkstemp(os.path.basename(sys.argv[1]))
+ file2, path2 = tempfile.mkstemp(os.path.basename(sys.argv[2]))
+ try:
+ os.write(file1, '{0}\n'.format(sexp_to_string(ir1)))
+ os.close(file1)
+ os.write(file2, '{0}\n'.format(sexp_to_string(ir2)))
+ os.close(file2)
+ subprocess.call(['diff', '-u', path1, path2])
+ finally:
+ os.remove(path1)
+ os.remove(path2)
+ exit(1)
diff --git a/src/glsl/tests/lower_jumps/.gitignore b/src/glsl/tests/lower_jumps/.gitignore
new file mode 100644
index 00000000000..f47cb2045f1
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/.gitignore
@@ -0,0 +1 @@
+*.out
diff --git a/src/glsl/tests/lower_jumps/create_test_cases.py b/src/glsl/tests/lower_jumps/create_test_cases.py
new file mode 100644
index 00000000000..fbc6f0a84ea
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/create_test_cases.py
@@ -0,0 +1,643 @@
+# 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 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 *
+
+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', '>', ['var_ref', var_name], const_float(0)]
+
+
+# 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_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 = ['../../glsl_test', 'optpass', '--quiet', '--input-ir', optimization]
+ test_file = '{0}.opt_test'.format(test_name)
+ with open(test_file, 'w') as f:
+ f.write('#!/bin/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 = '{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_not_return_flag(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_return_flag() +
+ loop(assign_x('a', const_float(1)) +
+ lowered_return_simple() +
+ break_()) +
+ if_not_return_flag(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_not_return_flag(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__':
+ 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()
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_1.opt_test b/src/glsl/tests/lower_jumps/lower_breaks_1.opt_test
new file mode 100755
index 00000000000..01ad7087a28
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_1.opt_test
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# If a loop contains an unconditional break at the bottom of
+# it, it should not be lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 1)' <<EOF
+((declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) break))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_1.opt_test.expected b/src/glsl/tests/lower_jumps/lower_breaks_1.opt_test.expected
new file mode 100644
index 00000000000..d4bb6fc0274
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_1.opt_test.expected
@@ -0,0 +1,5 @@
+((declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) break))))))
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_2.opt_test b/src/glsl/tests/lower_jumps/lower_breaks_2.opt_test
new file mode 100755
index 00000000000..0be22f953e1
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_2.opt_test
@@ -0,0 +1,15 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# If a loop contains a conditional break at the bottom of it,
+# it should not be lowered if it is in the then-clause.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 1)' <<EOF
+((declare (in) float b) (declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000))) (break)
+ ())))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_2.opt_test.expected b/src/glsl/tests/lower_jumps/lower_breaks_2.opt_test.expected
new file mode 100644
index 00000000000..a4cb2d6a125
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_2.opt_test.expected
@@ -0,0 +1,7 @@
+((declare (in) float b) (declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000))) (break)
+ ())))))))
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_3.opt_test b/src/glsl/tests/lower_jumps/lower_breaks_3.opt_test
new file mode 100755
index 00000000000..4149360b5d0
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_3.opt_test
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 1)' <<EOF
+((declare (in) float b) (declare (out) float a) (declare (out) float c)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((assign (x) (var_ref c) (constant float (1.000000))) break)
+ ())))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_3.opt_test.expected b/src/glsl/tests/lower_jumps/lower_breaks_3.opt_test.expected
new file mode 100644
index 00000000000..325f7b49a5d
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_3.opt_test.expected
@@ -0,0 +1,8 @@
+((declare (in) float b) (declare (out) float a) (declare (out) float c)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((assign (x) (var_ref c) (constant float (1.000000))) break)
+ ())))))))
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_4.opt_test b/src/glsl/tests/lower_jumps/lower_breaks_4.opt_test
new file mode 100755
index 00000000000..70458bb4f8e
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_4.opt_test
@@ -0,0 +1,15 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# If a loop contains a conditional break at the bottom of it,
+# it should not be lowered if it is in the else-clause.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 1)' <<EOF
+((declare (in) float b) (declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000))) ()
+ (break))))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_4.opt_test.expected b/src/glsl/tests/lower_jumps/lower_breaks_4.opt_test.expected
new file mode 100644
index 00000000000..a7735457cb8
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_4.opt_test.expected
@@ -0,0 +1,7 @@
+((declare (in) float b) (declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000))) ()
+ (break))))))))
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_5.opt_test b/src/glsl/tests/lower_jumps/lower_breaks_5.opt_test
new file mode 100755
index 00000000000..da9eef1105e
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_5.opt_test
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 1)' <<EOF
+((declare (in) float b) (declare (out) float a) (declare (out) float c)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000))) ()
+ ((assign (x) (var_ref c) (constant float (1.000000))) break))))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_5.opt_test.expected b/src/glsl/tests/lower_jumps/lower_breaks_5.opt_test.expected
new file mode 100644
index 00000000000..0dd4a529383
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_5.opt_test.expected
@@ -0,0 +1,7 @@
+((declare (in) float b) (declare (out) float a) (declare (out) float c)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (if (expression bool > (var_ref b) (constant float (0.000000))) ()
+ ((assign (x) (var_ref c) (constant float (1.000000))) break))))))))
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_6.opt_test b/src/glsl/tests/lower_jumps/lower_breaks_6.opt_test
new file mode 100755
index 00000000000..9440dfec897
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_6.opt_test
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 1, 1)' <<EOF
+((declare (in) float a) (declare (in) float ba) (declare (in) float bb)
+ (declare (in) float ca)
+ (declare (in) float cb)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ba) (constant float (0.000000)))
+ ((if (expression bool > (var_ref bb) (constant float (0.000000)))
+ (continue)
+ ()))
+ ())
+ (if (expression bool > (var_ref ca) (constant float (0.000000)))
+ ((if (expression bool > (var_ref cb) (constant float (0.000000)))
+ (break)
+ ()))
+ ()))
+ ())
+ break))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_breaks_6.opt_test.expected b/src/glsl/tests/lower_jumps/lower_breaks_6.opt_test.expected
new file mode 100644
index 00000000000..8222328e00c
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_breaks_6.opt_test.expected
@@ -0,0 +1,29 @@
+((declare (in) float a) (declare (in) float ba) (declare (in) float bb)
+ (declare (in) float ca)
+ (declare (in) float cb)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool break_flag)
+ (assign (x) (var_ref break_flag) (constant bool (0)))
+ (loop () () () ()
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ba) (constant float (0.000000)))
+ ((if (expression bool > (var_ref bb) (constant float (0.000000)))
+ ((assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())
+ (if (var_ref execute_flag)
+ ((if (expression bool > (var_ref ca) (constant float (0.000000)))
+ ((if (expression bool > (var_ref cb) (constant float (0.000000)))
+ ((assign (x) (var_ref break_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ()))
+ ()))
+ ())
+ (if (var_ref execute_flag)
+ ((assign (x) (var_ref break_flag) (constant bool (1))))
+ ())
+ (if (var_ref break_flag) (break) ())))))))
diff --git a/src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test b/src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test
new file mode 100755
index 00000000000..379aa59b5a2
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 1, 1)' <<EOF
+((declare (in) float aa) (declare (in) float ab) (declare (in) float b)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((if (expression bool > (var_ref aa) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ab) (constant float (0.000000)))
+ (continue)
+ ()))
+ ())
+ (if (expression bool > (var_ref b) (constant float (0.000000))) (break)
+ ())))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test.expected b/src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test.expected
new file mode 100644
index 00000000000..7c6e73f77f8
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_guarded_conditional_break.opt_test.expected
@@ -0,0 +1,20 @@
+((declare (in) float aa) (declare (in) float ab) (declare (in) float b)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool break_flag)
+ (assign (x) (var_ref break_flag) (constant bool (0)))
+ (loop () () () ()
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (if (expression bool > (var_ref aa) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ab) (constant float (0.000000)))
+ ((assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())
+ (if (var_ref execute_flag)
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((assign (x) (var_ref break_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())
+ (if (var_ref break_flag) (break) ())))))))
diff --git a/src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test b/src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test
new file mode 100755
index 00000000000..15f3c41d5a2
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(1, 0, 1, 0, 0)' <<EOF
+((declare (in) float aa) (declare (in) float ab) (declare (in) float b)
+ (declare (in) float c)
+ (declare (out) float d)
+ (function main
+ (signature void (parameters)
+ ((if (expression bool > (var_ref aa) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ab) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())
+ (loop () () () ()
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((if (expression bool > (var_ref c) (constant float (0.000000))) (break)
+ (continue)))
+ ((return)))))
+ (assign (x) (var_ref d) (constant float (1.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test.expected b/src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test.expected
new file mode 100644
index 00000000000..bf45c2c93b6
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_pulled_out_jump.opt_test.expected
@@ -0,0 +1,25 @@
+((declare (in) float aa) (declare (in) float ab) (declare (in) float b)
+ (declare (in) float c)
+ (declare (out) float d)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (if (expression bool > (var_ref aa) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ab) (constant float (0.000000)))
+ ((assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())
+ (if (var_ref execute_flag)
+ ((loop () () () ()
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((if (expression bool > (var_ref c) (constant float (0.000000))) ()
+ (continue)))
+ ((assign (x) (var_ref return_flag) (constant bool (1)))))
+ break))
+ (if (var_ref return_flag) ()
+ ((assign (x) (var_ref d) (constant float (1.000000))))))
+ ())))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_1.opt_test b/src/glsl/tests/lower_jumps/lower_returns_1.opt_test
new file mode 100755
index 00000000000..a1f895bbf78
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_1.opt_test
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a void return at the end of a function is
+# eliminated.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 1, 0, 0)' <<EOF
+((declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((assign (x) (var_ref a) (constant float (1.000000))) (return)))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_1.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_1.opt_test.expected
new file mode 100644
index 00000000000..7c3919c016e
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_1.opt_test.expected
@@ -0,0 +1,4 @@
+((declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((assign (x) (var_ref a) (constant float (1.000000)))))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_2.opt_test b/src/glsl/tests/lower_jumps/lower_returns_2.opt_test
new file mode 100755
index 00000000000..61673d4ef66
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_2.opt_test
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that lowering is not performed on a non-void return at
+# the end of subroutine.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 1, 0, 0, 0)' <<EOF
+((declare (out) float a)
+ (function sub
+ (signature float (parameters)
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (return (constant float (1.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_2.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_2.opt_test.expected
new file mode 100644
index 00000000000..7777927f5a3
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_2.opt_test.expected
@@ -0,0 +1,5 @@
+((declare (out) float a)
+ (function sub
+ (signature float (parameters)
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (return (constant float (1.000000)))))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_3.opt_test b/src/glsl/tests/lower_jumps/lower_returns_3.opt_test
new file mode 100755
index 00000000000..9881e249270
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_3.opt_test
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 1, 0, 0, 0)' <<EOF
+((declare (in) float a) (declare (in) float b)
+ (function sub
+ (signature float (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return (constant float (1.000000))))
+ ()))
+ ())
+ (return (constant float (2.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_3.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_3.opt_test.expected
new file mode 100644
index 00000000000..d4835e96b7c
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_3.opt_test.expected
@@ -0,0 +1,21 @@
+((declare (in) float a) (declare (in) float b)
+ (function sub
+ (signature float (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) float return_value)
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((assign (x) (var_ref return_value) (constant float (1.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())
+ (if (var_ref execute_flag)
+ ((assign (x) (var_ref return_value) (constant float (2.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ())
+ (return (var_ref return_value))))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_4.opt_test b/src/glsl/tests/lower_jumps/lower_returns_4.opt_test
new file mode 100755
index 00000000000..9f54c67a180
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_4.opt_test
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that returns are properly lowered when they occur in
+# both branches of an if-statement.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 1, 0, 0, 0)' <<EOF
+((declare (in) float a)
+ (function sub
+ (signature float (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((return (constant float (1.000000))))
+ ((return (constant float (2.000000)))))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_4.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_4.opt_test.expected
new file mode 100644
index 00000000000..b551a066f43
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_4.opt_test.expected
@@ -0,0 +1,16 @@
+((declare (in) float a)
+ (function sub
+ (signature float (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) float return_value)
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((assign (x) (var_ref return_value) (constant float (1.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ((assign (x) (var_ref return_value) (constant float (2.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0)))))
+ (return (var_ref return_value))))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test b/src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test
new file mode 100755
index 00000000000..5f97bfd3f5a
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that do_lower_jumps respects the lower_main_return
+# flag in deciding whether to lower returns in the main
+# function.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 0)' <<EOF
+((declare (in) float a) (declare (in) float b)
+ (function main
+ (signature void (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test.expected
new file mode 100644
index 00000000000..e8b36f14478
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_main_false.opt_test.expected
@@ -0,0 +1,8 @@
+((declare (in) float a) (declare (in) float b)
+ (function main
+ (signature void (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test b/src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test
new file mode 100755
index 00000000000..59c7ba1dd52
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that do_lower_jumps respects the lower_main_return
+# flag in deciding whether to lower returns in the main
+# function.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 1, 0, 0)' <<EOF
+((declare (in) float a) (declare (in) float b)
+ (function main
+ (signature void (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test.expected
new file mode 100644
index 00000000000..e15a97d1db2
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_main_true.opt_test.expected
@@ -0,0 +1,13 @@
+((declare (in) float a) (declare (in) float b)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test b/src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test
new file mode 100755
index 00000000000..40e784e3318
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that do_lower_jumps respects the lower_sub_return flag
+# in deciding whether to lower returns in subroutines.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 0)' <<EOF
+((declare (in) float a) (declare (in) float b)
+ (function sub
+ (signature void (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test.expected
new file mode 100644
index 00000000000..07db6e708f4
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_sub_false.opt_test.expected
@@ -0,0 +1,8 @@
+((declare (in) float a) (declare (in) float b)
+ (function sub
+ (signature void (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())))))
diff --git a/src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test b/src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test
new file mode 100755
index 00000000000..9fe6b90f085
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that do_lower_jumps respects the lower_sub_return flag
+# in deciding whether to lower returns in subroutines.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 1, 0, 0, 0)' <<EOF
+((declare (in) float a) (declare (in) float b)
+ (function sub
+ (signature void (parameters)
+ ((if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test.expected b/src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test.expected
new file mode 100644
index 00000000000..31109802351
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_returns_sub_true.opt_test.expected
@@ -0,0 +1,13 @@
+((declare (in) float a) (declare (in) float b)
+ (function sub
+ (signature void (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (if (expression bool > (var_ref a) (constant float (0.000000)))
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())))))
diff --git a/src/glsl/tests/lower_jumps/lower_unified_returns.opt_test b/src/glsl/tests/lower_jumps/lower_unified_returns.opt_test
new file mode 100755
index 00000000000..e7168131487
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_unified_returns.opt_test
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# 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.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(1, 0, 1, 0, 0)' <<EOF
+((declare (in) float aa) (declare (in) float ab) (declare (in) float b)
+ (declare (in) float c)
+ (function main
+ (signature void (parameters)
+ ((if (expression bool > (var_ref aa) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ab) (constant float (0.000000)))
+ ((return))
+ ()))
+ ())
+ (if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((if (expression bool > (var_ref c) (constant float (0.000000)))
+ ((return))
+ ((return))))
+ ())))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/lower_unified_returns.opt_test.expected b/src/glsl/tests/lower_jumps/lower_unified_returns.opt_test.expected
new file mode 100644
index 00000000000..271cd3b462e
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/lower_unified_returns.opt_test.expected
@@ -0,0 +1,21 @@
+((declare (in) float aa) (declare (in) float ab) (declare (in) float b)
+ (declare (in) float c)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (if (expression bool > (var_ref aa) (constant float (0.000000)))
+ ((if (expression bool > (var_ref ab) (constant float (0.000000)))
+ ((assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())
+ (if (var_ref execute_flag)
+ ((if (expression bool > (var_ref b) (constant float (0.000000)))
+ ((if (expression bool > (var_ref c) (constant float (0.000000))) () ())
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0))))
+ ()))
+ ())))))
diff --git a/src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test b/src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test
new file mode 100755
index 00000000000..18efc37f6e1
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a redundant continue-statement at the end of a
+# loop is removed.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 0)' <<EOF
+((declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) continue))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test.expected b/src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test.expected
new file mode 100644
index 00000000000..d2a02c6f380
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/remove_continue_at_end_of_loop.opt_test.expected
@@ -0,0 +1,5 @@
+((declare (out) float a)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))))))))
diff --git a/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test
new file mode 100755
index 00000000000..79c0e824512
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a non-void return at the end of a loop is
+# properly lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 0)' <<EOF
+((declare (out) float a) (declare (out) float b)
+ (function sub
+ (signature float (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (return (constant float (2.000000)))))
+ (assign (x) (var_ref b) (constant float (3.000000)))
+ (return (constant float (4.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test.expected b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test.expected
new file mode 100644
index 00000000000..2cf117a5ee1
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_nothing.opt_test.expected
@@ -0,0 +1,8 @@
+((declare (out) float a) (declare (out) float b)
+ (function sub
+ (signature float (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (return (constant float (2.000000)))))
+ (assign (x) (var_ref b) (constant float (3.000000)))
+ (return (constant float (4.000000)))))))
diff --git a/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test
new file mode 100755
index 00000000000..920d2ad9fba
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a non-void return at the end of a loop is
+# properly lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 1, 0, 0, 0)' <<EOF
+((declare (out) float a) (declare (out) float b)
+ (function sub
+ (signature float (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (return (constant float (2.000000)))))
+ (assign (x) (var_ref b) (constant float (3.000000)))
+ (return (constant float (4.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test.expected b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test.expected
new file mode 100644
index 00000000000..0bab8f16f30
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return.opt_test.expected
@@ -0,0 +1,19 @@
+((declare (out) float a) (declare (out) float b)
+ (function sub
+ (signature float (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) float return_value)
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (assign (x) (var_ref return_value) (constant float (2.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ break))
+ (if (var_ref return_flag) ()
+ ((assign (x) (var_ref b) (constant float (3.000000)))
+ (assign (x) (var_ref return_value) (constant float (4.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0)))))
+ (return (var_ref return_value))))))
diff --git a/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test
new file mode 100755
index 00000000000..99f1f863506
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a non-void return at the end of a loop is
+# properly lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 1, 0, 0, 1)' <<EOF
+((declare (out) float a) (declare (out) float b)
+ (function sub
+ (signature float (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (return (constant float (2.000000)))))
+ (assign (x) (var_ref b) (constant float (3.000000)))
+ (return (constant float (4.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test.expected b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test.expected
new file mode 100644
index 00000000000..0bab8f16f30
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_non_void_at_end_of_loop_lower_return_and_break.opt_test.expected
@@ -0,0 +1,19 @@
+((declare (out) float a) (declare (out) float b)
+ (function sub
+ (signature float (parameters)
+ ((declare (temporary) bool execute_flag)
+ (assign (x) (var_ref execute_flag) (constant bool (1)))
+ (declare (temporary) float return_value)
+ (declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (assign (x) (var_ref return_value) (constant float (2.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ break))
+ (if (var_ref return_flag) ()
+ ((assign (x) (var_ref b) (constant float (3.000000)))
+ (assign (x) (var_ref return_value) (constant float (4.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ (assign (x) (var_ref execute_flag) (constant bool (0)))))
+ (return (var_ref return_value))))))
diff --git a/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test
new file mode 100755
index 00000000000..63487d32691
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a return of void at the end of a loop is properly
+# lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 0, 0, 0)' <<EOF
+((declare (out) float a) (declare (out) float b)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) (return)))
+ (assign (x) (var_ref b) (constant float (2.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test.expected b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test.expected
new file mode 100644
index 00000000000..0bd8037bf00
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_nothing.opt_test.expected
@@ -0,0 +1,6 @@
+((declare (out) float a) (declare (out) float b)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) (return)))
+ (assign (x) (var_ref b) (constant float (2.000000)))))))
diff --git a/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test
new file mode 100755
index 00000000000..523c92a686d
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a return of void at the end of a loop is properly
+# lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 1, 0, 0)' <<EOF
+((declare (out) float a) (declare (out) float b)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) (return)))
+ (assign (x) (var_ref b) (constant float (2.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test.expected b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test.expected
new file mode 100644
index 00000000000..53814eaacad
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return.opt_test.expected
@@ -0,0 +1,11 @@
+((declare (out) float a) (declare (out) float b)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ break))
+ (if (var_ref return_flag) ()
+ ((assign (x) (var_ref b) (constant float (2.000000)))))))))
diff --git a/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test
new file mode 100755
index 00000000000..22b5581cbda
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# This file was generated by create_test_cases.py.
+#
+# Test that a return of void at the end of a loop is properly
+# lowered.
+../../glsl_test optpass --quiet --input-ir 'do_lower_jumps(0, 0, 1, 0, 1)' <<EOF
+((declare (out) float a) (declare (out) float b)
+ (function main
+ (signature void (parameters)
+ ((loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000))) (return)))
+ (assign (x) (var_ref b) (constant float (2.000000)))))))
+EOF
diff --git a/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test.expected b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test.expected
new file mode 100644
index 00000000000..53814eaacad
--- /dev/null
+++ b/src/glsl/tests/lower_jumps/return_void_at_end_of_loop_lower_return_and_break.opt_test.expected
@@ -0,0 +1,11 @@
+((declare (out) float a) (declare (out) float b)
+ (function main
+ (signature void (parameters)
+ ((declare (temporary) bool return_flag)
+ (assign (x) (var_ref return_flag) (constant bool (0)))
+ (loop () () () ()
+ ((assign (x) (var_ref a) (constant float (1.000000)))
+ (assign (x) (var_ref return_flag) (constant bool (1)))
+ break))
+ (if (var_ref return_flag) ()
+ ((assign (x) (var_ref b) (constant float (2.000000)))))))))
diff --git a/src/glsl/tests/optimization-test b/src/glsl/tests/optimization-test
new file mode 100755
index 00000000000..0c130be1379
--- /dev/null
+++ b/src/glsl/tests/optimization-test
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+total=0
+pass=0
+
+echo "====== Testing optimization passes ======"
+for test in `find . -iname '*.opt_test'`; do
+ echo -n "Testing $test..."
+ (cd `dirname "$test"`; ./`basename "$test"`) > "$test.out" 2>&1
+ total=$((total+1))
+ if ./compare_ir "$test.expected" "$test.out" >/dev/null 2>&1; then
+ echo "PASS"
+ pass=$((pass+1))
+ else
+ echo "FAIL"
+ ./compare_ir "$test.expected" "$test.out"
+ fi
+done
+
+echo ""
+echo "$pass/$total tests returned correct results"
+echo ""
+
+if [[ $pass == $total ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/src/glsl/tests/sexps.py b/src/glsl/tests/sexps.py
new file mode 100644
index 00000000000..a714af8d236
--- /dev/null
+++ b/src/glsl/tests/sexps.py
@@ -0,0 +1,103 @@
+# 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.
+
+# This file contains helper functions for manipulating sexps in Python.
+#
+# We represent a sexp in Python using nested lists containing strings.
+# So, for example, the sexp (constant float (1.000000)) is represented
+# as ['constant', 'float', ['1.000000']].
+
+import re
+
+def check_sexp(sexp):
+ """Verify that the argument is a proper sexp.
+
+ That is, raise an exception if the argument is not a string or a
+ list, or if it contains anything that is not a string or a list at
+ any nesting level.
+ """
+ if isinstance(sexp, list):
+ for s in sexp:
+ check_sexp(s)
+ elif not isinstance(sexp, basestring):
+ raise Exception('Not a sexp: {0!r}'.format(sexp))
+
+def parse_sexp(sexp):
+ """Convert a string, of the form that would be output by mesa,
+ into a sexp represented as nested lists containing strings.
+ """
+ sexp_token_regexp = re.compile(
+ '[a-zA-Z_]+(@[0-9]+)?|[0-9]+(\\.[0-9]+)?|[^ \n]')
+ stack = [[]]
+ for match in sexp_token_regexp.finditer(sexp):
+ token = match.group(0)
+ if token == '(':
+ stack.append([])
+ elif token == ')':
+ if len(stack) == 1:
+ raise Exception('Unmatched )')
+ sexp = stack.pop()
+ stack[-1].append(sexp)
+ else:
+ stack[-1].append(token)
+ if len(stack) != 1:
+ raise Exception('Unmatched (')
+ if len(stack[0]) != 1:
+ raise Exception('Multiple sexps')
+ return stack[0][0]
+
+def sexp_to_string(sexp):
+ """Convert a sexp, represented as nested lists containing strings,
+ into a single string of the form parseable by mesa.
+ """
+ if isinstance(sexp, basestring):
+ return sexp
+ assert isinstance(sexp, list)
+ result = ''
+ for s in sexp:
+ sub_result = sexp_to_string(s)
+ if result == '':
+ result = sub_result
+ elif '\n' not in result and '\n' not in sub_result and \
+ len(result) + len(sub_result) + 1 <= 70:
+ result += ' ' + sub_result
+ else:
+ result += '\n' + sub_result
+ return '({0})'.format(result.replace('\n', '\n '))
+
+def sort_decls(sexp):
+ """Sort all toplevel variable declarations in sexp.
+
+ This is used to work around the fact that
+ ir_reader::read_instructions reorders declarations.
+ """
+ assert isinstance(sexp, list)
+ decls = []
+ other_code = []
+ for s in sexp:
+ if isinstance(s, list) and len(s) >= 4 and s[0] == 'declare':
+ decls.append(s)
+ else:
+ other_code.append(s)
+ return sorted(decls) + other_code
+