]>
Commit | Line | Data |
---|---|---|
09cae750 PD |
1 | #!/usr/bin/env python |
2 | ||
3 | # RISC-V multilib list generator. | |
83ffe9cd | 4 | # Copyright (C) 2011-2023 Free Software Foundation, Inc. |
09cae750 PD |
5 | # Contributed by Andrew Waterman (andrew@sifive.com). |
6 | # | |
7 | # This file is part of GCC. | |
8 | # | |
9 | # GCC is free software; you can redistribute it and/or modify | |
10 | # it under the terms of the GNU General Public License as published by | |
11 | # the Free Software Foundation; either version 3, or (at your option) | |
12 | # any later version. | |
13 | # | |
14 | # GCC is distributed in the hope that it will be useful, | |
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | # GNU General Public License for more details. | |
18 | # | |
19 | # You should have received a copy of the GNU General Public License | |
20 | # along with GCC; see the file COPYING3. If not see | |
21 | # <http://www.gnu.org/licenses/>. | |
22 | ||
23 | # Each argument to this script is of the form | |
24 | # <primary arch>-<abi>-<additional arches>-<extensions> | |
df7f0a3a | 25 | # Example 1: |
09cae750 PD |
26 | # rv32imafd-ilp32d-rv32g-c,v |
27 | # means that, in addition to rv32imafd, these configurations can also use the | |
28 | # rv32imafd-ilp32d libraries: rv32imafdc, rv32imafdv, rv32g, rv32gc, rv32gv | |
df7f0a3a KC |
29 | # |
30 | # Example 2: | |
31 | # rv32imafd-ilp32d--c*b | |
32 | # means that, in addition to rv32imafd, these configurations can also use the | |
33 | # rv32imafd-ilp32d libraries: rv32imafdc-ilp32d, rv32imafdb-ilp32d, | |
34 | # rv32imafdcb-ilp32d | |
09cae750 PD |
35 | |
36 | from __future__ import print_function | |
37 | import sys | |
b20cd0c7 | 38 | import os |
09cae750 | 39 | import collections |
df7f0a3a KC |
40 | import itertools |
41 | from functools import reduce | |
b20cd0c7 | 42 | import subprocess |
fdd40498 | 43 | import argparse |
df7f0a3a KC |
44 | |
45 | # | |
46 | # TODO: Add test for this script. | |
47 | # | |
09cae750 | 48 | |
4132f6ba | 49 | SUPPORTED_ISA_SPEC = ["2.2", "20190608", "20191213"] |
09cae750 PD |
50 | arches = collections.OrderedDict() |
51 | abis = collections.OrderedDict() | |
52 | required = [] | |
53 | reuse = [] | |
54 | ||
4132f6ba | 55 | def arch_canonicalize(arch, isa_spec): |
b20cd0c7 KC |
56 | this_file = os.path.abspath(os.path.join( __file__)) |
57 | arch_can_script = \ | |
58 | os.path.join(os.path.dirname(this_file), "arch-canonicalize") | |
4132f6ba KC |
59 | proc = subprocess.Popen([sys.executable, arch_can_script, |
60 | '-misa-spec=%s' % isa_spec, arch], | |
8d63e3c2 | 61 | stdout=subprocess.PIPE) |
b20cd0c7 | 62 | out, err = proc.communicate() |
168be2b3 | 63 | return out.decode().strip() |
df7f0a3a KC |
64 | |
65 | # | |
66 | # Handle expansion operation. | |
67 | # | |
68 | # e.g. "a*b" -> [("a",), ("b",), ("a", "b")] | |
69 | # "a" -> [("a",)] | |
70 | # | |
71 | def _expand_combination(ext): | |
72 | exts = list(ext.split("*")) | |
73 | ||
df7f0a3a KC |
74 | # Add underline to every extension. |
75 | # e.g. | |
76 | # _b * zvamo => _b * _zvamo | |
77 | exts = list(map(lambda x: '_' + x, exts)) | |
78 | ||
9ee33d7c GQ |
79 | # No need to expand if there is no `*`. |
80 | if len(exts) == 1: | |
81 | return [(exts[0],)] | |
82 | ||
df7f0a3a KC |
83 | # Generate combination! |
84 | ext_combs = [] | |
85 | for comb_len in range(1, len(exts)+1): | |
86 | for ext_comb in itertools.combinations(exts, comb_len): | |
87 | ext_combs.append(ext_comb) | |
88 | ||
89 | return ext_combs | |
90 | ||
91 | # | |
92 | # Input a list and drop duplicated entry. | |
93 | # e.g. | |
94 | # ["a", "b", "ab", "a"] -> ["a", "b", "ab"] | |
95 | # | |
96 | def unique(x): | |
97 | # | |
98 | # Drop duplicated entry. | |
99 | # Convert list to set and then convert back to list. | |
100 | # | |
101 | # Add sorted to prevent non-deterministic results in different env. | |
102 | # | |
103 | return list(sorted(list(set(x)))) | |
104 | ||
105 | # | |
106 | # Expand EXT string if there is any expansion operator (*). | |
107 | # e.g. | |
108 | # "a*b,c" -> ["a", "b", "ab", "c"] | |
109 | # | |
110 | def expand_combination(ext): | |
111 | ext = list(filter(None, ext.split(','))) | |
112 | ||
113 | # Expand combination for EXT, got lots of list. | |
114 | # e.g. | |
115 | # a * b => [[("a",), ("b",)], [("a", "b")]] | |
116 | ext_combs = list(map(_expand_combination, ext)) | |
117 | ||
118 | # Then fold to single list. | |
119 | # e.g. | |
120 | # [[("a",), ("b",)], [("a", "b")]] => [("a",), ("b",), ("a", "b")] | |
121 | ext = list(reduce(lambda x, y: x + y, ext_combs, [])) | |
122 | ||
123 | # Fold the tuple to string. | |
124 | # e.g. | |
125 | # [("a",), ("b",), ("a", "b")] => ["a", "b", "ab"] | |
126 | ext = map(lambda e : reduce(lambda x, y: x + y, e), ext) | |
127 | ||
128 | # Drop duplicated entry. | |
129 | ext = unique(ext) | |
130 | ||
131 | return ext | |
132 | ||
fdd40498 KC |
133 | multilib_cfgs = filter(lambda x:not x.startswith("--"), sys.argv[1:]) |
134 | options = filter(lambda x:x.startswith("--"), sys.argv[1:]) | |
135 | ||
136 | parser = argparse.ArgumentParser() | |
137 | parser.add_argument("--cmodel", type=str) | |
4132f6ba KC |
138 | parser.add_argument('-misa-spec', type=str, |
139 | default='20191213', | |
140 | choices=SUPPORTED_ISA_SPEC) | |
fdd40498 KC |
141 | parser.add_argument("cfgs", type=str, nargs='*') |
142 | args = parser.parse_args() | |
143 | ||
144 | if args.cmodel: | |
145 | cmodels = [None] + args.cmodel.split(",") | |
146 | else: | |
147 | cmodels = [None] | |
148 | ||
149 | cmodel_options = '/'.join(['mcmodel=%s' % x for x in cmodels[1:]]) | |
150 | cmodel_dirnames = ' \\\n'.join(cmodels[1:]) | |
151 | ||
152 | for cmodel in cmodels: | |
153 | for cfg in args.cfgs: | |
154 | try: | |
155 | (arch, abi, extra, ext) = cfg.split('-') | |
156 | except: | |
157 | print ("Invalid configure string %s, <arch>-<abi>-<extra>-<extensions>\n" | |
158 | "<extra> and <extensions> can be empty, " | |
159 | "e.g. rv32imafd-ilp32--" % cfg) | |
160 | sys.exit(1) | |
161 | ||
162 | # Compact code model only support rv64. | |
163 | if cmodel == "compact" and arch.startswith("rv32"): | |
164 | continue | |
df7f0a3a | 165 | |
4132f6ba | 166 | arch = arch_canonicalize (arch, args.misa_spec) |
fdd40498 KC |
167 | arches[arch] = 1 |
168 | abis[abi] = 1 | |
169 | extra = list(filter(None, extra.split(','))) | |
170 | ext_combs = expand_combination(ext) | |
171 | alts = sum([[x] + [x + y for y in ext_combs] for x in [arch] + extra], []) | |
4132f6ba KC |
172 | alts = filter(lambda x: len(x) != 0, alts) |
173 | alts = list(map(lambda a : arch_canonicalize(a, args.misa_spec), alts)) | |
df7f0a3a | 174 | |
fdd40498 KC |
175 | # Drop duplicated entry. |
176 | alts = unique(alts) | |
177 | ||
37dd1f14 | 178 | for alt in alts: |
fdd40498 KC |
179 | if alt == arch: |
180 | continue | |
181 | arches[alt] = 1 | |
182 | reuse.append('march.%s/mabi.%s=march.%s/mabi.%s' % (arch, abi, alt, abi)) | |
183 | ||
184 | if cmodel: | |
185 | required.append('march=%s/mabi=%s/mcmodel=%s' % (arch, abi, cmodel)) | |
186 | else: | |
187 | required.append('march=%s/mabi=%s' % (arch, abi)) | |
09cae750 | 188 | |
fdd40498 KC |
189 | arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) |
190 | arch_dirnames = ' \\\n'.join(arches.keys()) | |
09cae750 | 191 | |
fdd40498 KC |
192 | abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) |
193 | abi_dirnames = ' \\\n'.join(abis.keys()) | |
09cae750 PD |
194 | |
195 | prog = sys.argv[0].split('/')[-1] | |
196 | print('# This file was generated by %s with the command:' % prog) | |
197 | print('# %s' % ' '.join(sys.argv)) | |
198 | ||
fdd40498 KC |
199 | print('MULTILIB_OPTIONS = %s %s %s' % (arch_options, abi_options, cmodel_options)) |
200 | print('MULTILIB_DIRNAMES = %s %s %s' % (arch_dirnames, abi_dirnames, cmodel_dirnames)) | |
09cae750 PD |
201 | print('MULTILIB_REQUIRED = %s' % ' \\\n'.join(required)) |
202 | print('MULTILIB_REUSE = %s' % ' \\\n'.join(reuse)) |