/
redgpu
/
clspv
Обзор
Документация
Войти
/
redgpu
/
clspv
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
utils/make_test.py
249 строк
7 KB
Kévin Petit
Fix make_test.py for Python 3 (#419)
12 авг 2019, 15:16
12 авг 2019, 15:16
32dd576
Код
Авторство
О чём код?
#!/usr/bin/env python # Copyright 2018 The Clspv Authors. All rights reserved. # # 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 argparse import collections import os import re import subprocess import tempfile DESCRIPTION = """This script can be used to help with writing test cases for clspv. When passed an OpenCL C source file, it will: 1. Build a SPIR-V module using clspv 2. Disassemble the module 3. Post-process the disassembly to introduce FileCheck variables and CHECK directives 4. Prepend appropriate run commands, append the source and print the final test case When passed a SPIR-V module, only the post-processed disassembly is printed. """ # When one of these regular expressions matches on a disassembly line # CHECK-DAG will be used instead of CHECK CHECK_DAG_INSTRUCTION_REGEXES = ( r'OpType[a-zA-Z]+', r'OpConstant[a-zA-Z]*', r'OpSpecConstant[a-zA-Z]*', r'OpCapability', r'OpUndef', r'OpVariable', ) CHECK_DAG = '// CHECK-DAG:' CHECK = '// CHECK:' DROP_REGEXES = { 'boilerplate': ( r'^;', r'OpCapability', r'OpExtension', r'OpMemoryModel', r'OpEntryPoint', r'OpExecutionMode', r'OpSource', r'OpDecorate', r'OpMemberDecorate', ), 'functions': ( r'OpTypeFunction', r'OpFunction', r'OpLabel', r'OpReturn', r'OpFunctionEnd', ), 'memory': ( r'OpTypeRuntimeArray', r'OpTypePointer', r'OpVariable', r'OpAccessChain', r'OpLoad', r'OpStore', ), } # Keep track of the FileCheck variables we're defining variables = set() def substitute_backreference(regex, value): return regex.replace(r'\1', value) def replace_ids_with_filecheck_variables(line): # regex to match IDs, (variable name pattern, variable definition pattern) regexp_repl = collections.OrderedDict(( (r'%([0-9]+)', (r'__original_id_\1', r'%[[\1:[0-9]+]]')), (r'%([0-9a-zA-Z_]+)', (r'\1', r'%[[\1:[0-9a-zA-Z_]+]]')), )) def repl(m): namerex, defrex = regexp_repl[m.re.pattern] var_match = m.group(1) # Get the final FileCheck variable name var = substitute_backreference(namerex, var_match) # Do we know that variable? if var in variables: # Just use it return '%[[{}]]'.format(var) else: # Add it to the list of known variables and define it in the output variables.add(var) return substitute_backreference(defrex, var) for rr in regexp_repl.items(): line = re.sub(rr[0], repl, line) return line def process_disasm_line(args, line): def format_line(check, line): return '{:{}} {}'.format(check, len(CHECK_DAG), line.strip()) # Drop the line? for drop_group in args.drop: for rex in DROP_REGEXES[drop_group]: if re.search(rex, line): return '' # First deal with IDs line = replace_ids_with_filecheck_variables(line) # Can we use CHECK-DAG? for rex in CHECK_DAG_INSTRUCTION_REGEXES: if re.search(rex, line): return format_line(CHECK_DAG, line) # Nope, use CHECK return format_line(CHECK, line) def generate_run_section(args): clspv_options = ' '.join(args.clspv_options) runsec = '' runsec += '// RUN: clspv {} %s -o %t.spv\n'.format(clspv_options) runsec += '// RUN: spirv-dis -o %t2.spvasm %t.spv\n' runsec += '// RUN: FileCheck %s < %t2.spvasm\n' runsec += '// RUN: spirv-val --target-env vulkan1.0 %t.spv\n' runsec += '\n' return runsec def disassemble_and_post_process(args, spirv_module): ret = '' # Get SPIR-V disassembly for the module cmd = [ 'spirv-dis', spirv_module ] disasm = subprocess.check_output(cmd).decode('utf-8') # Process the disassembly for line in disasm.split('\n'): if line.strip() == '': continue processed_line = process_disasm_line(args, line) if processed_line: ret += '{}\n'.format(processed_line) return ret def generate_test_case_from_source(args): tc = '' # Start with the RUN directives tc += generate_run_section(args) # Then compile the source fd, spirvfile = tempfile.mkstemp() os.close(fd) cmd = [ args.clspv, ] + args.clspv_options + [ '-o', spirvfile, args.spirv_module_or_cl_source ] subprocess.check_call(cmd) # Append the processed disassembly tc += disassemble_and_post_process(args, spirvfile) # Append the original source tc += '\n' with open(args.spirv_module_or_cl_source) as f: tc += f.read() # Finally, delete the temporary SPIR-V module os.remove(spirvfile) return tc def generate_test_case(args): # Determine whether we got source or SPIR-V _, inputext = os.path.splitext(args.spirv_module_or_cl_source) # Now choose the behaviour if inputext == '.cl': tc = generate_test_case_from_source(args) else: tc = disassemble_and_post_process(args.spirv_module_or_cl_source) return tc if __name__ == '__main__': # Parse command line arguments class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter): pass parser = argparse.ArgumentParser( description=DESCRIPTION, formatter_class=HelpFormatter ) parser.add_argument( '--clspv', default='clspv', help='clspv binary to use' ) parser.add_argument( '--clspv-options', action='append', default=[], help='Pass an option to clspv when building (can be used multiple times)' ) parser.add_argument( '--drop', action='append', default=[], choices=DROP_REGEXES.keys(), help='Remove specific groups of instructions from generated SPIR-V disassembly' ) parser.add_argument( 'spirv_module_or_cl_source', help='SPIR-V module or OpenCL C source file' ) args = parser.parse_args() # Generate test case and print to stdout print(generate_test_case(args))