• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2
3#####################################################################
4# Copyright (c) 2020 The Khronos Group Inc. All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#    http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#####################################################################
18
19"""Assembles the SPIR-V assembly files used by spirv_new into binaries,
20   and validates them using spirv-val.  Either run this from the parent
21   of the spirv_asm directory, or pass the --source-dir and --output-dir
22   options to specify the locations of the assembly files and the
23   binaries to be generated.
24"""
25
26import argparse
27import glob
28import os
29import subprocess
30import sys
31from textwrap import wrap
32
33
34def fatal(message):
35    """Print an error message and exit with a non-zero status, to
36       indicate failure.
37    """
38    print(message)
39    sys.exit(1)
40
41
42def assemble_spirv(asm_dir, bin_dir, spirv_as, verbose):
43    """Assemble SPIR-V source into binaries."""
44
45    if not os.path.exists(bin_dir):
46        os.makedirs(bin_dir)
47
48    assembly_failures = False
49
50    for asm_file_path in glob.glob(os.path.join(asm_dir, '*.spvasm*')):
51        asm_file = os.path.basename(asm_file_path)
52        if os.path.isfile(asm_file_path):
53            if verbose:
54                print(' Assembling {}'.format(asm_file))
55
56            asm_file_root, asm_file_ext = os.path.splitext(asm_file)
57            bin_file = asm_file_root + asm_file_ext.replace('asm', '')
58            bin_file_path = os.path.join(bin_dir, bin_file)
59
60            command = '"{}" --target-env spv1.0 "{}" -o "{}"'.format(
61                spirv_as, asm_file_path, bin_file_path)
62            if subprocess.call(command, shell=True) != 0:
63                assembly_failures = True
64                print('ERROR: Failure assembling {}: '
65                      'see above output.'.format(
66                          asm_file))
67                print()
68
69    if assembly_failures:
70        fatal('\n'.join(wrap(
71            'ERROR: Assembly failure(s) occurred.  See above for error '
72            'messages from the assembler, if any.')))
73
74
75def validate_spirv(bin_dir, spirv_val, verbose):
76    """Validates SPIR-V binaries.  Ignores known failures."""
77
78    validation_failures = False
79
80    for bin_file_path in glob.glob(os.path.join(bin_dir, '*.spv*')):
81        bin_file = os.path.basename(bin_file_path)
82        if os.path.isfile(bin_file_path):
83            if verbose:
84                print(' Validating {}'.format(bin_file))
85
86            command = '"{}" "{}"'.format(
87                spirv_val, bin_file_path)
88            if subprocess.call(command, shell=True) != 0:
89                print('ERROR: Failure validating {}: '
90                      'see above output.'.format(
91                          bin_file))
92                validation_failures = True
93                print()
94
95    if validation_failures:
96        fatal('ERROR: Validation failure(s) found.  '
97              'See above for validation output.')
98    else:
99        print('All SPIR-V binaries validated successfully.')
100
101
102def parse_args():
103    """Parse the command-line arguments."""
104
105    argparse_kwargs = (
106        {'allow_abbrev': False} if sys.version_info >= (3, 5) else {})
107    argparse_kwargs['description'] = (
108        '''Assembles the SPIR-V assembly files used by spirv_new into
109           binaries, and validates them using spirv-val.  Either run this
110           from the parent of the spirv_asm directory, or pass the
111           --source-dir and --output-dir options to specify the locations
112           the assembly files and the binaries to be generated.
113        ''')
114    parser = argparse.ArgumentParser(**argparse_kwargs)
115    parser.add_argument('-s', '--source-dir', metavar='DIR',
116                        default='spirv_asm',
117                        help='''specifies the directory containing SPIR-V
118                                assembly files''')
119    parser.add_argument('-o', '--output-dir', metavar='DIR',
120                        default='spirv_bin',
121                        help='''specifies the directory in which to
122                                output SPIR-V binary files''')
123    parser.add_argument('-a', '--assembler', metavar='PROGRAM',
124                        default='spirv-as',
125                        help='''specifies the program to use for assembly
126                                of SPIR-V, defaults to spirv-as''')
127    parser.add_argument('-l', '--validator', metavar='PROGRAM',
128                        default='spirv-val',
129                        help='''specifies the program to use for validation
130                                of SPIR-V, defaults to spirv-val''')
131    parser.add_argument('-k', '--skip-validation', action='store_true',
132                        default=False,
133                        help='skips validation of the genareted SPIR-V')
134    parser.add_argument('-v', '--verbose', action='store_true', default=False,
135                        help='''enable verbose output (i.e. prints the
136                                name of each SPIR-V assembly file or
137                                binary as it is assembled or validated)
138                             ''')
139    return parser.parse_args()
140
141
142def main():
143    """Main function.  Assembles and validates SPIR-V."""
144
145    args = parse_args()
146
147    print('Assembling SPIR-V source into binaries...')
148    assemble_spirv(args.source_dir, args.output_dir, args.assembler,
149                   args.verbose)
150    print('Finished assembling SPIR-V binaries.')
151    print()
152
153    if args.skip_validation:
154        print('Skipping validation of SPIR-V binaries as requested.')
155    else:
156        print('Validating SPIR-V binaries...')
157        validate_spirv(args.output_dir, args.validator, args.verbose)
158    print()
159
160    print('Done.')
161
162
163if __name__ == '__main__':
164    main()
165