xref: /aosp_15_r20/external/XNNPACK/tools/amalgamate-microkernels.py (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1#!/usr/bin/env python
2# Copyright 2019 Google LLC
3#
4# This source code is licensed under the BSD-style license found in the
5# LICENSE file in the root directory of this source tree.
6
7import argparse
8import codecs
9import math
10import os
11import re
12import sys
13import yaml
14
15
16ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
17
18
19parser = argparse.ArgumentParser(
20  description='Amalgamation utility for microkernels')
21parser.add_argument("-s", "--set", metavar="SET", required=True,
22                    help="List of microkernel filenames in the BUILD file")
23parser.add_argument("-o", "--output", metavar="FILE", required=True,
24                    help='Output (C source) file')
25
26
27def main(args):
28  options = parser.parse_args(args)
29
30  build_path = os.path.join(ROOT_DIR, "..", "BUILD")
31
32  with codecs.open(build_path, "r", encoding="utf-8") as build_file:
33    build_text = build_file.read()
34
35  pattern = r"\b" + options.set + r"\b\s*=\s*\["
36  match = re.search(pattern, build_text)
37  if not match:
38    raise ValueError(
39      "Failed to find file set %s (regex \"%s\") inside the BUILD file" %
40        (options.set, pattern))
41
42  start_pos = match.end()
43  end_pos = build_text.find("]", start_pos)
44
45  fileset = [filename.strip()[1:-1] for filename in
46             build_text[start_pos:end_pos].split(",")]
47
48  amalgam_lines = list()
49  amalgam_includes = set()
50  for filename in sorted(fileset):
51    if not filename:
52      continue
53
54    filepath = os.path.join(ROOT_DIR, "..", filename)
55    with codecs.open(filepath, "r", encoding="utf-8") as file:
56      filelines = file.read().splitlines()
57
58    consumed_license = False
59    consumed_includes = False
60    for line in filelines:
61      if line.startswith("//"):
62        if not consumed_license:
63          # Skip and generate a standard license header for amalgamated file
64          continue
65      elif line.lstrip().startswith("#"):
66        if not consumed_includes:
67          amalgam_includes.add(line)
68          continue
69        consumed_license = True
70      elif not line:
71        if not consumed_includes:
72          # Skip empty lines until end of headers
73          continue
74      else:
75        consumed_license = True
76        consumed_includes = True
77
78      amalgam_lines.append(line)
79
80    amalgam_lines.append("")
81
82  amalgam_includes.discard("#include <emmintrin.h>")
83  amalgam_includes.discard("#include <immintrin.h>")
84  amalgam_includes.discard("#include <nmmintrin.h>")
85  amalgam_includes.discard("#include <smmintrin.h>")
86  amalgam_includes.discard("#include <tmmintrin.h>")
87  amalgam_includes.discard("#include <xmmintrin.h>")
88
89  amalgam_text = """\
90// Copyright 2021 Google LLC
91//
92// This source code is licensed under the BSD-style license found in the
93// LICENSE file in the root directory of this source tree.
94
95"""
96
97  amalgam_text += "\n".join(sorted(inc for inc in amalgam_includes if
98                                   not inc.startswith("#include <xnnpack/")))
99  amalgam_text += "\n\n#include <immintrin.h>\n\n"
100  amalgam_text += "\n".join(sorted(inc for inc in amalgam_includes if
101                                   inc.startswith("#include <xnnpack/")))
102  amalgam_text += "\n\n\n"
103  amalgam_text += "\n".join(amalgam_lines)
104
105
106
107  txt_changed = True
108  if os.path.exists(options.output):
109    with open(options.output, "r", encoding="utf-8") as amalgam_file:
110      txt_changed = amalgam_file.read() != amalgam_text
111
112  if txt_changed:
113    with open(options.output, "w", encoding="utf-8") as amalgam_file:
114      amalgam_file.write(amalgam_text)
115
116
117if __name__ == "__main__":
118  main(sys.argv[1:])
119