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