1bdd1243dSDimitry Andric //===--- LoongArch.cpp - Implement LoongArch target feature support -------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric // This file implements LoongArch TargetInfo objects. 10bdd1243dSDimitry Andric // 11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12bdd1243dSDimitry Andric 13bdd1243dSDimitry Andric #include "LoongArch.h" 14bdd1243dSDimitry Andric #include "clang/Basic/Diagnostic.h" 15bdd1243dSDimitry Andric #include "clang/Basic/MacroBuilder.h" 16bdd1243dSDimitry Andric #include "clang/Basic/TargetBuiltins.h" 17bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 18*8a4dda33SDimitry Andric #include "llvm/TargetParser/LoongArchTargetParser.h" 19bdd1243dSDimitry Andric 20bdd1243dSDimitry Andric using namespace clang; 21bdd1243dSDimitry Andric using namespace clang::targets; 22bdd1243dSDimitry Andric 23bdd1243dSDimitry Andric ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const { 24bdd1243dSDimitry Andric static const char *const GCCRegNames[] = { 25bdd1243dSDimitry Andric // General purpose registers. 26bdd1243dSDimitry Andric "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", 27bdd1243dSDimitry Andric "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18", 28bdd1243dSDimitry Andric "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27", 29bdd1243dSDimitry Andric "$r28", "$r29", "$r30", "$r31", 30bdd1243dSDimitry Andric // Floating point registers. 31bdd1243dSDimitry Andric "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", 32bdd1243dSDimitry Andric "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", 33bdd1243dSDimitry Andric "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", 3406c3fb27SDimitry Andric "$f28", "$f29", "$f30", "$f31", 3506c3fb27SDimitry Andric // Condition flag registers. 3606c3fb27SDimitry Andric "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", 3706c3fb27SDimitry Andric // 128-bit vector registers. 3806c3fb27SDimitry Andric "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", "$vr7", "$vr8", 3906c3fb27SDimitry Andric "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr14", "$vr15", "$vr16", 4006c3fb27SDimitry Andric "$vr17", "$vr18", "$vr19", "$vr20", "$vr21", "$vr22", "$vr23", "$vr24", 4106c3fb27SDimitry Andric "$vr25", "$vr26", "$vr27", "$vr28", "$vr29", "$vr30", "$vr31", 4206c3fb27SDimitry Andric // 256-bit vector registers. 4306c3fb27SDimitry Andric "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", "$xr7", "$xr8", 4406c3fb27SDimitry Andric "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", "$xr15", "$xr16", 4506c3fb27SDimitry Andric "$xr17", "$xr18", "$xr19", "$xr20", "$xr21", "$xr22", "$xr23", "$xr24", 4606c3fb27SDimitry Andric "$xr25", "$xr26", "$xr27", "$xr28", "$xr29", "$xr30", "$xr31"}; 47bdd1243dSDimitry Andric return llvm::ArrayRef(GCCRegNames); 48bdd1243dSDimitry Andric } 49bdd1243dSDimitry Andric 50bdd1243dSDimitry Andric ArrayRef<TargetInfo::GCCRegAlias> 51bdd1243dSDimitry Andric LoongArchTargetInfo::getGCCRegAliases() const { 52bdd1243dSDimitry Andric static const TargetInfo::GCCRegAlias GCCRegAliases[] = { 5306c3fb27SDimitry Andric {{"zero", "$zero", "r0"}, "$r0"}, 5406c3fb27SDimitry Andric {{"ra", "$ra", "r1"}, "$r1"}, 5506c3fb27SDimitry Andric {{"tp", "$tp", "r2"}, "$r2"}, 5606c3fb27SDimitry Andric {{"sp", "$sp", "r3"}, "$r3"}, 5706c3fb27SDimitry Andric {{"a0", "$a0", "r4"}, "$r4"}, 5806c3fb27SDimitry Andric {{"a1", "$a1", "r5"}, "$r5"}, 5906c3fb27SDimitry Andric {{"a2", "$a2", "r6"}, "$r6"}, 6006c3fb27SDimitry Andric {{"a3", "$a3", "r7"}, "$r7"}, 6106c3fb27SDimitry Andric {{"a4", "$a4", "r8"}, "$r8"}, 6206c3fb27SDimitry Andric {{"a5", "$a5", "r9"}, "$r9"}, 6306c3fb27SDimitry Andric {{"a6", "$a6", "r10"}, "$r10"}, 6406c3fb27SDimitry Andric {{"a7", "$a7", "r11"}, "$r11"}, 6506c3fb27SDimitry Andric {{"t0", "$t0", "r12"}, "$r12"}, 6606c3fb27SDimitry Andric {{"t1", "$t1", "r13"}, "$r13"}, 6706c3fb27SDimitry Andric {{"t2", "$t2", "r14"}, "$r14"}, 6806c3fb27SDimitry Andric {{"t3", "$t3", "r15"}, "$r15"}, 6906c3fb27SDimitry Andric {{"t4", "$t4", "r16"}, "$r16"}, 7006c3fb27SDimitry Andric {{"t5", "$t5", "r17"}, "$r17"}, 7106c3fb27SDimitry Andric {{"t6", "$t6", "r18"}, "$r18"}, 7206c3fb27SDimitry Andric {{"t7", "$t7", "r19"}, "$r19"}, 7306c3fb27SDimitry Andric {{"t8", "$t8", "r20"}, "$r20"}, 7406c3fb27SDimitry Andric {{"r21"}, "$r21"}, 7506c3fb27SDimitry Andric {{"s9", "$s9", "r22", "fp", "$fp"}, "$r22"}, 7606c3fb27SDimitry Andric {{"s0", "$s0", "r23"}, "$r23"}, 7706c3fb27SDimitry Andric {{"s1", "$s1", "r24"}, "$r24"}, 7806c3fb27SDimitry Andric {{"s2", "$s2", "r25"}, "$r25"}, 7906c3fb27SDimitry Andric {{"s3", "$s3", "r26"}, "$r26"}, 8006c3fb27SDimitry Andric {{"s4", "$s4", "r27"}, "$r27"}, 8106c3fb27SDimitry Andric {{"s5", "$s5", "r28"}, "$r28"}, 8206c3fb27SDimitry Andric {{"s6", "$s6", "r29"}, "$r29"}, 8306c3fb27SDimitry Andric {{"s7", "$s7", "r30"}, "$r30"}, 8406c3fb27SDimitry Andric {{"s8", "$s8", "r31"}, "$r31"}, 8506c3fb27SDimitry Andric {{"$fa0"}, "$f0"}, 8606c3fb27SDimitry Andric {{"$fa1"}, "$f1"}, 8706c3fb27SDimitry Andric {{"$fa2"}, "$f2"}, 8806c3fb27SDimitry Andric {{"$fa3"}, "$f3"}, 8906c3fb27SDimitry Andric {{"$fa4"}, "$f4"}, 9006c3fb27SDimitry Andric {{"$fa5"}, "$f5"}, 9106c3fb27SDimitry Andric {{"$fa6"}, "$f6"}, 9206c3fb27SDimitry Andric {{"$fa7"}, "$f7"}, 9306c3fb27SDimitry Andric {{"$ft0"}, "$f8"}, 9406c3fb27SDimitry Andric {{"$ft1"}, "$f9"}, 9506c3fb27SDimitry Andric {{"$ft2"}, "$f10"}, 9606c3fb27SDimitry Andric {{"$ft3"}, "$f11"}, 9706c3fb27SDimitry Andric {{"$ft4"}, "$f12"}, 9806c3fb27SDimitry Andric {{"$ft5"}, "$f13"}, 9906c3fb27SDimitry Andric {{"$ft6"}, "$f14"}, 10006c3fb27SDimitry Andric {{"$ft7"}, "$f15"}, 10106c3fb27SDimitry Andric {{"$ft8"}, "$f16"}, 10206c3fb27SDimitry Andric {{"$ft9"}, "$f17"}, 10306c3fb27SDimitry Andric {{"$ft10"}, "$f18"}, 10406c3fb27SDimitry Andric {{"$ft11"}, "$f19"}, 10506c3fb27SDimitry Andric {{"$ft12"}, "$f20"}, 10606c3fb27SDimitry Andric {{"$ft13"}, "$f21"}, 10706c3fb27SDimitry Andric {{"$ft14"}, "$f22"}, 10806c3fb27SDimitry Andric {{"$ft15"}, "$f23"}, 10906c3fb27SDimitry Andric {{"$fs0"}, "$f24"}, 11006c3fb27SDimitry Andric {{"$fs1"}, "$f25"}, 11106c3fb27SDimitry Andric {{"$fs2"}, "$f26"}, 11206c3fb27SDimitry Andric {{"$fs3"}, "$f27"}, 11306c3fb27SDimitry Andric {{"$fs4"}, "$f28"}, 11406c3fb27SDimitry Andric {{"$fs5"}, "$f29"}, 11506c3fb27SDimitry Andric {{"$fs6"}, "$f30"}, 11606c3fb27SDimitry Andric {{"$fs7"}, "$f31"}, 117bdd1243dSDimitry Andric }; 118bdd1243dSDimitry Andric return llvm::ArrayRef(GCCRegAliases); 119bdd1243dSDimitry Andric } 120bdd1243dSDimitry Andric 121bdd1243dSDimitry Andric bool LoongArchTargetInfo::validateAsmConstraint( 122bdd1243dSDimitry Andric const char *&Name, TargetInfo::ConstraintInfo &Info) const { 123bdd1243dSDimitry Andric // See the GCC definitions here: 124bdd1243dSDimitry Andric // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html 125bdd1243dSDimitry Andric // Note that the 'm' constraint is handled in TargetInfo. 126bdd1243dSDimitry Andric switch (*Name) { 127bdd1243dSDimitry Andric default: 128bdd1243dSDimitry Andric return false; 129bdd1243dSDimitry Andric case 'f': 130bdd1243dSDimitry Andric // A floating-point register (if available). 131bdd1243dSDimitry Andric Info.setAllowsRegister(); 132bdd1243dSDimitry Andric return true; 133bdd1243dSDimitry Andric case 'k': 134bdd1243dSDimitry Andric // A memory operand whose address is formed by a base register and 135bdd1243dSDimitry Andric // (optionally scaled) index register. 136bdd1243dSDimitry Andric Info.setAllowsMemory(); 137bdd1243dSDimitry Andric return true; 138bdd1243dSDimitry Andric case 'l': 139bdd1243dSDimitry Andric // A signed 16-bit constant. 140bdd1243dSDimitry Andric Info.setRequiresImmediate(-32768, 32767); 141bdd1243dSDimitry Andric return true; 142bdd1243dSDimitry Andric case 'I': 143bdd1243dSDimitry Andric // A signed 12-bit constant (for arithmetic instructions). 144bdd1243dSDimitry Andric Info.setRequiresImmediate(-2048, 2047); 145bdd1243dSDimitry Andric return true; 146bdd1243dSDimitry Andric case 'J': 147bdd1243dSDimitry Andric // Integer zero. 148bdd1243dSDimitry Andric Info.setRequiresImmediate(0); 149bdd1243dSDimitry Andric return true; 150bdd1243dSDimitry Andric case 'K': 151bdd1243dSDimitry Andric // An unsigned 12-bit constant (for logic instructions). 152bdd1243dSDimitry Andric Info.setRequiresImmediate(0, 4095); 153bdd1243dSDimitry Andric return true; 154bdd1243dSDimitry Andric case 'Z': 155bdd1243dSDimitry Andric // ZB: An address that is held in a general-purpose register. The offset is 156bdd1243dSDimitry Andric // zero. 157bdd1243dSDimitry Andric // ZC: A memory operand whose address is formed by a base register 158bdd1243dSDimitry Andric // and offset that is suitable for use in instructions with the same 159bdd1243dSDimitry Andric // addressing mode as ll.w and sc.w. 160bdd1243dSDimitry Andric if (Name[1] == 'C' || Name[1] == 'B') { 161bdd1243dSDimitry Andric Info.setAllowsMemory(); 162bdd1243dSDimitry Andric ++Name; // Skip over 'Z'. 163bdd1243dSDimitry Andric return true; 164bdd1243dSDimitry Andric } 165bdd1243dSDimitry Andric return false; 166bdd1243dSDimitry Andric } 167bdd1243dSDimitry Andric } 168bdd1243dSDimitry Andric 169bdd1243dSDimitry Andric std::string 170bdd1243dSDimitry Andric LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { 171bdd1243dSDimitry Andric std::string R; 172bdd1243dSDimitry Andric switch (*Constraint) { 173bdd1243dSDimitry Andric case 'Z': 174bdd1243dSDimitry Andric // "ZC"/"ZB" are two-character constraints; add "^" hint for later 175bdd1243dSDimitry Andric // parsing. 176bdd1243dSDimitry Andric R = "^" + std::string(Constraint, 2); 177bdd1243dSDimitry Andric ++Constraint; 178bdd1243dSDimitry Andric break; 179bdd1243dSDimitry Andric default: 180bdd1243dSDimitry Andric R = TargetInfo::convertConstraint(Constraint); 181bdd1243dSDimitry Andric break; 182bdd1243dSDimitry Andric } 183bdd1243dSDimitry Andric return R; 184bdd1243dSDimitry Andric } 185bdd1243dSDimitry Andric 186bdd1243dSDimitry Andric void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, 187bdd1243dSDimitry Andric MacroBuilder &Builder) const { 188bdd1243dSDimitry Andric Builder.defineMacro("__loongarch__"); 189bdd1243dSDimitry Andric unsigned GRLen = getRegisterWidth(); 190bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_grlen", Twine(GRLen)); 191bdd1243dSDimitry Andric if (GRLen == 64) 192bdd1243dSDimitry Andric Builder.defineMacro("__loongarch64"); 193bdd1243dSDimitry Andric 194bdd1243dSDimitry Andric if (HasFeatureD) 195bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_frlen", "64"); 196bdd1243dSDimitry Andric else if (HasFeatureF) 197bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_frlen", "32"); 198bdd1243dSDimitry Andric else 199bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_frlen", "0"); 200bdd1243dSDimitry Andric 201*8a4dda33SDimitry Andric // Define __loongarch_arch. 202*8a4dda33SDimitry Andric StringRef ArchName = getCPU(); 203*8a4dda33SDimitry Andric Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"')); 204*8a4dda33SDimitry Andric 205*8a4dda33SDimitry Andric // Define __loongarch_tune. 206*8a4dda33SDimitry Andric StringRef TuneCPU = getTargetOpts().TuneCPU; 207*8a4dda33SDimitry Andric if (TuneCPU.empty()) 208*8a4dda33SDimitry Andric TuneCPU = ArchName; 209*8a4dda33SDimitry Andric Builder.defineMacro("__loongarch_tune", Twine('"') + TuneCPU + Twine('"')); 210bdd1243dSDimitry Andric 211bdd1243dSDimitry Andric StringRef ABI = getABI(); 212bdd1243dSDimitry Andric if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") 213bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_lp64"); 214bdd1243dSDimitry Andric 215bdd1243dSDimitry Andric if (ABI == "lp64d" || ABI == "ilp32d") { 216bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_hard_float"); 217bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_double_float"); 218bdd1243dSDimitry Andric } else if (ABI == "lp64f" || ABI == "ilp32f") { 219bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_hard_float"); 220bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_single_float"); 221bdd1243dSDimitry Andric } else if (ABI == "lp64s" || ABI == "ilp32s") { 222bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_soft_float"); 223bdd1243dSDimitry Andric } 224bdd1243dSDimitry Andric 225bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 226bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 227bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 228bdd1243dSDimitry Andric if (GRLen == 64) 229bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 230bdd1243dSDimitry Andric } 231bdd1243dSDimitry Andric 232bdd1243dSDimitry Andric static constexpr Builtin::Info BuiltinInfo[] = { 233bdd1243dSDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \ 234bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 235bdd1243dSDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 236bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 237bdd1243dSDimitry Andric #include "clang/Basic/BuiltinsLoongArch.def" 238bdd1243dSDimitry Andric }; 239bdd1243dSDimitry Andric 240bdd1243dSDimitry Andric bool LoongArchTargetInfo::initFeatureMap( 241bdd1243dSDimitry Andric llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 242bdd1243dSDimitry Andric const std::vector<std::string> &FeaturesVec) const { 243bdd1243dSDimitry Andric if (getTriple().getArch() == llvm::Triple::loongarch64) 244bdd1243dSDimitry Andric Features["64bit"] = true; 245bdd1243dSDimitry Andric if (getTriple().getArch() == llvm::Triple::loongarch32) 246bdd1243dSDimitry Andric Features["32bit"] = true; 247bdd1243dSDimitry Andric 248bdd1243dSDimitry Andric return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 249bdd1243dSDimitry Andric } 250bdd1243dSDimitry Andric 251bdd1243dSDimitry Andric /// Return true if has this feature. 252bdd1243dSDimitry Andric bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { 253bdd1243dSDimitry Andric bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; 254bdd1243dSDimitry Andric // TODO: Handle more features. 255bdd1243dSDimitry Andric return llvm::StringSwitch<bool>(Feature) 256bdd1243dSDimitry Andric .Case("loongarch32", !Is64Bit) 257bdd1243dSDimitry Andric .Case("loongarch64", Is64Bit) 258bdd1243dSDimitry Andric .Case("32bit", !Is64Bit) 259bdd1243dSDimitry Andric .Case("64bit", Is64Bit) 260bdd1243dSDimitry Andric .Default(false); 261bdd1243dSDimitry Andric } 262bdd1243dSDimitry Andric 263bdd1243dSDimitry Andric ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const { 264bdd1243dSDimitry Andric return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - 265bdd1243dSDimitry Andric Builtin::FirstTSBuiltin); 266bdd1243dSDimitry Andric } 267bdd1243dSDimitry Andric 268bdd1243dSDimitry Andric bool LoongArchTargetInfo::handleTargetFeatures( 269bdd1243dSDimitry Andric std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 270bdd1243dSDimitry Andric for (const auto &Feature : Features) { 271bdd1243dSDimitry Andric if (Feature == "+d" || Feature == "+f") { 272bdd1243dSDimitry Andric // "d" implies "f". 273bdd1243dSDimitry Andric HasFeatureF = true; 274bdd1243dSDimitry Andric if (Feature == "+d") { 275bdd1243dSDimitry Andric HasFeatureD = true; 276bdd1243dSDimitry Andric } 277bdd1243dSDimitry Andric } 278bdd1243dSDimitry Andric } 279bdd1243dSDimitry Andric return true; 280bdd1243dSDimitry Andric } 281*8a4dda33SDimitry Andric 282*8a4dda33SDimitry Andric bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const { 283*8a4dda33SDimitry Andric return llvm::LoongArch::isValidCPUName(Name); 284*8a4dda33SDimitry Andric } 285*8a4dda33SDimitry Andric 286*8a4dda33SDimitry Andric void LoongArchTargetInfo::fillValidCPUList( 287*8a4dda33SDimitry Andric SmallVectorImpl<StringRef> &Values) const { 288*8a4dda33SDimitry Andric llvm::LoongArch::fillValidCPUList(Values); 289*8a4dda33SDimitry Andric } 290