1#!/usr/bin/env python 2 3# Tool for canonical RISC-V architecture string. 4# Copyright (C) 2011-2021 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 24from __future__ import print_function 25import sys 26import collections 27import itertools 28from functools import reduce 29 30 31CANONICAL_ORDER = "mafdgqlcbjtpvn" 32LONG_EXT_PREFIXES = ['z', 's', 'h', 'x'] 33 34# 35# IMPLIED_EXT(ext) -> implied extension list. 36# 37IMPLIED_EXT = { 38 "d" : ["f"], 39} 40 41def arch_canonicalize(arch): 42 # TODO: Support extension version. 43 new_arch = "" 44 if arch[:5] in ['rv32e', 'rv32i', 'rv32g', 'rv64i', 'rv64g']: 45 # TODO: We should expand g to imad_zifencei once we support newer spec. 46 new_arch = arch[:5].replace("g", "imafd") 47 else: 48 raise Exception("Unexpected arch: `%s`" % arch[:5]) 49 50 # Find any Z, S, H or X 51 long_ext_prefixes_idx = map(lambda x: arch.find(x), LONG_EXT_PREFIXES) 52 53 # Filter out any non-existent index. 54 long_ext_prefixes_idx = list(filter(lambda x: x != -1, long_ext_prefixes_idx)) 55 if long_ext_prefixes_idx: 56 first_long_ext_idx = min(long_ext_prefixes_idx) 57 long_exts = arch[first_long_ext_idx:].split("_") 58 std_exts = list(arch[5:first_long_ext_idx]) 59 else: 60 long_exts = [] 61 std_exts = list(arch[5:]) 62 63 # 64 # Handle implied extensions. 65 # 66 for ext in std_exts + long_exts: 67 if ext in IMPLIED_EXT: 68 implied_exts = IMPLIED_EXT[ext] 69 for implied_ext in implied_exts: 70 if implied_ext not in std_exts + long_exts: 71 long_exts.append(implied_ext) 72 73 # Single letter extension might appear in the long_exts list, 74 # becasue we just append extensions list to the arch string. 75 std_exts += list(filter(lambda x:len(x) == 1, long_exts)) 76 77 def longext_sort (exts): 78 if not exts.startswith("zxm") and exts.startswith("z"): 79 # If "Z" extensions are named, they should be ordered first by CANONICAL. 80 if exts[1] not in CANONICAL_ORDER: 81 raise Exception("Unsupported extension `%s`" % exts) 82 canonical_sort = CANONICAL_ORDER.index(exts[1]) 83 else: 84 canonical_sort = -1 85 return (exts.startswith("x"), exts.startswith("zxm"), 86 LONG_EXT_PREFIXES.index(exts[0]), canonical_sort, exts[1:]) 87 88 # Multi-letter extension must be in lexicographic order. 89 long_exts = list(sorted(filter(lambda x:len(x) != 1, long_exts), 90 key=longext_sort)) 91 92 # Put extensions in canonical order. 93 for ext in CANONICAL_ORDER: 94 if ext in std_exts: 95 new_arch += ext 96 97 # Check every extension is processed. 98 for ext in std_exts: 99 if ext == '_': 100 continue 101 if ext not in CANONICAL_ORDER: 102 raise Exception("Unsupported extension `%s`" % ext) 103 104 # Concat rest of the multi-char extensions. 105 if long_exts: 106 new_arch += "_" + "_".join(long_exts) 107 return new_arch 108 109if len(sys.argv) < 2: 110 print ("Usage: %s <arch_str> [<arch_str>*]" % sys.argv) 111 sys.exit(1) 112 113for arg in sys.argv[1:]: 114 print (arch_canonicalize(arg)) 115