1# Copyright (c) 2018 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import placeholder 16import expect 17import re 18 19from spirv_test_framework import inside_spirv_testsuite 20 21 22def empty_main_assembly(): 23 return """ 24 OpCapability Shader 25 OpMemoryModel Logical GLSL450 26 OpEntryPoint Vertex %4 "main" 27 OpName %4 "main" 28 %2 = OpTypeVoid 29 %3 = OpTypeFunction %2 30 %4 = OpFunction %2 None %3 31 %5 = OpLabel 32 OpReturn 33 OpFunctionEnd""" 34 35 36@inside_spirv_testsuite('SpirvOptBase') 37class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_5): 38 """Tests that spirv-opt accepts a SPIR-V object file.""" 39 40 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 41 output = placeholder.TempFileName('output.spv') 42 spirv_args = [shader, '-o', output] 43 expected_object_filenames = (output) 44 45 46@inside_spirv_testsuite('SpirvOptFlags') 47class TestHelpFlag(expect.ReturnCodeIsZero, expect.StdoutMatch): 48 """Test the --help flag.""" 49 50 spirv_args = ['--help'] 51 expected_stdout = re.compile(r'.*The SPIR-V binary is read from <input>') 52 53 54@inside_spirv_testsuite('SpirvOptFlags') 55class TestValidPassFlags(expect.ValidObjectFile1_5, 56 expect.ExecutedListOfPasses): 57 """Tests that spirv-opt accepts all valid optimization flags.""" 58 59 flags = [ 60 '--wrap-opkill', '--ccp', '--cfg-cleanup', '--combine-access-chains', '--compact-ids', 61 '--convert-local-access-chains', '--copy-propagate-arrays', 62 '--eliminate-dead-branches', 63 '--eliminate-dead-code-aggressive', '--eliminate-dead-const', 64 '--eliminate-dead-functions', '--eliminate-dead-inserts', 65 '--eliminate-dead-variables', '--eliminate-insert-extract', 66 '--eliminate-local-multi-store', '--eliminate-local-single-block', 67 '--eliminate-local-single-store', '--flatten-decorations', 68 '--fold-spec-const-op-composite', '--freeze-spec-const', 69 '--if-conversion', '--inline-entry-points-exhaustive', '--loop-fission', 70 '20', '--loop-fusion', '5', '--loop-unroll', '--loop-unroll-partial', '3', 71 '--loop-peeling', '--merge-blocks', '--merge-return', '--loop-unswitch', 72 '--private-to-local', '--reduce-load-size', '--redundancy-elimination', 73 '--remove-duplicates', '--replace-invalid-opcode', '--ssa-rewrite', 74 '--scalar-replacement', '--scalar-replacement=42', '--strength-reduction', 75 '--strip-debug', '--strip-reflect', '--vector-dce', '--workaround-1209', 76 '--unify-const' 77 ] 78 expected_passes = [ 79 'wrap-opkill', 80 'ccp', 81 'cfg-cleanup', 82 'combine-access-chains', 83 'compact-ids', 84 'convert-local-access-chains', 85 'copy-propagate-arrays', 86 'eliminate-dead-branches', 87 'eliminate-dead-code-aggressive', 88 'eliminate-dead-const', 89 'eliminate-dead-functions', 90 'eliminate-dead-inserts', 91 'eliminate-dead-variables', 92 # --eliminate-insert-extract runs the simplify-instructions pass. 93 'simplify-instructions', 94 'ssa-rewrite', 95 'eliminate-local-single-block', 96 'eliminate-local-single-store', 97 'flatten-decorations', 98 'fold-spec-const-op-composite', 99 'freeze-spec-const', 100 'if-conversion', 101 'inline-entry-points-exhaustive', 102 'loop-fission', 103 'loop-fusion', 104 'loop-unroll', 105 'loop-unroll', 106 'loop-peeling', 107 'merge-blocks', 108 'merge-return', 109 'loop-unswitch', 110 'private-to-local', 111 'reduce-load-size', 112 'redundancy-elimination', 113 'remove-duplicates', 114 'replace-invalid-opcode', 115 'ssa-rewrite', 116 'scalar-replacement=100', 117 'scalar-replacement=42', 118 'strength-reduction', 119 'strip-debug', 120 'strip-reflect', 121 'vector-dce', 122 'workaround-1209', 123 'unify-const' 124 ] 125 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 126 output = placeholder.TempFileName('output.spv') 127 spirv_args = [shader, '-o', output, '--print-all'] + flags 128 expected_object_filenames = (output) 129 130 131@inside_spirv_testsuite('SpirvOptFlags') 132class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_5, 133 expect.ExecutedListOfPasses): 134 """Tests that spirv-opt schedules all the passes triggered by -O.""" 135 136 flags = ['-O'] 137 expected_passes = [ 138 'wrap-opkill', 139 'eliminate-dead-branches', 140 'merge-return', 141 'inline-entry-points-exhaustive', 142 'eliminate-dead-code-aggressive', 143 'private-to-local', 144 'eliminate-local-single-block', 145 'eliminate-local-single-store', 146 'eliminate-dead-code-aggressive', 147 'scalar-replacement=100', 148 'convert-local-access-chains', 149 'eliminate-local-single-block', 150 'eliminate-local-single-store', 151 'eliminate-dead-code-aggressive', 152 'ssa-rewrite', 153 'eliminate-dead-code-aggressive', 154 'ccp', 155 'eliminate-dead-code-aggressive', 156 'redundancy-elimination', 157 'combine-access-chains', 158 'simplify-instructions', 159 'vector-dce', 160 'eliminate-dead-inserts', 161 'eliminate-dead-branches', 162 'simplify-instructions', 163 'if-conversion', 164 'copy-propagate-arrays', 165 'reduce-load-size', 166 'eliminate-dead-code-aggressive', 167 'merge-blocks', 168 'redundancy-elimination', 169 'eliminate-dead-branches', 170 'merge-blocks', 171 'simplify-instructions', 172 ] 173 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 174 output = placeholder.TempFileName('output.spv') 175 spirv_args = [shader, '-o', output, '--print-all'] + flags 176 expected_object_filenames = (output) 177 178 179@inside_spirv_testsuite('SpirvOptFlags') 180class TestSizeOptimizationPasses(expect.ValidObjectFile1_5, 181 expect.ExecutedListOfPasses): 182 """Tests that spirv-opt schedules all the passes triggered by -Os.""" 183 184 flags = ['-Os'] 185 expected_passes = [ 186 'wrap-opkill', 187 'eliminate-dead-branches', 188 'merge-return', 189 'inline-entry-points-exhaustive', 190 'eliminate-dead-functions', 191 'private-to-local', 192 'scalar-replacement=0', 193 'ssa-rewrite', 194 'ccp', 195 'loop-unroll', 196 'eliminate-dead-branches', 197 'simplify-instructions', 198 'scalar-replacement=0', 199 'eliminate-local-single-store', 200 'if-conversion', 201 'simplify-instructions', 202 'eliminate-dead-code-aggressive', 203 'eliminate-dead-branches', 204 'merge-blocks', 205 'convert-local-access-chains', 206 'eliminate-local-single-block', 207 'eliminate-dead-code-aggressive', 208 'copy-propagate-arrays', 209 'vector-dce', 210 'eliminate-dead-inserts', 211 'eliminate-dead-members', 212 'eliminate-local-single-store', 213 'merge-blocks', 214 'ssa-rewrite', 215 'redundancy-elimination', 216 'simplify-instructions', 217 'eliminate-dead-code-aggressive', 218 'cfg-cleanup', 219 ] 220 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 221 output = placeholder.TempFileName('output.spv') 222 spirv_args = [shader, '-o', output, '--print-all'] + flags 223 expected_object_filenames = (output) 224 225 226@inside_spirv_testsuite('SpirvOptFlags') 227class TestLegalizationPasses(expect.ValidObjectFile1_5, 228 expect.ExecutedListOfPasses): 229 """Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl. 230 """ 231 232 flags = ['--legalize-hlsl'] 233 expected_passes = [ 234 'wrap-opkill', 235 'eliminate-dead-branches', 236 'merge-return', 237 'inline-entry-points-exhaustive', 238 'eliminate-dead-functions', 239 'private-to-local', 240 'fix-storage-class', 241 'eliminate-local-single-block', 242 'eliminate-local-single-store', 243 'eliminate-dead-code-aggressive', 244 'scalar-replacement=0', 245 'eliminate-local-single-block', 246 'eliminate-local-single-store', 247 'eliminate-dead-code-aggressive', 248 'ssa-rewrite', 249 'eliminate-dead-code-aggressive', 250 'ccp', 251 'loop-unroll', 252 'eliminate-dead-branches', 253 'simplify-instructions', 254 'eliminate-dead-code-aggressive', 255 'copy-propagate-arrays', 256 'vector-dce', 257 'eliminate-dead-inserts', 258 'reduce-load-size', 259 'eliminate-dead-code-aggressive', 260 ] 261 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 262 output = placeholder.TempFileName('output.spv') 263 spirv_args = [shader, '-o', output, '--print-all'] + flags 264 expected_object_filenames = (output) 265 266 267@inside_spirv_testsuite('SpirvOptFlags') 268class TestScalarReplacementArgsNegative(expect.ErrorMessageSubstr): 269 """Tests invalid arguments to --scalar-replacement.""" 270 271 spirv_args = ['--scalar-replacement=-10'] 272 expected_error_substr = 'must have no arguments or a non-negative integer argument' 273 274 275@inside_spirv_testsuite('SpirvOptFlags') 276class TestScalarReplacementArgsInvalidNumber(expect.ErrorMessageSubstr): 277 """Tests invalid arguments to --scalar-replacement.""" 278 279 spirv_args = ['--scalar-replacement=a10f'] 280 expected_error_substr = 'must have no arguments or a non-negative integer argument' 281 282 283@inside_spirv_testsuite('SpirvOptFlags') 284class TestLoopFissionArgsNegative(expect.ErrorMessageSubstr): 285 """Tests invalid arguments to --loop-fission.""" 286 287 spirv_args = ['--loop-fission=-10'] 288 expected_error_substr = 'must have a positive integer argument' 289 290 291@inside_spirv_testsuite('SpirvOptFlags') 292class TestLoopFissionArgsInvalidNumber(expect.ErrorMessageSubstr): 293 """Tests invalid arguments to --loop-fission.""" 294 295 spirv_args = ['--loop-fission=a10f'] 296 expected_error_substr = 'must have a positive integer argument' 297 298 299@inside_spirv_testsuite('SpirvOptFlags') 300class TestLoopFusionArgsNegative(expect.ErrorMessageSubstr): 301 """Tests invalid arguments to --loop-fusion.""" 302 303 spirv_args = ['--loop-fusion=-10'] 304 expected_error_substr = 'must have a positive integer argument' 305 306 307@inside_spirv_testsuite('SpirvOptFlags') 308class TestLoopFusionArgsInvalidNumber(expect.ErrorMessageSubstr): 309 """Tests invalid arguments to --loop-fusion.""" 310 311 spirv_args = ['--loop-fusion=a10f'] 312 expected_error_substr = 'must have a positive integer argument' 313 314 315@inside_spirv_testsuite('SpirvOptFlags') 316class TestLoopUnrollPartialArgsNegative(expect.ErrorMessageSubstr): 317 """Tests invalid arguments to --loop-unroll-partial.""" 318 319 spirv_args = ['--loop-unroll-partial=-10'] 320 expected_error_substr = 'must have a positive integer argument' 321 322 323@inside_spirv_testsuite('SpirvOptFlags') 324class TestLoopUnrollPartialArgsInvalidNumber(expect.ErrorMessageSubstr): 325 """Tests invalid arguments to --loop-unroll-partial.""" 326 327 spirv_args = ['--loop-unroll-partial=a10f'] 328 expected_error_substr = 'must have a positive integer argument' 329 330 331@inside_spirv_testsuite('SpirvOptFlags') 332class TestLoopPeelingThresholdArgsNegative(expect.ErrorMessageSubstr): 333 """Tests invalid arguments to --loop-peeling-threshold.""" 334 335 spirv_args = ['--loop-peeling-threshold=-10'] 336 expected_error_substr = 'must have a positive integer argument' 337 338 339@inside_spirv_testsuite('SpirvOptFlags') 340class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr): 341 """Tests invalid arguments to --loop-peeling-threshold.""" 342 343 spirv_args = ['--loop-peeling-threshold=a10f'] 344 expected_error_substr = 'must have a positive integer argument' 345 346@inside_spirv_testsuite('SpirvOptFlags') 347class TestWebGPUToVulkanThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 348 """Tests Vulkan->WebGPU flag cannot be used after WebGPU->Vulkan flag.""" 349 350 spirv_args = ['--webgpu-to-vulkan', '--vulkan-to-webgpu'] 351 expected_error_substr = 'Cannot use both' 352 353@inside_spirv_testsuite('SpirvOptFlags') 354class TestVulkanToWebGPUThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 355 """Tests WebGPU->Vulkan flag cannot be used after Vulkan->WebGPU flag.""" 356 357 spirv_args = ['--vulkan-to-webgpu', '--webgpu-to-vulkan'] 358 expected_error_substr = 'Cannot use both' 359 360@inside_spirv_testsuite('SpirvOptFlags') 361class TestTargetEnvThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 362 """Tests Vulkan->WebGPU flag cannot be used after target env flag.""" 363 364 spirv_args = ['--target-env=opengl4.0', '--vulkan-to-webgpu'] 365 expected_error_substr = 'defines the target environment' 366 367@inside_spirv_testsuite('SpirvOptFlags') 368class TestVulkanToWebGPUThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 369 """Tests target env flag cannot be used after Vulkan->WebGPU flag.""" 370 371 spirv_args = ['--vulkan-to-webgpu', '--target-env=opengl4.0'] 372 expected_error_substr = 'defines the target environment' 373 374@inside_spirv_testsuite('SpirvOptFlags') 375class TestTargetEnvThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 376 """Tests WebGPU->Vulkan flag cannot be used after target env flag.""" 377 378 spirv_args = ['--target-env=opengl4.0', '--webgpu-to-vulkan'] 379 expected_error_substr = 'defines the target environment' 380 381@inside_spirv_testsuite('SpirvOptFlags') 382class TestWebGPUToVulkanThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 383 """Tests target env flag cannot be used after WebGPU->Vulkan flag.""" 384 385 spirv_args = ['--webgpu-to-vulkan', '--target-env=opengl4.0'] 386 expected_error_substr = 'defines the target environment' 387