summaryrefslogtreecommitdiff
path: root/gcc/config/riscv/multilib-generator
blob: 1ea2fb25566692c5d274ea8d3d40459c78eb4ed1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#!/usr/bin/env python

# RISC-V multilib list generator.
# Copyright (C) 2011-2022 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))