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" 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': // A symbolic address 100 Info.setAllowsRegister(); 101 return true; 102 case 'v': 103 // A vector register. 104 if (Name[1] == 'r' || Name[1] == 'm') { 105 Info.setAllowsRegister(); 106 Name += 1; 107 return true; 108 } 109 return false; 110 } 111 } 112 113 std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { 114 std::string R; 115 switch (*Constraint) { 116 case 'v': 117 R = std::string("^") + std::string(Constraint, 2); 118 Constraint += 1; 119 break; 120 default: 121 R = TargetInfo::convertConstraint(Constraint); 122 break; 123 } 124 return R; 125 } 126 127 static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) { 128 return MajorVersion * 1000000 + MinorVersion * 1000; 129 } 130 131 void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, 132 MacroBuilder &Builder) const { 133 Builder.defineMacro("__riscv"); 134 bool Is64Bit = getTriple().isRISCV64(); 135 Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); 136 StringRef CodeModel = getTargetOpts().CodeModel; 137 unsigned FLen = ISAInfo->getFLen(); 138 unsigned MinVLen = ISAInfo->getMinVLen(); 139 unsigned MaxELen = ISAInfo->getMaxELen(); 140 unsigned MaxELenFp = ISAInfo->getMaxELenFp(); 141 if (CodeModel == "default") 142 CodeModel = "small"; 143 144 if (CodeModel == "small") 145 Builder.defineMacro("__riscv_cmodel_medlow"); 146 else if (CodeModel == "medium") 147 Builder.defineMacro("__riscv_cmodel_medany"); 148 149 StringRef ABIName = getABI(); 150 if (ABIName == "ilp32f" || ABIName == "lp64f") 151 Builder.defineMacro("__riscv_float_abi_single"); 152 else if (ABIName == "ilp32d" || ABIName == "lp64d") 153 Builder.defineMacro("__riscv_float_abi_double"); 154 else 155 Builder.defineMacro("__riscv_float_abi_soft"); 156 157 if (ABIName == "ilp32e") 158 Builder.defineMacro("__riscv_abi_rve"); 159 160 Builder.defineMacro("__riscv_arch_test"); 161 162 for (auto &Extension : ISAInfo->getExtensions()) { 163 auto ExtName = Extension.first; 164 auto ExtInfo = Extension.second; 165 166 Builder.defineMacro( 167 Twine("__riscv_", ExtName), 168 Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion))); 169 } 170 171 if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul")) 172 Builder.defineMacro("__riscv_mul"); 173 174 if (ISAInfo->hasExtension("m")) { 175 Builder.defineMacro("__riscv_div"); 176 Builder.defineMacro("__riscv_muldiv"); 177 } 178 179 if (ISAInfo->hasExtension("a")) { 180 Builder.defineMacro("__riscv_atomic"); 181 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 182 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 183 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 184 if (Is64Bit) 185 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 186 } 187 188 if (FLen) { 189 Builder.defineMacro("__riscv_flen", Twine(FLen)); 190 Builder.defineMacro("__riscv_fdiv"); 191 Builder.defineMacro("__riscv_fsqrt"); 192 } 193 194 if (MinVLen) { 195 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); 196 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen)); 197 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp)); 198 } 199 200 if (ISAInfo->hasExtension("c")) 201 Builder.defineMacro("__riscv_compressed"); 202 203 if (ISAInfo->hasExtension("zve32x")) { 204 Builder.defineMacro("__riscv_vector"); 205 // Currently we support the v0.12 RISC-V V intrinsics. 206 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12))); 207 } 208 209 auto VScale = getVScaleRange(Opts); 210 if (VScale && VScale->first && VScale->first == VScale->second) 211 Builder.defineMacro("__riscv_v_fixed_vlen", 212 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); 213 214 if (FastUnalignedAccess) 215 Builder.defineMacro("__riscv_misaligned_fast"); 216 else 217 Builder.defineMacro("__riscv_misaligned_avoid"); 218 } 219 220 static constexpr Builtin::Info BuiltinInfo[] = { 221 #define BUILTIN(ID, TYPE, ATTRS) \ 222 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 223 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 224 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 225 #include "clang/Basic/BuiltinsRISCVVector.def" 226 #define BUILTIN(ID, TYPE, ATTRS) \ 227 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 228 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 229 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 230 #include "clang/Basic/BuiltinsRISCV.def" 231 }; 232 233 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { 234 return llvm::ArrayRef(BuiltinInfo, 235 clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); 236 } 237 238 static std::vector<std::string> 239 collectNonISAExtFeature(ArrayRef<std::string> FeaturesNeedOverride, int XLen) { 240 auto ParseResult = 241 llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesNeedOverride); 242 243 if (!ParseResult) { 244 consumeError(ParseResult.takeError()); 245 return std::vector<std::string>(); 246 } 247 248 std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector(); 249 250 std::vector<std::string> NonISAExtFeatureVec; 251 252 llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec), 253 [&](const std::string &Feat) { 254 return !llvm::is_contained(ImpliedFeatures, Feat); 255 }); 256 257 return NonISAExtFeatureVec; 258 } 259 260 static std::vector<std::string> 261 resolveTargetAttrOverride(const std::vector<std::string> &FeaturesVec, 262 int XLen) { 263 auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride"); 264 if (I == FeaturesVec.end()) 265 return FeaturesVec; 266 267 ArrayRef<std::string> FeaturesNeedOverride(&*FeaturesVec.begin(), &*I); 268 std::vector<std::string> NonISAExtFeature = 269 collectNonISAExtFeature(FeaturesNeedOverride, XLen); 270 271 std::vector<std::string> ResolvedFeature(++I, FeaturesVec.end()); 272 ResolvedFeature.insert(ResolvedFeature.end(), NonISAExtFeature.begin(), 273 NonISAExtFeature.end()); 274 275 return ResolvedFeature; 276 } 277 278 bool RISCVTargetInfo::initFeatureMap( 279 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 280 const std::vector<std::string> &FeaturesVec) const { 281 282 unsigned XLen = 32; 283 284 if (getTriple().isRISCV64()) { 285 Features["64bit"] = true; 286 XLen = 64; 287 } else { 288 Features["32bit"] = true; 289 } 290 291 std::vector<std::string> NewFeaturesVec = 292 resolveTargetAttrOverride(FeaturesVec, XLen); 293 294 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, NewFeaturesVec); 295 if (!ParseResult) { 296 std::string Buffer; 297 llvm::raw_string_ostream OutputErrMsg(Buffer); 298 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 299 OutputErrMsg << ErrMsg.getMessage(); 300 }); 301 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 302 return false; 303 } 304 305 // RISCVISAInfo makes implications for ISA features 306 std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector(); 307 308 // parseFeatures normalizes the feature set by dropping any explicit 309 // negatives, and non-extension features. We need to preserve the later 310 // for correctness and want to preserve the former for consistency. 311 for (auto &Feature : NewFeaturesVec) { 312 StringRef ExtName = Feature; 313 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); 314 ExtName = ExtName.drop_front(1); // Drop '+' or '-' 315 if (!llvm::is_contained(ImpliedFeatures, ("+" + ExtName).str()) && 316 !llvm::is_contained(ImpliedFeatures, ("-" + ExtName).str())) 317 ImpliedFeatures.push_back(Feature); 318 } 319 return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures); 320 } 321 322 std::optional<std::pair<unsigned, unsigned>> 323 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const { 324 // RISCV::RVVBitsPerBlock is 64. 325 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; 326 327 if (LangOpts.VScaleMin || LangOpts.VScaleMax) { 328 // Treat Zvl*b as a lower bound on vscale. 329 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin); 330 unsigned VScaleMax = LangOpts.VScaleMax; 331 if (VScaleMax != 0 && VScaleMax < VScaleMin) 332 VScaleMax = VScaleMin; 333 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); 334 } 335 336 if (VScaleMin > 0) { 337 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; 338 return std::make_pair(VScaleMin, VScaleMax); 339 } 340 341 return std::nullopt; 342 } 343 344 /// Return true if has this feature, need to sync with handleTargetFeatures. 345 bool RISCVTargetInfo::hasFeature(StringRef Feature) const { 346 bool Is64Bit = getTriple().isRISCV64(); 347 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) 348 .Case("riscv", true) 349 .Case("riscv32", !Is64Bit) 350 .Case("riscv64", Is64Bit) 351 .Case("32bit", !Is64Bit) 352 .Case("64bit", Is64Bit) 353 .Case("experimental", HasExperimental) 354 .Default(std::nullopt); 355 if (Result) 356 return *Result; 357 358 return ISAInfo->hasExtension(Feature); 359 } 360 361 /// Perform initialization based on the user configured set of features. 362 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, 363 DiagnosticsEngine &Diags) { 364 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; 365 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); 366 if (!ParseResult) { 367 std::string Buffer; 368 llvm::raw_string_ostream OutputErrMsg(Buffer); 369 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 370 OutputErrMsg << ErrMsg.getMessage(); 371 }); 372 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 373 return false; 374 } else { 375 ISAInfo = std::move(*ParseResult); 376 } 377 378 if (ABI.empty()) 379 ABI = ISAInfo->computeDefaultABI().str(); 380 381 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx")) 382 HasLegalHalfType = true; 383 384 FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access"); 385 386 if (llvm::is_contained(Features, "+experimental")) 387 HasExperimental = true; 388 389 return true; 390 } 391 392 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { 393 bool Is64Bit = getTriple().isArch64Bit(); 394 return llvm::RISCV::parseCPU(Name, Is64Bit); 395 } 396 397 void RISCVTargetInfo::fillValidCPUList( 398 SmallVectorImpl<StringRef> &Values) const { 399 bool Is64Bit = getTriple().isArch64Bit(); 400 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit); 401 } 402 403 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { 404 bool Is64Bit = getTriple().isArch64Bit(); 405 return llvm::RISCV::parseTuneCPU(Name, Is64Bit); 406 } 407 408 void RISCVTargetInfo::fillValidTuneCPUList( 409 SmallVectorImpl<StringRef> &Values) const { 410 bool Is64Bit = getTriple().isArch64Bit(); 411 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); 412 } 413 414 static void handleFullArchString(StringRef FullArchStr, 415 std::vector<std::string> &Features) { 416 Features.push_back("__RISCV_TargetAttrNeedOverride"); 417 auto RII = llvm::RISCVISAInfo::parseArchString( 418 FullArchStr, /* EnableExperimentalExtension */ true); 419 if (!RII) { 420 consumeError(RII.takeError()); 421 // Forward the invalid FullArchStr. 422 Features.push_back("+" + FullArchStr.str()); 423 } else { 424 std::vector<std::string> FeatStrings = (*RII)->toFeatureVector(); 425 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); 426 } 427 } 428 429 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { 430 ParsedTargetAttr Ret; 431 if (Features == "default") 432 return Ret; 433 SmallVector<StringRef, 1> AttrFeatures; 434 Features.split(AttrFeatures, ";"); 435 bool FoundArch = false; 436 437 for (auto &Feature : AttrFeatures) { 438 Feature = Feature.trim(); 439 StringRef AttrString = Feature.split("=").second.trim(); 440 441 if (Feature.starts_with("arch=")) { 442 // Override last features 443 Ret.Features.clear(); 444 if (FoundArch) 445 Ret.Duplicate = "arch="; 446 FoundArch = true; 447 448 if (AttrString.starts_with("+")) { 449 // EXTENSION like arch=+v,+zbb 450 SmallVector<StringRef, 1> Exts; 451 AttrString.split(Exts, ","); 452 for (auto Ext : Exts) { 453 if (Ext.empty()) 454 continue; 455 456 StringRef ExtName = Ext.substr(1); 457 std::string TargetFeature = 458 llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName); 459 if (!TargetFeature.empty()) 460 Ret.Features.push_back(Ext.front() + TargetFeature); 461 else 462 Ret.Features.push_back(Ext.str()); 463 } 464 } else { 465 // full-arch-string like arch=rv64gcv 466 handleFullArchString(AttrString, Ret.Features); 467 } 468 } else if (Feature.starts_with("cpu=")) { 469 if (!Ret.CPU.empty()) 470 Ret.Duplicate = "cpu="; 471 472 Ret.CPU = AttrString; 473 474 if (!FoundArch) { 475 // Update Features with CPU's features 476 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); 477 if (MarchFromCPU != "") { 478 Ret.Features.clear(); 479 handleFullArchString(MarchFromCPU, Ret.Features); 480 } 481 } 482 } else if (Feature.starts_with("tune=")) { 483 if (!Ret.Tune.empty()) 484 Ret.Duplicate = "tune="; 485 486 Ret.Tune = AttrString; 487 } 488 } 489 return Ret; 490 } 491