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 std::vector<std::string> NonISAExtFeatureVec; 241 242 auto IsNonISAExtFeature = [](const std::string &Feature) { 243 assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-')); 244 StringRef Ext = StringRef(Feature).drop_front(); // drop the +/- 245 return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext); 246 }; 247 llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec), 248 IsNonISAExtFeature); 249 250 return NonISAExtFeatureVec; 251 } 252 253 static std::vector<std::string> 254 resolveTargetAttrOverride(const std::vector<std::string> &FeaturesVec, 255 int XLen) { 256 auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride"); 257 if (I == FeaturesVec.end()) 258 return FeaturesVec; 259 260 ArrayRef<std::string> FeaturesNeedOverride(&*FeaturesVec.begin(), &*I); 261 std::vector<std::string> NonISAExtFeature = 262 collectNonISAExtFeature(FeaturesNeedOverride, XLen); 263 264 std::vector<std::string> ResolvedFeature(++I, FeaturesVec.end()); 265 ResolvedFeature.insert(ResolvedFeature.end(), NonISAExtFeature.begin(), 266 NonISAExtFeature.end()); 267 268 return ResolvedFeature; 269 } 270 271 bool RISCVTargetInfo::initFeatureMap( 272 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 273 const std::vector<std::string> &FeaturesVec) const { 274 275 unsigned XLen = 32; 276 277 if (getTriple().isRISCV64()) { 278 Features["64bit"] = true; 279 XLen = 64; 280 } else { 281 Features["32bit"] = true; 282 } 283 284 std::vector<std::string> NewFeaturesVec = 285 resolveTargetAttrOverride(FeaturesVec, XLen); 286 287 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, NewFeaturesVec); 288 if (!ParseResult) { 289 std::string Buffer; 290 llvm::raw_string_ostream OutputErrMsg(Buffer); 291 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 292 OutputErrMsg << ErrMsg.getMessage(); 293 }); 294 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 295 return false; 296 } 297 298 // RISCVISAInfo makes implications for ISA features 299 std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatures(); 300 301 // parseFeatures normalizes the feature set by dropping any explicit 302 // negatives, and non-extension features. We need to preserve the later 303 // for correctness and want to preserve the former for consistency. 304 for (auto &Feature : NewFeaturesVec) { 305 StringRef ExtName = Feature; 306 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); 307 ExtName = ExtName.drop_front(1); // Drop '+' or '-' 308 if (!llvm::is_contained(ImpliedFeatures, ("+" + ExtName).str()) && 309 !llvm::is_contained(ImpliedFeatures, ("-" + ExtName).str())) 310 ImpliedFeatures.push_back(Feature); 311 } 312 return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures); 313 } 314 315 std::optional<std::pair<unsigned, unsigned>> 316 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const { 317 // RISCV::RVVBitsPerBlock is 64. 318 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; 319 320 if (LangOpts.VScaleMin || LangOpts.VScaleMax) { 321 // Treat Zvl*b as a lower bound on vscale. 322 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin); 323 unsigned VScaleMax = LangOpts.VScaleMax; 324 if (VScaleMax != 0 && VScaleMax < VScaleMin) 325 VScaleMax = VScaleMin; 326 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); 327 } 328 329 if (VScaleMin > 0) { 330 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; 331 return std::make_pair(VScaleMin, VScaleMax); 332 } 333 334 return std::nullopt; 335 } 336 337 /// Return true if has this feature, need to sync with handleTargetFeatures. 338 bool RISCVTargetInfo::hasFeature(StringRef Feature) const { 339 bool Is64Bit = getTriple().isRISCV64(); 340 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) 341 .Case("riscv", true) 342 .Case("riscv32", !Is64Bit) 343 .Case("riscv64", Is64Bit) 344 .Case("32bit", !Is64Bit) 345 .Case("64bit", Is64Bit) 346 .Case("experimental", HasExperimental) 347 .Default(std::nullopt); 348 if (Result) 349 return *Result; 350 351 return ISAInfo->hasExtension(Feature); 352 } 353 354 /// Perform initialization based on the user configured set of features. 355 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, 356 DiagnosticsEngine &Diags) { 357 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; 358 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); 359 if (!ParseResult) { 360 std::string Buffer; 361 llvm::raw_string_ostream OutputErrMsg(Buffer); 362 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 363 OutputErrMsg << ErrMsg.getMessage(); 364 }); 365 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 366 return false; 367 } else { 368 ISAInfo = std::move(*ParseResult); 369 } 370 371 if (ABI.empty()) 372 ABI = ISAInfo->computeDefaultABI().str(); 373 374 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx")) 375 HasLegalHalfType = true; 376 377 FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access"); 378 379 if (llvm::is_contained(Features, "+experimental")) 380 HasExperimental = true; 381 382 return true; 383 } 384 385 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { 386 bool Is64Bit = getTriple().isArch64Bit(); 387 return llvm::RISCV::parseCPU(Name, Is64Bit); 388 } 389 390 void RISCVTargetInfo::fillValidCPUList( 391 SmallVectorImpl<StringRef> &Values) const { 392 bool Is64Bit = getTriple().isArch64Bit(); 393 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit); 394 } 395 396 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { 397 bool Is64Bit = getTriple().isArch64Bit(); 398 return llvm::RISCV::parseTuneCPU(Name, Is64Bit); 399 } 400 401 void RISCVTargetInfo::fillValidTuneCPUList( 402 SmallVectorImpl<StringRef> &Values) const { 403 bool Is64Bit = getTriple().isArch64Bit(); 404 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); 405 } 406 407 static void handleFullArchString(StringRef FullArchStr, 408 std::vector<std::string> &Features) { 409 Features.push_back("__RISCV_TargetAttrNeedOverride"); 410 auto RII = llvm::RISCVISAInfo::parseArchString( 411 FullArchStr, /* EnableExperimentalExtension */ true); 412 if (llvm::errorToBool(RII.takeError())) { 413 // Forward the invalid FullArchStr. 414 Features.push_back("+" + FullArchStr.str()); 415 } else { 416 std::vector<std::string> FeatStrings = (*RII)->toFeatures(); 417 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); 418 } 419 } 420 421 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { 422 ParsedTargetAttr Ret; 423 if (Features == "default") 424 return Ret; 425 SmallVector<StringRef, 1> AttrFeatures; 426 Features.split(AttrFeatures, ";"); 427 bool FoundArch = false; 428 429 for (auto &Feature : AttrFeatures) { 430 Feature = Feature.trim(); 431 StringRef AttrString = Feature.split("=").second.trim(); 432 433 if (Feature.starts_with("arch=")) { 434 // Override last features 435 Ret.Features.clear(); 436 if (FoundArch) 437 Ret.Duplicate = "arch="; 438 FoundArch = true; 439 440 if (AttrString.starts_with("+")) { 441 // EXTENSION like arch=+v,+zbb 442 SmallVector<StringRef, 1> Exts; 443 AttrString.split(Exts, ","); 444 for (auto Ext : Exts) { 445 if (Ext.empty()) 446 continue; 447 448 StringRef ExtName = Ext.substr(1); 449 std::string TargetFeature = 450 llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName); 451 if (!TargetFeature.empty()) 452 Ret.Features.push_back(Ext.front() + TargetFeature); 453 else 454 Ret.Features.push_back(Ext.str()); 455 } 456 } else { 457 // full-arch-string like arch=rv64gcv 458 handleFullArchString(AttrString, Ret.Features); 459 } 460 } else if (Feature.starts_with("cpu=")) { 461 if (!Ret.CPU.empty()) 462 Ret.Duplicate = "cpu="; 463 464 Ret.CPU = AttrString; 465 466 if (!FoundArch) { 467 // Update Features with CPU's features 468 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); 469 if (MarchFromCPU != "") { 470 Ret.Features.clear(); 471 handleFullArchString(MarchFromCPU, Ret.Features); 472 } 473 } 474 } else if (Feature.starts_with("tune=")) { 475 if (!Ret.Tune.empty()) 476 Ret.Duplicate = "tune="; 477 478 Ret.Tune = AttrString; 479 } 480 } 481 return Ret; 482 } 483