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