1*bdd1243dSDimitry Andric //===--- LoongArch.cpp - Implement LoongArch target feature support -------===// 2*bdd1243dSDimitry Andric // 3*bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*bdd1243dSDimitry Andric // 7*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8*bdd1243dSDimitry Andric // 9*bdd1243dSDimitry Andric // This file implements LoongArch TargetInfo objects. 10*bdd1243dSDimitry Andric // 11*bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12*bdd1243dSDimitry Andric 13*bdd1243dSDimitry Andric #include "LoongArch.h" 14*bdd1243dSDimitry Andric #include "clang/Basic/Diagnostic.h" 15*bdd1243dSDimitry Andric #include "clang/Basic/MacroBuilder.h" 16*bdd1243dSDimitry Andric #include "clang/Basic/TargetBuiltins.h" 17*bdd1243dSDimitry Andric #include "llvm/Support/TargetParser.h" 18*bdd1243dSDimitry Andric #include "llvm/Support/raw_ostream.h" 19*bdd1243dSDimitry Andric 20*bdd1243dSDimitry Andric using namespace clang; 21*bdd1243dSDimitry Andric using namespace clang::targets; 22*bdd1243dSDimitry Andric 23*bdd1243dSDimitry Andric ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const { 24*bdd1243dSDimitry Andric static const char *const GCCRegNames[] = { 25*bdd1243dSDimitry Andric // General purpose registers. 26*bdd1243dSDimitry Andric "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", 27*bdd1243dSDimitry Andric "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18", 28*bdd1243dSDimitry Andric "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27", 29*bdd1243dSDimitry Andric "$r28", "$r29", "$r30", "$r31", 30*bdd1243dSDimitry Andric // Floating point registers. 31*bdd1243dSDimitry Andric "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", 32*bdd1243dSDimitry Andric "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", 33*bdd1243dSDimitry Andric "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", 34*bdd1243dSDimitry Andric "$f28", "$f29", "$f30", "$f31"}; 35*bdd1243dSDimitry Andric return llvm::ArrayRef(GCCRegNames); 36*bdd1243dSDimitry Andric } 37*bdd1243dSDimitry Andric 38*bdd1243dSDimitry Andric ArrayRef<TargetInfo::GCCRegAlias> 39*bdd1243dSDimitry Andric LoongArchTargetInfo::getGCCRegAliases() const { 40*bdd1243dSDimitry Andric static const TargetInfo::GCCRegAlias GCCRegAliases[] = { 41*bdd1243dSDimitry Andric {{"$zero"}, "$r0"}, {{"$ra"}, "$r1"}, {{"$tp"}, "$r2"}, 42*bdd1243dSDimitry Andric {{"$sp"}, "$r3"}, {{"$a0"}, "$r4"}, {{"$a1"}, "$r5"}, 43*bdd1243dSDimitry Andric {{"$a2"}, "$r6"}, {{"$a3"}, "$r7"}, {{"$a4"}, "$r8"}, 44*bdd1243dSDimitry Andric {{"$a5"}, "$r9"}, {{"$a6"}, "$r10"}, {{"$a7"}, "$r11"}, 45*bdd1243dSDimitry Andric {{"$t0"}, "$r12"}, {{"$t1"}, "$r13"}, {{"$t2"}, "$r14"}, 46*bdd1243dSDimitry Andric {{"$t3"}, "$r15"}, {{"$t4"}, "$r16"}, {{"$t5"}, "$r17"}, 47*bdd1243dSDimitry Andric {{"$t6"}, "$r18"}, {{"$t7"}, "$r19"}, {{"$t8"}, "$r20"}, 48*bdd1243dSDimitry Andric {{"$fp", "$s9"}, "$r22"}, {{"$s0"}, "$r23"}, {{"$s1"}, "$r24"}, 49*bdd1243dSDimitry Andric {{"$s2"}, "$r25"}, {{"$s3"}, "$r26"}, {{"$s4"}, "$r27"}, 50*bdd1243dSDimitry Andric {{"$s5"}, "$r28"}, {{"$s6"}, "$r29"}, {{"$s7"}, "$r30"}, 51*bdd1243dSDimitry Andric {{"$s8"}, "$r31"}, {{"$fa0"}, "$f0"}, {{"$fa1"}, "$f1"}, 52*bdd1243dSDimitry Andric {{"$fa2"}, "$f2"}, {{"$fa3"}, "$f3"}, {{"$fa4"}, "$f4"}, 53*bdd1243dSDimitry Andric {{"$fa5"}, "$f5"}, {{"$fa6"}, "$f6"}, {{"$fa7"}, "$f7"}, 54*bdd1243dSDimitry Andric {{"$ft0"}, "$f8"}, {{"$ft1"}, "$f9"}, {{"$ft2"}, "$f10"}, 55*bdd1243dSDimitry Andric {{"$ft3"}, "$f11"}, {{"$ft4"}, "$f12"}, {{"$ft5"}, "$f13"}, 56*bdd1243dSDimitry Andric {{"$ft6"}, "$f14"}, {{"$ft7"}, "$f15"}, {{"$ft8"}, "$f16"}, 57*bdd1243dSDimitry Andric {{"$ft9"}, "$f17"}, {{"$ft10"}, "$f18"}, {{"$ft11"}, "$f19"}, 58*bdd1243dSDimitry Andric {{"$ft12"}, "$f20"}, {{"$ft13"}, "$f21"}, {{"$ft14"}, "$f22"}, 59*bdd1243dSDimitry Andric {{"$ft15"}, "$f23"}, {{"$fs0"}, "$f24"}, {{"$fs1"}, "$f25"}, 60*bdd1243dSDimitry Andric {{"$fs2"}, "$f26"}, {{"$fs3"}, "$f27"}, {{"$fs4"}, "$f28"}, 61*bdd1243dSDimitry Andric {{"$fs5"}, "$f29"}, {{"$fs6"}, "$f30"}, {{"$fs7"}, "$f31"}, 62*bdd1243dSDimitry Andric }; 63*bdd1243dSDimitry Andric return llvm::ArrayRef(GCCRegAliases); 64*bdd1243dSDimitry Andric } 65*bdd1243dSDimitry Andric 66*bdd1243dSDimitry Andric bool LoongArchTargetInfo::validateAsmConstraint( 67*bdd1243dSDimitry Andric const char *&Name, TargetInfo::ConstraintInfo &Info) const { 68*bdd1243dSDimitry Andric // See the GCC definitions here: 69*bdd1243dSDimitry Andric // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html 70*bdd1243dSDimitry Andric // Note that the 'm' constraint is handled in TargetInfo. 71*bdd1243dSDimitry Andric switch (*Name) { 72*bdd1243dSDimitry Andric default: 73*bdd1243dSDimitry Andric return false; 74*bdd1243dSDimitry Andric case 'f': 75*bdd1243dSDimitry Andric // A floating-point register (if available). 76*bdd1243dSDimitry Andric Info.setAllowsRegister(); 77*bdd1243dSDimitry Andric return true; 78*bdd1243dSDimitry Andric case 'k': 79*bdd1243dSDimitry Andric // A memory operand whose address is formed by a base register and 80*bdd1243dSDimitry Andric // (optionally scaled) index register. 81*bdd1243dSDimitry Andric Info.setAllowsMemory(); 82*bdd1243dSDimitry Andric return true; 83*bdd1243dSDimitry Andric case 'l': 84*bdd1243dSDimitry Andric // A signed 16-bit constant. 85*bdd1243dSDimitry Andric Info.setRequiresImmediate(-32768, 32767); 86*bdd1243dSDimitry Andric return true; 87*bdd1243dSDimitry Andric case 'I': 88*bdd1243dSDimitry Andric // A signed 12-bit constant (for arithmetic instructions). 89*bdd1243dSDimitry Andric Info.setRequiresImmediate(-2048, 2047); 90*bdd1243dSDimitry Andric return true; 91*bdd1243dSDimitry Andric case 'J': 92*bdd1243dSDimitry Andric // Integer zero. 93*bdd1243dSDimitry Andric Info.setRequiresImmediate(0); 94*bdd1243dSDimitry Andric return true; 95*bdd1243dSDimitry Andric case 'K': 96*bdd1243dSDimitry Andric // An unsigned 12-bit constant (for logic instructions). 97*bdd1243dSDimitry Andric Info.setRequiresImmediate(0, 4095); 98*bdd1243dSDimitry Andric return true; 99*bdd1243dSDimitry Andric case 'Z': 100*bdd1243dSDimitry Andric // ZB: An address that is held in a general-purpose register. The offset is 101*bdd1243dSDimitry Andric // zero. 102*bdd1243dSDimitry Andric // ZC: A memory operand whose address is formed by a base register 103*bdd1243dSDimitry Andric // and offset that is suitable for use in instructions with the same 104*bdd1243dSDimitry Andric // addressing mode as ll.w and sc.w. 105*bdd1243dSDimitry Andric if (Name[1] == 'C' || Name[1] == 'B') { 106*bdd1243dSDimitry Andric Info.setAllowsMemory(); 107*bdd1243dSDimitry Andric ++Name; // Skip over 'Z'. 108*bdd1243dSDimitry Andric return true; 109*bdd1243dSDimitry Andric } 110*bdd1243dSDimitry Andric return false; 111*bdd1243dSDimitry Andric } 112*bdd1243dSDimitry Andric } 113*bdd1243dSDimitry Andric 114*bdd1243dSDimitry Andric std::string 115*bdd1243dSDimitry Andric LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { 116*bdd1243dSDimitry Andric std::string R; 117*bdd1243dSDimitry Andric switch (*Constraint) { 118*bdd1243dSDimitry Andric case 'Z': 119*bdd1243dSDimitry Andric // "ZC"/"ZB" are two-character constraints; add "^" hint for later 120*bdd1243dSDimitry Andric // parsing. 121*bdd1243dSDimitry Andric R = "^" + std::string(Constraint, 2); 122*bdd1243dSDimitry Andric ++Constraint; 123*bdd1243dSDimitry Andric break; 124*bdd1243dSDimitry Andric default: 125*bdd1243dSDimitry Andric R = TargetInfo::convertConstraint(Constraint); 126*bdd1243dSDimitry Andric break; 127*bdd1243dSDimitry Andric } 128*bdd1243dSDimitry Andric return R; 129*bdd1243dSDimitry Andric } 130*bdd1243dSDimitry Andric 131*bdd1243dSDimitry Andric void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, 132*bdd1243dSDimitry Andric MacroBuilder &Builder) const { 133*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch__"); 134*bdd1243dSDimitry Andric unsigned GRLen = getRegisterWidth(); 135*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_grlen", Twine(GRLen)); 136*bdd1243dSDimitry Andric if (GRLen == 64) 137*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch64"); 138*bdd1243dSDimitry Andric 139*bdd1243dSDimitry Andric if (HasFeatureD) 140*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_frlen", "64"); 141*bdd1243dSDimitry Andric else if (HasFeatureF) 142*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_frlen", "32"); 143*bdd1243dSDimitry Andric else 144*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_frlen", "0"); 145*bdd1243dSDimitry Andric 146*bdd1243dSDimitry Andric // TODO: define __loongarch_arch and __loongarch_tune. 147*bdd1243dSDimitry Andric 148*bdd1243dSDimitry Andric StringRef ABI = getABI(); 149*bdd1243dSDimitry Andric if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") 150*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_lp64"); 151*bdd1243dSDimitry Andric 152*bdd1243dSDimitry Andric if (ABI == "lp64d" || ABI == "ilp32d") { 153*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_hard_float"); 154*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_double_float"); 155*bdd1243dSDimitry Andric } else if (ABI == "lp64f" || ABI == "ilp32f") { 156*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_hard_float"); 157*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_single_float"); 158*bdd1243dSDimitry Andric } else if (ABI == "lp64s" || ABI == "ilp32s") { 159*bdd1243dSDimitry Andric Builder.defineMacro("__loongarch_soft_float"); 160*bdd1243dSDimitry Andric } 161*bdd1243dSDimitry Andric 162*bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 163*bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 164*bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 165*bdd1243dSDimitry Andric if (GRLen == 64) 166*bdd1243dSDimitry Andric Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 167*bdd1243dSDimitry Andric } 168*bdd1243dSDimitry Andric 169*bdd1243dSDimitry Andric static constexpr Builtin::Info BuiltinInfo[] = { 170*bdd1243dSDimitry Andric #define BUILTIN(ID, TYPE, ATTRS) \ 171*bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 172*bdd1243dSDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 173*bdd1243dSDimitry Andric {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 174*bdd1243dSDimitry Andric #include "clang/Basic/BuiltinsLoongArch.def" 175*bdd1243dSDimitry Andric }; 176*bdd1243dSDimitry Andric 177*bdd1243dSDimitry Andric bool LoongArchTargetInfo::initFeatureMap( 178*bdd1243dSDimitry Andric llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 179*bdd1243dSDimitry Andric const std::vector<std::string> &FeaturesVec) const { 180*bdd1243dSDimitry Andric if (getTriple().getArch() == llvm::Triple::loongarch64) 181*bdd1243dSDimitry Andric Features["64bit"] = true; 182*bdd1243dSDimitry Andric if (getTriple().getArch() == llvm::Triple::loongarch32) 183*bdd1243dSDimitry Andric Features["32bit"] = true; 184*bdd1243dSDimitry Andric 185*bdd1243dSDimitry Andric return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 186*bdd1243dSDimitry Andric } 187*bdd1243dSDimitry Andric 188*bdd1243dSDimitry Andric /// Return true if has this feature. 189*bdd1243dSDimitry Andric bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { 190*bdd1243dSDimitry Andric bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; 191*bdd1243dSDimitry Andric // TODO: Handle more features. 192*bdd1243dSDimitry Andric return llvm::StringSwitch<bool>(Feature) 193*bdd1243dSDimitry Andric .Case("loongarch32", !Is64Bit) 194*bdd1243dSDimitry Andric .Case("loongarch64", Is64Bit) 195*bdd1243dSDimitry Andric .Case("32bit", !Is64Bit) 196*bdd1243dSDimitry Andric .Case("64bit", Is64Bit) 197*bdd1243dSDimitry Andric .Default(false); 198*bdd1243dSDimitry Andric } 199*bdd1243dSDimitry Andric 200*bdd1243dSDimitry Andric ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const { 201*bdd1243dSDimitry Andric return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - 202*bdd1243dSDimitry Andric Builtin::FirstTSBuiltin); 203*bdd1243dSDimitry Andric } 204*bdd1243dSDimitry Andric 205*bdd1243dSDimitry Andric bool LoongArchTargetInfo::handleTargetFeatures( 206*bdd1243dSDimitry Andric std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 207*bdd1243dSDimitry Andric for (const auto &Feature : Features) { 208*bdd1243dSDimitry Andric if (Feature == "+d" || Feature == "+f") { 209*bdd1243dSDimitry Andric // "d" implies "f". 210*bdd1243dSDimitry Andric HasFeatureF = true; 211*bdd1243dSDimitry Andric if (Feature == "+d") { 212*bdd1243dSDimitry Andric HasFeatureD = true; 213*bdd1243dSDimitry Andric } 214*bdd1243dSDimitry Andric } 215*bdd1243dSDimitry Andric } 216*bdd1243dSDimitry Andric return true; 217*bdd1243dSDimitry Andric } 218