# Copyright (c) 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import placeholder import expect import re from spirv_test_framework import inside_spirv_testsuite def empty_main_assembly(): return """ OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %4 "main" OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %4 = OpFunction %2 None %3 %5 = OpLabel OpReturn OpFunctionEnd""" @inside_spirv_testsuite('SpirvOptBase') class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_3): """Tests that spirv-opt accepts a SPIR-V object file.""" shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') output = placeholder.TempFileName('output.spv') spirv_args = [shader, '-o', output] expected_object_filenames = (output) @inside_spirv_testsuite('SpirvOptFlags') class TestHelpFlag(expect.ReturnCodeIsZero, expect.StdoutMatch): """Test the --help flag.""" spirv_args = ['--help'] expected_stdout = re.compile(r'.*The SPIR-V binary is read from <input>') @inside_spirv_testsuite('SpirvOptFlags') class TestValidPassFlags(expect.ValidObjectFile1_3, expect.ExecutedListOfPasses): """Tests that spirv-opt accepts all valid optimization flags.""" flags = [ '--ccp', '--cfg-cleanup', '--combine-access-chains', '--compact-ids', '--convert-local-access-chains', '--copy-propagate-arrays', '--eliminate-common-uniform', '--eliminate-dead-branches', '--eliminate-dead-code-aggressive', '--eliminate-dead-const', '--eliminate-dead-functions', '--eliminate-dead-inserts', '--eliminate-dead-variables', '--eliminate-insert-extract', '--eliminate-local-multi-store', '--eliminate-local-single-block', '--eliminate-local-single-store', '--flatten-decorations', '--fold-spec-const-op-composite', '--freeze-spec-const', '--if-conversion', '--inline-entry-points-exhaustive', '--loop-fission', '20', '--loop-fusion', '5', '--loop-unroll', '--loop-unroll-partial', '3', '--loop-peeling', '--merge-blocks', '--merge-return', '--loop-unswitch', '--private-to-local', '--reduce-load-size', '--redundancy-elimination', '--remove-duplicates', '--replace-invalid-opcode', '--ssa-rewrite', '--scalar-replacement', '--scalar-replacement=42', '--strength-reduction', '--strip-debug', '--strip-reflect', '--vector-dce', '--workaround-1209', '--unify-const' ] expected_passes = [ 'ccp', 'cfg-cleanup', 'combine-access-chains', 'compact-ids', 'convert-local-access-chains', 'copy-propagate-arrays', 'eliminate-common-uniform', 'eliminate-dead-branches', 'eliminate-dead-code-aggressive', 'eliminate-dead-const', 'eliminate-dead-functions', 'eliminate-dead-inserts', 'eliminate-dead-variables', # --eliminate-insert-extract runs the simplify-instructions pass. 'simplify-instructions', 'eliminate-local-multi-store', 'eliminate-local-single-block', 'eliminate-local-single-store', 'flatten-decorations', 'fold-spec-const-op-composite', 'freeze-spec-const', 'if-conversion', 'inline-entry-points-exhaustive', 'loop-fission', 'loop-fusion', 'loop-unroll', 'loop-unroll', 'loop-peeling', 'merge-blocks', 'merge-return', 'loop-unswitch', 'private-to-local', 'reduce-load-size', 'redundancy-elimination', 'remove-duplicates', 'replace-invalid-opcode', 'ssa-rewrite', 'scalar-replacement=100', 'scalar-replacement=42', 'strength-reduction', 'strip-debug', 'strip-reflect', 'vector-dce', 'workaround-1209', 'unify-const' ] shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') output = placeholder.TempFileName('output.spv') spirv_args = [shader, '-o', output, '--print-all'] + flags expected_object_filenames = (output) @inside_spirv_testsuite('SpirvOptFlags') class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_3, expect.ExecutedListOfPasses): """Tests that spirv-opt schedules all the passes triggered by -O.""" flags = ['-O'] expected_passes = [ 'eliminate-dead-branches', 'merge-return', 'inline-entry-points-exhaustive', 'eliminate-dead-code-aggressive', 'private-to-local', 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', 'scalar-replacement=100', 'convert-local-access-chains', 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', 'eliminate-local-multi-store', 'eliminate-dead-code-aggressive', 'ccp', 'eliminate-dead-code-aggressive', 'redundancy-elimination', 'combine-access-chains', 'simplify-instructions', 'vector-dce', 'eliminate-dead-inserts', 'eliminate-dead-branches', 'simplify-instructions', 'if-conversion', 'copy-propagate-arrays', 'reduce-load-size', 'eliminate-dead-code-aggressive', 'merge-blocks', 'redundancy-elimination', 'eliminate-dead-branches', 'merge-blocks', 'simplify-instructions', ] shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') output = placeholder.TempFileName('output.spv') spirv_args = [shader, '-o', output, '--print-all'] + flags expected_object_filenames = (output) @inside_spirv_testsuite('SpirvOptFlags') class TestSizeOptimizationPasses(expect.ValidObjectFile1_3, expect.ExecutedListOfPasses): """Tests that spirv-opt schedules all the passes triggered by -Os.""" flags = ['-Os'] expected_passes = [ 'eliminate-dead-branches', 'merge-return', 'inline-entry-points-exhaustive', 'eliminate-dead-code-aggressive', 'private-to-local', 'scalar-replacement=100', 'convert-local-access-chains', 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', 'simplify-instructions', 'eliminate-dead-inserts', 'eliminate-local-multi-store', 'eliminate-dead-code-aggressive', 'ccp', 'eliminate-dead-code-aggressive', 'eliminate-dead-branches', 'if-conversion', 'eliminate-dead-code-aggressive', 'merge-blocks', 'simplify-instructions', 'eliminate-dead-inserts', 'redundancy-elimination', 'cfg-cleanup', 'eliminate-dead-code-aggressive', ] shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') output = placeholder.TempFileName('output.spv') spirv_args = [shader, '-o', output, '--print-all'] + flags expected_object_filenames = (output) @inside_spirv_testsuite('SpirvOptFlags') class TestLegalizationPasses(expect.ValidObjectFile1_3, expect.ExecutedListOfPasses): """Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl. """ flags = ['--legalize-hlsl'] expected_passes = [ 'eliminate-dead-branches', 'merge-return', 'inline-entry-points-exhaustive', 'eliminate-dead-functions', 'private-to-local', 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', 'scalar-replacement=0', 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', 'eliminate-local-multi-store', 'eliminate-dead-code-aggressive', 'ccp', 'loop-unroll', 'eliminate-dead-branches', 'simplify-instructions', 'eliminate-dead-code-aggressive', 'copy-propagate-arrays', 'vector-dce', 'eliminate-dead-inserts', 'reduce-load-size', 'eliminate-dead-code-aggressive', ] shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') output = placeholder.TempFileName('output.spv') spirv_args = [shader, '-o', output, '--print-all'] + flags expected_object_filenames = (output) @inside_spirv_testsuite('SpirvOptFlags') class TestScalarReplacementArgsNegative(expect.ErrorMessageSubstr): """Tests invalid arguments to --scalar-replacement.""" spirv_args = ['--scalar-replacement=-10'] expected_error_substr = 'must have no arguments or a non-negative integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestScalarReplacementArgsInvalidNumber(expect.ErrorMessageSubstr): """Tests invalid arguments to --scalar-replacement.""" spirv_args = ['--scalar-replacement=a10f'] expected_error_substr = 'must have no arguments or a non-negative integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopFissionArgsNegative(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-fission.""" spirv_args = ['--loop-fission=-10'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopFissionArgsInvalidNumber(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-fission.""" spirv_args = ['--loop-fission=a10f'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopFusionArgsNegative(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-fusion.""" spirv_args = ['--loop-fusion=-10'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopFusionArgsInvalidNumber(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-fusion.""" spirv_args = ['--loop-fusion=a10f'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopUnrollPartialArgsNegative(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-unroll-partial.""" spirv_args = ['--loop-unroll-partial=-10'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopUnrollPartialArgsInvalidNumber(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-unroll-partial.""" spirv_args = ['--loop-unroll-partial=a10f'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopPeelingThresholdArgsNegative(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-peeling-threshold.""" spirv_args = ['--loop-peeling-threshold=-10'] expected_error_substr = 'must have a positive integer argument' @inside_spirv_testsuite('SpirvOptFlags') class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr): """Tests invalid arguments to --loop-peeling-threshold.""" spirv_args = ['--loop-peeling-threshold=a10f'] expected_error_substr = 'must have a positive integer argument'