Dosyalar
rocm-systems/script/gen_ostream_ops.py
T

246 satır
11 KiB
Python
Ham Normal Görünüm Geçmiş

#!/usr/bin/python3
2019-10-10 10:00:27 -04:00
import os, sys, re
import CppHeaderParser
import argparse
2020-08-28 06:31:24 -05:00
import string
2019-10-10 10:00:27 -04:00
LICENSE = \
'/*\n' + \
'Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.\n' + \
'\n' + \
'Permission is hereby granted, free of charge, to any person obtaining a copy\n' + \
'of this software and associated documentation files (the "Software"), to deal\n' + \
'in the Software without restriction, including without limitation the rights\n' + \
'to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n' + \
'copies of the Software, and to permit persons to whom the Software is\n' + \
'furnished to do so, subject to the following conditions:\n' + \
'\n' + \
'The above copyright notice and this permission notice shall be included in\n' + \
'all copies or substantial portions of the Software.\n' + \
'\n' + \
'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n' + \
'IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n' + \
'FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n' + \
'AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n' + \
'LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n' + \
'OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n' + \
'THE SOFTWARE.\n' + \
'*/\n'
2020-06-26 16:32:49 -04:00
header = 'template <typename T>\n' + \
2019-10-10 10:00:27 -04:00
'struct output_streamer {\n' + \
' inline static std::ostream& put(std::ostream& out, const T& v) { return out; }\n' + \
2020-06-26 16:32:49 -04:00
'};\n\n'
2019-10-10 10:00:27 -04:00
2020-08-28 06:31:24 -05:00
header_basic = \
2020-04-21 10:53:00 -04:00
'template <typename T>\n' + \
2020-06-19 12:54:00 -05:00
' inline static std::ostream& operator<<(std::ostream& out, const T& v) {\n' + \
' using std::operator<<;\n' + \
' static bool recursion = false;\n' + \
' if (recursion == false) { recursion = true; out << v; recursion = false; }\n' + \
2020-06-26 16:32:49 -04:00
' return out; }\n'
2019-10-10 10:00:27 -04:00
2020-04-21 10:53:00 -04:00
structs_analyzed = {}
global_ops_hip = ''
2020-08-28 06:31:24 -05:00
global_str = ''
2020-04-21 10:53:00 -04:00
# process_struct traverses recursively all structs to extract all fields
def process_struct(file_handle, cppHeader_struct, cppHeader, parent_hier_name, apiname):
# file_handle: handle for output file {api_name}_ostream_ops.h to be generated
2020-06-26 16:32:49 -04:00
# cppHeader_struct: cppHeader struct being processed
# cppHeader: cppHeader object created by CppHeaderParser.CppHeader(...)
2020-04-21 10:53:00 -04:00
# parent_hier_name: parent hierarchical name used for nested structs/enums
# apiname: for example hip, kfd.
2020-08-28 06:31:24 -05:00
global global_str
2020-04-21 10:53:00 -04:00
if cppHeader_struct == 'max_align_t': #function pointers not working in cppheaderparser
return
if cppHeader_struct not in cppHeader.classes:
2019-11-07 16:06:21 -05:00
return
2020-04-21 10:53:00 -04:00
if cppHeader_struct in structs_analyzed:
2019-11-07 16:06:21 -05:00
return
2019-10-10 10:00:27 -04:00
2020-08-28 06:31:24 -05:00
structs_analyzed[cppHeader_struct] = 1
2020-04-21 10:53:00 -04:00
for l in reversed(range(len(cppHeader.classes[cppHeader_struct]["properties"]["public"]))):
2019-11-12 09:55:46 -05:00
key = 'name'
name = ""
2020-04-21 10:53:00 -04:00
if key in cppHeader.classes[cppHeader_struct]["properties"]["public"][l]:
if parent_hier_name != '':
name = parent_hier_name + '.' + cppHeader.classes[cppHeader_struct]["properties"]["public"][l][key]
else:
name = cppHeader.classes[cppHeader_struct]["properties"]["public"][l][key]
if name == '':
continue
2019-11-12 09:55:46 -05:00
key2 = 'type'
mtype = ""
2020-04-21 10:53:00 -04:00
if key2 in cppHeader.classes[cppHeader_struct]["properties"]["public"][l]:
mtype = cppHeader.classes[cppHeader_struct]["properties"]["public"][l][key2]
if mtype == '':
continue
2019-11-12 09:55:46 -05:00
key3 = 'array_size'
array_size = ""
2020-04-21 10:53:00 -04:00
if key3 in cppHeader.classes[cppHeader_struct]["properties"]["public"][l]:
array_size = cppHeader.classes[cppHeader_struct]["properties"]["public"][l][key3]
2019-11-12 09:55:46 -05:00
key4 = 'property_of_class'
prop = ""
2020-04-21 10:53:00 -04:00
if key4 in cppHeader.classes[cppHeader_struct]["properties"]["public"][l]:
prop = cppHeader.classes[cppHeader_struct]["properties"]["public"][l][key4]
2019-10-10 10:00:27 -04:00
2020-08-28 06:31:24 -05:00
str = ''
2020-04-21 10:53:00 -04:00
if "union" not in mtype:
2020-06-26 16:32:49 -04:00
if apiname.lower() == 'hip' or apiname.lower() == 'hsa':
2020-08-28 06:31:24 -05:00
str += " roctracer::" + apiname.lower() + "_support::operator<<(out, \"" + name + " = \");\n"
str += " roctracer::" + apiname.lower() + "_support::operator<<(out, v."+name+");\n"
str += " roctracer::" + apiname.lower() + "_support::operator<<(out, \", \");\n"
2019-11-07 16:06:21 -05:00
else:
2020-08-28 06:31:24 -05:00
str += " roctracer::" + apiname.lower() + "_support::output_streamer<const char*>::put(out, \"" + name + " = \");\n"
2020-04-21 10:53:00 -04:00
if array_size == "":
2020-08-28 06:31:24 -05:00
str += " roctracer::" + apiname.lower() + "_support::output_streamer<" + mtype + ">::put(out, v." + name + ");\n"
2020-04-21 10:53:00 -04:00
else:
2020-08-28 06:31:24 -05:00
str += " roctracer::" + apiname.lower() + "_support::output_streamer<" + mtype + "[" + array_size + "]>::put(out, v." + name + ");\n"
str += " roctracer::" + apiname.lower() + "_support::output_streamer<const char*>::put(out, \", \");\n"
2019-11-07 16:06:21 -05:00
if "void" not in mtype:
2020-08-28 06:31:24 -05:00
global_str += str
2019-11-07 16:06:21 -05:00
else:
2020-04-21 10:53:00 -04:00
if prop != '':
next_cppHeader_struct = prop + "::"
process_struct(file_handle, next_cppHeader_struct, cppHeader, name, apiname)
next_cppHeader_struct = prop + "::" + mtype + " "
process_struct(file_handle, next_cppHeader_struct, cppHeader, name, apiname)
next_cppHeader_struct = cppHeader_struct + "::"
process_struct(file_handle, next_cppHeader_struct, cppHeader, name, apiname)
2019-11-07 16:06:21 -05:00
2020-06-26 16:32:49 -04:00
# Parses API header file and generates ostream ops files ostream_ops.h
2020-08-28 06:31:24 -05:00
def gen_cppheader(infilepath, outfilepath, structs_depth):
2020-04-21 10:53:00 -04:00
# infilepath: API Header file to be parsed
# outfilepath: Output file where ostream operators are written
global_ops_hip = ''
2020-06-26 16:32:49 -04:00
global_ops_hsa = ''
2020-08-28 06:31:24 -05:00
global global_str
2019-11-07 16:06:21 -05:00
try:
cppHeader = CppHeaderParser.CppHeader(infilepath)
except CppHeaderParser.CppParseError as e:
print(e)
sys.exit(1)
2019-12-27 12:14:27 -05:00
mpath = os.path.dirname(outfilepath)
if mpath == "":
mpath = os.getcwd()
apiname = outfilepath.replace(mpath+"/","")
apiname = apiname.replace("_ostream_ops.h","")
apiname = apiname.upper()
2019-11-12 09:55:46 -05:00
f = open(outfilepath,"w+")
2019-10-10 10:00:27 -04:00
f.write("// automatically generated\n")
2019-12-27 12:14:27 -05:00
f.write(LICENSE + '\n')
2020-04-21 10:53:00 -04:00
header_s = \
2019-12-27 12:14:27 -05:00
'#ifndef INC_' + apiname + '_OSTREAM_OPS_H_\n' + \
'#define INC_' + apiname + '_OSTREAM_OPS_H_\n' + \
2020-04-21 10:53:00 -04:00
'#ifdef __cplusplus\n' + \
2019-10-30 17:01:39 -04:00
'#include <iostream>\n' + \
'\n' + \
2019-12-27 12:14:27 -05:00
'#include "roctracer.h"\n'
2020-04-21 10:53:00 -04:00
if apiname.lower() == 'hip':
header_s = header_s + '\n' + \
'#include "hip/hip_runtime_api.h"\n' + \
'#include "hip/hcc_detail/hip_vector_types.h"\n\n'
2020-06-26 16:32:49 -04:00
2020-04-21 10:53:00 -04:00
f.write(header_s)
2019-10-30 17:01:39 -04:00
f.write('\n')
2019-11-07 16:06:21 -05:00
f.write('namespace roctracer {\n')
2019-12-27 12:14:27 -05:00
f.write('namespace ' + apiname.lower() + '_support {\n')
2020-08-28 06:31:24 -05:00
if structs_depth != -1:
f.write('static int ' + apiname.upper() + '_depth_max = ' + str(structs_depth) + ';\n')
2019-12-27 12:14:27 -05:00
f.write('// begin ostream ops for '+ apiname + ' \n')
2020-06-26 16:32:49 -04:00
if apiname.lower() == "hip" or apiname.lower() == "hsa":
f.write("// basic ostream ops\n")
2020-08-28 06:31:24 -05:00
f.write(header_basic)
2020-06-26 16:32:49 -04:00
f.write("// End of basic ostream ops\n\n")
else:
f.write(header)
2019-11-07 16:06:21 -05:00
for c in cppHeader.classes:
if "union" in c:
continue
2020-06-26 16:32:49 -04:00
if apiname.lower() == 'hsa':
if c == 'max_align_t' or c == '__fsid_t': #already defined for hip
continue
2019-12-27 12:14:27 -05:00
if len(cppHeader.classes[c]["properties"]["public"])!=0:
2020-06-26 16:32:49 -04:00
if apiname.lower() == 'hip' or apiname.lower() == 'hsa':
f.write("inline static std::ostream& operator<<(std::ostream& out, const " + c + "& v)\n")
2020-04-21 10:53:00 -04:00
f.write("{\n")
2020-08-28 06:31:24 -05:00
f.write(" roctracer::" + apiname.lower() + "_support::operator<<(out, '{');\n")
if structs_depth != -1:
f.write(" " + apiname.upper() + "_depth_max++;\n")
f.write(" if (" + apiname.upper() + "_depth_max <= " + str(structs_depth) + ") {\n" )
2020-04-21 10:53:00 -04:00
process_struct(f, c, cppHeader, "", apiname)
2020-08-28 06:31:24 -05:00
global_str = "\n".join(global_str.split("\n")[0:-2])
if structs_depth != -1: #reindent
global_str = global_str.split('\n')
global_str = [' ' + line.lstrip() for line in global_str]
global_str = "\n".join(global_str)
2020-08-28 06:31:24 -05:00
f.write(global_str+"\n")
if structs_depth != -1:
f.write(" };\n")
f.write(" " + apiname.upper() + "_depth_max--;\n")
f.write(" roctracer::" + apiname.lower() + "_support::operator<<(out, '}');\n")
f.write(" return out;\n")
2020-04-21 10:53:00 -04:00
f.write("}\n")
2020-08-28 06:31:24 -05:00
global_str = ''
2020-04-21 10:53:00 -04:00
else:
2019-12-27 12:14:27 -05:00
f.write("\ntemplate<>\n")
2020-04-21 10:53:00 -04:00
f.write("struct output_streamer<" + c + "&> {\n")
2019-12-27 12:14:27 -05:00
f.write(" inline static std::ostream& put(std::ostream& out, "+c+"& v)\n")
f.write("{\n")
2020-08-28 06:31:24 -05:00
f.write(" roctracer::" + apiname.lower() + "_support::output_streamer<char>::put(out, '{');\n")
if structs_depth != -1:
f.write(apiname.upper() + "_depth_max++;\n")
f.write(" if (" + apiname.upper() + "_depth_max <= " + str(structs_depth) + ") {\n" )
2020-04-21 10:53:00 -04:00
process_struct(f, c, cppHeader, "", apiname)
2020-08-28 06:31:24 -05:00
global_str = "\n".join(global_str.split("\n")[0:-2])
if structs_depth != -1: #reindent
global_str = global_str.split('\n')
global_str = [' ' + line.lstrip() for line in global_str]
global_str = "\n".join(global_str)
2020-08-28 06:31:24 -05:00
f.write(global_str+"\n")
if structs_depth != -1:
f.write(" };\n")
f.write(" " + apiname.upper() + "_depth_max--;\n")
f.write(" roctracer::" + apiname.lower() + "_support::output_streamer<char>::put(out, '}');\n")
f.write(" return out;\n")
2019-12-27 12:14:27 -05:00
f.write("}\n")
f.write("};\n")
2020-08-28 06:31:24 -05:00
global_str = ''
2020-06-26 16:32:49 -04:00
if apiname.lower() == 'hip':
2020-08-28 06:31:24 -05:00
global_ops_hip += "inline static std::ostream& operator<<(std::ostream& out, const " + c + "& v)\n" + "{\n" + " roctracer::hip_support::operator<<(out, v);\n" + " return out;\n" + "}\n\n"
2020-06-26 16:32:49 -04:00
if apiname.lower() == 'hsa':
2020-08-28 06:31:24 -05:00
global_ops_hsa += "inline static std::ostream& operator<<(std::ostream& out, const " + c + "& v)\n" + "{\n" + " roctracer::hsa_support::operator<<(out, v);\n" + " return out;\n" + "}\n\n"
2019-11-07 16:06:21 -05:00
2020-04-21 10:53:00 -04:00
footer = \
2019-12-27 12:14:27 -05:00
'// end ostream ops for '+ apiname + ' \n'
2020-04-21 10:53:00 -04:00
footer += '};};\n\n'
f.write(footer)
f.write(global_ops_hip)
2020-06-26 16:32:49 -04:00
f.write(global_ops_hsa)
2020-04-21 10:53:00 -04:00
footer = '#endif //__cplusplus\n' + \
'#endif // INC_' + apiname + '_OSTREAM_OPS_H_\n' + \
' \n'
f.write(footer)
2019-10-10 10:00:27 -04:00
f.close()
2019-12-27 12:14:27 -05:00
print('File ' + outfilepath + ' generated')
2019-10-10 10:00:27 -04:00
return
parser = argparse.ArgumentParser(description='genOstreamOps.py: generates ostream operators for all typedefs in provided input file.')
2019-11-12 09:55:46 -05:00
requiredNamed = parser.add_argument_group('Required arguments')
2020-01-22 14:06:58 -05:00
requiredNamed.add_argument('-in', metavar='file', help='Header file to be parsed', required=True)
requiredNamed.add_argument('-out', metavar='file', help='Output file with ostream operators', required=True)
2020-08-28 06:31:24 -05:00
requiredNamed.add_argument('-depth', metavar='N', type=int, help='Depth for nested structs', required=False)
2019-10-30 17:01:39 -04:00
2020-08-28 06:31:24 -05:00
structs_depth = 0
2019-10-10 10:00:27 -04:00
args = vars(parser.parse_args())
if __name__ == '__main__':
2020-08-28 06:31:24 -05:00
if args['depth'] != None: structs_depth = args['depth']
gen_cppheader(args['in'], args['out'], structs_depth)