arch-canonicalize revision 1.1.1.1 1 1.1 mrg #!/usr/bin/env python
2 1.1 mrg
3 1.1 mrg # Tool for canonical RISC-V architecture string.
4 1.1 mrg # Copyright (C) 2011-2022 Free Software Foundation, Inc.
5 1.1 mrg # Contributed by Andrew Waterman (andrew (at] sifive.com).
6 1.1 mrg #
7 1.1 mrg # This file is part of GCC.
8 1.1 mrg #
9 1.1 mrg # GCC is free software; you can redistribute it and/or modify
10 1.1 mrg # it under the terms of the GNU General Public License as published by
11 1.1 mrg # the Free Software Foundation; either version 3, or (at your option)
12 1.1 mrg # any later version.
13 1.1 mrg #
14 1.1 mrg # GCC is distributed in the hope that it will be useful,
15 1.1 mrg # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1 mrg # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 1.1 mrg # GNU General Public License for more details.
18 1.1 mrg #
19 1.1 mrg # You should have received a copy of the GNU General Public License
20 1.1 mrg # along with GCC; see the file COPYING3. If not see
21 1.1 mrg # <http://www.gnu.org/licenses/>.
22 1.1 mrg
23 1.1 mrg # TODO: Extract riscv_subset_t from riscv-common.cc and make it can be compiled
24 1.1 mrg # standalone to replace this script, that also prevents us implementing
25 1.1 mrg # that twice and keep sync again and again.
26 1.1 mrg
27 1.1 mrg from __future__ import print_function
28 1.1 mrg import sys
29 1.1 mrg import argparse
30 1.1 mrg import collections
31 1.1 mrg import itertools
32 1.1 mrg from functools import reduce
33 1.1 mrg
34 1.1 mrg SUPPORTED_ISA_SPEC = ["2.2", "20190608", "20191213"]
35 1.1 mrg CANONICAL_ORDER = "imafdgqlcbjktpvn"
36 1.1 mrg LONG_EXT_PREFIXES = ['z', 's', 'h', 'x']
37 1.1 mrg
38 1.1 mrg #
39 1.1 mrg # IMPLIED_EXT(ext) -> implied extension list.
40 1.1 mrg #
41 1.1 mrg IMPLIED_EXT = {
42 1.1 mrg "d" : ["f", "zicsr"],
43 1.1 mrg "f" : ["zicsr"],
44 1.1 mrg "zk" : ["zkn", "zkr", "zkt"],
45 1.1 mrg "zkn" : ["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"],
46 1.1 mrg "zks" : ["zbkb", "zbkc", "zbkx", "zksed", "zksh"],
47 1.1 mrg
48 1.1 mrg "v" : ["zvl128b", "zve64d"],
49 1.1 mrg "zve32x" : ["zvl32b"],
50 1.1 mrg "zve64x" : ["zve32x", "zvl64b"],
51 1.1 mrg "zve32f" : ["f", "zve32x"],
52 1.1 mrg "zve64f" : ["f", "zve32f", "zve64x"],
53 1.1 mrg "zve64d" : ["d", "zve64f"],
54 1.1 mrg
55 1.1 mrg "zvl64b" : ["zvl32b"],
56 1.1 mrg "zvl128b" : ["zvl64b"],
57 1.1 mrg "zvl256b" : ["zvl128b"],
58 1.1 mrg "zvl512b" : ["zvl256b"],
59 1.1 mrg "zvl1024b" : ["zvl512b"],
60 1.1 mrg "zvl2048b" : ["zvl1024b"],
61 1.1 mrg "zvl4096b" : ["zvl2048b"],
62 1.1 mrg "zvl8192b" : ["zvl4096b"],
63 1.1 mrg "zvl16384b" : ["zvl8192b"],
64 1.1 mrg "zvl32768b" : ["zvl16384b"],
65 1.1 mrg "zvl65536b" : ["zvl32768b"],
66 1.1 mrg }
67 1.1 mrg
68 1.1 mrg def arch_canonicalize(arch, isa_spec):
69 1.1 mrg # TODO: Support extension version.
70 1.1 mrg is_isa_spec_2p2 = isa_spec == '2.2'
71 1.1 mrg new_arch = ""
72 1.1 mrg extra_long_ext = []
73 1.1 mrg std_exts = []
74 1.1 mrg if arch[:5] in ['rv32e', 'rv32i', 'rv32g', 'rv64i', 'rv64g']:
75 1.1 mrg new_arch = arch[:5].replace("g", "i")
76 1.1 mrg if arch[:5] in ['rv32g', 'rv64g']:
77 1.1 mrg std_exts = ['m', 'a', 'f', 'd']
78 1.1 mrg if not is_isa_spec_2p2:
79 1.1 mrg extra_long_ext = ['zicsr', 'zifencei']
80 1.1 mrg else:
81 1.1 mrg raise Exception("Unexpected arch: `%s`" % arch[:5])
82 1.1 mrg
83 1.1 mrg # Find any Z, S, H or X
84 1.1 mrg long_ext_prefixes_idx = map(lambda x: arch.find(x), LONG_EXT_PREFIXES)
85 1.1 mrg
86 1.1 mrg # Filter out any non-existent index.
87 1.1 mrg long_ext_prefixes_idx = list(filter(lambda x: x != -1, long_ext_prefixes_idx))
88 1.1 mrg if long_ext_prefixes_idx:
89 1.1 mrg first_long_ext_idx = min(long_ext_prefixes_idx)
90 1.1 mrg long_exts = arch[first_long_ext_idx:].split("_")
91 1.1 mrg std_exts += list(arch[5:first_long_ext_idx])
92 1.1 mrg else:
93 1.1 mrg long_exts = []
94 1.1 mrg std_exts += list(arch[5:])
95 1.1 mrg
96 1.1 mrg long_exts += extra_long_ext
97 1.1 mrg
98 1.1 mrg #
99 1.1 mrg # Handle implied extensions.
100 1.1 mrg #
101 1.1 mrg any_change = True
102 1.1 mrg while any_change:
103 1.1 mrg any_change = False
104 1.1 mrg for ext in std_exts + long_exts:
105 1.1 mrg if ext in IMPLIED_EXT:
106 1.1 mrg implied_exts = IMPLIED_EXT[ext]
107 1.1 mrg for implied_ext in implied_exts:
108 1.1 mrg if implied_ext == 'zicsr' and is_isa_spec_2p2:
109 1.1 mrg continue
110 1.1 mrg
111 1.1 mrg if implied_ext not in std_exts + long_exts:
112 1.1 mrg long_exts.append(implied_ext)
113 1.1 mrg any_change = True
114 1.1 mrg
115 1.1 mrg # Single letter extension might appear in the long_exts list,
116 1.1 mrg # becasue we just append extensions list to the arch string.
117 1.1 mrg std_exts += list(filter(lambda x:len(x) == 1, long_exts))
118 1.1 mrg
119 1.1 mrg def longext_sort (exts):
120 1.1 mrg if not exts.startswith("zxm") and exts.startswith("z"):
121 1.1 mrg # If "Z" extensions are named, they should be ordered first by CANONICAL.
122 1.1 mrg if exts[1] not in CANONICAL_ORDER:
123 1.1 mrg raise Exception("Unsupported extension `%s`" % exts)
124 1.1 mrg canonical_sort = CANONICAL_ORDER.index(exts[1])
125 1.1 mrg else:
126 1.1 mrg canonical_sort = -1
127 1.1 mrg return (exts.startswith("x"), exts.startswith("zxm"),
128 1.1 mrg LONG_EXT_PREFIXES.index(exts[0]), canonical_sort, exts[1:])
129 1.1 mrg
130 1.1 mrg # Removing duplicates.
131 1.1 mrg long_exts = list(set(long_exts))
132 1.1 mrg
133 1.1 mrg # Multi-letter extension must be in lexicographic order.
134 1.1 mrg long_exts = list(sorted(filter(lambda x:len(x) != 1, long_exts),
135 1.1 mrg key=longext_sort))
136 1.1 mrg
137 1.1 mrg # Put extensions in canonical order.
138 1.1 mrg for ext in CANONICAL_ORDER:
139 1.1 mrg if ext in std_exts:
140 1.1 mrg new_arch += ext
141 1.1 mrg
142 1.1 mrg # Check every extension is processed.
143 1.1 mrg for ext in std_exts:
144 1.1 mrg if ext == '_':
145 1.1 mrg continue
146 1.1 mrg if ext not in CANONICAL_ORDER:
147 1.1 mrg raise Exception("Unsupported extension `%s`" % ext)
148 1.1 mrg
149 1.1 mrg # Concat rest of the multi-char extensions.
150 1.1 mrg if long_exts:
151 1.1 mrg new_arch += "_" + "_".join(long_exts)
152 1.1 mrg
153 1.1 mrg return new_arch
154 1.1 mrg
155 1.1 mrg if len(sys.argv) < 2:
156 1.1 mrg print ("Usage: %s <arch_str> [<arch_str>*]" % sys.argv)
157 1.1 mrg sys.exit(1)
158 1.1 mrg
159 1.1 mrg parser = argparse.ArgumentParser()
160 1.1 mrg parser.add_argument('-misa-spec', type=str,
161 1.1 mrg default='20191213',
162 1.1 mrg choices=SUPPORTED_ISA_SPEC)
163 1.1 mrg parser.add_argument('arch_strs', nargs=argparse.REMAINDER)
164 1.1 mrg
165 1.1 mrg args = parser.parse_args()
166 1.1 mrg
167 1.1 mrg for arch in args.arch_strs:
168 1.1 mrg print (arch_canonicalize(arch, args.misa_spec))
169