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" || ABIName == "lp64e") 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(Twine("__riscv_", ExtName), 167 Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor))); 168 } 169 170 if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul")) 171 Builder.defineMacro("__riscv_mul"); 172 173 if (ISAInfo->hasExtension("m")) { 174 Builder.defineMacro("__riscv_div"); 175 Builder.defineMacro("__riscv_muldiv"); 176 } 177 178 if (ISAInfo->hasExtension("a")) { 179 Builder.defineMacro("__riscv_atomic"); 180 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 181 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 182 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 183 if (Is64Bit) 184 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 185 } 186 187 if (FLen) { 188 Builder.defineMacro("__riscv_flen", Twine(FLen)); 189 Builder.defineMacro("__riscv_fdiv"); 190 Builder.defineMacro("__riscv_fsqrt"); 191 } 192 193 if (MinVLen) { 194 Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); 195 Builder.defineMacro("__riscv_v_elen", Twine(MaxELen)); 196 Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp)); 197 } 198 199 if (ISAInfo->hasExtension("c")) 200 Builder.defineMacro("__riscv_compressed"); 201 202 if (ISAInfo->hasExtension("zve32x")) { 203 Builder.defineMacro("__riscv_vector"); 204 // Currently we support the v0.12 RISC-V V intrinsics. 205 Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12))); 206 } 207 208 auto VScale = getVScaleRange(Opts); 209 if (VScale && VScale->first && VScale->first == VScale->second) 210 Builder.defineMacro("__riscv_v_fixed_vlen", 211 Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock)); 212 213 if (FastUnalignedAccess) 214 Builder.defineMacro("__riscv_misaligned_fast"); 215 else 216 Builder.defineMacro("__riscv_misaligned_avoid"); 217 218 if (ISAInfo->hasExtension("e")) { 219 if (Is64Bit) 220 Builder.defineMacro("__riscv_64e"); 221 else 222 Builder.defineMacro("__riscv_32e"); 223 } 224 } 225 226 static constexpr Builtin::Info BuiltinInfo[] = { 227 #define BUILTIN(ID, TYPE, ATTRS) \ 228 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 229 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 230 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 231 #include "clang/Basic/BuiltinsRISCVVector.def" 232 #define BUILTIN(ID, TYPE, ATTRS) \ 233 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 234 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 235 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 236 #include "clang/Basic/BuiltinsRISCV.def" 237 }; 238 239 ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { 240 return llvm::ArrayRef(BuiltinInfo, 241 clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); 242 } 243 244 bool RISCVTargetInfo::initFeatureMap( 245 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 246 const std::vector<std::string> &FeaturesVec) const { 247 248 unsigned XLen = 32; 249 250 if (getTriple().isRISCV64()) { 251 Features["64bit"] = true; 252 XLen = 64; 253 } else { 254 Features["32bit"] = true; 255 } 256 257 // If a target attribute specified a full arch string, override all the ISA 258 // extension target features. 259 const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride"); 260 if (I != FeaturesVec.end()) { 261 std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end()); 262 263 // Add back any non ISA extension features, e.g. +relax. 264 auto IsNonISAExtFeature = [](StringRef Feature) { 265 assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-')); 266 StringRef Ext = Feature.substr(1); // drop the +/- 267 return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext); 268 }; 269 llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I), 270 std::back_inserter(OverrideFeatures), IsNonISAExtFeature); 271 272 return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures); 273 } 274 275 // Otherwise, parse the features and add any implied extensions. 276 std::vector<std::string> AllFeatures = FeaturesVec; 277 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec); 278 if (!ParseResult) { 279 std::string Buffer; 280 llvm::raw_string_ostream OutputErrMsg(Buffer); 281 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 282 OutputErrMsg << ErrMsg.getMessage(); 283 }); 284 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 285 return false; 286 } 287 288 // Append all features, not just new ones, so we override any negatives. 289 llvm::append_range(AllFeatures, (*ParseResult)->toFeatures()); 290 return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures); 291 } 292 293 std::optional<std::pair<unsigned, unsigned>> 294 RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const { 295 // RISCV::RVVBitsPerBlock is 64. 296 unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock; 297 298 if (LangOpts.VScaleMin || LangOpts.VScaleMax) { 299 // Treat Zvl*b as a lower bound on vscale. 300 VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin); 301 unsigned VScaleMax = LangOpts.VScaleMax; 302 if (VScaleMax != 0 && VScaleMax < VScaleMin) 303 VScaleMax = VScaleMin; 304 return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax); 305 } 306 307 if (VScaleMin > 0) { 308 unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock; 309 return std::make_pair(VScaleMin, VScaleMax); 310 } 311 312 return std::nullopt; 313 } 314 315 /// Return true if has this feature, need to sync with handleTargetFeatures. 316 bool RISCVTargetInfo::hasFeature(StringRef Feature) const { 317 bool Is64Bit = getTriple().isRISCV64(); 318 auto Result = llvm::StringSwitch<std::optional<bool>>(Feature) 319 .Case("riscv", true) 320 .Case("riscv32", !Is64Bit) 321 .Case("riscv64", Is64Bit) 322 .Case("32bit", !Is64Bit) 323 .Case("64bit", Is64Bit) 324 .Case("experimental", HasExperimental) 325 .Default(std::nullopt); 326 if (Result) 327 return *Result; 328 329 return ISAInfo->hasExtension(Feature); 330 } 331 332 /// Perform initialization based on the user configured set of features. 333 bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, 334 DiagnosticsEngine &Diags) { 335 unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; 336 auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); 337 if (!ParseResult) { 338 std::string Buffer; 339 llvm::raw_string_ostream OutputErrMsg(Buffer); 340 handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { 341 OutputErrMsg << ErrMsg.getMessage(); 342 }); 343 Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); 344 return false; 345 } else { 346 ISAInfo = std::move(*ParseResult); 347 } 348 349 if (ABI.empty()) 350 ABI = ISAInfo->computeDefaultABI().str(); 351 352 if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx")) 353 HasLegalHalfType = true; 354 355 FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access"); 356 357 if (llvm::is_contained(Features, "+experimental")) 358 HasExperimental = true; 359 360 if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) { 361 Diags.Report(diag::err_invalid_feature_combination) 362 << "ILP32E cannot be used with the D ISA extension"; 363 return false; 364 } 365 return true; 366 } 367 368 bool RISCVTargetInfo::isValidCPUName(StringRef Name) const { 369 bool Is64Bit = getTriple().isArch64Bit(); 370 return llvm::RISCV::parseCPU(Name, Is64Bit); 371 } 372 373 void RISCVTargetInfo::fillValidCPUList( 374 SmallVectorImpl<StringRef> &Values) const { 375 bool Is64Bit = getTriple().isArch64Bit(); 376 llvm::RISCV::fillValidCPUArchList(Values, Is64Bit); 377 } 378 379 bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const { 380 bool Is64Bit = getTriple().isArch64Bit(); 381 return llvm::RISCV::parseTuneCPU(Name, Is64Bit); 382 } 383 384 void RISCVTargetInfo::fillValidTuneCPUList( 385 SmallVectorImpl<StringRef> &Values) const { 386 bool Is64Bit = getTriple().isArch64Bit(); 387 llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit); 388 } 389 390 static void handleFullArchString(StringRef FullArchStr, 391 std::vector<std::string> &Features) { 392 Features.push_back("__RISCV_TargetAttrNeedOverride"); 393 auto RII = llvm::RISCVISAInfo::parseArchString( 394 FullArchStr, /* EnableExperimentalExtension */ true); 395 if (llvm::errorToBool(RII.takeError())) { 396 // Forward the invalid FullArchStr. 397 Features.push_back("+" + FullArchStr.str()); 398 } else { 399 // Append a full list of features, including any negative extensions so that 400 // we override the CPU's features. 401 std::vector<std::string> FeatStrings = 402 (*RII)->toFeatures(/* AddAllExtensions */ true); 403 Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end()); 404 } 405 } 406 407 ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { 408 ParsedTargetAttr Ret; 409 if (Features == "default") 410 return Ret; 411 SmallVector<StringRef, 1> AttrFeatures; 412 Features.split(AttrFeatures, ";"); 413 bool FoundArch = false; 414 415 for (auto &Feature : AttrFeatures) { 416 Feature = Feature.trim(); 417 StringRef AttrString = Feature.split("=").second.trim(); 418 419 if (Feature.starts_with("arch=")) { 420 // Override last features 421 Ret.Features.clear(); 422 if (FoundArch) 423 Ret.Duplicate = "arch="; 424 FoundArch = true; 425 426 if (AttrString.starts_with("+")) { 427 // EXTENSION like arch=+v,+zbb 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 Ret.Features.push_back(Ext.front() + TargetFeature); 439 else 440 Ret.Features.push_back(Ext.str()); 441 } 442 } else { 443 // full-arch-string like arch=rv64gcv 444 handleFullArchString(AttrString, Ret.Features); 445 } 446 } else if (Feature.starts_with("cpu=")) { 447 if (!Ret.CPU.empty()) 448 Ret.Duplicate = "cpu="; 449 450 Ret.CPU = AttrString; 451 452 if (!FoundArch) { 453 // Update Features with CPU's features 454 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU); 455 if (MarchFromCPU != "") { 456 Ret.Features.clear(); 457 handleFullArchString(MarchFromCPU, Ret.Features); 458 } 459 } 460 } else if (Feature.starts_with("tune=")) { 461 if (!Ret.Tune.empty()) 462 Ret.Duplicate = "tune="; 463 464 Ret.Tune = AttrString; 465 } 466 } 467 return Ret; 468 } 469