1 //===--- RISCV.cpp - Implement RISC-V target feature support --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements RISC-V TargetInfo objects. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "RISCV.h" 14 #include "clang/Basic/Diagnostic.h" 15 #include "clang/Basic/MacroBuilder.h" 16 #include "clang/Basic/TargetBuiltins.h" 17 #include "llvm/ADT/StringSwitch.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include "llvm/TargetParser/RISCVTargetParser.h" 20 #include <optional> 21 22 using namespace clang; 23 using namespace clang::targets; 24 25 ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const { 26 // clang-format off 27 static const char *const GCCRegNames[] = { 28 // Integer registers 29 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 30 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 31 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 32 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", 33 34 // Floating point registers 35 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 36 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", 37 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", 38 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", 39 40 // Vector registers 41 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", 42 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", 43 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", 44 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", 45 46 // CSRs 47 "fflags", "frm", "vtype", "vl", "vxsat", "vxrm", "sf.vcix_state" 48 }; 49 // clang-format on 50 return llvm::ArrayRef(GCCRegNames); 51 } 52 53 ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const { 54 static const TargetInfo::GCCRegAlias GCCRegAliases[] = { 55 {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"}, 56 {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"}, 57 {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"}, 58 {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"}, 59 {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"}, 60 {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"}, 61 {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"}, 62 {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"}, 63 {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"}, 64 {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"}, 65 {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"}, 66 {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"}, 67 {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"}, 68 {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"}, 69 {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"}, 70 {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}}; 71 return llvm::ArrayRef(GCCRegAliases); 72 } 73 74 bool RISCVTargetInfo::validateAsmConstraint( 75 const char *&Name, TargetInfo::ConstraintInfo &Info) const { 76 switch (*Name) { 77 default: 78 return false; 79 case 'I': 80 // A 12-bit signed immediate. 81 Info.setRequiresImmediate(-2048, 2047); 82 return true; 83 case 'J': 84 // Integer zero. 85 Info.setRequiresImmediate(0); 86 return true; 87 case 'K': 88 // A 5-bit unsigned immediate for CSR access instructions. 89 Info.setRequiresImmediate(0, 31); 90 return true; 91 case 'f': 92 // A floating-point register. 93 Info.setAllowsRegister(); 94 return true; 95 case 'A': 96 // An address that is held in a general-purpose register. 97 Info.setAllowsMemory(); 98 return true; 99 case 's': 100 case 'S': // A symbol or label reference with a constant offset 101 Info.setAllowsRegister(); 102 return true; 103 case 'c': 104 // A RVC register - GPR or FPR 105 if (Name[1] == 'r' || Name[1] == 'R' || Name[1] == 'f') { 106 Info.setAllowsRegister(); 107 Name += 1; 108 return true; 109 } 110 return false; 111 case 'R': 112 // An even-odd GPR pair 113 Info.setAllowsRegister(); 114 return true; 115 case 'v': 116 // A vector register. 117 if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') { 118 Info.setAllowsRegister(); 119 Name += 1; 120 return true; 121 } 122 return false; 123 } 124 } 125 126 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { 127 std::string R; 128 switch (*Constraint) { 129 // c* and v* are two-letter constraints on RISC-V. 130 case 'c': 131 case 'v': 132 R = std::string("^") + std::string(Constraint, 2); 133 Constraint += 1; 134 break; 135 default: 136 R = TargetInfo::convertConstraint(Constraint); 137 break; 138 } 139 return R; 140 } 141 142 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) { 143 return MajorVersion * 1000000 + MinorVersion * 1000; 144 } 145 146 void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, 147 MacroBuilder &Builder) const { 148 Builder.defineMacro("__riscv"); 149 bool Is64Bit = getTriple().isRISCV64(); 150 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); 151 StringRef CodeModel = getTargetOpts().CodeModel; 152 unsigned FLen = ISAInfo->getFLen(); 153 unsigned MinVLen = ISAInfo->getMinVLen(); 154 unsigned MaxELen = ISAInfo->getMaxELen(); 155 unsigned MaxELenFp = ISAInfo->getMaxELenFp(); 156 if (CodeModel == "default") 157 CodeModel = "small"; 158 159 if (CodeModel == "small") 160 Builder.defineMacro("__riscv_cmodel_medlow"); 161 else if (CodeModel == "medium") 162 Builder.defineMacro("__riscv_cmodel_medany"); 163 else if (CodeModel == "large") 164 Builder.defineMacro("__riscv_cmodel_large"); 165 166 StringRef ABIName = getABI(); 167 if (ABIName == "ilp32f" || ABIName == "lp64f") 168 Builder.defineMacro("__riscv_float_abi_single"); 169 else if (ABIName == "ilp32d" || ABIName == "lp64d") 170 Builder.defineMacro("__riscv_float_abi_double"); 171 else 172 Builder.defineMacro("__riscv_float_abi_soft"); 173 174 if (ABIName == "ilp32e" || ABIName == "lp64e") 175 Builder.defineMacro("__riscv_abi_rve"); 176 177 Builder.defineMacro("__riscv_arch_test"); 178 179 for (auto &Extension : ISAInfo->getExtensions()) { 180 auto ExtName = Extension.first; 181 auto ExtInfo = Extension.second; 182 183 Builder.defineMacro(Twine("__riscv_", ExtName), 184 Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor))); 185 } 186 187 if (ISAInfo->hasExtension("zmmul")) 188 Builder.defineMacro("__riscv_mul"); 189 190 if (ISAInfo->hasExtension("m")) { 191 Builder.defineMacro("__riscv_div"); 192 Builder.defineMacro("__riscv_muldiv"); 193 } 194 195 if (ISAInfo->hasExtension("a")) { 196 Builder.defineMacro("__riscv_atomic"); 197 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 198 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 199 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 200 if (Is64Bit) 201 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 202 } 203 204 if (FLen) { 205 Builder.defineMacro("__riscv_flen", Twine(FLen)); 206 Builder.defineMacro("__riscv_fdiv"); 207 Builder.defineMacro("__riscv_fsqrt"); 208 } 209 210 if (MinVLen) { 211 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); 212 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen)); 213 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp)); 214 } 215 216 if (ISAInfo->hasExtension("c")) 217 Builder.defineMacro("__riscv_compressed"); 218 219 if (ISAInfo->hasExtension("zve32x")) 220 Builder.defineMacro("__riscv_vector"); 221 222 // Currently we support the v1.0 RISC-V V intrinsics. 223 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0))); 224 225 auto VScale = getVScaleRange(Opts); 226 if (VScale && VScale->first && VScale->first == VScale->second) 227 Builder.defineMacro("__riscv_v_fixed_vlen", 228 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); 229 230 if (FastScalarUnalignedAccess) 231 Builder.defineMacro("__riscv_misaligned_fast"); 232 else 233 Builder.defineMacro("__riscv_misaligned_avoid"); 234 235 if (ISAInfo->hasExtension("e")) { 236 if (Is64Bit) 237 Builder.defineMacro("__riscv_64e"); 238 else 239 Builder.defineMacro("__riscv_32e"); 240 } 241 } 242 243 static constexpr Builtin::Info BuiltinInfo[] = { 244 #define BUILTIN(ID, TYPE, ATTRS) \ 245 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 246 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 247 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 248 #include "clang/Basic/BuiltinsRISCVVector.def" 249 #define BUILTIN(ID, TYPE, ATTRS) \ 250 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 251 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 252 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 253 #include "clang/Basic/BuiltinsRISCV.inc" 254 }; 255 256 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { 257 return llvm::ArrayRef(BuiltinInfo, 258 clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); 259 } 260 261 bool RISCVTargetInfo::initFeatureMap( 262 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 263 const std::vector<std::string> &FeaturesVec) const { 264 265 unsigned XLen = 32; 266 267 if (getTriple().isRISCV64()) { 268 Features["64bit"] = true; 269 XLen = 64; 270 } else { 271 Features["32bit"] = true; 272 } 273 274 std::vector<std::string> AllFeatures = FeaturesVec; 275 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec); 276 if (!ParseResult) { 277 std::string Buffer; 278 llvm::raw_string_ostream OutputErrMsg(Buffer); 279 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 280 OutputErrMsg << ErrMsg.getMessage(); 281 }); 282 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 283 return false; 284 } 285 286 // Append all features, not just new ones, so we override any negatives. 287 llvm::append_range(AllFeatures, (*ParseResult)->toFeatures()); 288 return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures); 289 } 290 291 std::optional<std::pair<unsigned, unsigned>> 292 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const { 293 // RISCV::RVVBitsPerBlock is 64. 294 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; 295 296 if (LangOpts.VScaleMin || LangOpts.VScaleMax) { 297 // Treat Zvl*b as a lower bound on vscale. 298 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin); 299 unsigned VScaleMax = LangOpts.VScaleMax; 300 if (VScaleMax != 0 && VScaleMax < VScaleMin) 301 VScaleMax = VScaleMin; 302 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); 303 } 304 305 if (VScaleMin > 0) { 306 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; 307 return std::make_pair(VScaleMin, VScaleMax); 308 } 309 310 return std::nullopt; 311 } 312 313 /// Return true if has this feature, need to sync with handleTargetFeatures. 314 bool RISCVTargetInfo::hasFeature(StringRef Feature) const { 315 bool Is64Bit = getTriple().isRISCV64(); 316 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) 317 .Case("riscv", true) 318 .Case("riscv32", !Is64Bit) 319 .Case("riscv64", Is64Bit) 320 .Case("32bit", !Is64Bit) 321 .Case("64bit", Is64Bit) 322 .Case("experimental", HasExperimental) 323 .Default(std::nullopt); 324 if (Result) 325 return *Result; 326 327 return ISAInfo->hasExtension(Feature); 328 } 329 330 /// Perform initialization based on the user configured set of features. 331 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, 332 DiagnosticsEngine &Diags) { 333 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; 334 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); 335 if (!ParseResult) { 336 std::string Buffer; 337 llvm::raw_string_ostream OutputErrMsg(Buffer); 338 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 339 OutputErrMsg << ErrMsg.getMessage(); 340 }); 341 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 342 return false; 343 } else { 344 ISAInfo = std::move(*ParseResult); 345 } 346 347 if (ABI.empty()) 348 ABI = ISAInfo->computeDefaultABI().str(); 349 350 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx")) 351 HasLegalHalfType = true; 352 353 FastScalarUnalignedAccess = 354 llvm::is_contained(Features, "+unaligned-scalar-mem"); 355 356 if (llvm::is_contained(Features, "+experimental")) 357 HasExperimental = true; 358 359 if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) { 360 Diags.Report(diag::err_invalid_feature_combination) 361 << "ILP32E cannot be used with the D ISA extension"; 362 return false; 363 } 364 return true; 365 } 366 367 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { 368 bool Is64Bit = getTriple().isArch64Bit(); 369 return llvm::RISCV::parseCPU(Name, Is64Bit); 370 } 371 372 void RISCVTargetInfo::fillValidCPUList( 373 SmallVectorImpl<StringRef> &Values) const { 374 bool Is64Bit = getTriple().isArch64Bit(); 375 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit); 376 } 377 378 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { 379 bool Is64Bit = getTriple().isArch64Bit(); 380 return llvm::RISCV::parseTuneCPU(Name, Is64Bit); 381 } 382 383 void RISCVTargetInfo::fillValidTuneCPUList( 384 SmallVectorImpl<StringRef> &Values) const { 385 bool Is64Bit = getTriple().isArch64Bit(); 386 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); 387 } 388 389 static void populateNegativeRISCVFeatures(std::vector<std::string> &Features) { 390 auto RII = llvm::RISCVISAInfo::parseArchString( 391 "rv64i", /* EnableExperimentalExtension */ true); 392 393 if (llvm::errorToBool(RII.takeError())) 394 llvm_unreachable("unsupport rv64i"); 395 396 std::vector<std::string> FeatStrings = 397 (*RII)->toFeatures(/* AddAllExtensions */ true); 398 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); 399 } 400 401 static void handleFullArchString(StringRef FullArchStr, 402 std::vector<std::string> &Features) { 403 auto RII = llvm::RISCVISAInfo::parseArchString( 404 FullArchStr, /* EnableExperimentalExtension */ true); 405 if (llvm::errorToBool(RII.takeError())) { 406 // Forward the invalid FullArchStr. 407 Features.push_back(FullArchStr.str()); 408 } else { 409 // Append a full list of features, including any negative extensions so that 410 // we override the CPU's features. 411 populateNegativeRISCVFeatures(Features); 412 std::vector<std::string> FeatStrings = 413 (*RII)->toFeatures(/* AddAllExtensions */ true); 414 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); 415 } 416 } 417 418 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { 419 ParsedTargetAttr Ret; 420 if (Features == "default") 421 return Ret; 422 SmallVector<StringRef, 1> AttrFeatures; 423 Features.split(AttrFeatures, ";"); 424 bool FoundArch = false; 425 426 auto handleArchExtension = [](StringRef AttrString, 427 std::vector<std::string> &Features) { 428 SmallVector<StringRef, 1> Exts; 429 AttrString.split(Exts, ","); 430 for (auto Ext : Exts) { 431 if (Ext.empty()) 432 continue; 433 434 StringRef ExtName = Ext.substr(1); 435 std::string TargetFeature = 436 llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName); 437 if (!TargetFeature.empty()) 438 Features.push_back(Ext.front() + TargetFeature); 439 else 440 Features.push_back(Ext.str()); 441 } 442 }; 443 444 for (auto &Feature : AttrFeatures) { 445 Feature = Feature.trim(); 446 StringRef AttrString = Feature.split("=").second.trim(); 447 448 if (Feature.starts_with("arch=")) { 449 // Override last features 450 Ret.Features.clear(); 451 if (FoundArch) 452 Ret.Duplicate = "arch="; 453 FoundArch = true; 454 455 if (AttrString.starts_with("+")) { 456 // EXTENSION like arch=+v,+zbb 457 handleArchExtension(AttrString, Ret.Features); 458 } else { 459 // full-arch-string like arch=rv64gcv 460 handleFullArchString(AttrString, Ret.Features); 461 } 462 } else if (Feature.starts_with("cpu=")) { 463 if (!Ret.CPU.empty()) 464 Ret.Duplicate = "cpu="; 465 466 Ret.CPU = AttrString; 467 468 if (!FoundArch) { 469 // Update Features with CPU's features 470 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); 471 if (MarchFromCPU != "") { 472 Ret.Features.clear(); 473 handleFullArchString(MarchFromCPU, Ret.Features); 474 } 475 } 476 } else if (Feature.starts_with("tune=")) { 477 if (!Ret.Tune.empty()) 478 Ret.Duplicate = "tune="; 479 480 Ret.Tune = AttrString; 481 } else if (Feature.starts_with("priority")) { 482 // Skip because it only use for FMV. 483 } else if (Feature.starts_with("+")) { 484 // Handle target_version/target_clones attribute strings 485 // that are already delimited by ',' 486 handleArchExtension(Feature, Ret.Features); 487 } 488 } 489 return Ret; 490 } 491 492 uint64_t RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const { 493 // Priority is explicitly specified on RISC-V unlike on other targets, where 494 // it is derived by all the features of a specific version. Therefore if a 495 // feature contains the priority string, then return it immediately. 496 for (StringRef Feature : Features) { 497 auto [LHS, RHS] = Feature.rsplit(';'); 498 if (LHS.consume_front("priority=")) 499 Feature = LHS; 500 else if (RHS.consume_front("priority=")) 501 Feature = RHS; 502 else 503 continue; 504 uint64_t Priority; 505 if (!Feature.getAsInteger(0, Priority)) 506 return Priority; 507 } 508 // Default Priority is zero. 509 return 0; 510 } 511 512 TargetInfo::CallingConvCheckResult 513 RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { 514 switch (CC) { 515 default: 516 return CCCR_Warning; 517 case CC_C: 518 case CC_RISCVVectorCall: 519 return CCCR_OK; 520 } 521 } 522 523 bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const { 524 // Only allow extensions we have a known bit position for in the 525 // __riscv_feature_bits structure. 526 return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Feature).second; 527 } 528 529 bool RISCVTargetInfo::isValidFeatureName(StringRef Name) const { 530 return llvm::RISCVISAInfo::isSupportedExtensionFeature(Name); 531 } 532 533 bool RISCVTargetInfo::validateGlobalRegisterVariable( 534 StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const { 535 if (RegName == "ra" || RegName == "sp" || RegName == "gp" || 536 RegName == "tp" || RegName.starts_with("x") || RegName.starts_with("a") || 537 RegName.starts_with("s") || RegName.starts_with("t")) { 538 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; 539 HasSizeMismatch = RegSize != XLen; 540 return true; 541 } 542 return false; 543 } 544 545 bool RISCVTargetInfo::validateCpuIs(StringRef CPUName) const { 546 assert(getTriple().isOSLinux() && 547 "__builtin_cpu_is() is only supported for Linux."); 548 549 return llvm::RISCV::hasValidCPUModel(CPUName); 550 } 551