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