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 .Default(std::nullopt); 354 if (Result) 355 return *Result; 356 357 return ISAInfo->hasExtension(Feature); 358 } 359 360 /// Perform initialization based on the user configured set of features. 361 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, 362 DiagnosticsEngine &Diags) { 363 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; 364 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); 365 if (!ParseResult) { 366 std::string Buffer; 367 llvm::raw_string_ostream OutputErrMsg(Buffer); 368 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 369 OutputErrMsg << ErrMsg.getMessage(); 370 }); 371 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 372 return false; 373 } else { 374 ISAInfo = std::move(*ParseResult); 375 } 376 377 if (ABI.empty()) 378 ABI = ISAInfo->computeDefaultABI().str(); 379 380 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx")) 381 HasLegalHalfType = true; 382 383 FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access"); 384 385 return true; 386 } 387 388 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { 389 bool Is64Bit = getTriple().isArch64Bit(); 390 return llvm::RISCV::parseCPU(Name, Is64Bit); 391 } 392 393 void RISCVTargetInfo::fillValidCPUList( 394 SmallVectorImpl<StringRef> &Values) const { 395 bool Is64Bit = getTriple().isArch64Bit(); 396 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit); 397 } 398 399 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { 400 bool Is64Bit = getTriple().isArch64Bit(); 401 return llvm::RISCV::parseTuneCPU(Name, Is64Bit); 402 } 403 404 void RISCVTargetInfo::fillValidTuneCPUList( 405 SmallVectorImpl<StringRef> &Values) const { 406 bool Is64Bit = getTriple().isArch64Bit(); 407 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); 408 } 409 410 static void handleFullArchString(StringRef FullArchStr, 411 std::vector<std::string> &Features) { 412 Features.push_back("__RISCV_TargetAttrNeedOverride"); 413 auto RII = llvm::RISCVISAInfo::parseArchString( 414 FullArchStr, /* EnableExperimentalExtension */ true); 415 if (!RII) { 416 consumeError(RII.takeError()); 417 // Forward the invalid FullArchStr. 418 Features.push_back("+" + FullArchStr.str()); 419 } else { 420 std::vector<std::string> FeatStrings = (*RII)->toFeatureVector(); 421 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); 422 } 423 } 424 425 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { 426 ParsedTargetAttr Ret; 427 if (Features == "default") 428 return Ret; 429 SmallVector<StringRef, 1> AttrFeatures; 430 Features.split(AttrFeatures, ";"); 431 bool FoundArch = false; 432 433 for (auto &Feature : AttrFeatures) { 434 Feature = Feature.trim(); 435 StringRef AttrString = Feature.split("=").second.trim(); 436 437 if (Feature.starts_with("arch=")) { 438 // Override last features 439 Ret.Features.clear(); 440 if (FoundArch) 441 Ret.Duplicate = "arch="; 442 FoundArch = true; 443 444 if (AttrString.starts_with("+")) { 445 // EXTENSION like arch=+v,+zbb 446 SmallVector<StringRef, 1> Exts; 447 AttrString.split(Exts, ","); 448 for (auto Ext : Exts) { 449 if (Ext.empty()) 450 continue; 451 452 StringRef ExtName = Ext.substr(1); 453 std::string TargetFeature = 454 llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName); 455 if (!TargetFeature.empty()) 456 Ret.Features.push_back(Ext.front() + TargetFeature); 457 else 458 Ret.Features.push_back(Ext.str()); 459 } 460 } else { 461 // full-arch-string like arch=rv64gcv 462 handleFullArchString(AttrString, Ret.Features); 463 } 464 } else if (Feature.starts_with("cpu=")) { 465 if (!Ret.CPU.empty()) 466 Ret.Duplicate = "cpu="; 467 468 Ret.CPU = AttrString; 469 470 if (!FoundArch) { 471 // Update Features with CPU's features 472 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); 473 if (MarchFromCPU != "") { 474 Ret.Features.clear(); 475 handleFullArchString(MarchFromCPU, Ret.Features); 476 } 477 } 478 } else if (Feature.starts_with("tune=")) { 479 if (!Ret.Tune.empty()) 480 Ret.Duplicate = "tune="; 481 482 Ret.Tune = AttrString; 483 } 484 } 485 return Ret; 486 } 487