xref: /aosp_15_r20/external/ComputeLibrary/scripts/generate_build_files.py (revision c217d954acce2dbc11938adb493fc0abd69584f3)
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