1 //===--- LoongArch.cpp - Implement LoongArch 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 LoongArch TargetInfo objects. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "LoongArch.h" 14 #include "clang/Basic/Diagnostic.h" 15 #include "clang/Basic/MacroBuilder.h" 16 #include "clang/Basic/TargetBuiltins.h" 17 #include "llvm/TargetParser/LoongArchTargetParser.h" 18 19 using namespace clang; 20 using namespace clang::targets; 21 22 ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const { 23 static const char *const GCCRegNames[] = { 24 // General purpose registers. 25 "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", 26 "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18", 27 "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27", 28 "$r28", "$r29", "$r30", "$r31", 29 // Floating point registers. 30 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", 31 "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", 32 "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", 33 "$f28", "$f29", "$f30", "$f31", 34 // Condition flag registers. 35 "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", 36 // 128-bit vector registers. 37 "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", "$vr7", "$vr8", 38 "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr14", "$vr15", "$vr16", 39 "$vr17", "$vr18", "$vr19", "$vr20", "$vr21", "$vr22", "$vr23", "$vr24", 40 "$vr25", "$vr26", "$vr27", "$vr28", "$vr29", "$vr30", "$vr31", 41 // 256-bit vector registers. 42 "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", "$xr7", "$xr8", 43 "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", "$xr15", "$xr16", 44 "$xr17", "$xr18", "$xr19", "$xr20", "$xr21", "$xr22", "$xr23", "$xr24", 45 "$xr25", "$xr26", "$xr27", "$xr28", "$xr29", "$xr30", "$xr31"}; 46 return llvm::ArrayRef(GCCRegNames); 47 } 48 49 ArrayRef<TargetInfo::GCCRegAlias> 50 LoongArchTargetInfo::getGCCRegAliases() const { 51 static const TargetInfo::GCCRegAlias GCCRegAliases[] = { 52 {{"zero", "$zero", "r0"}, "$r0"}, 53 {{"ra", "$ra", "r1"}, "$r1"}, 54 {{"tp", "$tp", "r2"}, "$r2"}, 55 {{"sp", "$sp", "r3"}, "$r3"}, 56 {{"a0", "$a0", "r4"}, "$r4"}, 57 {{"a1", "$a1", "r5"}, "$r5"}, 58 {{"a2", "$a2", "r6"}, "$r6"}, 59 {{"a3", "$a3", "r7"}, "$r7"}, 60 {{"a4", "$a4", "r8"}, "$r8"}, 61 {{"a5", "$a5", "r9"}, "$r9"}, 62 {{"a6", "$a6", "r10"}, "$r10"}, 63 {{"a7", "$a7", "r11"}, "$r11"}, 64 {{"t0", "$t0", "r12"}, "$r12"}, 65 {{"t1", "$t1", "r13"}, "$r13"}, 66 {{"t2", "$t2", "r14"}, "$r14"}, 67 {{"t3", "$t3", "r15"}, "$r15"}, 68 {{"t4", "$t4", "r16"}, "$r16"}, 69 {{"t5", "$t5", "r17"}, "$r17"}, 70 {{"t6", "$t6", "r18"}, "$r18"}, 71 {{"t7", "$t7", "r19"}, "$r19"}, 72 {{"t8", "$t8", "r20"}, "$r20"}, 73 {{"r21"}, "$r21"}, 74 {{"s9", "$s9", "r22", "fp", "$fp"}, "$r22"}, 75 {{"s0", "$s0", "r23"}, "$r23"}, 76 {{"s1", "$s1", "r24"}, "$r24"}, 77 {{"s2", "$s2", "r25"}, "$r25"}, 78 {{"s3", "$s3", "r26"}, "$r26"}, 79 {{"s4", "$s4", "r27"}, "$r27"}, 80 {{"s5", "$s5", "r28"}, "$r28"}, 81 {{"s6", "$s6", "r29"}, "$r29"}, 82 {{"s7", "$s7", "r30"}, "$r30"}, 83 {{"s8", "$s8", "r31"}, "$r31"}, 84 {{"fa0", "$fa0", "f0"}, "$f0"}, 85 {{"fa1", "$fa1", "f1"}, "$f1"}, 86 {{"fa2", "$fa2", "f2"}, "$f2"}, 87 {{"fa3", "$fa3", "f3"}, "$f3"}, 88 {{"fa4", "$fa4", "f4"}, "$f4"}, 89 {{"fa5", "$fa5", "f5"}, "$f5"}, 90 {{"fa6", "$fa6", "f6"}, "$f6"}, 91 {{"fa7", "$fa7", "f7"}, "$f7"}, 92 {{"ft0", "$ft0", "f8"}, "$f8"}, 93 {{"ft1", "$ft1", "f9"}, "$f9"}, 94 {{"ft2", "$ft2", "f10"}, "$f10"}, 95 {{"ft3", "$ft3", "f11"}, "$f11"}, 96 {{"ft4", "$ft4", "f12"}, "$f12"}, 97 {{"ft5", "$ft5", "f13"}, "$f13"}, 98 {{"ft6", "$ft6", "f14"}, "$f14"}, 99 {{"ft7", "$ft7", "f15"}, "$f15"}, 100 {{"ft8", "$ft8", "f16"}, "$f16"}, 101 {{"ft9", "$ft9", "f17"}, "$f17"}, 102 {{"ft10", "$ft10", "f18"}, "$f18"}, 103 {{"ft11", "$ft11", "f19"}, "$f19"}, 104 {{"ft12", "$ft12", "f20"}, "$f20"}, 105 {{"ft13", "$ft13", "f21"}, "$f21"}, 106 {{"ft14", "$ft14", "f22"}, "$f22"}, 107 {{"ft15", "$ft15", "f23"}, "$f23"}, 108 {{"fs0", "$fs0", "f24"}, "$f24"}, 109 {{"fs1", "$fs1", "f25"}, "$f25"}, 110 {{"fs2", "$fs2", "f26"}, "$f26"}, 111 {{"fs3", "$fs3", "f27"}, "$f27"}, 112 {{"fs4", "$fs4", "f28"}, "$f28"}, 113 {{"fs5", "$fs5", "f29"}, "$f29"}, 114 {{"fs6", "$fs6", "f30"}, "$f30"}, 115 {{"fs7", "$fs7", "f31"}, "$f31"}, 116 {{"fcc0"}, "$fcc0"}, 117 {{"fcc1"}, "$fcc1"}, 118 {{"fcc2"}, "$fcc2"}, 119 {{"fcc3"}, "$fcc3"}, 120 {{"fcc4"}, "$fcc4"}, 121 {{"fcc5"}, "$fcc5"}, 122 {{"fcc6"}, "$fcc6"}, 123 {{"fcc7"}, "$fcc7"}, 124 }; 125 return llvm::ArrayRef(GCCRegAliases); 126 } 127 128 bool LoongArchTargetInfo::validateAsmConstraint( 129 const char *&Name, TargetInfo::ConstraintInfo &Info) const { 130 // See the GCC definitions here: 131 // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html 132 // Note that the 'm' constraint is handled in TargetInfo. 133 switch (*Name) { 134 default: 135 return false; 136 case 'f': 137 // A floating-point register (if available). 138 Info.setAllowsRegister(); 139 return true; 140 case 'k': 141 // A memory operand whose address is formed by a base register and 142 // (optionally scaled) index register. 143 Info.setAllowsMemory(); 144 return true; 145 case 'l': 146 // A signed 16-bit constant. 147 Info.setRequiresImmediate(-32768, 32767); 148 return true; 149 case 'q': 150 // A general-purpose register except for $r0 and $r1 (for the csrxchg 151 // instruction) 152 Info.setAllowsRegister(); 153 return true; 154 case 'I': 155 // A signed 12-bit constant (for arithmetic instructions). 156 Info.setRequiresImmediate(-2048, 2047); 157 return true; 158 case 'J': 159 // Integer zero. 160 Info.setRequiresImmediate(0); 161 return true; 162 case 'K': 163 // An unsigned 12-bit constant (for logic instructions). 164 Info.setRequiresImmediate(0, 4095); 165 return true; 166 case 'Z': 167 // ZB: An address that is held in a general-purpose register. The offset is 168 // zero. 169 // ZC: A memory operand whose address is formed by a base register 170 // and offset that is suitable for use in instructions with the same 171 // addressing mode as ll.w and sc.w. 172 if (Name[1] == 'C' || Name[1] == 'B') { 173 Info.setAllowsMemory(); 174 ++Name; // Skip over 'Z'. 175 return true; 176 } 177 return false; 178 } 179 } 180 181 std::string 182 LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { 183 std::string R; 184 switch (*Constraint) { 185 case 'Z': 186 // "ZC"/"ZB" are two-character constraints; add "^" hint for later 187 // parsing. 188 R = "^" + std::string(Constraint, 2); 189 ++Constraint; 190 break; 191 default: 192 R = TargetInfo::convertConstraint(Constraint); 193 break; 194 } 195 return R; 196 } 197 198 void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, 199 MacroBuilder &Builder) const { 200 Builder.defineMacro("__loongarch__"); 201 unsigned GRLen = getRegisterWidth(); 202 Builder.defineMacro("__loongarch_grlen", Twine(GRLen)); 203 if (GRLen == 64) 204 Builder.defineMacro("__loongarch64"); 205 206 if (HasFeatureD) 207 Builder.defineMacro("__loongarch_frlen", "64"); 208 else if (HasFeatureF) 209 Builder.defineMacro("__loongarch_frlen", "32"); 210 else 211 Builder.defineMacro("__loongarch_frlen", "0"); 212 213 // Define __loongarch_arch. 214 StringRef ArchName = getCPU(); 215 if (ArchName == "loongarch64") { 216 if (HasFeatureLSX) { 217 // TODO: As more features of the V1.1 ISA are supported, a unified "v1.1" 218 // arch feature set will be used to include all sub-features belonging to 219 // the V1.1 ISA version. 220 if (HasFeatureFrecipe && HasFeatureLAM_BH && HasFeatureLAMCAS && 221 HasFeatureLD_SEQ_SA && HasFeatureDiv32 && HasFeatureSCQ) 222 Builder.defineMacro("__loongarch_arch", 223 Twine('"') + "la64v1.1" + Twine('"')); 224 else 225 Builder.defineMacro("__loongarch_arch", 226 Twine('"') + "la64v1.0" + Twine('"')); 227 } else { 228 Builder.defineMacro("__loongarch_arch", 229 Twine('"') + ArchName + Twine('"')); 230 } 231 } else { 232 Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"')); 233 } 234 235 // Define __loongarch_tune. 236 StringRef TuneCPU = getTargetOpts().TuneCPU; 237 if (TuneCPU.empty()) 238 TuneCPU = ArchName; 239 Builder.defineMacro("__loongarch_tune", Twine('"') + TuneCPU + Twine('"')); 240 241 if (HasFeatureLASX) { 242 Builder.defineMacro("__loongarch_simd_width", "256"); 243 Builder.defineMacro("__loongarch_sx", Twine(1)); 244 Builder.defineMacro("__loongarch_asx", Twine(1)); 245 } else if (HasFeatureLSX) { 246 Builder.defineMacro("__loongarch_simd_width", "128"); 247 Builder.defineMacro("__loongarch_sx", Twine(1)); 248 } 249 if (HasFeatureFrecipe) 250 Builder.defineMacro("__loongarch_frecipe", Twine(1)); 251 252 if (HasFeatureLAM_BH) 253 Builder.defineMacro("__loongarch_lam_bh", Twine(1)); 254 255 if (HasFeatureLAMCAS) 256 Builder.defineMacro("__loongarch_lamcas", Twine(1)); 257 258 if (HasFeatureLD_SEQ_SA) 259 Builder.defineMacro("__loongarch_ld_seq_sa", Twine(1)); 260 261 if (HasFeatureDiv32) 262 Builder.defineMacro("__loongarch_div32", Twine(1)); 263 264 if (HasFeatureSCQ) 265 Builder.defineMacro("__loongarch_scq", Twine(1)); 266 267 StringRef ABI = getABI(); 268 if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") 269 Builder.defineMacro("__loongarch_lp64"); 270 271 if (ABI == "lp64d" || ABI == "ilp32d") { 272 Builder.defineMacro("__loongarch_hard_float"); 273 Builder.defineMacro("__loongarch_double_float"); 274 } else if (ABI == "lp64f" || ABI == "ilp32f") { 275 Builder.defineMacro("__loongarch_hard_float"); 276 Builder.defineMacro("__loongarch_single_float"); 277 } else if (ABI == "lp64s" || ABI == "ilp32s") { 278 Builder.defineMacro("__loongarch_soft_float"); 279 } 280 281 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 282 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 283 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 284 if (GRLen == 64) 285 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 286 } 287 288 static constexpr int NumBaseBuiltins = 289 LoongArch::FirstLSXBuiltin - Builtin::FirstTSBuiltin; 290 static constexpr int NumLSXBuiltins = 291 LoongArch::FirstLASXBuiltin - LoongArch::FirstLSXBuiltin; 292 static constexpr int NumLASXBuiltins = 293 LoongArch::LastTSBuiltin - LoongArch::FirstLASXBuiltin; 294 static constexpr int NumBuiltins = 295 LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin; 296 static_assert(NumBuiltins == 297 (NumBaseBuiltins + NumLSXBuiltins + NumLASXBuiltins)); 298 299 static constexpr llvm::StringTable BuiltinBaseStrings = 300 CLANG_BUILTIN_STR_TABLE_START 301 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE 302 #include "clang/Basic/BuiltinsLoongArchBase.def" 303 #undef TARGET_BUILTIN 304 ; 305 306 static constexpr auto BuiltinBaseInfos = Builtin::MakeInfos<NumBaseBuiltins>({ 307 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY 308 #include "clang/Basic/BuiltinsLoongArchBase.def" 309 #undef TARGET_BUILTIN 310 }); 311 312 static constexpr llvm::StringTable BuiltinLSXStrings = 313 CLANG_BUILTIN_STR_TABLE_START 314 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE 315 #include "clang/Basic/BuiltinsLoongArchLSX.def" 316 #undef TARGET_BUILTIN 317 ; 318 319 static constexpr auto BuiltinLSXInfos = Builtin::MakeInfos<NumLSXBuiltins>({ 320 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY 321 #include "clang/Basic/BuiltinsLoongArchLSX.def" 322 #undef TARGET_BUILTIN 323 }); 324 325 static constexpr llvm::StringTable BuiltinLASXStrings = 326 CLANG_BUILTIN_STR_TABLE_START 327 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE 328 #include "clang/Basic/BuiltinsLoongArchLASX.def" 329 #undef TARGET_BUILTIN 330 ; 331 332 static constexpr auto BuiltinLASXInfos = Builtin::MakeInfos<NumLASXBuiltins>({ 333 #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY 334 #include "clang/Basic/BuiltinsLoongArchLASX.def" 335 #undef TARGET_BUILTIN 336 }); 337 338 bool LoongArchTargetInfo::initFeatureMap( 339 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 340 const std::vector<std::string> &FeaturesVec) const { 341 if (getTriple().getArch() == llvm::Triple::loongarch64) 342 Features["64bit"] = true; 343 if (getTriple().getArch() == llvm::Triple::loongarch32) 344 Features["32bit"] = true; 345 346 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 347 } 348 349 /// Return true if has this feature. 350 bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { 351 bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; 352 // TODO: Handle more features. 353 return llvm::StringSwitch<bool>(Feature) 354 .Case("loongarch32", !Is64Bit) 355 .Case("loongarch64", Is64Bit) 356 .Case("32bit", !Is64Bit) 357 .Case("64bit", Is64Bit) 358 .Case("lsx", HasFeatureLSX) 359 .Case("lasx", HasFeatureLASX) 360 .Default(false); 361 } 362 363 llvm::SmallVector<Builtin::InfosShard> 364 LoongArchTargetInfo::getTargetBuiltins() const { 365 return { 366 {&BuiltinBaseStrings, BuiltinBaseInfos}, 367 {&BuiltinLSXStrings, BuiltinLSXInfos}, 368 {&BuiltinLASXStrings, BuiltinLASXInfos}, 369 }; 370 } 371 372 bool LoongArchTargetInfo::handleTargetFeatures( 373 std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 374 for (const auto &Feature : Features) { 375 if (Feature == "+d" || Feature == "+f") { 376 // "d" implies "f". 377 HasFeatureF = true; 378 if (Feature == "+d") { 379 HasFeatureD = true; 380 } 381 } else if (Feature == "+lsx") 382 HasFeatureLSX = true; 383 else if (Feature == "+lasx") 384 HasFeatureLASX = true; 385 else if (Feature == "-ual") 386 HasUnalignedAccess = false; 387 else if (Feature == "+frecipe") 388 HasFeatureFrecipe = true; 389 else if (Feature == "+lam-bh") 390 HasFeatureLAM_BH = true; 391 else if (Feature == "+lamcas") 392 HasFeatureLAMCAS = true; 393 else if (Feature == "+ld-seq-sa") 394 HasFeatureLD_SEQ_SA = true; 395 else if (Feature == "+div32") 396 HasFeatureDiv32 = true; 397 else if (Feature == "+scq") 398 HasFeatureSCQ = true; 399 } 400 return true; 401 } 402 403 enum class AttrFeatureKind { Arch, Tune, NoFeature, Feature }; 404 405 static std::pair<AttrFeatureKind, llvm::StringRef> 406 getAttrFeatureTypeAndValue(llvm::StringRef AttrFeature) { 407 if (auto Split = AttrFeature.split("="); !Split.second.empty()) { 408 if (Split.first.trim() == "arch") 409 return {AttrFeatureKind::Arch, Split.second.trim()}; 410 if (Split.first.trim() == "tune") 411 return {AttrFeatureKind::Tune, Split.second.trim()}; 412 } 413 if (AttrFeature.starts_with("no-")) 414 return {AttrFeatureKind::NoFeature, AttrFeature.drop_front(3)}; 415 return {AttrFeatureKind::Feature, AttrFeature}; 416 } 417 418 ParsedTargetAttr 419 LoongArchTargetInfo::parseTargetAttr(StringRef Features) const { 420 ParsedTargetAttr Ret; 421 if (Features == "default") 422 return Ret; 423 SmallVector<StringRef, 1> AttrFeatures; 424 Features.split(AttrFeatures, ","); 425 426 for (auto &Feature : AttrFeatures) { 427 auto [Kind, Value] = getAttrFeatureTypeAndValue(Feature.trim()); 428 429 switch (Kind) { 430 case AttrFeatureKind::Arch: { 431 if (llvm::LoongArch::isValidArchName(Value) || Value == "la64v1.0" || 432 Value == "la64v1.1") { 433 std::vector<llvm::StringRef> ArchFeatures; 434 if (llvm::LoongArch::getArchFeatures(Value, ArchFeatures)) { 435 Ret.Features.insert(Ret.Features.end(), ArchFeatures.begin(), 436 ArchFeatures.end()); 437 } 438 439 if (!Ret.CPU.empty()) 440 Ret.Duplicate = "arch="; 441 else if (Value == "la64v1.0" || Value == "la64v1.1") 442 Ret.CPU = "loongarch64"; 443 else 444 Ret.CPU = Value; 445 } else { 446 Ret.Features.push_back("!arch=" + Value.str()); 447 } 448 break; 449 } 450 451 case AttrFeatureKind::Tune: 452 if (!Ret.Tune.empty()) 453 Ret.Duplicate = "tune="; 454 else 455 Ret.Tune = Value; 456 break; 457 458 case AttrFeatureKind::NoFeature: 459 Ret.Features.push_back("-" + Value.str()); 460 break; 461 462 case AttrFeatureKind::Feature: 463 Ret.Features.push_back("+" + Value.str()); 464 if (Value == "lasx") 465 Ret.Features.push_back("+lsx"); 466 break; 467 } 468 } 469 return Ret; 470 } 471 472 bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const { 473 return llvm::LoongArch::isValidCPUName(Name); 474 } 475 476 void LoongArchTargetInfo::fillValidCPUList( 477 SmallVectorImpl<StringRef> &Values) const { 478 llvm::LoongArch::fillValidCPUList(Values); 479 } 480 481 bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const { 482 return llvm::LoongArch::isValidFeatureName(Name); 483 } 484