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*06c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.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", 34*06c3fb27SDimitry Andric "$f28", "$f29", "$f30", "$f31", 35*06c3fb27SDimitry Andric // Condition flag registers. 36*06c3fb27SDimitry Andric "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", 37*06c3fb27SDimitry Andric // 128-bit vector registers. 38*06c3fb27SDimitry Andric "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", "$vr7", "$vr8", 39*06c3fb27SDimitry Andric "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr14", "$vr15", "$vr16", 40*06c3fb27SDimitry Andric "$vr17", "$vr18", "$vr19", "$vr20", "$vr21", "$vr22", "$vr23", "$vr24", 41*06c3fb27SDimitry Andric "$vr25", "$vr26", "$vr27", "$vr28", "$vr29", "$vr30", "$vr31", 42*06c3fb27SDimitry Andric // 256-bit vector registers. 43*06c3fb27SDimitry Andric "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", "$xr7", "$xr8", 44*06c3fb27SDimitry Andric "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", "$xr15", "$xr16", 45*06c3fb27SDimitry Andric "$xr17", "$xr18", "$xr19", "$xr20", "$xr21", "$xr22", "$xr23", "$xr24", 46*06c3fb27SDimitry 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[] = { 53*06c3fb27SDimitry Andric {{"zero", "$zero", "r0"}, "$r0"}, 54*06c3fb27SDimitry Andric {{"ra", "$ra", "r1"}, "$r1"}, 55*06c3fb27SDimitry Andric {{"tp", "$tp", "r2"}, "$r2"}, 56*06c3fb27SDimitry Andric {{"sp", "$sp", "r3"}, "$r3"}, 57*06c3fb27SDimitry Andric {{"a0", "$a0", "r4"}, "$r4"}, 58*06c3fb27SDimitry Andric {{"a1", "$a1", "r5"}, "$r5"}, 59*06c3fb27SDimitry Andric {{"a2", "$a2", "r6"}, "$r6"}, 60*06c3fb27SDimitry Andric {{"a3", "$a3", "r7"}, "$r7"}, 61*06c3fb27SDimitry Andric {{"a4", "$a4", "r8"}, "$r8"}, 62*06c3fb27SDimitry Andric {{"a5", "$a5", "r9"}, "$r9"}, 63*06c3fb27SDimitry Andric {{"a6", "$a6", "r10"}, "$r10"}, 64*06c3fb27SDimitry Andric {{"a7", "$a7", "r11"}, "$r11"}, 65*06c3fb27SDimitry Andric {{"t0", "$t0", "r12"}, "$r12"}, 66*06c3fb27SDimitry Andric {{"t1", "$t1", "r13"}, "$r13"}, 67*06c3fb27SDimitry Andric {{"t2", "$t2", "r14"}, "$r14"}, 68*06c3fb27SDimitry Andric {{"t3", "$t3", "r15"}, "$r15"}, 69*06c3fb27SDimitry Andric {{"t4", "$t4", "r16"}, "$r16"}, 70*06c3fb27SDimitry Andric {{"t5", "$t5", "r17"}, "$r17"}, 71*06c3fb27SDimitry Andric {{"t6", "$t6", "r18"}, "$r18"}, 72*06c3fb27SDimitry Andric {{"t7", "$t7", "r19"}, "$r19"}, 73*06c3fb27SDimitry Andric {{"t8", "$t8", "r20"}, "$r20"}, 74*06c3fb27SDimitry Andric {{"r21"}, "$r21"}, 75*06c3fb27SDimitry Andric {{"s9", "$s9", "r22", "fp", "$fp"}, "$r22"}, 76*06c3fb27SDimitry Andric {{"s0", "$s0", "r23"}, "$r23"}, 77*06c3fb27SDimitry Andric {{"s1", "$s1", "r24"}, "$r24"}, 78*06c3fb27SDimitry Andric {{"s2", "$s2", "r25"}, "$r25"}, 79*06c3fb27SDimitry Andric {{"s3", "$s3", "r26"}, "$r26"}, 80*06c3fb27SDimitry Andric {{"s4", "$s4", "r27"}, "$r27"}, 81*06c3fb27SDimitry Andric {{"s5", "$s5", "r28"}, "$r28"}, 82*06c3fb27SDimitry Andric {{"s6", "$s6", "r29"}, "$r29"}, 83*06c3fb27SDimitry Andric {{"s7", "$s7", "r30"}, "$r30"}, 84*06c3fb27SDimitry Andric {{"s8", "$s8", "r31"}, "$r31"}, 85*06c3fb27SDimitry Andric {{"$fa0"}, "$f0"}, 86*06c3fb27SDimitry Andric {{"$fa1"}, "$f1"}, 87*06c3fb27SDimitry Andric {{"$fa2"}, "$f2"}, 88*06c3fb27SDimitry Andric {{"$fa3"}, "$f3"}, 89*06c3fb27SDimitry Andric {{"$fa4"}, "$f4"}, 90*06c3fb27SDimitry Andric {{"$fa5"}, "$f5"}, 91*06c3fb27SDimitry Andric {{"$fa6"}, "$f6"}, 92*06c3fb27SDimitry Andric {{"$fa7"}, "$f7"}, 93*06c3fb27SDimitry Andric {{"$ft0"}, "$f8"}, 94*06c3fb27SDimitry Andric {{"$ft1"}, "$f9"}, 95*06c3fb27SDimitry Andric {{"$ft2"}, "$f10"}, 96*06c3fb27SDimitry Andric {{"$ft3"}, "$f11"}, 97*06c3fb27SDimitry Andric {{"$ft4"}, "$f12"}, 98*06c3fb27SDimitry Andric {{"$ft5"}, "$f13"}, 99*06c3fb27SDimitry Andric {{"$ft6"}, "$f14"}, 100*06c3fb27SDimitry Andric {{"$ft7"}, "$f15"}, 101*06c3fb27SDimitry Andric {{"$ft8"}, "$f16"}, 102*06c3fb27SDimitry Andric {{"$ft9"}, "$f17"}, 103*06c3fb27SDimitry Andric {{"$ft10"}, "$f18"}, 104*06c3fb27SDimitry Andric {{"$ft11"}, "$f19"}, 105*06c3fb27SDimitry Andric {{"$ft12"}, "$f20"}, 106*06c3fb27SDimitry Andric {{"$ft13"}, "$f21"}, 107*06c3fb27SDimitry Andric {{"$ft14"}, "$f22"}, 108*06c3fb27SDimitry Andric {{"$ft15"}, "$f23"}, 109*06c3fb27SDimitry Andric {{"$fs0"}, "$f24"}, 110*06c3fb27SDimitry Andric {{"$fs1"}, "$f25"}, 111*06c3fb27SDimitry Andric {{"$fs2"}, "$f26"}, 112*06c3fb27SDimitry Andric {{"$fs3"}, "$f27"}, 113*06c3fb27SDimitry Andric {{"$fs4"}, "$f28"}, 114*06c3fb27SDimitry Andric {{"$fs5"}, "$f29"}, 115*06c3fb27SDimitry Andric {{"$fs6"}, "$f30"}, 116*06c3fb27SDimitry 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 201bdd1243dSDimitry Andric // TODO: define __loongarch_arch and __loongarch_tune. 202bdd1243dSDimitry Andric 203bdd1243dSDimitry Andric StringRef ABI = getABI(); 204bdd1243dSDimitry Andric if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") 205bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_lp64"); 206bdd1243dSDimitry Andric 207bdd1243dSDimitry Andric if (ABI == "lp64d" || ABI == "ilp32d") { 208bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_hard_float"); 209bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_double_float"); 210bdd1243dSDimitry Andric } else if (ABI == "lp64f" || ABI == "ilp32f") { 211bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_hard_float"); 212bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_single_float"); 213bdd1243dSDimitry Andric } else if (ABI == "lp64s" || ABI == "ilp32s") { 214bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_soft_float"); 215bdd1243dSDimitry Andric } 216bdd1243dSDimitry Andric 217bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 218bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 219bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 220bdd1243dSDimitry Andric if (GRLen == 64) 221bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 222bdd1243dSDimitry Andric } 223bdd1243dSDimitry Andric 224bdd1243dSDimitry Andric static constexpr Builtin::Info BuiltinInfo[] = { 225bdd1243dSDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \ 226bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 227bdd1243dSDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 228bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 229bdd1243dSDimitry Andric #include "clang/Basic/BuiltinsLoongArch.def" 230bdd1243dSDimitry Andric }; 231bdd1243dSDimitry Andric 232bdd1243dSDimitry Andric bool LoongArchTargetInfo::initFeatureMap( 233bdd1243dSDimitry Andric llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 234bdd1243dSDimitry Andric const std::vector<std::string> &FeaturesVec) const { 235bdd1243dSDimitry Andric if (getTriple().getArch() == llvm::Triple::loongarch64) 236bdd1243dSDimitry Andric Features["64bit"] = true; 237bdd1243dSDimitry Andric if (getTriple().getArch() == llvm::Triple::loongarch32) 238bdd1243dSDimitry Andric Features["32bit"] = true; 239bdd1243dSDimitry Andric 240bdd1243dSDimitry Andric return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 241bdd1243dSDimitry Andric } 242bdd1243dSDimitry Andric 243bdd1243dSDimitry Andric /// Return true if has this feature. 244bdd1243dSDimitry Andric bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { 245bdd1243dSDimitry Andric bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; 246bdd1243dSDimitry Andric // TODO: Handle more features. 247bdd1243dSDimitry Andric return llvm::StringSwitch<bool>(Feature) 248bdd1243dSDimitry Andric .Case("loongarch32", !Is64Bit) 249bdd1243dSDimitry Andric .Case("loongarch64", Is64Bit) 250bdd1243dSDimitry Andric .Case("32bit", !Is64Bit) 251bdd1243dSDimitry Andric .Case("64bit", Is64Bit) 252bdd1243dSDimitry Andric .Default(false); 253bdd1243dSDimitry Andric } 254bdd1243dSDimitry Andric 255bdd1243dSDimitry Andric ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const { 256bdd1243dSDimitry Andric return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - 257bdd1243dSDimitry Andric Builtin::FirstTSBuiltin); 258bdd1243dSDimitry Andric } 259bdd1243dSDimitry Andric 260bdd1243dSDimitry Andric bool LoongArchTargetInfo::handleTargetFeatures( 261bdd1243dSDimitry Andric std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 262bdd1243dSDimitry Andric for (const auto &Feature : Features) { 263bdd1243dSDimitry Andric if (Feature == "+d" || Feature == "+f") { 264bdd1243dSDimitry Andric // "d" implies "f". 265bdd1243dSDimitry Andric HasFeatureF = true; 266bdd1243dSDimitry Andric if (Feature == "+d") { 267bdd1243dSDimitry Andric HasFeatureD = true; 268bdd1243dSDimitry Andric } 269bdd1243dSDimitry Andric } 270bdd1243dSDimitry Andric } 271bdd1243dSDimitry Andric return true; 272bdd1243dSDimitry Andric } 273