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', '--legalize-vector-shuffle', 77 '--split-invalid-unreachable', '--generate-webgpu-initializers', 78 '--decompose-initialized-variables', '--graphics-robust-access', 79 '--wrap-opkill', '--amd-ext-to-khr' 80 ] 81 expected_passes = [ 82 'wrap-opkill', 83 'ccp', 84 'cfg-cleanup', 85 'combine-access-chains', 86 'compact-ids', 87 'convert-local-access-chains', 88 'copy-propagate-arrays', 89 'eliminate-dead-branches', 90 'eliminate-dead-code-aggressive', 91 'eliminate-dead-const', 92 'eliminate-dead-functions', 93 'eliminate-dead-inserts', 94 'eliminate-dead-variables', 95 # --eliminate-insert-extract runs the simplify-instructions pass. 96 'simplify-instructions', 97 'ssa-rewrite', 98 'eliminate-local-single-block', 99 'eliminate-local-single-store', 100 'flatten-decorations', 101 'fold-spec-const-op-composite', 102 'freeze-spec-const', 103 'if-conversion', 104 'inline-entry-points-exhaustive', 105 'loop-fission', 106 'loop-fusion', 107 'loop-unroll', 108 'loop-unroll', 109 'loop-peeling', 110 'merge-blocks', 111 'merge-return', 112 'loop-unswitch', 113 'private-to-local', 114 'reduce-load-size', 115 'redundancy-elimination', 116 'remove-duplicates', 117 'replace-invalid-opcode', 118 'ssa-rewrite', 119 'scalar-replacement=100', 120 'scalar-replacement=42', 121 'strength-reduction', 122 'strip-debug', 123 'strip-reflect', 124 'vector-dce', 125 'workaround-1209', 126 'unify-const', 127 'legalize-vector-shuffle', 128 'split-invalid-unreachable', 129 'generate-webgpu-initializers', 130 'decompose-initialized-variables', 131 'graphics-robust-access', 132 'wrap-opkill', 133 'amd-ext-to-khr' 134 ] 135 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 136 output = placeholder.TempFileName('output.spv') 137 spirv_args = [shader, '-o', output, '--print-all'] + flags 138 expected_object_filenames = (output) 139 140 141@inside_spirv_testsuite('SpirvOptFlags') 142class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_5, 143 expect.ExecutedListOfPasses): 144 """Tests that spirv-opt schedules all the passes triggered by -O.""" 145 146 flags = ['-O'] 147 expected_passes = [ 148 'wrap-opkill', 149 'eliminate-dead-branches', 150 'merge-return', 151 'inline-entry-points-exhaustive', 152 'eliminate-dead-code-aggressive', 153 'private-to-local', 154 'eliminate-local-single-block', 155 'eliminate-local-single-store', 156 'eliminate-dead-code-aggressive', 157 'scalar-replacement=100', 158 'convert-local-access-chains', 159 'eliminate-local-single-block', 160 'eliminate-local-single-store', 161 'eliminate-dead-code-aggressive', 162 'ssa-rewrite', 163 'eliminate-dead-code-aggressive', 164 'ccp', 165 'eliminate-dead-code-aggressive', 166 'redundancy-elimination', 167 'combine-access-chains', 168 'simplify-instructions', 169 'vector-dce', 170 'eliminate-dead-inserts', 171 'eliminate-dead-branches', 172 'simplify-instructions', 173 'if-conversion', 174 'copy-propagate-arrays', 175 'reduce-load-size', 176 'eliminate-dead-code-aggressive', 177 'merge-blocks', 178 'redundancy-elimination', 179 'eliminate-dead-branches', 180 'merge-blocks', 181 'simplify-instructions', 182 ] 183 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 184 output = placeholder.TempFileName('output.spv') 185 spirv_args = [shader, '-o', output, '--print-all'] + flags 186 expected_object_filenames = (output) 187 188 189@inside_spirv_testsuite('SpirvOptFlags') 190class TestSizeOptimizationPasses(expect.ValidObjectFile1_5, 191 expect.ExecutedListOfPasses): 192 """Tests that spirv-opt schedules all the passes triggered by -Os.""" 193 194 flags = ['-Os'] 195 expected_passes = [ 196 'wrap-opkill', 197 'eliminate-dead-branches', 198 'merge-return', 199 'inline-entry-points-exhaustive', 200 'eliminate-dead-functions', 201 'private-to-local', 202 'scalar-replacement=0', 203 'ssa-rewrite', 204 'ccp', 205 'loop-unroll', 206 'eliminate-dead-branches', 207 'simplify-instructions', 208 'scalar-replacement=0', 209 'eliminate-local-single-store', 210 'if-conversion', 211 'simplify-instructions', 212 'eliminate-dead-code-aggressive', 213 'eliminate-dead-branches', 214 'merge-blocks', 215 'convert-local-access-chains', 216 'eliminate-local-single-block', 217 'eliminate-dead-code-aggressive', 218 'copy-propagate-arrays', 219 'vector-dce', 220 'eliminate-dead-inserts', 221 'eliminate-dead-members', 222 'eliminate-local-single-store', 223 'merge-blocks', 224 'ssa-rewrite', 225 'redundancy-elimination', 226 'simplify-instructions', 227 'eliminate-dead-code-aggressive', 228 'cfg-cleanup', 229 ] 230 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 231 output = placeholder.TempFileName('output.spv') 232 spirv_args = [shader, '-o', output, '--print-all'] + flags 233 expected_object_filenames = (output) 234 235 236@inside_spirv_testsuite('SpirvOptFlags') 237class TestLegalizationPasses(expect.ValidObjectFile1_5, 238 expect.ExecutedListOfPasses): 239 """Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl. 240 """ 241 242 flags = ['--legalize-hlsl'] 243 expected_passes = [ 244 'wrap-opkill', 245 'eliminate-dead-branches', 246 'merge-return', 247 'inline-entry-points-exhaustive', 248 'eliminate-dead-functions', 249 'private-to-local', 250 'fix-storage-class', 251 'eliminate-local-single-block', 252 'eliminate-local-single-store', 253 'eliminate-dead-code-aggressive', 254 'scalar-replacement=0', 255 'eliminate-local-single-block', 256 'eliminate-local-single-store', 257 'eliminate-dead-code-aggressive', 258 'ssa-rewrite', 259 'eliminate-dead-code-aggressive', 260 'ccp', 261 'loop-unroll', 262 'eliminate-dead-branches', 263 'simplify-instructions', 264 'eliminate-dead-code-aggressive', 265 'copy-propagate-arrays', 266 'vector-dce', 267 'eliminate-dead-inserts', 268 'reduce-load-size', 269 'eliminate-dead-code-aggressive', 270 ] 271 shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') 272 output = placeholder.TempFileName('output.spv') 273 spirv_args = [shader, '-o', output, '--print-all'] + flags 274 expected_object_filenames = (output) 275 276 277@inside_spirv_testsuite('SpirvOptFlags') 278class TestScalarReplacementArgsNegative(expect.ErrorMessageSubstr): 279 """Tests invalid arguments to --scalar-replacement.""" 280 281 spirv_args = ['--scalar-replacement=-10'] 282 expected_error_substr = 'must have no arguments or a non-negative integer argument' 283 284 285@inside_spirv_testsuite('SpirvOptFlags') 286class TestScalarReplacementArgsInvalidNumber(expect.ErrorMessageSubstr): 287 """Tests invalid arguments to --scalar-replacement.""" 288 289 spirv_args = ['--scalar-replacement=a10f'] 290 expected_error_substr = 'must have no arguments or a non-negative integer argument' 291 292 293@inside_spirv_testsuite('SpirvOptFlags') 294class TestLoopFissionArgsNegative(expect.ErrorMessageSubstr): 295 """Tests invalid arguments to --loop-fission.""" 296 297 spirv_args = ['--loop-fission=-10'] 298 expected_error_substr = 'must have a positive integer argument' 299 300 301@inside_spirv_testsuite('SpirvOptFlags') 302class TestLoopFissionArgsInvalidNumber(expect.ErrorMessageSubstr): 303 """Tests invalid arguments to --loop-fission.""" 304 305 spirv_args = ['--loop-fission=a10f'] 306 expected_error_substr = 'must have a positive integer argument' 307 308 309@inside_spirv_testsuite('SpirvOptFlags') 310class TestLoopFusionArgsNegative(expect.ErrorMessageSubstr): 311 """Tests invalid arguments to --loop-fusion.""" 312 313 spirv_args = ['--loop-fusion=-10'] 314 expected_error_substr = 'must have a positive integer argument' 315 316 317@inside_spirv_testsuite('SpirvOptFlags') 318class TestLoopFusionArgsInvalidNumber(expect.ErrorMessageSubstr): 319 """Tests invalid arguments to --loop-fusion.""" 320 321 spirv_args = ['--loop-fusion=a10f'] 322 expected_error_substr = 'must have a positive integer argument' 323 324 325@inside_spirv_testsuite('SpirvOptFlags') 326class TestLoopUnrollPartialArgsNegative(expect.ErrorMessageSubstr): 327 """Tests invalid arguments to --loop-unroll-partial.""" 328 329 spirv_args = ['--loop-unroll-partial=-10'] 330 expected_error_substr = 'must have a positive integer argument' 331 332 333@inside_spirv_testsuite('SpirvOptFlags') 334class TestLoopUnrollPartialArgsInvalidNumber(expect.ErrorMessageSubstr): 335 """Tests invalid arguments to --loop-unroll-partial.""" 336 337 spirv_args = ['--loop-unroll-partial=a10f'] 338 expected_error_substr = 'must have a positive integer argument' 339 340 341@inside_spirv_testsuite('SpirvOptFlags') 342class TestLoopPeelingThresholdArgsNegative(expect.ErrorMessageSubstr): 343 """Tests invalid arguments to --loop-peeling-threshold.""" 344 345 spirv_args = ['--loop-peeling-threshold=-10'] 346 expected_error_substr = 'must have a positive integer argument' 347 348 349@inside_spirv_testsuite('SpirvOptFlags') 350class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr): 351 """Tests invalid arguments to --loop-peeling-threshold.""" 352 353 spirv_args = ['--loop-peeling-threshold=a10f'] 354 expected_error_substr = 'must have a positive integer argument' 355 356@inside_spirv_testsuite('SpirvOptFlags') 357class TestWebGPUToVulkanThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 358 """Tests Vulkan->WebGPU flag cannot be used after WebGPU->Vulkan flag.""" 359 360 spirv_args = ['--webgpu-to-vulkan', '--vulkan-to-webgpu'] 361 expected_error_substr = 'Cannot use both' 362 363@inside_spirv_testsuite('SpirvOptFlags') 364class TestVulkanToWebGPUThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 365 """Tests WebGPU->Vulkan flag cannot be used after Vulkan->WebGPU flag.""" 366 367 spirv_args = ['--vulkan-to-webgpu', '--webgpu-to-vulkan'] 368 expected_error_substr = 'Cannot use both' 369 370@inside_spirv_testsuite('SpirvOptFlags') 371class TestTargetEnvThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 372 """Tests Vulkan->WebGPU flag cannot be used after target env flag.""" 373 374 spirv_args = ['--target-env=opengl4.0', '--vulkan-to-webgpu'] 375 expected_error_substr = 'defines the target environment' 376 377@inside_spirv_testsuite('SpirvOptFlags') 378class TestVulkanToWebGPUThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 379 """Tests target env flag cannot be used after Vulkan->WebGPU flag.""" 380 381 spirv_args = ['--vulkan-to-webgpu', '--target-env=opengl4.0'] 382 expected_error_substr = 'defines the target environment' 383 384@inside_spirv_testsuite('SpirvOptFlags') 385class TestTargetEnvThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 386 """Tests WebGPU->Vulkan flag cannot be used after target env flag.""" 387 388 spirv_args = ['--target-env=opengl4.0', '--webgpu-to-vulkan'] 389 expected_error_substr = 'defines the target environment' 390 391@inside_spirv_testsuite('SpirvOptFlags') 392class TestWebGPUToVulkanThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): 393 """Tests target env flag cannot be used after WebGPU->Vulkan flag.""" 394 395 spirv_args = ['--webgpu-to-vulkan', '--target-env=opengl4.0'] 396 expected_error_substr = 'defines the target environment' 397