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