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