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_6):
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_6,
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-nonsemantic', '--vector-dce', '--workaround-1209',
76      '--unify-const', '--graphics-robust-access', '--wrap-opkill', '--amd-ext-to-khr'
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-nonsemantic',
121      'vector-dce',
122      'workaround-1209',
123      'unify-const',
124      'graphics-robust-access',
125      'wrap-opkill',
126      'amd-ext-to-khr'
127  ]
128  shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm')
129  output = placeholder.TempFileName('output.spv')
130  spirv_args = [shader, '-o', output, '--print-all'] + flags
131  expected_object_filenames = (output)
132
133
134@inside_spirv_testsuite('SpirvOptFlags')
135class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_6,
136                                        expect.ExecutedListOfPasses):
137  """Tests that spirv-opt schedules all the passes triggered by -O."""
138
139  flags = ['-O']
140  expected_passes = [
141      'wrap-opkill',
142      'eliminate-dead-branches',
143      'merge-return',
144      'inline-entry-points-exhaustive',
145      'eliminate-dead-functions',
146      'eliminate-dead-code-aggressive',
147      'private-to-local',
148      'eliminate-local-single-block',
149      'eliminate-local-single-store',
150      'eliminate-dead-code-aggressive',
151      'scalar-replacement=100',
152      'convert-local-access-chains',
153      'eliminate-local-single-block',
154      'eliminate-local-single-store',
155      'eliminate-dead-code-aggressive',
156      'ssa-rewrite',
157      'eliminate-dead-code-aggressive',
158      'ccp',
159      'eliminate-dead-code-aggressive',
160      'loop-unroll',
161      'eliminate-dead-branches',
162      'redundancy-elimination',
163      'combine-access-chains',
164      'simplify-instructions',
165      'scalar-replacement=100',
166      'convert-local-access-chains',
167      'eliminate-local-single-block',
168      'eliminate-local-single-store',
169      'eliminate-dead-code-aggressive',
170      'ssa-rewrite',
171      'eliminate-dead-code-aggressive',
172      'vector-dce',
173      'eliminate-dead-inserts',
174      'eliminate-dead-branches',
175      'simplify-instructions',
176      'if-conversion',
177      'copy-propagate-arrays',
178      'reduce-load-size',
179      'eliminate-dead-code-aggressive',
180      'merge-blocks',
181      'redundancy-elimination',
182      'eliminate-dead-branches',
183      'merge-blocks',
184      'simplify-instructions',
185  ]
186  shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm')
187  output = placeholder.TempFileName('output.spv')
188  spirv_args = [shader, '-o', output, '--print-all'] + flags
189  expected_object_filenames = (output)
190
191
192@inside_spirv_testsuite('SpirvOptFlags')
193class TestSizeOptimizationPasses(expect.ValidObjectFile1_6,
194                                 expect.ExecutedListOfPasses):
195  """Tests that spirv-opt schedules all the passes triggered by -Os."""
196
197  flags = ['-Os']
198  expected_passes = [
199      'wrap-opkill',
200      'eliminate-dead-branches',
201      'merge-return',
202      'inline-entry-points-exhaustive',
203      'eliminate-dead-functions',
204      'private-to-local',
205      'scalar-replacement=0',
206      'ssa-rewrite',
207      'ccp',
208      'loop-unroll',
209      'eliminate-dead-branches',
210      'simplify-instructions',
211      'scalar-replacement=0',
212      'eliminate-local-single-store',
213      'if-conversion',
214      'simplify-instructions',
215      'eliminate-dead-code-aggressive',
216      'eliminate-dead-branches',
217      'merge-blocks',
218      'convert-local-access-chains',
219      'eliminate-local-single-block',
220      'eliminate-dead-code-aggressive',
221      'copy-propagate-arrays',
222      'vector-dce',
223      'eliminate-dead-inserts',
224      'eliminate-dead-members',
225      'eliminate-local-single-store',
226      'merge-blocks',
227      'ssa-rewrite',
228      'redundancy-elimination',
229      'simplify-instructions',
230      'eliminate-dead-code-aggressive',
231      'cfg-cleanup',
232  ]
233  shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm')
234  output = placeholder.TempFileName('output.spv')
235  spirv_args = [shader, '-o', output, '--print-all'] + flags
236  expected_object_filenames = (output)
237
238
239@inside_spirv_testsuite('SpirvOptFlags')
240class TestLegalizationPasses(expect.ValidObjectFile1_6,
241                             expect.ExecutedListOfPasses):
242  """Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl.
243  """
244
245  flags = ['--legalize-hlsl']
246  expected_passes = [
247      'wrap-opkill',
248      'eliminate-dead-branches',
249      'merge-return',
250      'inline-entry-points-exhaustive',
251      'eliminate-dead-functions',
252      'private-to-local',
253      'fix-storage-class',
254      'eliminate-local-single-block',
255      'eliminate-local-single-store',
256      'eliminate-dead-code-aggressive',
257      'scalar-replacement=0',
258      'eliminate-local-single-block',
259      'eliminate-local-single-store',
260      'eliminate-dead-code-aggressive',
261      'ssa-rewrite',
262      'eliminate-dead-code-aggressive',
263      'ccp',
264      'loop-unroll',
265      'eliminate-dead-branches',
266      'simplify-instructions',
267      'eliminate-dead-code-aggressive',
268      'copy-propagate-arrays',
269      'vector-dce',
270      'eliminate-dead-inserts',
271      'reduce-load-size',
272      'eliminate-dead-code-aggressive',
273  ]
274  shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm')
275  output = placeholder.TempFileName('output.spv')
276  spirv_args = [shader, '-o', output, '--print-all'] + flags
277  expected_object_filenames = (output)
278
279
280@inside_spirv_testsuite('SpirvOptFlags')
281class TestScalarReplacementArgsNegative(expect.ErrorMessageSubstr):
282  """Tests invalid arguments to --scalar-replacement."""
283
284  spirv_args = ['--scalar-replacement=-10']
285  expected_error_substr = 'must have no arguments or a non-negative integer argument'
286
287
288@inside_spirv_testsuite('SpirvOptFlags')
289class TestScalarReplacementArgsInvalidNumber(expect.ErrorMessageSubstr):
290  """Tests invalid arguments to --scalar-replacement."""
291
292  spirv_args = ['--scalar-replacement=a10f']
293  expected_error_substr = 'must have no arguments or a non-negative integer argument'
294
295
296@inside_spirv_testsuite('SpirvOptFlags')
297class TestLoopFissionArgsNegative(expect.ErrorMessageSubstr):
298  """Tests invalid arguments to --loop-fission."""
299
300  spirv_args = ['--loop-fission=-10']
301  expected_error_substr = 'must have a positive integer argument'
302
303
304@inside_spirv_testsuite('SpirvOptFlags')
305class TestLoopFissionArgsInvalidNumber(expect.ErrorMessageSubstr):
306  """Tests invalid arguments to --loop-fission."""
307
308  spirv_args = ['--loop-fission=a10f']
309  expected_error_substr = 'must have a positive integer argument'
310
311
312@inside_spirv_testsuite('SpirvOptFlags')
313class TestLoopFusionArgsNegative(expect.ErrorMessageSubstr):
314  """Tests invalid arguments to --loop-fusion."""
315
316  spirv_args = ['--loop-fusion=-10']
317  expected_error_substr = 'must have a positive integer argument'
318
319
320@inside_spirv_testsuite('SpirvOptFlags')
321class TestLoopFusionArgsInvalidNumber(expect.ErrorMessageSubstr):
322  """Tests invalid arguments to --loop-fusion."""
323
324  spirv_args = ['--loop-fusion=a10f']
325  expected_error_substr = 'must have a positive integer argument'
326
327
328@inside_spirv_testsuite('SpirvOptFlags')
329class TestLoopUnrollPartialArgsNegative(expect.ErrorMessageSubstr):
330  """Tests invalid arguments to --loop-unroll-partial."""
331
332  spirv_args = ['--loop-unroll-partial=-10']
333  expected_error_substr = 'must have a positive integer argument'
334
335
336@inside_spirv_testsuite('SpirvOptFlags')
337class TestLoopUnrollPartialArgsInvalidNumber(expect.ErrorMessageSubstr):
338  """Tests invalid arguments to --loop-unroll-partial."""
339
340  spirv_args = ['--loop-unroll-partial=a10f']
341  expected_error_substr = 'must have a positive integer argument'
342
343
344@inside_spirv_testsuite('SpirvOptFlags')
345class TestLoopPeelingThresholdArgsNegative(expect.ErrorMessageSubstr):
346  """Tests invalid arguments to --loop-peeling-threshold."""
347
348  spirv_args = ['--loop-peeling-threshold=-10']
349  expected_error_substr = 'must have a positive integer argument'
350
351
352@inside_spirv_testsuite('SpirvOptFlags')
353class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr):
354  """Tests invalid arguments to --loop-peeling-threshold."""
355
356  spirv_args = ['--loop-peeling-threshold=a10f']
357  expected_error_substr = 'must have a positive integer argument'
358