diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-01-29 11:08:07 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-01-29 11:08:07 +0000 |
commit | 6b139c2063623e9310025247cd966490b9aa57ea (patch) | |
tree | 375acfd898ca3d721250aa17291bbb90a8d7250a /lib/mesa/src/compiler/glsl/tests | |
parent | cce99579dcfb1d54c54cff65573be3430e77f2c5 (diff) |
Import Mesa 18.3.2
Diffstat (limited to 'lib/mesa/src/compiler/glsl/tests')
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/.deps/cache_test-cache_test.Po | 1 | ||||
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp | 1 | ||||
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/lower_jump_cases.py | 643 | ||||
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/meson.build | 110 | ||||
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/optimization_test.py | 96 | ||||
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/sexps.py | 11 | ||||
-rw-r--r-- | lib/mesa/src/compiler/glsl/tests/warnings_test.py | 73 |
7 files changed, 891 insertions, 44 deletions
diff --git a/lib/mesa/src/compiler/glsl/tests/.deps/cache_test-cache_test.Po b/lib/mesa/src/compiler/glsl/tests/.deps/cache_test-cache_test.Po new file mode 100644 index 000000000..9ce06a81e --- /dev/null +++ b/lib/mesa/src/compiler/glsl/tests/.deps/cache_test-cache_test.Po @@ -0,0 +1 @@ +# dummy diff --git a/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp b/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp index 0d8f4521c..45c204dc2 100644 --- a/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp +++ b/lib/mesa/src/compiler/glsl/tests/array_refcount_test.cpp @@ -160,7 +160,6 @@ validate_variables_in_hash_table(struct hash_table *ht, va_end(args); - struct hash_entry *entry; hash_table_foreach(ht, entry) { const ir_instruction *const ir = (ir_instruction *) entry->key; const ir_variable *const v = ir->as_variable(); diff --git a/lib/mesa/src/compiler/glsl/tests/lower_jump_cases.py b/lib/mesa/src/compiler/glsl/tests/lower_jump_cases.py new file mode 100644 index 000000000..1977f3a9b --- /dev/null +++ b/lib/mesa/src/compiler/glsl/tests/lower_jump_cases.py @@ -0,0 +1,643 @@ +# coding=utf-8 +# +# Copyright © 2011, 2018 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +from sexps import * + +def make_test_case(f_name, ret_type, body): + """Create a simple optimization test case consisting of a single + function with the given name, return type, and body. + + Global declarations are automatically created for any undeclared + variables that are referenced by the function. All undeclared + variables are assumed to be floats. + """ + check_sexp(body) + declarations = {} + def make_declarations(sexp, already_declared = ()): + if isinstance(sexp, list): + if len(sexp) == 2 and sexp[0] == 'var_ref': + if sexp[1] not in already_declared: + declarations[sexp[1]] = [ + 'declare', ['in'], 'float', sexp[1]] + elif len(sexp) == 4 and sexp[0] == 'assign': + assert sexp[2][0] == 'var_ref' + if sexp[2][1] not in already_declared: + declarations[sexp[2][1]] = [ + 'declare', ['out'], 'float', sexp[2][1]] + make_declarations(sexp[3], already_declared) + else: + already_declared = set(already_declared) + for s in sexp: + if isinstance(s, list) and len(s) >= 4 and \ + s[0] == 'declare': + already_declared.add(s[3]) + else: + make_declarations(s, already_declared) + make_declarations(body) + return list(declarations.values()) + \ + [['function', f_name, ['signature', ret_type, ['parameters'], body]]] + + +# The following functions can be used to build expressions. + +def const_float(value): + """Create an expression representing the given floating point value.""" + return ['constant', 'float', ['{0:.6f}'.format(value)]] + +def const_bool(value): + """Create an expression representing the given boolean value. + + If value is not a boolean, it is converted to a boolean. So, for + instance, const_bool(1) is equivalent to const_bool(True). + """ + return ['constant', 'bool', ['{0}'.format(1 if value else 0)]] + +def gt_zero(var_name): + """Create Construct the expression var_name > 0""" + return ['expression', 'bool', '<', const_float(0), ['var_ref', var_name]] + + +# The following functions can be used to build complex control flow +# statements. All of these functions return statement lists (even +# those which only create a single statement), so that statements can +# be sequenced together using the '+' operator. + +def return_(value = None): + """Create a return statement.""" + if value is not None: + return [['return', value]] + else: + return [['return']] + +def break_(): + """Create a break statement.""" + return ['break'] + +def continue_(): + """Create a continue statement.""" + return ['continue'] + +def simple_if(var_name, then_statements, else_statements = None): + """Create a statement of the form + + if (var_name > 0.0) { + <then_statements> + } else { + <else_statements> + } + + else_statements may be omitted. + """ + if else_statements is None: + else_statements = [] + check_sexp(then_statements) + check_sexp(else_statements) + return [['if', gt_zero(var_name), then_statements, else_statements]] + +def loop(statements): + """Create a loop containing the given statements as its loop + body. + """ + check_sexp(statements) + return [['loop', statements]] + +def declare_temp(var_type, var_name): + """Create a declaration of the form + + (declare (temporary) <var_type> <var_name) + """ + return [['declare', ['temporary'], var_type, var_name]] + +def assign_x(var_name, value): + """Create a statement that assigns <value> to the variable + <var_name>. The assignment uses the mask (x). + """ + check_sexp(value) + return [['assign', ['x'], ['var_ref', var_name], value]] + +def complex_if(var_prefix, statements): + """Create a statement of the form + + if (<var_prefix>a > 0.0) { + if (<var_prefix>b > 0.0) { + <statements> + } + } + + This is useful in testing jump lowering, because if <statements> + ends in a jump, lower_jumps.cpp won't try to combine this + construct with the code that follows it, as it might do for a + simple if. + + All variables used in the if statement are prefixed with + var_prefix. This can be used to ensure uniqueness. + """ + check_sexp(statements) + return simple_if(var_prefix + 'a', simple_if(var_prefix + 'b', statements)) + +def declare_execute_flag(): + """Create the statements that lower_jumps.cpp uses to declare and + initialize the temporary boolean execute_flag. + """ + return declare_temp('bool', 'execute_flag') + \ + assign_x('execute_flag', const_bool(True)) + +def declare_return_flag(): + """Create the statements that lower_jumps.cpp uses to declare and + initialize the temporary boolean return_flag. + """ + return declare_temp('bool', 'return_flag') + \ + assign_x('return_flag', const_bool(False)) + +def declare_return_value(): + """Create the statements that lower_jumps.cpp uses to declare and + initialize the temporary variable return_value. Assume that + return_value is a float. + """ + return declare_temp('float', 'return_value') + +def declare_break_flag(): + """Create the statements that lower_jumps.cpp uses to declare and + initialize the temporary boolean break_flag. + """ + return declare_temp('bool', 'break_flag') + \ + assign_x('break_flag', const_bool(False)) + +def lowered_return_simple(value = None): + """Create the statements that lower_jumps.cpp lowers a return + statement to, in situations where it does not need to clear the + execute flag. + """ + if value: + result = assign_x('return_value', value) + else: + result = [] + return result + assign_x('return_flag', const_bool(True)) + +def lowered_return(value = None): + """Create the statements that lower_jumps.cpp lowers a return + statement to, in situations where it needs to clear the execute + flag. + """ + return lowered_return_simple(value) + \ + assign_x('execute_flag', const_bool(False)) + +def lowered_continue(): + """Create the statement that lower_jumps.cpp lowers a continue + statement to. + """ + return assign_x('execute_flag', const_bool(False)) + +def lowered_break_simple(): + """Create the statement that lower_jumps.cpp lowers a break + statement to, in situations where it does not need to clear the + execute flag. + """ + return assign_x('break_flag', const_bool(True)) + +def lowered_break(): + """Create the statement that lower_jumps.cpp lowers a break + statement to, in situations where it needs to clear the execute + flag. + """ + return lowered_break_simple() + assign_x('execute_flag', const_bool(False)) + +def if_execute_flag(statements): + """Wrap statements in an if test so that they will only execute if + execute_flag is True. + """ + check_sexp(statements) + return [['if', ['var_ref', 'execute_flag'], statements, []]] + +def if_return_flag(then_statements, else_statements): + """Wrap statements in an if test with return_flag as the condition. + """ + check_sexp(then_statements) + check_sexp(else_statements) + return [['if', ['var_ref', 'return_flag'], then_statements, else_statements]] + +def if_not_return_flag(statements): + """Wrap statements in an if test so that they will only execute if + return_flag is False. + """ + check_sexp(statements) + return [['if', ['var_ref', 'return_flag'], [], statements]] + +def final_return(): + """Create the return statement that lower_jumps.cpp places at the + end of a function when lowering returns. + """ + return [['return', ['var_ref', 'return_value']]] + +def final_break(): + """Create the conditional break statement that lower_jumps.cpp + places at the end of a function when lowering breaks. + """ + return [['if', ['var_ref', 'break_flag'], break_(), []]] + +def bash_quote(*args): + """Quote the arguments appropriately so that bash will understand + each argument as a single word. + """ + def quote_word(word): + for c in word: + if not (c.isalpha() or c.isdigit() or c in '@%_-+=:,./'): + break + else: + if not word: + return "''" + return word + return "'{0}'".format(word.replace("'", "'\"'\"'")) + return ' '.join(quote_word(word) for word in args) + +def create_test_case(input_sexp, expected_sexp, test_name, + pull_out_jumps=False, lower_sub_return=False, + lower_main_return=False, lower_continue=False, + lower_break=False): + """Create a test case that verifies that do_lower_jumps transforms + the given code in the expected way. + """ + check_sexp(input_sexp) + check_sexp(expected_sexp) + input_str = sexp_to_string(sort_decls(input_sexp)) + expected_output = sexp_to_string(sort_decls(expected_sexp)) # XXX: don't stringify this + optimization = ( + 'do_lower_jumps({0:d}, {1:d}, {2:d}, {3:d}, {4:d})'.format( + pull_out_jumps, lower_sub_return, lower_main_return, + lower_continue, lower_break)) + + return (test_name, optimization, input_str, expected_output) + +def test_lower_returns_main(): + """Test that do_lower_jumps respects the lower_main_return flag in deciding + whether to lower returns in the main function. + """ + input_sexp = make_test_case('main', 'void', ( + complex_if('', return_()) + )) + expected_sexp = make_test_case('main', 'void', ( + declare_execute_flag() + + declare_return_flag() + + complex_if('', lowered_return()) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_returns_main_true', + lower_main_return=True) + yield create_test_case( + input_sexp, input_sexp, 'lower_returns_main_false', + lower_main_return=False) + +def test_lower_returns_sub(): + """Test that do_lower_jumps respects the lower_sub_return flag in deciding + whether to lower returns in subroutines. + """ + input_sexp = make_test_case('sub', 'void', ( + complex_if('', return_()) + )) + expected_sexp = make_test_case('sub', 'void', ( + declare_execute_flag() + + declare_return_flag() + + complex_if('', lowered_return()) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_returns_sub_true', + lower_sub_return=True) + yield create_test_case( + input_sexp, input_sexp, 'lower_returns_sub_false', + lower_sub_return=False) + +def test_lower_returns_1(): + """Test that a void return at the end of a function is eliminated.""" + input_sexp = make_test_case('main', 'void', ( + assign_x('a', const_float(1)) + + return_() + )) + expected_sexp = make_test_case('main', 'void', ( + assign_x('a', const_float(1)) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_returns_1', lower_main_return=True) + +def test_lower_returns_2(): + """Test that lowering is not performed on a non-void return at the end of + subroutine. + """ + input_sexp = make_test_case('sub', 'float', ( + assign_x('a', const_float(1)) + + return_(const_float(1)) + )) + yield create_test_case( + input_sexp, input_sexp, 'lower_returns_2', lower_sub_return=True) + +def test_lower_returns_3(): + """Test lowering of returns when there is one nested inside a complex + structure of ifs, and one at the end of a function. + + In this case, the latter return needs to be lowered because it will not be + at the end of the function once the final return is inserted. + """ + input_sexp = make_test_case('sub', 'float', ( + complex_if('', return_(const_float(1))) + + return_(const_float(2)) + )) + expected_sexp = make_test_case('sub', 'float', ( + declare_execute_flag() + + declare_return_value() + + declare_return_flag() + + complex_if('', lowered_return(const_float(1))) + + if_execute_flag(lowered_return(const_float(2))) + + final_return() + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_returns_3', lower_sub_return=True) + +def test_lower_returns_4(): + """Test that returns are properly lowered when they occur in both branches + of an if-statement. + """ + input_sexp = make_test_case('sub', 'float', ( + simple_if('a', return_(const_float(1)), + return_(const_float(2))) + )) + expected_sexp = make_test_case('sub', 'float', ( + declare_execute_flag() + + declare_return_value() + + declare_return_flag() + + simple_if('a', lowered_return(const_float(1)), + lowered_return(const_float(2))) + + final_return() + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_returns_4', lower_sub_return=True) + +def test_lower_unified_returns(): + """If both branches of an if statement end in a return, and pull_out_jumps + is True, then those returns should be lifted outside the if and then + properly lowered. + + Verify that this lowering occurs during the same pass as the lowering of + other returns by checking that extra temporary variables aren't generated. + """ + input_sexp = make_test_case('main', 'void', ( + complex_if('a', return_()) + + simple_if('b', simple_if('c', return_(), return_())) + )) + expected_sexp = make_test_case('main', 'void', ( + declare_execute_flag() + + declare_return_flag() + + complex_if('a', lowered_return()) + + if_execute_flag(simple_if('b', (simple_if('c', [], []) + + lowered_return()))) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_unified_returns', + lower_main_return=True, pull_out_jumps=True) + +def test_lower_pulled_out_jump(): + doc_string = """If one branch of an if ends in a jump, and control cannot + fall out the bottom of the other branch, and pull_out_jumps is + True, then the jump is lifted outside the if. + + Verify that this lowering occurs during the same pass as the + lowering of other jumps by checking that extra temporary + variables aren't generated. + """ + input_sexp = make_test_case('main', 'void', ( + complex_if('a', return_()) + + loop(simple_if('b', simple_if('c', break_(), continue_()), + return_())) + + assign_x('d', const_float(1)) + )) + # Note: optimization produces two other effects: the break + # gets lifted out of the if statements, and the code after the + # loop gets guarded so that it only executes if the return + # flag is clear. + expected_sexp = make_test_case('main', 'void', ( + declare_execute_flag() + + declare_return_flag() + + complex_if('a', lowered_return()) + + if_execute_flag( + loop(simple_if('b', simple_if('c', [], continue_()), + lowered_return_simple()) + + break_()) + + + if_return_flag(assign_x('return_flag', const_bool(1)) + + assign_x('execute_flag', const_bool(0)), + assign_x('d', const_float(1)))) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_pulled_out_jump', + lower_main_return=True, pull_out_jumps=True) + +def test_lower_breaks_1(): + """If a loop contains an unconditional break at the bottom of it, it should + not be lowered. + """ + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + break_()) + )) + expected_sexp = input_sexp + yield create_test_case( + input_sexp, expected_sexp, 'lower_breaks_1', lower_break=True) + +def test_lower_breaks_2(): + """If a loop contains a conditional break at the bottom of it, it should + not be lowered if it is in the then-clause. + """ + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + simple_if('b', break_())) + )) + expected_sexp = input_sexp + yield create_test_case( + input_sexp, expected_sexp, 'lower_breaks_2', lower_break=True) + +def test_lower_breaks_3(): + """If a loop contains a conditional break at the bottom of it, it should + not be lowered if it is in the then-clause, even if there are statements + preceding the break. + """ + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + simple_if('b', (assign_x('c', const_float(1)) + + break_()))) + )) + expected_sexp = input_sexp + yield create_test_case( + input_sexp, expected_sexp, 'lower_breaks_3', lower_break=True) + +def test_lower_breaks_4(): + """If a loop contains a conditional break at the bottom of it, it should + not be lowered if it is in the else-clause. + """ + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + simple_if('b', [], break_())) + )) + expected_sexp = input_sexp + yield create_test_case( + input_sexp, expected_sexp, 'lower_breaks_4', lower_break=True) + +def test_lower_breaks_5(): + """If a loop contains a conditional break at the bottom of it, it should + not be lowered if it is in the else-clause, even if there are statements + preceding the break. + """ + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + simple_if('b', [], (assign_x('c', const_float(1)) + + break_()))) + )) + expected_sexp = input_sexp + yield create_test_case( + input_sexp, expected_sexp, 'lower_breaks_5', lower_break=True) + +def test_lower_breaks_6(): + """If a loop contains conditional breaks and continues, and ends in an + unconditional break, then the unconditional break needs to be lowered, + because it will no longer be at the end of the loop after the final break + is added. + """ + input_sexp = make_test_case('main', 'void', ( + loop(simple_if('a', (complex_if('b', continue_()) + + complex_if('c', break_()))) + + break_()) + )) + expected_sexp = make_test_case('main', 'void', ( + declare_break_flag() + + loop(declare_execute_flag() + + simple_if( + 'a', + (complex_if('b', lowered_continue()) + + if_execute_flag( + complex_if('c', lowered_break())))) + + if_execute_flag(lowered_break_simple()) + + final_break()) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_breaks_6', lower_break=True, + lower_continue=True) + +def test_lower_guarded_conditional_break(): + """Normally a conditional break at the end of a loop isn't lowered, however + if the conditional break gets placed inside an if(execute_flag) because of + earlier lowering of continues, then the break needs to be lowered. + """ + input_sexp = make_test_case('main', 'void', ( + loop(complex_if('a', continue_()) + + simple_if('b', break_())) + )) + expected_sexp = make_test_case('main', 'void', ( + declare_break_flag() + + loop(declare_execute_flag() + + complex_if('a', lowered_continue()) + + if_execute_flag(simple_if('b', lowered_break())) + + final_break()) + )) + yield create_test_case( + input_sexp, expected_sexp, 'lower_guarded_conditional_break', + lower_break=True, lower_continue=True) + +def test_remove_continue_at_end_of_loop(): + """Test that a redundant continue-statement at the end of a loop is + removed. + """ + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + continue_()) + )) + expected_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1))) + )) + yield create_test_case(input_sexp, expected_sexp, 'remove_continue_at_end_of_loop') + +def test_lower_return_void_at_end_of_loop(): + """Test that a return of void at the end of a loop is properly lowered.""" + input_sexp = make_test_case('main', 'void', ( + loop(assign_x('a', const_float(1)) + + return_()) + + assign_x('b', const_float(2)) + )) + expected_sexp = make_test_case('main', 'void', ( + declare_execute_flag() + + declare_return_flag() + + loop(assign_x('a', const_float(1)) + + lowered_return_simple() + + break_()) + + if_return_flag(assign_x('return_flag', const_bool(1)) + + assign_x('execute_flag', const_bool(0)), + assign_x('b', const_float(2))) + )) + yield create_test_case( + input_sexp, input_sexp, 'return_void_at_end_of_loop_lower_nothing') + yield create_test_case( + input_sexp, expected_sexp, 'return_void_at_end_of_loop_lower_return', + lower_main_return=True) + yield create_test_case( + input_sexp, expected_sexp, + 'return_void_at_end_of_loop_lower_return_and_break', + lower_main_return=True, lower_break=True) + +def test_lower_return_non_void_at_end_of_loop(): + """Test that a non-void return at the end of a loop is properly lowered.""" + input_sexp = make_test_case('sub', 'float', ( + loop(assign_x('a', const_float(1)) + + return_(const_float(2))) + + assign_x('b', const_float(3)) + + return_(const_float(4)) + )) + expected_sexp = make_test_case('sub', 'float', ( + declare_execute_flag() + + declare_return_value() + + declare_return_flag() + + loop(assign_x('a', const_float(1)) + + lowered_return_simple(const_float(2)) + + break_()) + + if_return_flag(assign_x('return_value', '(var_ref return_value)') + + assign_x('return_flag', const_bool(1)) + + assign_x('execute_flag', const_bool(0)), + assign_x('b', const_float(3)) + + lowered_return(const_float(4))) + + final_return() + )) + yield create_test_case( + input_sexp, input_sexp, 'return_non_void_at_end_of_loop_lower_nothing') + yield create_test_case( + input_sexp, expected_sexp, + 'return_non_void_at_end_of_loop_lower_return', lower_sub_return=True) + yield create_test_case( + input_sexp, expected_sexp, + 'return_non_void_at_end_of_loop_lower_return_and_break', + lower_sub_return=True, lower_break=True) + +CASES = [ + test_lower_breaks_1, test_lower_breaks_2, test_lower_breaks_3, + test_lower_breaks_4, test_lower_breaks_5, test_lower_breaks_6, + test_lower_guarded_conditional_break, test_lower_pulled_out_jump, + test_lower_return_non_void_at_end_of_loop, + test_lower_return_void_at_end_of_loop, + test_lower_returns_1, test_lower_returns_2, test_lower_returns_3, + test_lower_returns_4, test_lower_returns_main, test_lower_returns_sub, + test_lower_unified_returns, test_remove_continue_at_end_of_loop, +] diff --git a/lib/mesa/src/compiler/glsl/tests/meson.build b/lib/mesa/src/compiler/glsl/tests/meson.build index 27f34075b..2a41e30a2 100644 --- a/lib/mesa/src/compiler/glsl/tests/meson.build +++ b/lib/mesa/src/compiler/glsl/tests/meson.build @@ -18,59 +18,87 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -glsl_blob_test = executable( +test( 'blob_test', - 'blob_test.c', - c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args], - include_directories : [inc_common, inc_compiler], - link_with : [libglsl], + executable( + 'blob_test', + 'blob_test.c', + c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args], + include_directories : [inc_common, inc_compiler], + link_with : [libglsl], + ) ) -glsl_cache_test = executable( +test( 'cache_test', - 'cache_test.c', - c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args], - include_directories : [inc_common, inc_glsl], - link_with : [libglsl], - dependencies : [dep_clock, dep_thread], + executable( + 'cache_test', + 'cache_test.c', + c_args : [c_vis_args, c_msvc_compat_args, no_override_init_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl], + dependencies : [dep_clock, dep_thread], + ) ) -glsl_general_ir_test = executable( + +test( 'general_ir_test', - ['array_refcount_test.cpp', 'builtin_variable_test.cpp', - 'invalidate_locations_test.cpp', 'general_ir_test.cpp', - 'lower_int64_test.cpp', 'opt_add_neg_to_sub_test.cpp', 'varyings_test.cpp', - ir_expression_operation_h], - cpp_args : [cpp_vis_args, cpp_msvc_compat_args], - include_directories : [inc_common, inc_glsl], - link_with : [libglsl, libglsl_standalone, libglsl_util], - dependencies : [dep_clock, dep_thread, idep_gtest], + executable( + 'general_ir_test', + ['array_refcount_test.cpp', 'builtin_variable_test.cpp', + 'invalidate_locations_test.cpp', 'general_ir_test.cpp', + 'lower_int64_test.cpp', 'opt_add_neg_to_sub_test.cpp', + 'varyings_test.cpp', ir_expression_operation_h], + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl, libglsl_standalone, libglsl_util], + dependencies : [dep_clock, dep_thread, idep_gtest], + ) ) -glsl_uniform_initializer_test = executable( +test( 'uniform_initializer_test', - ['copy_constant_to_storage_tests.cpp', 'set_uniform_initializer_tests.cpp', - 'uniform_initializer_utils.cpp', 'uniform_initializer_utils.h', - ir_expression_operation_h], - cpp_args : [cpp_vis_args, cpp_msvc_compat_args], - include_directories : [inc_common, inc_glsl], - link_with : [libglsl, libglsl_util], - dependencies : [dep_thread, idep_gtest], + executable( + 'uniform_initializer_test', + ['copy_constant_to_storage_tests.cpp', 'set_uniform_initializer_tests.cpp', + 'uniform_initializer_utils.cpp', 'uniform_initializer_utils.h', + ir_expression_operation_h], + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl, libglsl_util], + dependencies : [dep_thread, idep_gtest], + ) ) -glsl_sampler_types_test = executable( +test( 'sampler_types_test', - ['sampler_types_test.cpp', ir_expression_operation_h], - cpp_args : [cpp_vis_args, cpp_msvc_compat_args], - include_directories : [inc_common, inc_glsl], - link_with : [libglsl, libglsl_util], - dependencies : [dep_thread, idep_gtest], + executable( + 'sampler_types_test', + ['sampler_types_test.cpp', ir_expression_operation_h], + cpp_args : [cpp_vis_args, cpp_msvc_compat_args], + include_directories : [inc_common, inc_glsl], + link_with : [libglsl, libglsl_util], + dependencies : [dep_thread, idep_gtest], + ) ) -test('blob_test', glsl_blob_test) -test('cache_test', glsl_cache_test) -test('general_ir_test', glsl_general_ir_test) -test('uniform_initializer_test', glsl_uniform_initializer_test) -test('sampler_types_test', glsl_sampler_types_test) - -# TODO: figure out how to get the shell based tests to work? +test( + 'glsl compiler warnings', + prog_python, + args : [ + join_paths(meson.current_source_dir(), 'warnings_test.py'), + '--glsl-compiler', glsl_compiler, + '--test-directory', join_paths( + meson.source_root(), 'src', 'compiler', 'glsl', 'tests', 'warnings' + ), + ], +) +test( + 'glsl optimization', + prog_python, + args : [ + join_paths(meson.current_source_dir(), 'optimization_test.py'), + '--test-runner', glsl_test + ], +) diff --git a/lib/mesa/src/compiler/glsl/tests/optimization_test.py b/lib/mesa/src/compiler/glsl/tests/optimization_test.py new file mode 100644 index 000000000..15ca3216f --- /dev/null +++ b/lib/mesa/src/compiler/glsl/tests/optimization_test.py @@ -0,0 +1,96 @@ +# encoding=utf-8 +# Copyright © 2018 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Script to generate and run glsl optimization tests.""" + +from __future__ import print_function +import argparse +import difflib +import subprocess +import sys + +import sexps +import lower_jump_cases + + +def arg_parser(): + parser = argparse.ArgumentParser() + parser.add_argument( + '--test-runner', + required=True, + help='The glsl_test binary.') + return parser.parse_args() + + +def compare(actual, expected): + """Compare the s-expresions and return a diff if they are different.""" + actual = sexps.sort_decls(sexps.parse_sexp(actual)) + expected = sexps.sort_decls(sexps.parse_sexp(expected)) + + if actual == expected: + return None + + actual = sexps.sexp_to_string(actual) + expected = sexps.sexp_to_string(expected) + + return difflib.unified_diff(expected.splitlines(), actual.splitlines()) + + +def main(): + """Generate each test and report pass or fail.""" + args = arg_parser() + + total = 0 + passes = 0 + + for gen in lower_jump_cases.CASES: + for name, opt, source, expected in gen(): + total += 1 + print('{}: '.format(name), end='') + proc = subprocess.Popen( + [args.test_runner, 'optpass', '--quiet', '--input-ir', opt], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE) + out, err = proc.communicate(source.encode('utf-8')) + out = out.decode('utf-8') + err = err.decode('utf-8') + if err: + print('FAIL') + print('Unexpected output on stderr: {}'.format(err), + file=sys.stdout) + continue + + result = compare(out, expected) + if result is not None: + print('FAIL') + for l in result: + print(l, file=sys.stderr) + else: + print('PASS') + passes += 1 + + print('{}/{} tests returned correct results'.format(passes, total)) + exit(0 if passes == total else 1) + + +if __name__ == '__main__': + main() diff --git a/lib/mesa/src/compiler/glsl/tests/sexps.py b/lib/mesa/src/compiler/glsl/tests/sexps.py index a714af8d2..7939b42f9 100644 --- a/lib/mesa/src/compiler/glsl/tests/sexps.py +++ b/lib/mesa/src/compiler/glsl/tests/sexps.py @@ -28,6 +28,11 @@ # as ['constant', 'float', ['1.000000']]. import re +import sys +if sys.version_info >= (3, 0, 0): + STRING_TYPE = str +else: + STRING_TYPE = unicode def check_sexp(sexp): """Verify that the argument is a proper sexp. @@ -39,7 +44,7 @@ def check_sexp(sexp): if isinstance(sexp, list): for s in sexp: check_sexp(s) - elif not isinstance(sexp, basestring): + elif not isinstance(sexp, (STRING_TYPE, bytes)): raise Exception('Not a sexp: {0!r}'.format(sexp)) def parse_sexp(sexp): @@ -70,8 +75,10 @@ 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): + if isinstance(sexp, STRING_TYPE): return sexp + if isinstance(sexp, bytes): + return sexp.encode('utf-8') assert isinstance(sexp, list) result = '' for s in sexp: diff --git a/lib/mesa/src/compiler/glsl/tests/warnings_test.py b/lib/mesa/src/compiler/glsl/tests/warnings_test.py new file mode 100644 index 000000000..2c4fa5a0d --- /dev/null +++ b/lib/mesa/src/compiler/glsl/tests/warnings_test.py @@ -0,0 +1,73 @@ +# encoding=utf-8 +# Copyright © 2017 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from __future__ import print_function +import argparse +import os +import subprocess + + +def arg_parser(): + parser = argparse.ArgumentParser() + parser.add_argument( + '--glsl-compiler', + required=True, + help='Path to the standalone glsl compiler') + parser.add_argument( + '--test-directory', + required=True, + help='Directory containing tests to run.') + return parser.parse_args() + + +def main(): + args = arg_parser() + files = [f for f in os.listdir(args.test_directory) if f.endswith('.vert')] + passed = 0 + + if not files: + print('Could not find any tests') + exit(1) + + print('====== Testing compilation output ======') + for file in files: + print('Testing {} ...'.format(file), end='') + file = os.path.join(args.test_directory, file) + + with open('{}.expected'.format(file), 'rb') as f: + expected = f.read().strip() + + actual = subprocess.check_output( + [args.glsl_compiler, '--just-log', '--version', '150', file] + ).strip() + + if actual == expected: + print('PASS') + passed += 1 + else: + print('FAIL') + + print('{}/{} tests returned correct results'.format(passed, len(files))) + exit(0 if passed == len(files) else 1) + + +if __name__ == '__main__': + main() |