xref: /freebsd-src/contrib/llvm-project/llvm/lib/Support/RISCVISAUtils.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===-- RISCVISAUtils.cpp - RISC-V ISA Utilities --------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // Utilities shared by TableGen and RISCVISAInfo.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "llvm/Support/RISCVISAUtils.h"
14*0fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h"
15*0fca6ea1SDimitry Andric #include <cassert>
16*0fca6ea1SDimitry Andric 
17*0fca6ea1SDimitry Andric using namespace llvm;
18*0fca6ea1SDimitry Andric 
19*0fca6ea1SDimitry Andric // We rank extensions in the following order:
20*0fca6ea1SDimitry Andric // -Single letter extensions in canonical order.
21*0fca6ea1SDimitry Andric // -Unknown single letter extensions in alphabetical order.
22*0fca6ea1SDimitry Andric // -Multi-letter extensions starting with 'z' sorted by canonical order of
23*0fca6ea1SDimitry Andric //  the second letter then sorted alphabetically.
24*0fca6ea1SDimitry Andric // -Multi-letter extensions starting with 's' in alphabetical order.
25*0fca6ea1SDimitry Andric // -(TODO) Multi-letter extensions starting with 'zxm' in alphabetical order.
26*0fca6ea1SDimitry Andric // -X extensions in alphabetical order.
27*0fca6ea1SDimitry Andric // -Unknown multi-letter extensions in alphabetical order.
28*0fca6ea1SDimitry Andric // These flags are used to indicate the category. The first 6 bits store the
29*0fca6ea1SDimitry Andric // single letter extension rank for single letter and multi-letter extensions
30*0fca6ea1SDimitry Andric // starting with 'z'.
31*0fca6ea1SDimitry Andric enum RankFlags {
32*0fca6ea1SDimitry Andric   RF_Z_EXTENSION = 1 << 6,
33*0fca6ea1SDimitry Andric   RF_S_EXTENSION = 2 << 6,
34*0fca6ea1SDimitry Andric   RF_X_EXTENSION = 3 << 6,
35*0fca6ea1SDimitry Andric   RF_UNKNOWN_MULTILETTER_EXTENSION = 4 << 6,
36*0fca6ea1SDimitry Andric };
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric // Get the rank for single-letter extension, lower value meaning higher
39*0fca6ea1SDimitry Andric // priority.
40*0fca6ea1SDimitry Andric static unsigned singleLetterExtensionRank(char Ext) {
41*0fca6ea1SDimitry Andric   assert(isLower(Ext));
42*0fca6ea1SDimitry Andric   switch (Ext) {
43*0fca6ea1SDimitry Andric   case 'i':
44*0fca6ea1SDimitry Andric     return 0;
45*0fca6ea1SDimitry Andric   case 'e':
46*0fca6ea1SDimitry Andric     return 1;
47*0fca6ea1SDimitry Andric   }
48*0fca6ea1SDimitry Andric 
49*0fca6ea1SDimitry Andric   size_t Pos = RISCVISAUtils::AllStdExts.find(Ext);
50*0fca6ea1SDimitry Andric   if (Pos != StringRef::npos)
51*0fca6ea1SDimitry Andric     return Pos + 2; // Skip 'e' and 'i' from above.
52*0fca6ea1SDimitry Andric 
53*0fca6ea1SDimitry Andric   // If we got an unknown extension letter, then give it an alphabetical
54*0fca6ea1SDimitry Andric   // order, but after all known standard extensions.
55*0fca6ea1SDimitry Andric   return 2 + RISCVISAUtils::AllStdExts.size() + (Ext - 'a');
56*0fca6ea1SDimitry Andric }
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric // Get the rank for multi-letter extension, lower value meaning higher
59*0fca6ea1SDimitry Andric // priority/order in canonical order.
60*0fca6ea1SDimitry Andric static unsigned getExtensionRank(const std::string &ExtName) {
61*0fca6ea1SDimitry Andric   assert(ExtName.size() >= 1);
62*0fca6ea1SDimitry Andric   switch (ExtName[0]) {
63*0fca6ea1SDimitry Andric   case 's':
64*0fca6ea1SDimitry Andric     return RF_S_EXTENSION;
65*0fca6ea1SDimitry Andric   case 'z':
66*0fca6ea1SDimitry Andric     assert(ExtName.size() >= 2);
67*0fca6ea1SDimitry Andric     // `z` extension must be sorted by canonical order of second letter.
68*0fca6ea1SDimitry Andric     // e.g. zmx has higher rank than zax.
69*0fca6ea1SDimitry Andric     return RF_Z_EXTENSION | singleLetterExtensionRank(ExtName[1]);
70*0fca6ea1SDimitry Andric   case 'x':
71*0fca6ea1SDimitry Andric     return RF_X_EXTENSION;
72*0fca6ea1SDimitry Andric   default:
73*0fca6ea1SDimitry Andric     if (ExtName.size() == 1)
74*0fca6ea1SDimitry Andric       return singleLetterExtensionRank(ExtName[0]);
75*0fca6ea1SDimitry Andric     return RF_UNKNOWN_MULTILETTER_EXTENSION;
76*0fca6ea1SDimitry Andric   }
77*0fca6ea1SDimitry Andric }
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric // Compare function for extension.
80*0fca6ea1SDimitry Andric // Only compare the extension name, ignore version comparison.
81*0fca6ea1SDimitry Andric bool llvm::RISCVISAUtils::compareExtension(const std::string &LHS,
82*0fca6ea1SDimitry Andric                                            const std::string &RHS) {
83*0fca6ea1SDimitry Andric   unsigned LHSRank = getExtensionRank(LHS);
84*0fca6ea1SDimitry Andric   unsigned RHSRank = getExtensionRank(RHS);
85*0fca6ea1SDimitry Andric 
86*0fca6ea1SDimitry Andric   // If the ranks differ, pick the lower rank.
87*0fca6ea1SDimitry Andric   if (LHSRank != RHSRank)
88*0fca6ea1SDimitry Andric     return LHSRank < RHSRank;
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric   // If the rank is same, it must be sorted by lexicographic order.
91*0fca6ea1SDimitry Andric   return LHS < RHS;
92*0fca6ea1SDimitry Andric }
93