485 lines · cpp
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-exception6//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 19using namespace clang;20using namespace clang::targets;21 22ArrayRef<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 49ArrayRef<TargetInfo::GCCRegAlias>50LoongArchTargetInfo::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 128bool 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.html132 // 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 and142 // (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 csrxchg151 // 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 is168 // zero.169 // ZC: A memory operand whose address is formed by a base register170 // and offset that is suitable for use in instructions with the same171 // 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 181std::string182LoongArchTargetInfo::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 later187 // 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 198void 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 else211 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 to219 // 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 else225 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 Builder.defineMacro("__loongarch_asx_sx_conv", Twine(1));246 } else if (HasFeatureLSX) {247 Builder.defineMacro("__loongarch_simd_width", "128");248 Builder.defineMacro("__loongarch_sx", Twine(1));249 }250 if (HasFeatureFrecipe)251 Builder.defineMacro("__loongarch_frecipe", Twine(1));252 253 if (HasFeatureLAM_BH)254 Builder.defineMacro("__loongarch_lam_bh", Twine(1));255 256 if (HasFeatureLAMCAS)257 Builder.defineMacro("__loongarch_lamcas", Twine(1));258 259 if (HasFeatureLD_SEQ_SA)260 Builder.defineMacro("__loongarch_ld_seq_sa", Twine(1));261 262 if (HasFeatureDiv32)263 Builder.defineMacro("__loongarch_div32", Twine(1));264 265 if (HasFeatureSCQ)266 Builder.defineMacro("__loongarch_scq", Twine(1));267 268 StringRef ABI = getABI();269 if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")270 Builder.defineMacro("__loongarch_lp64");271 272 if (ABI == "lp64d" || ABI == "ilp32d") {273 Builder.defineMacro("__loongarch_hard_float");274 Builder.defineMacro("__loongarch_double_float");275 } else if (ABI == "lp64f" || ABI == "ilp32f") {276 Builder.defineMacro("__loongarch_hard_float");277 Builder.defineMacro("__loongarch_single_float");278 } else if (ABI == "lp64s" || ABI == "ilp32s") {279 Builder.defineMacro("__loongarch_soft_float");280 }281 282 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");283 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");284 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");285 if (GRLen == 64)286 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");287}288 289static constexpr int NumBaseBuiltins =290 LoongArch::FirstLSXBuiltin - Builtin::FirstTSBuiltin;291static constexpr int NumLSXBuiltins =292 LoongArch::FirstLASXBuiltin - LoongArch::FirstLSXBuiltin;293static constexpr int NumLASXBuiltins =294 LoongArch::LastTSBuiltin - LoongArch::FirstLASXBuiltin;295static constexpr int NumBuiltins =296 LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin;297static_assert(NumBuiltins ==298 (NumBaseBuiltins + NumLSXBuiltins + NumLASXBuiltins));299 300static constexpr llvm::StringTable BuiltinBaseStrings =301 CLANG_BUILTIN_STR_TABLE_START302#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE303#include "clang/Basic/BuiltinsLoongArchBase.def"304#undef TARGET_BUILTIN305 ;306 307static constexpr auto BuiltinBaseInfos = Builtin::MakeInfos<NumBaseBuiltins>({308#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY309#include "clang/Basic/BuiltinsLoongArchBase.def"310#undef TARGET_BUILTIN311});312 313static constexpr llvm::StringTable BuiltinLSXStrings =314 CLANG_BUILTIN_STR_TABLE_START315#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE316#include "clang/Basic/BuiltinsLoongArchLSX.def"317#undef TARGET_BUILTIN318 ;319 320static constexpr auto BuiltinLSXInfos = Builtin::MakeInfos<NumLSXBuiltins>({321#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY322#include "clang/Basic/BuiltinsLoongArchLSX.def"323#undef TARGET_BUILTIN324});325 326static constexpr llvm::StringTable BuiltinLASXStrings =327 CLANG_BUILTIN_STR_TABLE_START328#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE329#include "clang/Basic/BuiltinsLoongArchLASX.def"330#undef TARGET_BUILTIN331 ;332 333static constexpr auto BuiltinLASXInfos = Builtin::MakeInfos<NumLASXBuiltins>({334#define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY335#include "clang/Basic/BuiltinsLoongArchLASX.def"336#undef TARGET_BUILTIN337});338 339bool LoongArchTargetInfo::initFeatureMap(340 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,341 const std::vector<std::string> &FeaturesVec) const {342 if (getTriple().getArch() == llvm::Triple::loongarch64)343 Features["64bit"] = true;344 if (getTriple().getArch() == llvm::Triple::loongarch32)345 Features["32bit"] = true;346 347 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);348}349 350/// Return true if has this feature.351bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {352 bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;353 // TODO: Handle more features.354 return llvm::StringSwitch<bool>(Feature)355 .Case("loongarch32", !Is64Bit)356 .Case("loongarch64", Is64Bit)357 .Case("32bit", !Is64Bit)358 .Case("64bit", Is64Bit)359 .Case("lsx", HasFeatureLSX)360 .Case("lasx", HasFeatureLASX)361 .Default(false);362}363 364llvm::SmallVector<Builtin::InfosShard>365LoongArchTargetInfo::getTargetBuiltins() const {366 return {367 {&BuiltinBaseStrings, BuiltinBaseInfos},368 {&BuiltinLSXStrings, BuiltinLSXInfos},369 {&BuiltinLASXStrings, BuiltinLASXInfos},370 };371}372 373bool LoongArchTargetInfo::handleTargetFeatures(374 std::vector<std::string> &Features, DiagnosticsEngine &Diags) {375 for (const auto &Feature : Features) {376 if (Feature == "+d" || Feature == "+f") {377 // "d" implies "f".378 HasFeatureF = true;379 if (Feature == "+d") {380 HasFeatureD = true;381 }382 } else if (Feature == "+lsx")383 HasFeatureLSX = true;384 else if (Feature == "+lasx")385 HasFeatureLASX = true;386 else if (Feature == "-ual")387 HasUnalignedAccess = false;388 else if (Feature == "+frecipe")389 HasFeatureFrecipe = true;390 else if (Feature == "+lam-bh")391 HasFeatureLAM_BH = true;392 else if (Feature == "+lamcas")393 HasFeatureLAMCAS = true;394 else if (Feature == "+ld-seq-sa")395 HasFeatureLD_SEQ_SA = true;396 else if (Feature == "+div32")397 HasFeatureDiv32 = true;398 else if (Feature == "+scq")399 HasFeatureSCQ = true;400 }401 return true;402}403 404enum class AttrFeatureKind { Arch, Tune, NoFeature, Feature };405 406static std::pair<AttrFeatureKind, llvm::StringRef>407getAttrFeatureTypeAndValue(llvm::StringRef AttrFeature) {408 if (auto Split = AttrFeature.split("="); !Split.second.empty()) {409 if (Split.first.trim() == "arch")410 return {AttrFeatureKind::Arch, Split.second.trim()};411 if (Split.first.trim() == "tune")412 return {AttrFeatureKind::Tune, Split.second.trim()};413 }414 if (AttrFeature.starts_with("no-"))415 return {AttrFeatureKind::NoFeature, AttrFeature.drop_front(3)};416 return {AttrFeatureKind::Feature, AttrFeature};417}418 419ParsedTargetAttr420LoongArchTargetInfo::parseTargetAttr(StringRef Features) const {421 ParsedTargetAttr Ret;422 if (Features == "default")423 return Ret;424 SmallVector<StringRef, 1> AttrFeatures;425 Features.split(AttrFeatures, ",");426 427 for (auto &Feature : AttrFeatures) {428 auto [Kind, Value] = getAttrFeatureTypeAndValue(Feature.trim());429 430 switch (Kind) {431 case AttrFeatureKind::Arch: {432 if (llvm::LoongArch::isValidArchName(Value) || Value == "la64v1.0" ||433 Value == "la64v1.1") {434 std::vector<llvm::StringRef> ArchFeatures;435 if (llvm::LoongArch::getArchFeatures(Value, ArchFeatures)) {436 Ret.Features.insert(Ret.Features.end(), ArchFeatures.begin(),437 ArchFeatures.end());438 }439 440 if (!Ret.CPU.empty())441 Ret.Duplicate = "arch=";442 else if (Value == "la64v1.0" || Value == "la64v1.1")443 Ret.CPU = "loongarch64";444 else445 Ret.CPU = Value;446 } else {447 Ret.Features.push_back("!arch=" + Value.str());448 }449 break;450 }451 452 case AttrFeatureKind::Tune:453 if (!Ret.Tune.empty())454 Ret.Duplicate = "tune=";455 else456 Ret.Tune = Value;457 break;458 459 case AttrFeatureKind::NoFeature:460 Ret.Features.push_back("-" + Value.str());461 break;462 463 case AttrFeatureKind::Feature:464 Ret.Features.push_back("+" + Value.str());465 if (Value == "lasx")466 Ret.Features.push_back("+lsx");467 break;468 }469 }470 return Ret;471}472 473bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const {474 return llvm::LoongArch::isValidCPUName(Name);475}476 477void LoongArchTargetInfo::fillValidCPUList(478 SmallVectorImpl<StringRef> &Values) const {479 llvm::LoongArch::fillValidCPUList(Values);480}481 482bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const {483 return llvm::LoongArch::isValidFeatureName(Name);484}485