1e5dd7070Spatrick //===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick 9e5dd7070Spatrick #include "RISCV.h" 10e5dd7070Spatrick #include "clang/Basic/CharInfo.h" 11e5dd7070Spatrick #include "clang/Driver/Driver.h" 12e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h" 13e5dd7070Spatrick #include "clang/Driver/Options.h" 14e5dd7070Spatrick #include "llvm/Option/ArgList.h" 15e5dd7070Spatrick #include "llvm/ADT/Optional.h" 16e5dd7070Spatrick #include "llvm/Support/TargetParser.h" 17e5dd7070Spatrick #include "llvm/Support/raw_ostream.h" 18e5dd7070Spatrick #include "ToolChains/CommonArgs.h" 19e5dd7070Spatrick 20e5dd7070Spatrick using namespace clang::driver; 21e5dd7070Spatrick using namespace clang::driver::tools; 22e5dd7070Spatrick using namespace clang; 23e5dd7070Spatrick using namespace llvm::opt; 24e5dd7070Spatrick 25ec727ea7Spatrick namespace { 26ec727ea7Spatrick // Represents the major and version number components of a RISC-V extension 27ec727ea7Spatrick struct RISCVExtensionVersion { 28ec727ea7Spatrick StringRef Major; 29ec727ea7Spatrick StringRef Minor; 30ec727ea7Spatrick }; 31ec727ea7Spatrick } // end anonymous namespace 32ec727ea7Spatrick 33e5dd7070Spatrick static StringRef getExtensionTypeDesc(StringRef Ext) { 34e5dd7070Spatrick if (Ext.startswith("sx")) 35e5dd7070Spatrick return "non-standard supervisor-level extension"; 36e5dd7070Spatrick if (Ext.startswith("s")) 37e5dd7070Spatrick return "standard supervisor-level extension"; 38e5dd7070Spatrick if (Ext.startswith("x")) 39e5dd7070Spatrick return "non-standard user-level extension"; 40ec727ea7Spatrick if (Ext.startswith("z")) 41ec727ea7Spatrick return "standard user-level extension"; 42e5dd7070Spatrick return StringRef(); 43e5dd7070Spatrick } 44e5dd7070Spatrick 45e5dd7070Spatrick static StringRef getExtensionType(StringRef Ext) { 46e5dd7070Spatrick if (Ext.startswith("sx")) 47e5dd7070Spatrick return "sx"; 48e5dd7070Spatrick if (Ext.startswith("s")) 49e5dd7070Spatrick return "s"; 50e5dd7070Spatrick if (Ext.startswith("x")) 51e5dd7070Spatrick return "x"; 52ec727ea7Spatrick if (Ext.startswith("z")) 53ec727ea7Spatrick return "z"; 54e5dd7070Spatrick return StringRef(); 55e5dd7070Spatrick } 56e5dd7070Spatrick 57ec727ea7Spatrick // If the extension is supported as experimental, return the version of that 58ec727ea7Spatrick // extension that the compiler currently supports. 59ec727ea7Spatrick static Optional<RISCVExtensionVersion> 60ec727ea7Spatrick isExperimentalExtension(StringRef Ext) { 61ec727ea7Spatrick if (Ext == "b" || Ext == "zbb" || Ext == "zbc" || Ext == "zbe" || 62ec727ea7Spatrick Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || Ext == "zbr" || 63ec727ea7Spatrick Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc") 64ec727ea7Spatrick return RISCVExtensionVersion{"0", "92"}; 65ec727ea7Spatrick if (Ext == "v") 66ec727ea7Spatrick return RISCVExtensionVersion{"0", "8"}; 67ec727ea7Spatrick return None; 68ec727ea7Spatrick } 69ec727ea7Spatrick 70e5dd7070Spatrick static bool isSupportedExtension(StringRef Ext) { 71ec727ea7Spatrick // LLVM supports "z" extensions which are marked as experimental. 72ec727ea7Spatrick if (isExperimentalExtension(Ext)) 73ec727ea7Spatrick return true; 74ec727ea7Spatrick 75e5dd7070Spatrick // LLVM does not support "sx", "s" nor "x" extensions. 76e5dd7070Spatrick return false; 77e5dd7070Spatrick } 78e5dd7070Spatrick 79e5dd7070Spatrick // Extensions may have a version number, and may be separated by 80e5dd7070Spatrick // an underscore '_' e.g.: rv32i2_m2. 81e5dd7070Spatrick // Version number is divided into major and minor version numbers, 82e5dd7070Spatrick // separated by a 'p'. If the minor version is 0 then 'p0' can be 83e5dd7070Spatrick // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. 84ec727ea7Spatrick static bool getExtensionVersion(const Driver &D, const ArgList &Args, 85ec727ea7Spatrick StringRef MArch, StringRef Ext, StringRef In, 86e5dd7070Spatrick std::string &Major, std::string &Minor) { 87ec727ea7Spatrick Major = std::string(In.take_while(isDigit)); 88e5dd7070Spatrick In = In.substr(Major.size()); 89e5dd7070Spatrick 90ec727ea7Spatrick if (Major.size() && In.consume_front("p")) { 91ec727ea7Spatrick Minor = std::string(In.take_while(isDigit)); 92ec727ea7Spatrick In = In.substr(Major.size() + 1); 93e5dd7070Spatrick 94e5dd7070Spatrick // Expected 'p' to be followed by minor version number. 95e5dd7070Spatrick if (Minor.empty()) { 96e5dd7070Spatrick std::string Error = 97e5dd7070Spatrick "minor version number missing after 'p' for extension"; 98e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 99e5dd7070Spatrick << MArch << Error << Ext; 100e5dd7070Spatrick return false; 101e5dd7070Spatrick } 102e5dd7070Spatrick } 103e5dd7070Spatrick 104ec727ea7Spatrick // Expected multi-character extension with version number to have no 105ec727ea7Spatrick // subsequent characters (i.e. must either end string or be followed by 106ec727ea7Spatrick // an underscore). 107ec727ea7Spatrick if (Ext.size() > 1 && In.size()) { 108ec727ea7Spatrick std::string Error = 109ec727ea7Spatrick "multi-character extensions must be separated by underscores"; 110ec727ea7Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << In; 111ec727ea7Spatrick return false; 112ec727ea7Spatrick } 113ec727ea7Spatrick 114ec727ea7Spatrick // If experimental extension, require use of current version number number 115ec727ea7Spatrick if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { 116ec727ea7Spatrick if (!Args.hasArg(options::OPT_menable_experimental_extensions)) { 117ec727ea7Spatrick std::string Error = 118ec727ea7Spatrick "requires '-menable-experimental-extensions' for experimental extension"; 119ec727ea7Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 120ec727ea7Spatrick << MArch << Error << Ext; 121ec727ea7Spatrick return false; 122ec727ea7Spatrick } else if (Major.empty() && Minor.empty()) { 123ec727ea7Spatrick std::string Error = 124ec727ea7Spatrick "experimental extension requires explicit version number"; 125ec727ea7Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 126ec727ea7Spatrick << MArch << Error << Ext; 127ec727ea7Spatrick return false; 128ec727ea7Spatrick } 129ec727ea7Spatrick auto SupportedVers = *ExperimentalExtension; 130ec727ea7Spatrick if (Major != SupportedVers.Major || Minor != SupportedVers.Minor) { 131ec727ea7Spatrick std::string Error = 132ec727ea7Spatrick "unsupported version number " + Major; 133ec727ea7Spatrick if (!Minor.empty()) 134ec727ea7Spatrick Error += "." + Minor; 135ec727ea7Spatrick Error += " for experimental extension (this compiler supports " 136ec727ea7Spatrick + SupportedVers.Major.str() + "." 137ec727ea7Spatrick + SupportedVers.Minor.str() + ")"; 138ec727ea7Spatrick 139ec727ea7Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 140ec727ea7Spatrick << MArch << Error << Ext; 141ec727ea7Spatrick return false; 142ec727ea7Spatrick } 143ec727ea7Spatrick return true; 144ec727ea7Spatrick } 145ec727ea7Spatrick 146ec727ea7Spatrick // Allow extensions to declare no version number 147ec727ea7Spatrick if (Major.empty() && Minor.empty()) 148ec727ea7Spatrick return true; 149ec727ea7Spatrick 150ec727ea7Spatrick // TODO: Handle supported extensions with version number. 151e5dd7070Spatrick std::string Error = "unsupported version number " + Major; 152e5dd7070Spatrick if (!Minor.empty()) 153e5dd7070Spatrick Error += "." + Minor; 154e5dd7070Spatrick Error += " for extension"; 155e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext; 156e5dd7070Spatrick 157e5dd7070Spatrick return false; 158e5dd7070Spatrick } 159e5dd7070Spatrick 160e5dd7070Spatrick // Handle other types of extensions other than the standard 161e5dd7070Spatrick // general purpose and standard user-level extensions. 162e5dd7070Spatrick // Parse the ISA string containing non-standard user-level 163e5dd7070Spatrick // extensions, standard supervisor-level extensions and 164e5dd7070Spatrick // non-standard supervisor-level extensions. 165ec727ea7Spatrick // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a 166e5dd7070Spatrick // canonical order, might have a version number (major, minor) 167e5dd7070Spatrick // and are separated by a single underscore '_'. 168e5dd7070Spatrick // Set the hardware features for the extensions that are supported. 169e5dd7070Spatrick static void getExtensionFeatures(const Driver &D, 170e5dd7070Spatrick const ArgList &Args, 171e5dd7070Spatrick std::vector<StringRef> &Features, 172e5dd7070Spatrick StringRef &MArch, StringRef &Exts) { 173e5dd7070Spatrick if (Exts.empty()) 174e5dd7070Spatrick return; 175e5dd7070Spatrick 176e5dd7070Spatrick // Multi-letter extensions are seperated by a single underscore 177e5dd7070Spatrick // as described in RISC-V User-Level ISA V2.2. 178e5dd7070Spatrick SmallVector<StringRef, 8> Split; 179e5dd7070Spatrick Exts.split(Split, StringRef("_")); 180e5dd7070Spatrick 181ec727ea7Spatrick SmallVector<StringRef, 4> Prefix{"z", "x", "s", "sx"}; 182e5dd7070Spatrick auto I = Prefix.begin(); 183e5dd7070Spatrick auto E = Prefix.end(); 184e5dd7070Spatrick 185e5dd7070Spatrick SmallVector<StringRef, 8> AllExts; 186e5dd7070Spatrick 187e5dd7070Spatrick for (StringRef Ext : Split) { 188e5dd7070Spatrick if (Ext.empty()) { 189e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch 190e5dd7070Spatrick << "extension name missing after separator '_'"; 191e5dd7070Spatrick return; 192e5dd7070Spatrick } 193e5dd7070Spatrick 194e5dd7070Spatrick StringRef Type = getExtensionType(Ext); 195e5dd7070Spatrick StringRef Desc = getExtensionTypeDesc(Ext); 196ec727ea7Spatrick auto Pos = Ext.find_if(isDigit); 197ec727ea7Spatrick StringRef Name(Ext.substr(0, Pos)); 198ec727ea7Spatrick StringRef Vers(Ext.substr(Pos)); 199e5dd7070Spatrick 200e5dd7070Spatrick if (Type.empty()) { 201e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 202e5dd7070Spatrick << MArch << "invalid extension prefix" << Ext; 203e5dd7070Spatrick return; 204e5dd7070Spatrick } 205e5dd7070Spatrick 206e5dd7070Spatrick // Check ISA extensions are specified in the canonical order. 207e5dd7070Spatrick while (I != E && *I != Type) 208e5dd7070Spatrick ++I; 209e5dd7070Spatrick 210e5dd7070Spatrick if (I == E) { 211ec727ea7Spatrick std::string Error = std::string(Desc); 212e5dd7070Spatrick Error += " not given in canonical order"; 213e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 214e5dd7070Spatrick << MArch << Error << Ext; 215e5dd7070Spatrick return; 216e5dd7070Spatrick } 217e5dd7070Spatrick 218e5dd7070Spatrick // The order is OK, do not advance I to the next prefix 219e5dd7070Spatrick // to allow repeated extension type, e.g.: rv32ixabc_xdef. 220e5dd7070Spatrick 221ec727ea7Spatrick if (Name.size() == Type.size()) { 222ec727ea7Spatrick std::string Error = std::string(Desc); 223e5dd7070Spatrick Error += " name missing after"; 224e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 225ec727ea7Spatrick << MArch << Error << Type; 226e5dd7070Spatrick return; 227e5dd7070Spatrick } 228e5dd7070Spatrick 229e5dd7070Spatrick std::string Major, Minor; 230ec727ea7Spatrick if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor)) 231e5dd7070Spatrick return; 232e5dd7070Spatrick 233e5dd7070Spatrick // Check if duplicated extension. 234ec727ea7Spatrick if (llvm::is_contained(AllExts, Name)) { 235e5dd7070Spatrick std::string Error = "duplicated "; 236e5dd7070Spatrick Error += Desc; 237e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 238ec727ea7Spatrick << MArch << Error << Name; 239e5dd7070Spatrick return; 240e5dd7070Spatrick } 241e5dd7070Spatrick 242e5dd7070Spatrick // Extension format is correct, keep parsing the extensions. 243e5dd7070Spatrick // TODO: Save Type, Name, Major, Minor to avoid parsing them later. 244ec727ea7Spatrick AllExts.push_back(Name); 245e5dd7070Spatrick } 246e5dd7070Spatrick 247e5dd7070Spatrick // Set target features. 248e5dd7070Spatrick // TODO: Hardware features to be handled in Support/TargetParser.cpp. 249e5dd7070Spatrick // TODO: Use version number when setting target features. 250e5dd7070Spatrick for (auto Ext : AllExts) { 251e5dd7070Spatrick if (!isSupportedExtension(Ext)) { 252e5dd7070Spatrick StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); 253e5dd7070Spatrick std::string Error = "unsupported "; 254e5dd7070Spatrick Error += Desc; 255e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 256e5dd7070Spatrick << MArch << Error << Ext; 257e5dd7070Spatrick return; 258e5dd7070Spatrick } 259ec727ea7Spatrick if (isExperimentalExtension(Ext)) 260ec727ea7Spatrick Features.push_back(Args.MakeArgString("+experimental-" + Ext)); 261ec727ea7Spatrick else 262e5dd7070Spatrick Features.push_back(Args.MakeArgString("+" + Ext)); 263e5dd7070Spatrick } 264e5dd7070Spatrick } 265e5dd7070Spatrick 266e5dd7070Spatrick // Returns false if an error is diagnosed. 267e5dd7070Spatrick static bool getArchFeatures(const Driver &D, StringRef MArch, 268e5dd7070Spatrick std::vector<StringRef> &Features, 269e5dd7070Spatrick const ArgList &Args) { 270e5dd7070Spatrick // RISC-V ISA strings must be lowercase. 271e5dd7070Spatrick if (llvm::any_of(MArch, [](char c) { return isupper(c); })) { 272e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_arch_name) 273e5dd7070Spatrick << MArch << "string must be lowercase"; 274e5dd7070Spatrick return false; 275e5dd7070Spatrick } 276e5dd7070Spatrick 277e5dd7070Spatrick // ISA string must begin with rv32 or rv64. 278e5dd7070Spatrick if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) || 279e5dd7070Spatrick (MArch.size() < 5)) { 280e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_arch_name) 281e5dd7070Spatrick << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}"; 282e5dd7070Spatrick return false; 283e5dd7070Spatrick } 284e5dd7070Spatrick 285e5dd7070Spatrick bool HasRV64 = MArch.startswith("rv64"); 286e5dd7070Spatrick 287e5dd7070Spatrick // The canonical order specified in ISA manual. 288e5dd7070Spatrick // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 289e5dd7070Spatrick StringRef StdExts = "mafdqlcbjtpvn"; 290e5dd7070Spatrick bool HasF = false, HasD = false; 291e5dd7070Spatrick char Baseline = MArch[4]; 292e5dd7070Spatrick 293e5dd7070Spatrick // First letter should be 'e', 'i' or 'g'. 294e5dd7070Spatrick switch (Baseline) { 295e5dd7070Spatrick default: 296e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_arch_name) 297e5dd7070Spatrick << MArch << "first letter should be 'e', 'i' or 'g'"; 298e5dd7070Spatrick return false; 299e5dd7070Spatrick case 'e': { 300e5dd7070Spatrick StringRef Error; 301e5dd7070Spatrick // Currently LLVM does not support 'e'. 302e5dd7070Spatrick // Extension 'e' is not allowed in rv64. 303e5dd7070Spatrick if (HasRV64) 304e5dd7070Spatrick Error = "standard user-level extension 'e' requires 'rv32'"; 305e5dd7070Spatrick else 306e5dd7070Spatrick Error = "unsupported standard user-level extension 'e'"; 307e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error; 308e5dd7070Spatrick return false; 309e5dd7070Spatrick } 310e5dd7070Spatrick case 'i': 311e5dd7070Spatrick break; 312e5dd7070Spatrick case 'g': 313e5dd7070Spatrick // g = imafd 314e5dd7070Spatrick StdExts = StdExts.drop_front(4); 315e5dd7070Spatrick Features.push_back("+m"); 316e5dd7070Spatrick Features.push_back("+a"); 317e5dd7070Spatrick Features.push_back("+f"); 318e5dd7070Spatrick Features.push_back("+d"); 319e5dd7070Spatrick HasF = true; 320e5dd7070Spatrick HasD = true; 321e5dd7070Spatrick break; 322e5dd7070Spatrick } 323e5dd7070Spatrick 324e5dd7070Spatrick // Skip rvxxx 325e5dd7070Spatrick StringRef Exts = MArch.substr(5); 326e5dd7070Spatrick 327ec727ea7Spatrick // Remove multi-letter standard extensions, non-standard extensions and 328ec727ea7Spatrick // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes. 329ec727ea7Spatrick // Parse them at the end. 330ec727ea7Spatrick // Find the very first occurrence of 's', 'x' or 'z'. 331e5dd7070Spatrick StringRef OtherExts; 332ec727ea7Spatrick size_t Pos = Exts.find_first_of("zsx"); 333e5dd7070Spatrick if (Pos != StringRef::npos) { 334e5dd7070Spatrick OtherExts = Exts.substr(Pos); 335e5dd7070Spatrick Exts = Exts.substr(0, Pos); 336e5dd7070Spatrick } 337e5dd7070Spatrick 338e5dd7070Spatrick std::string Major, Minor; 339ec727ea7Spatrick if (!getExtensionVersion(D, Args, MArch, std::string(1, Baseline), Exts, 340ec727ea7Spatrick Major, Minor)) 341e5dd7070Spatrick return false; 342e5dd7070Spatrick 343ec727ea7Spatrick // Consume the base ISA version number and any '_' between rvxxx and the 344ec727ea7Spatrick // first extension 345ec727ea7Spatrick Exts = Exts.drop_front(Major.size()); 346ec727ea7Spatrick if (!Minor.empty()) 347ec727ea7Spatrick Exts = Exts.drop_front(Minor.size() + 1 /*'p'*/); 348ec727ea7Spatrick Exts.consume_front("_"); 349ec727ea7Spatrick 350e5dd7070Spatrick // TODO: Use version number when setting target features 351e5dd7070Spatrick 352e5dd7070Spatrick auto StdExtsItr = StdExts.begin(); 353e5dd7070Spatrick auto StdExtsEnd = StdExts.end(); 354e5dd7070Spatrick 355ec727ea7Spatrick for (auto I = Exts.begin(), E = Exts.end(); I != E; ) { 356e5dd7070Spatrick char c = *I; 357e5dd7070Spatrick 358e5dd7070Spatrick // Check ISA extensions are specified in the canonical order. 359e5dd7070Spatrick while (StdExtsItr != StdExtsEnd && *StdExtsItr != c) 360e5dd7070Spatrick ++StdExtsItr; 361e5dd7070Spatrick 362e5dd7070Spatrick if (StdExtsItr == StdExtsEnd) { 363e5dd7070Spatrick // Either c contains a valid extension but it was not given in 364e5dd7070Spatrick // canonical order or it is an invalid extension. 365e5dd7070Spatrick StringRef Error; 366e5dd7070Spatrick if (StdExts.contains(c)) 367e5dd7070Spatrick Error = "standard user-level extension not given in canonical order"; 368e5dd7070Spatrick else 369e5dd7070Spatrick Error = "invalid standard user-level extension"; 370e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 371e5dd7070Spatrick << MArch << Error << std::string(1, c); 372e5dd7070Spatrick return false; 373e5dd7070Spatrick } 374e5dd7070Spatrick 375e5dd7070Spatrick // Move to next char to prevent repeated letter. 376e5dd7070Spatrick ++StdExtsItr; 377e5dd7070Spatrick 378ec727ea7Spatrick std::string Next, Major, Minor; 379ec727ea7Spatrick if (std::next(I) != E) 380ec727ea7Spatrick Next = std::string(std::next(I), E); 381ec727ea7Spatrick if (!getExtensionVersion(D, Args, MArch, std::string(1, c), Next, Major, 382ec727ea7Spatrick Minor)) 383e5dd7070Spatrick return false; 384e5dd7070Spatrick 385e5dd7070Spatrick // The order is OK, then push it into features. 386ec727ea7Spatrick // TODO: Use version number when setting target features 387e5dd7070Spatrick switch (c) { 388e5dd7070Spatrick default: 389e5dd7070Spatrick // Currently LLVM supports only "mafdc". 390e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) 391e5dd7070Spatrick << MArch << "unsupported standard user-level extension" 392e5dd7070Spatrick << std::string(1, c); 393e5dd7070Spatrick return false; 394e5dd7070Spatrick case 'm': 395e5dd7070Spatrick Features.push_back("+m"); 396e5dd7070Spatrick break; 397e5dd7070Spatrick case 'a': 398e5dd7070Spatrick Features.push_back("+a"); 399e5dd7070Spatrick break; 400e5dd7070Spatrick case 'f': 401e5dd7070Spatrick Features.push_back("+f"); 402e5dd7070Spatrick HasF = true; 403e5dd7070Spatrick break; 404e5dd7070Spatrick case 'd': 405e5dd7070Spatrick Features.push_back("+d"); 406e5dd7070Spatrick HasD = true; 407e5dd7070Spatrick break; 408e5dd7070Spatrick case 'c': 409e5dd7070Spatrick Features.push_back("+c"); 410e5dd7070Spatrick break; 411ec727ea7Spatrick case 'b': 412ec727ea7Spatrick Features.push_back("+experimental-b"); 413ec727ea7Spatrick break; 414ec727ea7Spatrick case 'v': 415ec727ea7Spatrick Features.push_back("+experimental-v"); 416ec727ea7Spatrick break; 417e5dd7070Spatrick } 418ec727ea7Spatrick 419ec727ea7Spatrick // Consume full extension name and version, including any optional '_' 420ec727ea7Spatrick // between this extension and the next 421ec727ea7Spatrick ++I; 422ec727ea7Spatrick I += Major.size(); 423ec727ea7Spatrick if (Minor.size()) 424ec727ea7Spatrick I += Minor.size() + 1 /*'p'*/; 425ec727ea7Spatrick if (*I == '_') 426ec727ea7Spatrick ++I; 427e5dd7070Spatrick } 428e5dd7070Spatrick 429e5dd7070Spatrick // Dependency check. 430e5dd7070Spatrick // It's illegal to specify the 'd' (double-precision floating point) 431e5dd7070Spatrick // extension without also specifying the 'f' (single precision 432e5dd7070Spatrick // floating-point) extension. 433e5dd7070Spatrick if (HasD && !HasF) { 434e5dd7070Spatrick D.Diag(diag::err_drv_invalid_riscv_arch_name) 435e5dd7070Spatrick << MArch << "d requires f extension to also be specified"; 436e5dd7070Spatrick return false; 437e5dd7070Spatrick } 438e5dd7070Spatrick 439e5dd7070Spatrick // Additional dependency checks. 440e5dd7070Spatrick // TODO: The 'q' extension requires rv64. 441e5dd7070Spatrick // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. 442e5dd7070Spatrick 443e5dd7070Spatrick // Handle all other types of extensions. 444e5dd7070Spatrick getExtensionFeatures(D, Args, Features, MArch, OtherExts); 445e5dd7070Spatrick 446e5dd7070Spatrick return true; 447e5dd7070Spatrick } 448e5dd7070Spatrick 449ec727ea7Spatrick // Get features except standard extension feature 450ec727ea7Spatrick void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple, 451ec727ea7Spatrick const llvm::opt::ArgList &Args, 452ec727ea7Spatrick const llvm::opt::Arg *A, StringRef Mcpu, 453ec727ea7Spatrick std::vector<StringRef> &Features) { 454ec727ea7Spatrick bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64); 455ec727ea7Spatrick llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu); 456ec727ea7Spatrick if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) || 457ec727ea7Spatrick !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) { 458ec727ea7Spatrick D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); 459ec727ea7Spatrick } 460ec727ea7Spatrick } 461ec727ea7Spatrick 462e5dd7070Spatrick void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, 463e5dd7070Spatrick const ArgList &Args, 464e5dd7070Spatrick std::vector<StringRef> &Features) { 465e5dd7070Spatrick StringRef MArch = getRISCVArch(Args, Triple); 466e5dd7070Spatrick 467e5dd7070Spatrick if (!getArchFeatures(D, MArch, Features, Args)) 468e5dd7070Spatrick return; 469e5dd7070Spatrick 470ec727ea7Spatrick // If users give march and mcpu, get std extension feature from MArch 471ec727ea7Spatrick // and other features (ex. mirco architecture feature) from mcpu 472ec727ea7Spatrick if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) 473ec727ea7Spatrick getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features); 474ec727ea7Spatrick 475e5dd7070Spatrick // Handle features corresponding to "-ffixed-X" options 476e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x1)) 477e5dd7070Spatrick Features.push_back("+reserve-x1"); 478e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x2)) 479e5dd7070Spatrick Features.push_back("+reserve-x2"); 480e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x3)) 481e5dd7070Spatrick Features.push_back("+reserve-x3"); 482e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x4)) 483e5dd7070Spatrick Features.push_back("+reserve-x4"); 484e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x5)) 485e5dd7070Spatrick Features.push_back("+reserve-x5"); 486e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x6)) 487e5dd7070Spatrick Features.push_back("+reserve-x6"); 488e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x7)) 489e5dd7070Spatrick Features.push_back("+reserve-x7"); 490e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x8)) 491e5dd7070Spatrick Features.push_back("+reserve-x8"); 492e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x9)) 493e5dd7070Spatrick Features.push_back("+reserve-x9"); 494e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x10)) 495e5dd7070Spatrick Features.push_back("+reserve-x10"); 496e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x11)) 497e5dd7070Spatrick Features.push_back("+reserve-x11"); 498e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x12)) 499e5dd7070Spatrick Features.push_back("+reserve-x12"); 500e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x13)) 501e5dd7070Spatrick Features.push_back("+reserve-x13"); 502e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x14)) 503e5dd7070Spatrick Features.push_back("+reserve-x14"); 504e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x15)) 505e5dd7070Spatrick Features.push_back("+reserve-x15"); 506e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x16)) 507e5dd7070Spatrick Features.push_back("+reserve-x16"); 508e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x17)) 509e5dd7070Spatrick Features.push_back("+reserve-x17"); 510e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x18)) 511e5dd7070Spatrick Features.push_back("+reserve-x18"); 512e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x19)) 513e5dd7070Spatrick Features.push_back("+reserve-x19"); 514e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x20)) 515e5dd7070Spatrick Features.push_back("+reserve-x20"); 516e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x21)) 517e5dd7070Spatrick Features.push_back("+reserve-x21"); 518e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x22)) 519e5dd7070Spatrick Features.push_back("+reserve-x22"); 520e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x23)) 521e5dd7070Spatrick Features.push_back("+reserve-x23"); 522e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x24)) 523e5dd7070Spatrick Features.push_back("+reserve-x24"); 524e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x25)) 525e5dd7070Spatrick Features.push_back("+reserve-x25"); 526e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x26)) 527e5dd7070Spatrick Features.push_back("+reserve-x26"); 528e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x27)) 529e5dd7070Spatrick Features.push_back("+reserve-x27"); 530e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x28)) 531e5dd7070Spatrick Features.push_back("+reserve-x28"); 532e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x29)) 533e5dd7070Spatrick Features.push_back("+reserve-x29"); 534e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x30)) 535e5dd7070Spatrick Features.push_back("+reserve-x30"); 536e5dd7070Spatrick if (Args.hasArg(options::OPT_ffixed_x31)) 537e5dd7070Spatrick Features.push_back("+reserve-x31"); 538e5dd7070Spatrick 539*e15071f8Skettenis #ifdef __OpenBSD__ 540*e15071f8Skettenis // -mno-relax is default, unless -mrelax is specified. 541*e15071f8Skettenis if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) 542*e15071f8Skettenis Features.push_back("+relax"); 543*e15071f8Skettenis else 544*e15071f8Skettenis Features.push_back("-relax"); 545*e15071f8Skettenis #else 546e5dd7070Spatrick // -mrelax is default, unless -mno-relax is specified. 547e5dd7070Spatrick if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) 548e5dd7070Spatrick Features.push_back("+relax"); 549e5dd7070Spatrick else 550e5dd7070Spatrick Features.push_back("-relax"); 551*e15071f8Skettenis #endif 552e5dd7070Spatrick 553e5dd7070Spatrick // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is 554ec727ea7Spatrick // specified. 555ec727ea7Spatrick if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) 556ec727ea7Spatrick Features.push_back("+save-restore"); 557ec727ea7Spatrick else 558ec727ea7Spatrick Features.push_back("-save-restore"); 559e5dd7070Spatrick 560e5dd7070Spatrick // Now add any that the user explicitly requested on the command line, 561e5dd7070Spatrick // which may override the defaults. 562e5dd7070Spatrick handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); 563e5dd7070Spatrick } 564e5dd7070Spatrick 565e5dd7070Spatrick StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { 566e5dd7070Spatrick assert((Triple.getArch() == llvm::Triple::riscv32 || 567e5dd7070Spatrick Triple.getArch() == llvm::Triple::riscv64) && 568e5dd7070Spatrick "Unexpected triple"); 569e5dd7070Spatrick 570e5dd7070Spatrick // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not 571e5dd7070Spatrick // configured using `--with-abi=`, then the logic for the default choice is 572ec727ea7Spatrick // defined in config.gcc. This function is based on the logic in GCC 9.2.0. 573e5dd7070Spatrick // 574ec727ea7Spatrick // The logic used in GCC 9.2.0 is the following, in order: 575e5dd7070Spatrick // 1. Explicit choices using `--with-abi=` 576e5dd7070Spatrick // 2. A default based on `--with-arch=`, if provided 577e5dd7070Spatrick // 3. A default based on the target triple's arch 578e5dd7070Spatrick // 579e5dd7070Spatrick // The logic in config.gcc is a little circular but it is not inconsistent. 580e5dd7070Spatrick // 581e5dd7070Spatrick // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` 582e5dd7070Spatrick // and `-mabi=` respectively instead. 583ec727ea7Spatrick // 584ec727ea7Spatrick // In order to make chosing logic more clear, Clang uses the following logic, 585ec727ea7Spatrick // in order: 586ec727ea7Spatrick // 1. Explicit choices using `-mabi=` 587ec727ea7Spatrick // 2. A default based on the architecture as determined by getRISCVArch 588ec727ea7Spatrick // 3. Choose a default based on the triple 589e5dd7070Spatrick 590e5dd7070Spatrick // 1. If `-mabi=` is specified, use it. 591e5dd7070Spatrick if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) 592e5dd7070Spatrick return A->getValue(); 593e5dd7070Spatrick 594ec727ea7Spatrick // 2. Choose a default based on the target architecture. 595e5dd7070Spatrick // 596e5dd7070Spatrick // rv32g | rv32*d -> ilp32d 597e5dd7070Spatrick // rv32e -> ilp32e 598e5dd7070Spatrick // rv32* -> ilp32 599e5dd7070Spatrick // rv64g | rv64*d -> lp64d 600e5dd7070Spatrick // rv64* -> lp64 601ec727ea7Spatrick StringRef MArch = getRISCVArch(Args, Triple); 602e5dd7070Spatrick 603e5dd7070Spatrick if (MArch.startswith_lower("rv32")) { 604e5dd7070Spatrick // FIXME: parse `March` to find `D` extension properly 605ec727ea7Spatrick if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv32g")) 606e5dd7070Spatrick return "ilp32d"; 607e5dd7070Spatrick else if (MArch.startswith_lower("rv32e")) 608e5dd7070Spatrick return "ilp32e"; 609e5dd7070Spatrick else 610e5dd7070Spatrick return "ilp32"; 611e5dd7070Spatrick } else if (MArch.startswith_lower("rv64")) { 612e5dd7070Spatrick // FIXME: parse `March` to find `D` extension properly 613ec727ea7Spatrick if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv64g")) 614e5dd7070Spatrick return "lp64d"; 615e5dd7070Spatrick else 616e5dd7070Spatrick return "lp64"; 617e5dd7070Spatrick } 618e5dd7070Spatrick 619e5dd7070Spatrick // 3. Choose a default based on the triple 620e5dd7070Spatrick // 621e5dd7070Spatrick // We deviate from GCC's defaults here: 622e5dd7070Spatrick // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. 623e5dd7070Spatrick // - On all other OSs we use the double floating point calling convention. 624e5dd7070Spatrick if (Triple.getArch() == llvm::Triple::riscv32) { 625e5dd7070Spatrick if (Triple.getOS() == llvm::Triple::UnknownOS) 626e5dd7070Spatrick return "ilp32"; 627e5dd7070Spatrick else 628e5dd7070Spatrick return "ilp32d"; 629e5dd7070Spatrick } else { 630e5dd7070Spatrick if (Triple.getOS() == llvm::Triple::UnknownOS) 631e5dd7070Spatrick return "lp64"; 632e5dd7070Spatrick else 633e5dd7070Spatrick return "lp64d"; 634e5dd7070Spatrick } 635e5dd7070Spatrick } 636e5dd7070Spatrick 637e5dd7070Spatrick StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, 638e5dd7070Spatrick const llvm::Triple &Triple) { 639e5dd7070Spatrick assert((Triple.getArch() == llvm::Triple::riscv32 || 640e5dd7070Spatrick Triple.getArch() == llvm::Triple::riscv64) && 641e5dd7070Spatrick "Unexpected triple"); 642e5dd7070Spatrick 643e5dd7070Spatrick // GCC's logic around choosing a default `-march=` is complex. If GCC is not 644e5dd7070Spatrick // configured using `--with-arch=`, then the logic for the default choice is 645e5dd7070Spatrick // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We 646ec727ea7Spatrick // deviate from GCC's default on additional `-mcpu` option (GCC does not 647ec727ea7Spatrick // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march` 648ec727ea7Spatrick // nor `-mabi` is specified. 649e5dd7070Spatrick // 650ec727ea7Spatrick // The logic used in GCC 9.2.0 is the following, in order: 651e5dd7070Spatrick // 1. Explicit choices using `--with-arch=` 652e5dd7070Spatrick // 2. A default based on `--with-abi=`, if provided 653e5dd7070Spatrick // 3. A default based on the target triple's arch 654e5dd7070Spatrick // 655e5dd7070Spatrick // The logic in config.gcc is a little circular but it is not inconsistent. 656e5dd7070Spatrick // 657e5dd7070Spatrick // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` 658e5dd7070Spatrick // and `-mabi=` respectively instead. 659e5dd7070Spatrick // 660ec727ea7Spatrick // Clang uses the following logic, in order: 661ec727ea7Spatrick // 1. Explicit choices using `-march=` 662ec727ea7Spatrick // 2. Based on `-mcpu` if the target CPU has a default ISA string 663ec727ea7Spatrick // 3. A default based on `-mabi`, if provided 664ec727ea7Spatrick // 4. A default based on the target triple's arch 665ec727ea7Spatrick // 666e5dd7070Spatrick // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc` 667e5dd7070Spatrick // instead of `rv{XLEN}gc` though they are (currently) equivalent. 668e5dd7070Spatrick 669e5dd7070Spatrick // 1. If `-march=` is specified, use it. 670e5dd7070Spatrick if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) 671e5dd7070Spatrick return A->getValue(); 672e5dd7070Spatrick 673ec727ea7Spatrick // 2. Get march (isa string) based on `-mcpu=` 674ec727ea7Spatrick if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { 675ec727ea7Spatrick StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue()); 676ec727ea7Spatrick // Bypass if target cpu's default march is empty. 677ec727ea7Spatrick if (MArch != "") 678ec727ea7Spatrick return MArch; 679ec727ea7Spatrick } 680ec727ea7Spatrick 681ec727ea7Spatrick // 3. Choose a default based on `-mabi=` 682e5dd7070Spatrick // 683e5dd7070Spatrick // ilp32e -> rv32e 684e5dd7070Spatrick // ilp32 | ilp32f | ilp32d -> rv32imafdc 685e5dd7070Spatrick // lp64 | lp64f | lp64d -> rv64imafdc 686e5dd7070Spatrick if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { 687e5dd7070Spatrick StringRef MABI = A->getValue(); 688e5dd7070Spatrick 689e5dd7070Spatrick if (MABI.equals_lower("ilp32e")) 690e5dd7070Spatrick return "rv32e"; 691e5dd7070Spatrick else if (MABI.startswith_lower("ilp32")) 692e5dd7070Spatrick return "rv32imafdc"; 693e5dd7070Spatrick else if (MABI.startswith_lower("lp64")) 694e5dd7070Spatrick return "rv64imafdc"; 695e5dd7070Spatrick } 696e5dd7070Spatrick 697ec727ea7Spatrick // 4. Choose a default based on the triple 698e5dd7070Spatrick // 699e5dd7070Spatrick // We deviate from GCC's defaults here: 700e5dd7070Spatrick // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` 701e5dd7070Spatrick // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) 702e5dd7070Spatrick if (Triple.getArch() == llvm::Triple::riscv32) { 703e5dd7070Spatrick if (Triple.getOS() == llvm::Triple::UnknownOS) 704e5dd7070Spatrick return "rv32imac"; 705e5dd7070Spatrick else 706e5dd7070Spatrick return "rv32imafdc"; 707e5dd7070Spatrick } else { 708e5dd7070Spatrick if (Triple.getOS() == llvm::Triple::UnknownOS) 709e5dd7070Spatrick return "rv64imac"; 710e5dd7070Spatrick else 711e5dd7070Spatrick return "rv64imafdc"; 712e5dd7070Spatrick } 713e5dd7070Spatrick } 714