[Mesa-dev,v2,2/9] glsl: Refactor the python test case generator

Submitted by Iago Toral Quiroga on Oct. 1, 2014, 6:35 a.m.

Details

Message ID 1412145345-3974-3-git-send-email-itoral@igalia.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Iago Toral Quiroga Oct. 1, 2014, 6:35 a.m.
From: Petri Latvala <petri.latvala@intel.com>

Move the IR sexp builder helpers and test script creation parts of
tests/lower_jumps/create_test_cases.py into tests/test_case_generator.py

No functional changes.

Signed-off-by: Petri Latvala <petri.latvala@intel.com>
---
 src/glsl/tests/lower_jumps/create_test_cases.py | 336 +++---------------------
 src/glsl/tests/test_case_generator.py           | 293 +++++++++++++++++++++
 2 files changed, 334 insertions(+), 295 deletions(-)
 create mode 100644 src/glsl/tests/test_case_generator.py

Patch hide | download patch | download mbox

diff --git a/src/glsl/tests/lower_jumps/create_test_cases.py b/src/glsl/tests/lower_jumps/create_test_cases.py
index 3be1079..9783627 100644
--- a/src/glsl/tests/lower_jumps/create_test_cases.py
+++ b/src/glsl/tests/lower_jumps/create_test_cases.py
@@ -27,278 +27,9 @@  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
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) # For access to sexps.py and test_case_generator.py, which are 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('#!/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 = '{0}.opt_test.expected'.format(test_name)
-    with open(expected_file, 'w') as f:
-        f.write('{0}\n'.format(expected_output))
+from test_case_generator import *
 
 def test_lower_returns_main():
     doc_string = """Test that do_lower_jumps respects the lower_main_return
@@ -314,9 +45,9 @@  def test_lower_returns_main():
             complex_if('', lowered_return())
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_main_true',
-                     lower_main_return=True)
+                     create_opt_string(lower_main_return=True))
     create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_main_false',
-                     lower_main_return=False)
+                     create_opt_string(lower_main_return=False))
 
 def test_lower_returns_sub():
     doc_string = """Test that do_lower_jumps respects the lower_sub_return flag
@@ -331,9 +62,9 @@  def test_lower_returns_sub():
             complex_if('', lowered_return())
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_sub_true',
-                     lower_sub_return=True)
+                     create_opt_string(lower_sub_return=True))
     create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_sub_false',
-                     lower_sub_return=False)
+                     create_opt_string(lower_sub_return=False))
 
 def test_lower_returns_1():
     doc_string = """Test that a void return at the end of a function is
@@ -347,7 +78,7 @@  def test_lower_returns_1():
             assign_x('a', const_float(1))
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_1',
-                     lower_main_return=True)
+                     create_opt_string(lower_main_return=True))
 
 def test_lower_returns_2():
     doc_string = """Test that lowering is not performed on a non-void return at
@@ -358,7 +89,7 @@  def test_lower_returns_2():
             return_(const_float(1))
             ))
     create_test_case(doc_string, input_sexp, input_sexp, 'lower_returns_2',
-                     lower_sub_return=True)
+                     create_opt_string(lower_sub_return=True))
 
 def test_lower_returns_3():
     doc_string = """Test lowering of returns when there is one nested inside a
@@ -381,7 +112,7 @@  def test_lower_returns_3():
             final_return()
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_3',
-                     lower_sub_return=True)
+                     create_opt_string(lower_sub_return=True))
 
 def test_lower_returns_4():
     doc_string = """Test that returns are properly lowered when they occur in
@@ -400,7 +131,7 @@  def test_lower_returns_4():
             final_return()
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_returns_4',
-                     lower_sub_return=True)
+                     create_opt_string(lower_sub_return=True))
 
 def test_lower_unified_returns():
     doc_string = """If both branches of an if statement end in a return, and
@@ -423,7 +154,7 @@  def test_lower_unified_returns():
                                             lowered_return())))
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_unified_returns',
-                     lower_main_return=True, pull_out_jumps=True)
+                     create_opt_string(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
@@ -455,7 +186,7 @@  def test_lower_pulled_out_jump():
                 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)
+                     create_opt_string(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
@@ -465,7 +196,8 @@  def test_lower_breaks_1():
                  break_())
             ))
     expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_1', lower_break=True)
+    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_1',
+                     create_opt_string(lower_break=True))
 
 def test_lower_breaks_2():
     doc_string = """If a loop contains a conditional break at the bottom of it,
@@ -476,7 +208,8 @@  def test_lower_breaks_2():
                  simple_if('b', break_()))
             ))
     expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_2', lower_break=True)
+    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_2',
+                     create_opt_string(lower_break=True))
 
 def test_lower_breaks_3():
     doc_string = """If a loop contains a conditional break at the bottom of it,
@@ -489,7 +222,8 @@  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)
+    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_3',
+                     create_opt_string(lower_break=True))
 
 def test_lower_breaks_4():
     doc_string = """If a loop contains a conditional break at the bottom of it,
@@ -500,7 +234,8 @@  def test_lower_breaks_4():
                  simple_if('b', [], break_()))
             ))
     expected_sexp = input_sexp
-    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_4', lower_break=True)
+    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_4',
+                     create_opt_string(lower_break=True))
 
 def test_lower_breaks_5():
     doc_string = """If a loop contains a conditional break at the bottom of it,
@@ -513,7 +248,8 @@  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)
+    create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_5',
+                     create_opt_string(lower_break=True))
 
 def test_lower_breaks_6():
     doc_string = """If a loop contains conditional breaks and continues, and
@@ -538,7 +274,7 @@  def test_lower_breaks_6():
                  final_break())
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_breaks_6',
-                     lower_break=True, lower_continue=True)
+                     create_opt_string(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
@@ -558,7 +294,7 @@  def test_lower_guarded_conditional_break():
                  final_break())
             ))
     create_test_case(doc_string, input_sexp, expected_sexp, 'lower_guarded_conditional_break',
-                     lower_break=True, lower_continue=True)
+                     create_opt_string(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
@@ -571,7 +307,8 @@  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')
+    create_test_case(doc_string, input_sexp, expected_sexp, 'remove_continue_at_end_of_loop',
+                     create_opt_string())
 
 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
@@ -589,11 +326,12 @@  def test_lower_return_void_at_end_of_loop():
                  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, input_sexp, 'return_void_at_end_of_loop_lower_nothing',
+                     create_opt_string())
     create_test_case(doc_string, input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return',
-                     lower_main_return=True)
+                     create_opt_string(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)
+                     create_opt_string(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
@@ -616,11 +354,19 @@  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, input_sexp, 'return_non_void_at_end_of_loop_lower_nothing',
+                     create_opt_string())
     create_test_case(doc_string, input_sexp, expected_sexp, 'return_non_void_at_end_of_loop_lower_return',
-                     lower_sub_return=True)
+                     create_opt_string(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)
+                     create_opt_string(lower_sub_return=True, lower_break=True))
+
+def create_opt_string(pull_out_jumps=False, lower_sub_return=False,
+                      lower_main_return=False, lower_continue=False,
+                      lower_break=False):
+    return ('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))
 
 if __name__ == '__main__':
     test_lower_returns_main()
diff --git a/src/glsl/tests/test_case_generator.py b/src/glsl/tests/test_case_generator.py
new file mode 100644
index 0000000..d6754fc8
--- /dev/null
+++ b/src/glsl/tests/test_case_generator.py
@@ -0,0 +1,293 @@ 
+# 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
+
+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, optimization):
+    """Create a test case that verifies that the given optimization pass 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))
+
+    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('#!/usr/bin/env bash\n#\n# This file was automatically generated.\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))