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/raw_ostream.h" 18 #include "llvm/TargetParser/LoongArchTargetParser.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 // Condition flag registers. 36 "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", 37 // 128-bit vector registers. 38 "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", "$vr7", "$vr8", 39 "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr14", "$vr15", "$vr16", 40 "$vr17", "$vr18", "$vr19", "$vr20", "$vr21", "$vr22", "$vr23", "$vr24", 41 "$vr25", "$vr26", "$vr27", "$vr28", "$vr29", "$vr30", "$vr31", 42 // 256-bit vector registers. 43 "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", "$xr7", "$xr8", 44 "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", "$xr15", "$xr16", 45 "$xr17", "$xr18", "$xr19", "$xr20", "$xr21", "$xr22", "$xr23", "$xr24", 46 "$xr25", "$xr26", "$xr27", "$xr28", "$xr29", "$xr30", "$xr31"}; 47 return llvm::ArrayRef(GCCRegNames); 48 } 49 50 ArrayRef<TargetInfo::GCCRegAlias> 51 LoongArchTargetInfo::getGCCRegAliases() const { 52 static const TargetInfo::GCCRegAlias GCCRegAliases[] = { 53 {{"zero", "$zero", "r0"}, "$r0"}, 54 {{"ra", "$ra", "r1"}, "$r1"}, 55 {{"tp", "$tp", "r2"}, "$r2"}, 56 {{"sp", "$sp", "r3"}, "$r3"}, 57 {{"a0", "$a0", "r4"}, "$r4"}, 58 {{"a1", "$a1", "r5"}, "$r5"}, 59 {{"a2", "$a2", "r6"}, "$r6"}, 60 {{"a3", "$a3", "r7"}, "$r7"}, 61 {{"a4", "$a4", "r8"}, "$r8"}, 62 {{"a5", "$a5", "r9"}, "$r9"}, 63 {{"a6", "$a6", "r10"}, "$r10"}, 64 {{"a7", "$a7", "r11"}, "$r11"}, 65 {{"t0", "$t0", "r12"}, "$r12"}, 66 {{"t1", "$t1", "r13"}, "$r13"}, 67 {{"t2", "$t2", "r14"}, "$r14"}, 68 {{"t3", "$t3", "r15"}, "$r15"}, 69 {{"t4", "$t4", "r16"}, "$r16"}, 70 {{"t5", "$t5", "r17"}, "$r17"}, 71 {{"t6", "$t6", "r18"}, "$r18"}, 72 {{"t7", "$t7", "r19"}, "$r19"}, 73 {{"t8", "$t8", "r20"}, "$r20"}, 74 {{"r21"}, "$r21"}, 75 {{"s9", "$s9", "r22", "fp", "$fp"}, "$r22"}, 76 {{"s0", "$s0", "r23"}, "$r23"}, 77 {{"s1", "$s1", "r24"}, "$r24"}, 78 {{"s2", "$s2", "r25"}, "$r25"}, 79 {{"s3", "$s3", "r26"}, "$r26"}, 80 {{"s4", "$s4", "r27"}, "$r27"}, 81 {{"s5", "$s5", "r28"}, "$r28"}, 82 {{"s6", "$s6", "r29"}, "$r29"}, 83 {{"s7", "$s7", "r30"}, "$r30"}, 84 {{"s8", "$s8", "r31"}, "$r31"}, 85 {{"$fa0"}, "$f0"}, 86 {{"$fa1"}, "$f1"}, 87 {{"$fa2"}, "$f2"}, 88 {{"$fa3"}, "$f3"}, 89 {{"$fa4"}, "$f4"}, 90 {{"$fa5"}, "$f5"}, 91 {{"$fa6"}, "$f6"}, 92 {{"$fa7"}, "$f7"}, 93 {{"$ft0"}, "$f8"}, 94 {{"$ft1"}, "$f9"}, 95 {{"$ft2"}, "$f10"}, 96 {{"$ft3"}, "$f11"}, 97 {{"$ft4"}, "$f12"}, 98 {{"$ft5"}, "$f13"}, 99 {{"$ft6"}, "$f14"}, 100 {{"$ft7"}, "$f15"}, 101 {{"$ft8"}, "$f16"}, 102 {{"$ft9"}, "$f17"}, 103 {{"$ft10"}, "$f18"}, 104 {{"$ft11"}, "$f19"}, 105 {{"$ft12"}, "$f20"}, 106 {{"$ft13"}, "$f21"}, 107 {{"$ft14"}, "$f22"}, 108 {{"$ft15"}, "$f23"}, 109 {{"$fs0"}, "$f24"}, 110 {{"$fs1"}, "$f25"}, 111 {{"$fs2"}, "$f26"}, 112 {{"$fs3"}, "$f27"}, 113 {{"$fs4"}, "$f28"}, 114 {{"$fs5"}, "$f29"}, 115 {{"$fs6"}, "$f30"}, 116 {{"$fs7"}, "$f31"}, 117 }; 118 return llvm::ArrayRef(GCCRegAliases); 119 } 120 121 bool LoongArchTargetInfo::validateAsmConstraint( 122 const char *&Name, TargetInfo::ConstraintInfo &Info) const { 123 // See the GCC definitions here: 124 // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html 125 // Note that the 'm' constraint is handled in TargetInfo. 126 switch (*Name) { 127 default: 128 return false; 129 case 'f': 130 // A floating-point register (if available). 131 Info.setAllowsRegister(); 132 return true; 133 case 'k': 134 // A memory operand whose address is formed by a base register and 135 // (optionally scaled) index register. 136 Info.setAllowsMemory(); 137 return true; 138 case 'l': 139 // A signed 16-bit constant. 140 Info.setRequiresImmediate(-32768, 32767); 141 return true; 142 case 'I': 143 // A signed 12-bit constant (for arithmetic instructions). 144 Info.setRequiresImmediate(-2048, 2047); 145 return true; 146 case 'J': 147 // Integer zero. 148 Info.setRequiresImmediate(0); 149 return true; 150 case 'K': 151 // An unsigned 12-bit constant (for logic instructions). 152 Info.setRequiresImmediate(0, 4095); 153 return true; 154 case 'Z': 155 // ZB: An address that is held in a general-purpose register. The offset is 156 // zero. 157 // ZC: A memory operand whose address is formed by a base register 158 // and offset that is suitable for use in instructions with the same 159 // addressing mode as ll.w and sc.w. 160 if (Name[1] == 'C' || Name[1] == 'B') { 161 Info.setAllowsMemory(); 162 ++Name; // Skip over 'Z'. 163 return true; 164 } 165 return false; 166 } 167 } 168 169 std::string 170 LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { 171 std::string R; 172 switch (*Constraint) { 173 case 'Z': 174 // "ZC"/"ZB" are two-character constraints; add "^" hint for later 175 // parsing. 176 R = "^" + std::string(Constraint, 2); 177 ++Constraint; 178 break; 179 default: 180 R = TargetInfo::convertConstraint(Constraint); 181 break; 182 } 183 return R; 184 } 185 186 void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, 187 MacroBuilder &Builder) const { 188 Builder.defineMacro("__loongarch__"); 189 unsigned GRLen = getRegisterWidth(); 190 Builder.defineMacro("__loongarch_grlen", Twine(GRLen)); 191 if (GRLen == 64) 192 Builder.defineMacro("__loongarch64"); 193 194 if (HasFeatureD) 195 Builder.defineMacro("__loongarch_frlen", "64"); 196 else if (HasFeatureF) 197 Builder.defineMacro("__loongarch_frlen", "32"); 198 else 199 Builder.defineMacro("__loongarch_frlen", "0"); 200 201 // Define __loongarch_arch. 202 StringRef ArchName = getCPU(); 203 Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"')); 204 205 // Define __loongarch_tune. 206 StringRef TuneCPU = getTargetOpts().TuneCPU; 207 if (TuneCPU.empty()) 208 TuneCPU = ArchName; 209 Builder.defineMacro("__loongarch_tune", Twine('"') + TuneCPU + Twine('"')); 210 211 StringRef ABI = getABI(); 212 if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") 213 Builder.defineMacro("__loongarch_lp64"); 214 215 if (ABI == "lp64d" || ABI == "ilp32d") { 216 Builder.defineMacro("__loongarch_hard_float"); 217 Builder.defineMacro("__loongarch_double_float"); 218 } else if (ABI == "lp64f" || ABI == "ilp32f") { 219 Builder.defineMacro("__loongarch_hard_float"); 220 Builder.defineMacro("__loongarch_single_float"); 221 } else if (ABI == "lp64s" || ABI == "ilp32s") { 222 Builder.defineMacro("__loongarch_soft_float"); 223 } 224 225 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); 226 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); 227 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); 228 if (GRLen == 64) 229 Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); 230 } 231 232 static constexpr Builtin::Info BuiltinInfo[] = { 233 #define BUILTIN(ID, TYPE, ATTRS) \ 234 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 235 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ 236 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, 237 #include "clang/Basic/BuiltinsLoongArch.def" 238 }; 239 240 bool LoongArchTargetInfo::initFeatureMap( 241 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, 242 const std::vector<std::string> &FeaturesVec) const { 243 if (getTriple().getArch() == llvm::Triple::loongarch64) 244 Features["64bit"] = true; 245 if (getTriple().getArch() == llvm::Triple::loongarch32) 246 Features["32bit"] = true; 247 248 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); 249 } 250 251 /// Return true if has this feature. 252 bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { 253 bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; 254 // TODO: Handle more features. 255 return llvm::StringSwitch<bool>(Feature) 256 .Case("loongarch32", !Is64Bit) 257 .Case("loongarch64", Is64Bit) 258 .Case("32bit", !Is64Bit) 259 .Case("64bit", Is64Bit) 260 .Default(false); 261 } 262 263 ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const { 264 return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - 265 Builtin::FirstTSBuiltin); 266 } 267 268 bool LoongArchTargetInfo::handleTargetFeatures( 269 std::vector<std::string> &Features, DiagnosticsEngine &Diags) { 270 for (const auto &Feature : Features) { 271 if (Feature == "+d" || Feature == "+f") { 272 // "d" implies "f". 273 HasFeatureF = true; 274 if (Feature == "+d") { 275 HasFeatureD = true; 276 } 277 } 278 } 279 return true; 280 } 281 282 bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const { 283 return llvm::LoongArch::isValidCPUName(Name); 284 } 285 286 void LoongArchTargetInfo::fillValidCPUList( 287 SmallVectorImpl<StringRef> &Values) const { 288 llvm::LoongArch::fillValidCPUList(Values); 289 } 290