1 #!/usr/bin/env python 2 3 # RISC-V multilib list generator. 4 # Copyright (C) 2011-2022 Free Software Foundation, Inc. 5 # Contributed by Andrew Waterman (andrew (at] 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> 25 # Example 1: 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 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 35 36 from __future__ import print_function 37 import sys 38 import os 39 import collections 40 import itertools 41 from functools import reduce 42 import subprocess 43 import argparse 44 45 # 46 # TODO: Add test for this script. 47 # 48 49 SUPPORTED_ISA_SPEC = ["2.2", "20190608", "20191213"] 50 arches = collections.OrderedDict() 51 abis = collections.OrderedDict() 52 required = [] 53 reuse = [] 54 55 def arch_canonicalize(arch, isa_spec): 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") 59 proc = subprocess.Popen([sys.executable, arch_can_script, 60 '-misa-spec=%s' % isa_spec, arch], 61 stdout=subprocess.PIPE) 62 out, err = proc.communicate() 63 return out.decode().strip() 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 74 # Add underline to every extension. 75 # e.g. 76 # _b * zvamo => _b * _zvamo 77 exts = list(map(lambda x: '_' + x, exts)) 78 79 # No need to expand if there is no `*`. 80 if len(exts) == 1: 81 return [(exts[0],)] 82 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 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) 138 parser.add_argument('-misa-spec', type=str, 139 default='20191213', 140 choices=SUPPORTED_ISA_SPEC) 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 165 166 arch = arch_canonicalize (arch, args.misa_spec) 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], []) 172 alts = filter(lambda x: len(x) != 0, alts) 173 alts = list(map(lambda a : arch_canonicalize(a, args.misa_spec), alts)) 174 175 # Drop duplicated entry. 176 alts = unique(alts) 177 178 for alt in alts[1:]: 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)) 188 189 arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) 190 arch_dirnames = ' \\\n'.join(arches.keys()) 191 192 abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) 193 abi_dirnames = ' \\\n'.join(abis.keys()) 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 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)) 201 print('MULTILIB_REQUIRED = %s' % ' \\\n'.join(required)) 202 print('MULTILIB_REUSE = %s' % ' \\\n'.join(reuse)) 203