1*c217d954SCole Faust#!/usr/bin/python 2*c217d954SCole Faust# -*- coding: utf-8 -*- 3*c217d954SCole Faust 4*c217d954SCole Faust# Copyright (c) 2023 Arm Limited. 5*c217d954SCole Faust# 6*c217d954SCole Faust# SPDX-License-Identifier: MIT 7*c217d954SCole Faust# 8*c217d954SCole Faust# Permission is hereby granted, free of charge, to any person obtaining a copy 9*c217d954SCole Faust# of this software and associated documentation files (the "Software"), to 10*c217d954SCole Faust# deal in the Software without restriction, including without limitation the 11*c217d954SCole Faust# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 12*c217d954SCole Faust# sell copies of the Software, and to permit persons to whom the Software is 13*c217d954SCole Faust# furnished to do so, subject to the following conditions: 14*c217d954SCole Faust# 15*c217d954SCole Faust# The above copyright notice and this permission notice shall be included in all 16*c217d954SCole Faust# copies or substantial portions of the Software. 17*c217d954SCole Faust# 18*c217d954SCole Faust# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*c217d954SCole Faust# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*c217d954SCole Faust# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21*c217d954SCole Faust# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22*c217d954SCole Faust# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23*c217d954SCole Faust# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24*c217d954SCole Faust# SOFTWARE. 25*c217d954SCole Faust 26*c217d954SCole Faust"""Generates build files for either bazel or cmake experimental builds using filelist.json 27*c217d954SCole FaustUsage 28*c217d954SCole Faust python scripts/generate_build_files.py --bazel 29*c217d954SCole Faust python scripts/generate_build_files.py --cmake 30*c217d954SCole Faust 31*c217d954SCole FaustWrites generated file to the bazel BUILD file located under src/ if using --bazel flag. 32*c217d954SCole FaustWrites generated file to the CMake CMakeLists.txt file located under src/ if using --cmake flag. 33*c217d954SCole Faust""" 34*c217d954SCole Faust 35*c217d954SCole Faustimport argparse 36*c217d954SCole Faustimport json 37*c217d954SCole Faustimport glob 38*c217d954SCole Faust 39*c217d954SCole Faust 40*c217d954SCole Faustdef get_operator_backend_files(filelist, operators, backend='', techs=[], attrs=[]): 41*c217d954SCole Faust files = {"common": []} 42*c217d954SCole Faust 43*c217d954SCole Faust # Early return if filelist is empty 44*c217d954SCole Faust if backend not in filelist: 45*c217d954SCole Faust return files 46*c217d954SCole Faust 47*c217d954SCole Faust # Iterate over operators and create the file lists to compiler 48*c217d954SCole Faust for operator in operators: 49*c217d954SCole Faust if operator in filelist[backend]['operators']: 50*c217d954SCole Faust files['common'] += filelist[backend]['operators'][operator]["files"]["common"] 51*c217d954SCole Faust for tech in techs: 52*c217d954SCole Faust if tech in filelist[backend]['operators'][operator]["files"]: 53*c217d954SCole Faust # Add tech as a key to dictionary if not there 54*c217d954SCole Faust if tech not in files: 55*c217d954SCole Faust files[tech] = [] 56*c217d954SCole Faust 57*c217d954SCole Faust # Add tech files to the tech file list 58*c217d954SCole Faust tech_files = filelist[backend]['operators'][operator]["files"][tech] 59*c217d954SCole Faust files[tech] += tech_files.get('common', []) 60*c217d954SCole Faust for attr in attrs: 61*c217d954SCole Faust files[tech] += tech_files.get(attr, []) 62*c217d954SCole Faust 63*c217d954SCole Faust # Remove duplicates if they exist 64*c217d954SCole Faust return {k: list(set(v)) for k, v in files.items()} 65*c217d954SCole Faust 66*c217d954SCole Faust 67*c217d954SCole Faustdef collect_operators(filelist, operators, backend=''): 68*c217d954SCole Faust ops = set() 69*c217d954SCole Faust for operator in operators: 70*c217d954SCole Faust if operator in filelist[backend]['operators']: 71*c217d954SCole Faust ops.add(operator) 72*c217d954SCole Faust if 'deps' in filelist[backend]['operators'][operator]: 73*c217d954SCole Faust ops.update(filelist[backend]['operators'][operator]['deps']) 74*c217d954SCole Faust else: 75*c217d954SCole Faust print("Operator {0} is unsupported on {1} backend!".format( 76*c217d954SCole Faust operator, backend)) 77*c217d954SCole Faust 78*c217d954SCole Faust return ops 79*c217d954SCole Faust 80*c217d954SCole Faust 81*c217d954SCole Faustdef resolve_operator_dependencies(filelist, operators, backend=''): 82*c217d954SCole Faust resolved_operators = collect_operators(filelist, operators, backend) 83*c217d954SCole Faust 84*c217d954SCole Faust are_ops_resolved = False 85*c217d954SCole Faust while not are_ops_resolved: 86*c217d954SCole Faust resolution_pass = collect_operators( 87*c217d954SCole Faust filelist, resolved_operators, backend) 88*c217d954SCole Faust if len(resolution_pass) != len(resolved_operators): 89*c217d954SCole Faust resolved_operators.update(resolution_pass) 90*c217d954SCole Faust else: 91*c217d954SCole Faust are_ops_resolved = True 92*c217d954SCole Faust 93*c217d954SCole Faust return resolved_operators 94*c217d954SCole Faust 95*c217d954SCole Faustdef get_template_header(): 96*c217d954SCole Faust return """# Copyright (c) 2023 Arm Limited. 97*c217d954SCole Faust# 98*c217d954SCole Faust# SPDX-License-Identifier: MIT 99*c217d954SCole Faust# 100*c217d954SCole Faust# Permission is hereby granted, free of charge, to any person obtaining a copy 101*c217d954SCole Faust# of this software and associated documentation files (the "Software"), to 102*c217d954SCole Faust# deal in the Software without restriction, including without limitation the 103*c217d954SCole Faust# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 104*c217d954SCole Faust# sell copies of the Software, and to permit persons to whom the Software is 105*c217d954SCole Faust# furnished to do so, subject to the following conditions: 106*c217d954SCole Faust# 107*c217d954SCole Faust# The above copyright notice and this permission notice shall be included in all 108*c217d954SCole Faust# copies or substantial portions of the Software. 109*c217d954SCole Faust# 110*c217d954SCole Faust# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 111*c217d954SCole Faust# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 112*c217d954SCole Faust# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 113*c217d954SCole Faust# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 114*c217d954SCole Faust# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 115*c217d954SCole Faust# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 116*c217d954SCole Faust# SOFTWARE.""" 117*c217d954SCole Faust 118*c217d954SCole Faustdef build_from_template_bazel(srcs_graph, srcs_sve, srcs_sve2, srcs_core): 119*c217d954SCole Faust 120*c217d954SCole Faust line_separator = '",\n\t"' 121*c217d954SCole Faust 122*c217d954SCole Faust template = f"""{get_template_header()} 123*c217d954SCole Faust 124*c217d954SCole Faustfilegroup( 125*c217d954SCole Faust name = "arm_compute_graph_srcs", 126*c217d954SCole Faust srcs = ["{line_separator.join(srcs_graph)}"] + 127*c217d954SCole Faust glob(["**/*.h", 128*c217d954SCole Faust "**/*.hpp", 129*c217d954SCole Faust "**/*.inl"]), 130*c217d954SCole Faust visibility = ["//visibility:public"] 131*c217d954SCole Faust) 132*c217d954SCole Faust 133*c217d954SCole Faustfilegroup( 134*c217d954SCole Faust name = "arm_compute_sve2_srcs", 135*c217d954SCole Faust srcs = ["{line_separator.join(srcs_sve2)}"] + 136*c217d954SCole Faust glob(["**/*.h", 137*c217d954SCole Faust "**/*.hpp", 138*c217d954SCole Faust "**/*.inl"]), 139*c217d954SCole Faust visibility = ["//visibility:public"] 140*c217d954SCole Faust) 141*c217d954SCole Faust 142*c217d954SCole Faustfilegroup( 143*c217d954SCole Faust name = "arm_compute_sve_srcs", 144*c217d954SCole Faust srcs = ["{line_separator.join(srcs_sve)}"] + 145*c217d954SCole Faust glob(["**/*.h", 146*c217d954SCole Faust "**/*.hpp", 147*c217d954SCole Faust "**/*.inl"]), 148*c217d954SCole Faust visibility = ["//visibility:public"] 149*c217d954SCole Faust) 150*c217d954SCole Faust 151*c217d954SCole Faustfilegroup( 152*c217d954SCole Faust name = "arm_compute_srcs", 153*c217d954SCole Faust srcs = ["{line_separator.join(srcs_core)}"] + 154*c217d954SCole Faust glob(["**/*.h", 155*c217d954SCole Faust "**/*.hpp", 156*c217d954SCole Faust "**/*.inl"]), 157*c217d954SCole Faust visibility = ["//visibility:public"] 158*c217d954SCole Faust) 159*c217d954SCole Faust""" 160*c217d954SCole Faust 161*c217d954SCole Faust return template 162*c217d954SCole Faust 163*c217d954SCole Faust 164*c217d954SCole Faustdef build_from_template_cmake(srcs_graph, srcs_sve, srcs_sve2, srcs_core): 165*c217d954SCole Faust 166*c217d954SCole Faust line_separator = '\n\t' 167*c217d954SCole Faust 168*c217d954SCole Faust template = f"""{get_template_header()} 169*c217d954SCole Faust 170*c217d954SCole Fausttarget_sources( 171*c217d954SCole Faust arm_compute_graph 172*c217d954SCole Faust PRIVATE 173*c217d954SCole Faust {line_separator.join(srcs_graph)} 174*c217d954SCole Faust) 175*c217d954SCole Faust 176*c217d954SCole Fausttarget_sources( 177*c217d954SCole Faust arm_compute_sve 178*c217d954SCole Faust PRIVATE 179*c217d954SCole Faust {line_separator.join(srcs_sve)} 180*c217d954SCole Faust) 181*c217d954SCole Faust 182*c217d954SCole Fausttarget_sources( 183*c217d954SCole Faust arm_compute_sve2 184*c217d954SCole Faust PRIVATE 185*c217d954SCole Faust {line_separator.join(srcs_sve2)} 186*c217d954SCole Faust) 187*c217d954SCole Faust 188*c217d954SCole Fausttarget_sources( 189*c217d954SCole Faust arm_compute_core 190*c217d954SCole Faust PRIVATE 191*c217d954SCole Faust {line_separator.join(srcs_core)} 192*c217d954SCole Faust) 193*c217d954SCole Faust """ 194*c217d954SCole Faust return template 195*c217d954SCole Faust 196*c217d954SCole Faust 197*c217d954SCole Faustdef gather_sources(): 198*c217d954SCole Faust 199*c217d954SCole Faust # Source file list 200*c217d954SCole Faust with open("filelist.json") as fp: 201*c217d954SCole Faust filelist = json.load(fp) 202*c217d954SCole Faust 203*c217d954SCole Faust # Common backend files 204*c217d954SCole Faust lib_files = filelist['common'] 205*c217d954SCole Faust 206*c217d954SCole Faust # TODO Add Fixed format GEMM kernels ? 207*c217d954SCole Faust 208*c217d954SCole Faust # Logging files 209*c217d954SCole Faust lib_files += filelist['logging'] 210*c217d954SCole Faust 211*c217d954SCole Faust # C API files 212*c217d954SCole Faust lib_files += filelist['c_api']['common'] 213*c217d954SCole Faust lib_files += filelist['c_api']['operators'] 214*c217d954SCole Faust 215*c217d954SCole Faust # Scheduler infrastructure 216*c217d954SCole Faust lib_files += filelist['scheduler']['single'] 217*c217d954SCole Faust # Add both cppthreads and omp sources for now 218*c217d954SCole Faust lib_files += filelist['scheduler']['threads'] 219*c217d954SCole Faust lib_files += filelist['scheduler']['omp'] 220*c217d954SCole Faust 221*c217d954SCole Faust # Graph files 222*c217d954SCole Faust graph_files = glob.glob('src/graph/*.cpp') 223*c217d954SCole Faust graph_files += glob.glob('src/graph/*/*.cpp') 224*c217d954SCole Faust 225*c217d954SCole Faust lib_files_sve = [] 226*c217d954SCole Faust lib_files_sve2 = [] 227*c217d954SCole Faust 228*c217d954SCole Faust # ------------------------------------- 229*c217d954SCole Faust # NEON files 230*c217d954SCole Faust lib_files += filelist['cpu']['common'] 231*c217d954SCole Faust simd = ['neon', 'sve', 'sve2'] 232*c217d954SCole Faust 233*c217d954SCole Faust # Get attributes 234*c217d954SCole Faust data_types = ["qasymm8", "qasymm8_signed", "qsymm16", 235*c217d954SCole Faust "fp16", "fp32", "integer"] # Are all needed? 236*c217d954SCole Faust data_layouts = ["nhwc", "nchw"] # Are both needed? 237*c217d954SCole Faust experimental_fixed_format_kernels = ["experimental_fixed_format_kernels"] 238*c217d954SCole Faust attrs = data_types + data_layouts + \ 239*c217d954SCole Faust experimental_fixed_format_kernels + ["estate64"] 240*c217d954SCole Faust 241*c217d954SCole Faust # Setup data-type and data-layout files to include 242*c217d954SCole Faust cpu_operators = filelist['cpu']['operators'].keys() 243*c217d954SCole Faust cpu_ops_to_build = resolve_operator_dependencies( 244*c217d954SCole Faust filelist, cpu_operators, 'cpu') 245*c217d954SCole Faust cpu_files = get_operator_backend_files( 246*c217d954SCole Faust filelist, cpu_ops_to_build, 'cpu', simd, attrs) 247*c217d954SCole Faust 248*c217d954SCole Faust # Shared among ALL CPU files 249*c217d954SCole Faust lib_files += cpu_files.get('common', []) 250*c217d954SCole Faust 251*c217d954SCole Faust # Arm® Neon™ specific files 252*c217d954SCole Faust lib_files += cpu_files.get('neon', []) 253*c217d954SCole Faust 254*c217d954SCole Faust # SVE files only 255*c217d954SCole Faust lib_files_sve = cpu_files.get('sve', []) 256*c217d954SCole Faust 257*c217d954SCole Faust # SVE2 files only 258*c217d954SCole Faust lib_files_sve2 = cpu_files.get('sve2', []) 259*c217d954SCole Faust 260*c217d954SCole Faust graph_files += glob.glob('src/graph/backends/NEON/*.cpp') 261*c217d954SCole Faust 262*c217d954SCole Faust # ------------------------------------- 263*c217d954SCole Faust 264*c217d954SCole Faust graph_files = sorted([path.replace("src/", "") for path in graph_files]) 265*c217d954SCole Faust lib_files_sve = sorted([path.replace("src/", "") for path in lib_files_sve]) 266*c217d954SCole Faust lib_files_sve2 = sorted([path.replace("src/", "") for path in lib_files_sve2]) 267*c217d954SCole Faust lib_files = sorted([path.replace("src/", "") for path in lib_files]) 268*c217d954SCole Faust 269*c217d954SCole Faust return graph_files, lib_files_sve, lib_files_sve2, lib_files 270*c217d954SCole Faust 271*c217d954SCole Faust 272*c217d954SCole Faustif "__main__" in __name__: 273*c217d954SCole Faust 274*c217d954SCole Faust parser = argparse.ArgumentParser() 275*c217d954SCole Faust parser.add_argument("--bazel", action="store_true") 276*c217d954SCole Faust parser.add_argument("--cmake", action="store_true") 277*c217d954SCole Faust args = parser.parse_args() 278*c217d954SCole Faust 279*c217d954SCole Faust graph_files, lib_files_sve, lib_files_sve2, lib_files = gather_sources() 280*c217d954SCole Faust 281*c217d954SCole Faust if args.bazel: 282*c217d954SCole Faust bazel_build_string = build_from_template_bazel( 283*c217d954SCole Faust graph_files, lib_files_sve, lib_files_sve2, lib_files) 284*c217d954SCole Faust print(bazel_build_string) 285*c217d954SCole Faust with open("src/BUILD.bazel", "w") as fp: 286*c217d954SCole Faust fp.write(bazel_build_string) 287*c217d954SCole Faust 288*c217d954SCole Faust if args.cmake: 289*c217d954SCole Faust cmake_build_string = build_from_template_cmake( 290*c217d954SCole Faust graph_files, lib_files_sve, lib_files_sve2, lib_files) 291*c217d954SCole Faust print(cmake_build_string) 292*c217d954SCole Faust with open("src/CMakeLists.txt", "w") as fp: 293*c217d954SCole Faust fp.write(cmake_build_string) 294*c217d954SCole Faust 295*c217d954SCole Faust if not args.cmake and not args.bazel: 296*c217d954SCole Faust print("Supply either --bazel or --cmake flag to generate build files for corresponding build") 297