| #!/usr/bin/env python |
| |
| # RISC-V multilib list generator. |
| # Copyright (C) 2011-2021 Free Software Foundation, Inc. |
| # Contributed by Andrew Waterman (andrew@sifive.com). |
| # |
| # This file is part of GCC. |
| # |
| # GCC is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 3, or (at your option) |
| # any later version. |
| # |
| # GCC is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with GCC; see the file COPYING3. If not see |
| # <http://www.gnu.org/licenses/>. |
| |
| # Each argument to this script is of the form |
| # <primary arch>-<abi>-<additional arches>-<extensions> |
| # Example 1: |
| # rv32imafd-ilp32d-rv32g-c,v |
| # means that, in addition to rv32imafd, these configurations can also use the |
| # rv32imafd-ilp32d libraries: rv32imafdc, rv32imafdv, rv32g, rv32gc, rv32gv |
| # |
| # Example 2: |
| # rv32imafd-ilp32d--c*b |
| # means that, in addition to rv32imafd, these configurations can also use the |
| # rv32imafd-ilp32d libraries: rv32imafdc-ilp32d, rv32imafdb-ilp32d, |
| # rv32imafdcb-ilp32d |
| |
| from __future__ import print_function |
| import sys |
| import os |
| import collections |
| import itertools |
| from functools import reduce |
| import subprocess |
| import argparse |
| |
| # |
| # TODO: Add test for this script. |
| # |
| |
| arches = collections.OrderedDict() |
| abis = collections.OrderedDict() |
| required = [] |
| reuse = [] |
| |
| def arch_canonicalize(arch): |
| this_file = os.path.abspath(os.path.join( __file__)) |
| arch_can_script = \ |
| os.path.join(os.path.dirname(this_file), "arch-canonicalize") |
| proc = subprocess.Popen([sys.executable, arch_can_script, arch], |
| stdout=subprocess.PIPE) |
| out, err = proc.communicate() |
| return out.decode().strip() |
| |
| # |
| # Handle expansion operation. |
| # |
| # e.g. "a*b" -> [("a",), ("b",), ("a", "b")] |
| # "a" -> [("a",)] |
| # |
| def _expand_combination(ext): |
| exts = list(ext.split("*")) |
| |
| # Add underline to every extension. |
| # e.g. |
| # _b * zvamo => _b * _zvamo |
| exts = list(map(lambda x: '_' + x, exts)) |
| |
| # No need to expand if there is no `*`. |
| if len(exts) == 1: |
| return [(exts[0],)] |
| |
| # Generate combination! |
| ext_combs = [] |
| for comb_len in range(1, len(exts)+1): |
| for ext_comb in itertools.combinations(exts, comb_len): |
| ext_combs.append(ext_comb) |
| |
| return ext_combs |
| |
| # |
| # Input a list and drop duplicated entry. |
| # e.g. |
| # ["a", "b", "ab", "a"] -> ["a", "b", "ab"] |
| # |
| def unique(x): |
| # |
| # Drop duplicated entry. |
| # Convert list to set and then convert back to list. |
| # |
| # Add sorted to prevent non-deterministic results in different env. |
| # |
| return list(sorted(list(set(x)))) |
| |
| # |
| # Expand EXT string if there is any expansion operator (*). |
| # e.g. |
| # "a*b,c" -> ["a", "b", "ab", "c"] |
| # |
| def expand_combination(ext): |
| ext = list(filter(None, ext.split(','))) |
| |
| # Expand combination for EXT, got lots of list. |
| # e.g. |
| # a * b => [[("a",), ("b",)], [("a", "b")]] |
| ext_combs = list(map(_expand_combination, ext)) |
| |
| # Then fold to single list. |
| # e.g. |
| # [[("a",), ("b",)], [("a", "b")]] => [("a",), ("b",), ("a", "b")] |
| ext = list(reduce(lambda x, y: x + y, ext_combs, [])) |
| |
| # Fold the tuple to string. |
| # e.g. |
| # [("a",), ("b",), ("a", "b")] => ["a", "b", "ab"] |
| ext = map(lambda e : reduce(lambda x, y: x + y, e), ext) |
| |
| # Drop duplicated entry. |
| ext = unique(ext) |
| |
| return ext |
| |
| multilib_cfgs = filter(lambda x:not x.startswith("--"), sys.argv[1:]) |
| options = filter(lambda x:x.startswith("--"), sys.argv[1:]) |
| |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--cmodel", type=str) |
| parser.add_argument("cfgs", type=str, nargs='*') |
| args = parser.parse_args() |
| |
| if args.cmodel: |
| cmodels = [None] + args.cmodel.split(",") |
| else: |
| cmodels = [None] |
| |
| cmodel_options = '/'.join(['mcmodel=%s' % x for x in cmodels[1:]]) |
| cmodel_dirnames = ' \\\n'.join(cmodels[1:]) |
| |
| for cmodel in cmodels: |
| for cfg in args.cfgs: |
| try: |
| (arch, abi, extra, ext) = cfg.split('-') |
| except: |
| print ("Invalid configure string %s, <arch>-<abi>-<extra>-<extensions>\n" |
| "<extra> and <extensions> can be empty, " |
| "e.g. rv32imafd-ilp32--" % cfg) |
| sys.exit(1) |
| |
| # Compact code model only support rv64. |
| if cmodel == "compact" and arch.startswith("rv32"): |
| continue |
| |
| arch = arch_canonicalize (arch) |
| arches[arch] = 1 |
| abis[abi] = 1 |
| extra = list(filter(None, extra.split(','))) |
| ext_combs = expand_combination(ext) |
| alts = sum([[x] + [x + y for y in ext_combs] for x in [arch] + extra], []) |
| alts = list(map(arch_canonicalize, alts)) |
| |
| # Drop duplicated entry. |
| alts = unique(alts) |
| |
| for alt in alts[1:]: |
| if alt == arch: |
| continue |
| arches[alt] = 1 |
| reuse.append('march.%s/mabi.%s=march.%s/mabi.%s' % (arch, abi, alt, abi)) |
| |
| if cmodel: |
| required.append('march=%s/mabi=%s/mcmodel=%s' % (arch, abi, cmodel)) |
| else: |
| required.append('march=%s/mabi=%s' % (arch, abi)) |
| |
| arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) |
| arch_dirnames = ' \\\n'.join(arches.keys()) |
| |
| abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) |
| abi_dirnames = ' \\\n'.join(abis.keys()) |
| |
| prog = sys.argv[0].split('/')[-1] |
| print('# This file was generated by %s with the command:' % prog) |
| print('# %s' % ' '.join(sys.argv)) |
| |
| print('MULTILIB_OPTIONS = %s %s %s' % (arch_options, abi_options, cmodel_options)) |
| print('MULTILIB_DIRNAMES = %s %s %s' % (arch_dirnames, abi_dirnames, cmodel_dirnames)) |
| print('MULTILIB_REQUIRED = %s' % ' \\\n'.join(required)) |
| print('MULTILIB_REUSE = %s' % ' \\\n'.join(reuse)) |