| 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/TargetParser/LoongArchTargetParser.h" |
| 18 | |
| 19 | using namespace clang; |
| 20 | using namespace clang::targets; |
| 21 | |
| 22 | ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const { |
| 23 | static const char *const GCCRegNames[] = { |
| 24 | // General purpose registers. |
| 25 | "$r0" , "$r1" , "$r2" , "$r3" , "$r4" , "$r5" , "$r6" , "$r7" , "$r8" , "$r9" , |
| 26 | "$r10" , "$r11" , "$r12" , "$r13" , "$r14" , "$r15" , "$r16" , "$r17" , "$r18" , |
| 27 | "$r19" , "$r20" , "$r21" , "$r22" , "$r23" , "$r24" , "$r25" , "$r26" , "$r27" , |
| 28 | "$r28" , "$r29" , "$r30" , "$r31" , |
| 29 | // Floating point registers. |
| 30 | "$f0" , "$f1" , "$f2" , "$f3" , "$f4" , "$f5" , "$f6" , "$f7" , "$f8" , "$f9" , |
| 31 | "$f10" , "$f11" , "$f12" , "$f13" , "$f14" , "$f15" , "$f16" , "$f17" , "$f18" , |
| 32 | "$f19" , "$f20" , "$f21" , "$f22" , "$f23" , "$f24" , "$f25" , "$f26" , "$f27" , |
| 33 | "$f28" , "$f29" , "$f30" , "$f31" , |
| 34 | // Condition flag registers. |
| 35 | "$fcc0" , "$fcc1" , "$fcc2" , "$fcc3" , "$fcc4" , "$fcc5" , "$fcc6" , "$fcc7" , |
| 36 | // 128-bit vector registers. |
| 37 | "$vr0" , "$vr1" , "$vr2" , "$vr3" , "$vr4" , "$vr5" , "$vr6" , "$vr7" , "$vr8" , |
| 38 | "$vr9" , "$vr10" , "$vr11" , "$vr12" , "$vr13" , "$vr14" , "$vr15" , "$vr16" , |
| 39 | "$vr17" , "$vr18" , "$vr19" , "$vr20" , "$vr21" , "$vr22" , "$vr23" , "$vr24" , |
| 40 | "$vr25" , "$vr26" , "$vr27" , "$vr28" , "$vr29" , "$vr30" , "$vr31" , |
| 41 | // 256-bit vector registers. |
| 42 | "$xr0" , "$xr1" , "$xr2" , "$xr3" , "$xr4" , "$xr5" , "$xr6" , "$xr7" , "$xr8" , |
| 43 | "$xr9" , "$xr10" , "$xr11" , "$xr12" , "$xr13" , "$xr14" , "$xr15" , "$xr16" , |
| 44 | "$xr17" , "$xr18" , "$xr19" , "$xr20" , "$xr21" , "$xr22" , "$xr23" , "$xr24" , |
| 45 | "$xr25" , "$xr26" , "$xr27" , "$xr28" , "$xr29" , "$xr30" , "$xr31" }; |
| 46 | return llvm::ArrayRef(GCCRegNames); |
| 47 | } |
| 48 | |
| 49 | ArrayRef<TargetInfo::GCCRegAlias> |
| 50 | LoongArchTargetInfo::getGCCRegAliases() const { |
| 51 | static const TargetInfo::GCCRegAlias GCCRegAliases[] = { |
| 52 | {.Aliases: {"zero" , "$zero" , "r0" }, .Register: "$r0" }, |
| 53 | {.Aliases: {"ra" , "$ra" , "r1" }, .Register: "$r1" }, |
| 54 | {.Aliases: {"tp" , "$tp" , "r2" }, .Register: "$r2" }, |
| 55 | {.Aliases: {"sp" , "$sp" , "r3" }, .Register: "$r3" }, |
| 56 | {.Aliases: {"a0" , "$a0" , "r4" }, .Register: "$r4" }, |
| 57 | {.Aliases: {"a1" , "$a1" , "r5" }, .Register: "$r5" }, |
| 58 | {.Aliases: {"a2" , "$a2" , "r6" }, .Register: "$r6" }, |
| 59 | {.Aliases: {"a3" , "$a3" , "r7" }, .Register: "$r7" }, |
| 60 | {.Aliases: {"a4" , "$a4" , "r8" }, .Register: "$r8" }, |
| 61 | {.Aliases: {"a5" , "$a5" , "r9" }, .Register: "$r9" }, |
| 62 | {.Aliases: {"a6" , "$a6" , "r10" }, .Register: "$r10" }, |
| 63 | {.Aliases: {"a7" , "$a7" , "r11" }, .Register: "$r11" }, |
| 64 | {.Aliases: {"t0" , "$t0" , "r12" }, .Register: "$r12" }, |
| 65 | {.Aliases: {"t1" , "$t1" , "r13" }, .Register: "$r13" }, |
| 66 | {.Aliases: {"t2" , "$t2" , "r14" }, .Register: "$r14" }, |
| 67 | {.Aliases: {"t3" , "$t3" , "r15" }, .Register: "$r15" }, |
| 68 | {.Aliases: {"t4" , "$t4" , "r16" }, .Register: "$r16" }, |
| 69 | {.Aliases: {"t5" , "$t5" , "r17" }, .Register: "$r17" }, |
| 70 | {.Aliases: {"t6" , "$t6" , "r18" }, .Register: "$r18" }, |
| 71 | {.Aliases: {"t7" , "$t7" , "r19" }, .Register: "$r19" }, |
| 72 | {.Aliases: {"t8" , "$t8" , "r20" }, .Register: "$r20" }, |
| 73 | {.Aliases: {"r21" }, .Register: "$r21" }, |
| 74 | {.Aliases: {"s9" , "$s9" , "r22" , "fp" , "$fp" }, .Register: "$r22" }, |
| 75 | {.Aliases: {"s0" , "$s0" , "r23" }, .Register: "$r23" }, |
| 76 | {.Aliases: {"s1" , "$s1" , "r24" }, .Register: "$r24" }, |
| 77 | {.Aliases: {"s2" , "$s2" , "r25" }, .Register: "$r25" }, |
| 78 | {.Aliases: {"s3" , "$s3" , "r26" }, .Register: "$r26" }, |
| 79 | {.Aliases: {"s4" , "$s4" , "r27" }, .Register: "$r27" }, |
| 80 | {.Aliases: {"s5" , "$s5" , "r28" }, .Register: "$r28" }, |
| 81 | {.Aliases: {"s6" , "$s6" , "r29" }, .Register: "$r29" }, |
| 82 | {.Aliases: {"s7" , "$s7" , "r30" }, .Register: "$r30" }, |
| 83 | {.Aliases: {"s8" , "$s8" , "r31" }, .Register: "$r31" }, |
| 84 | {.Aliases: {"fa0" , "$fa0" , "f0" }, .Register: "$f0" }, |
| 85 | {.Aliases: {"fa1" , "$fa1" , "f1" }, .Register: "$f1" }, |
| 86 | {.Aliases: {"fa2" , "$fa2" , "f2" }, .Register: "$f2" }, |
| 87 | {.Aliases: {"fa3" , "$fa3" , "f3" }, .Register: "$f3" }, |
| 88 | {.Aliases: {"fa4" , "$fa4" , "f4" }, .Register: "$f4" }, |
| 89 | {.Aliases: {"fa5" , "$fa5" , "f5" }, .Register: "$f5" }, |
| 90 | {.Aliases: {"fa6" , "$fa6" , "f6" }, .Register: "$f6" }, |
| 91 | {.Aliases: {"fa7" , "$fa7" , "f7" }, .Register: "$f7" }, |
| 92 | {.Aliases: {"ft0" , "$ft0" , "f8" }, .Register: "$f8" }, |
| 93 | {.Aliases: {"ft1" , "$ft1" , "f9" }, .Register: "$f9" }, |
| 94 | {.Aliases: {"ft2" , "$ft2" , "f10" }, .Register: "$f10" }, |
| 95 | {.Aliases: {"ft3" , "$ft3" , "f11" }, .Register: "$f11" }, |
| 96 | {.Aliases: {"ft4" , "$ft4" , "f12" }, .Register: "$f12" }, |
| 97 | {.Aliases: {"ft5" , "$ft5" , "f13" }, .Register: "$f13" }, |
| 98 | {.Aliases: {"ft6" , "$ft6" , "f14" }, .Register: "$f14" }, |
| 99 | {.Aliases: {"ft7" , "$ft7" , "f15" }, .Register: "$f15" }, |
| 100 | {.Aliases: {"ft8" , "$ft8" , "f16" }, .Register: "$f16" }, |
| 101 | {.Aliases: {"ft9" , "$ft9" , "f17" }, .Register: "$f17" }, |
| 102 | {.Aliases: {"ft10" , "$ft10" , "f18" }, .Register: "$f18" }, |
| 103 | {.Aliases: {"ft11" , "$ft11" , "f19" }, .Register: "$f19" }, |
| 104 | {.Aliases: {"ft12" , "$ft12" , "f20" }, .Register: "$f20" }, |
| 105 | {.Aliases: {"ft13" , "$ft13" , "f21" }, .Register: "$f21" }, |
| 106 | {.Aliases: {"ft14" , "$ft14" , "f22" }, .Register: "$f22" }, |
| 107 | {.Aliases: {"ft15" , "$ft15" , "f23" }, .Register: "$f23" }, |
| 108 | {.Aliases: {"fs0" , "$fs0" , "f24" }, .Register: "$f24" }, |
| 109 | {.Aliases: {"fs1" , "$fs1" , "f25" }, .Register: "$f25" }, |
| 110 | {.Aliases: {"fs2" , "$fs2" , "f26" }, .Register: "$f26" }, |
| 111 | {.Aliases: {"fs3" , "$fs3" , "f27" }, .Register: "$f27" }, |
| 112 | {.Aliases: {"fs4" , "$fs4" , "f28" }, .Register: "$f28" }, |
| 113 | {.Aliases: {"fs5" , "$fs5" , "f29" }, .Register: "$f29" }, |
| 114 | {.Aliases: {"fs6" , "$fs6" , "f30" }, .Register: "$f30" }, |
| 115 | {.Aliases: {"fs7" , "$fs7" , "f31" }, .Register: "$f31" }, |
| 116 | {.Aliases: {"fcc0" }, .Register: "$fcc0" }, |
| 117 | {.Aliases: {"fcc1" }, .Register: "$fcc1" }, |
| 118 | {.Aliases: {"fcc2" }, .Register: "$fcc2" }, |
| 119 | {.Aliases: {"fcc3" }, .Register: "$fcc3" }, |
| 120 | {.Aliases: {"fcc4" }, .Register: "$fcc4" }, |
| 121 | {.Aliases: {"fcc5" }, .Register: "$fcc5" }, |
| 122 | {.Aliases: {"fcc6" }, .Register: "$fcc6" }, |
| 123 | {.Aliases: {"fcc7" }, .Register: "$fcc7" }, |
| 124 | }; |
| 125 | return llvm::ArrayRef(GCCRegAliases); |
| 126 | } |
| 127 | |
| 128 | bool LoongArchTargetInfo::validateAsmConstraint( |
| 129 | const char *&Name, TargetInfo::ConstraintInfo &Info) const { |
| 130 | // See the GCC definitions here: |
| 131 | // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html |
| 132 | // Note that the 'm' constraint is handled in TargetInfo. |
| 133 | switch (*Name) { |
| 134 | default: |
| 135 | return false; |
| 136 | case 'f': |
| 137 | // A floating-point register (if available). |
| 138 | Info.setAllowsRegister(); |
| 139 | return true; |
| 140 | case 'k': |
| 141 | // A memory operand whose address is formed by a base register and |
| 142 | // (optionally scaled) index register. |
| 143 | Info.setAllowsMemory(); |
| 144 | return true; |
| 145 | case 'l': |
| 146 | // A signed 16-bit constant. |
| 147 | Info.setRequiresImmediate(Min: -32768, Max: 32767); |
| 148 | return true; |
| 149 | case 'q': |
| 150 | // A general-purpose register except for $r0 and $r1 (for the csrxchg |
| 151 | // instruction) |
| 152 | Info.setAllowsRegister(); |
| 153 | return true; |
| 154 | case 'I': |
| 155 | // A signed 12-bit constant (for arithmetic instructions). |
| 156 | Info.setRequiresImmediate(Min: -2048, Max: 2047); |
| 157 | return true; |
| 158 | case 'J': |
| 159 | // Integer zero. |
| 160 | Info.setRequiresImmediate(0); |
| 161 | return true; |
| 162 | case 'K': |
| 163 | // An unsigned 12-bit constant (for logic instructions). |
| 164 | Info.setRequiresImmediate(Min: 0, Max: 4095); |
| 165 | return true; |
| 166 | case 'Z': |
| 167 | // ZB: An address that is held in a general-purpose register. The offset is |
| 168 | // zero. |
| 169 | // ZC: A memory operand whose address is formed by a base register |
| 170 | // and offset that is suitable for use in instructions with the same |
| 171 | // addressing mode as ll.w and sc.w. |
| 172 | if (Name[1] == 'C' || Name[1] == 'B') { |
| 173 | Info.setAllowsMemory(); |
| 174 | ++Name; // Skip over 'Z'. |
| 175 | return true; |
| 176 | } |
| 177 | return false; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | std::string |
| 182 | LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { |
| 183 | std::string R; |
| 184 | switch (*Constraint) { |
| 185 | case 'Z': |
| 186 | // "ZC"/"ZB" are two-character constraints; add "^" hint for later |
| 187 | // parsing. |
| 188 | R = "^" + std::string(Constraint, 2); |
| 189 | ++Constraint; |
| 190 | break; |
| 191 | default: |
| 192 | R = TargetInfo::convertConstraint(Constraint); |
| 193 | break; |
| 194 | } |
| 195 | return R; |
| 196 | } |
| 197 | |
| 198 | void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, |
| 199 | MacroBuilder &Builder) const { |
| 200 | Builder.defineMacro(Name: "__loongarch__" ); |
| 201 | unsigned GRLen = getRegisterWidth(); |
| 202 | Builder.defineMacro(Name: "__loongarch_grlen" , Value: Twine(GRLen)); |
| 203 | if (GRLen == 64) |
| 204 | Builder.defineMacro(Name: "__loongarch64" ); |
| 205 | |
| 206 | if (HasFeatureD) |
| 207 | Builder.defineMacro(Name: "__loongarch_frlen" , Value: "64" ); |
| 208 | else if (HasFeatureF) |
| 209 | Builder.defineMacro(Name: "__loongarch_frlen" , Value: "32" ); |
| 210 | else |
| 211 | Builder.defineMacro(Name: "__loongarch_frlen" , Value: "0" ); |
| 212 | |
| 213 | // Define __loongarch_arch. |
| 214 | StringRef ArchName = getCPU(); |
| 215 | if (ArchName == "loongarch64" ) { |
| 216 | if (HasFeatureLSX) { |
| 217 | // TODO: As more features of the V1.1 ISA are supported, a unified "v1.1" |
| 218 | // arch feature set will be used to include all sub-features belonging to |
| 219 | // the V1.1 ISA version. |
| 220 | if (HasFeatureFrecipe && HasFeatureLAM_BH && HasFeatureLAMCAS && |
| 221 | HasFeatureLD_SEQ_SA && HasFeatureDiv32 && HasFeatureSCQ) |
| 222 | Builder.defineMacro(Name: "__loongarch_arch" , |
| 223 | Value: Twine('"') + "la64v1.1" + Twine('"')); |
| 224 | else |
| 225 | Builder.defineMacro(Name: "__loongarch_arch" , |
| 226 | Value: Twine('"') + "la64v1.0" + Twine('"')); |
| 227 | } else { |
| 228 | Builder.defineMacro(Name: "__loongarch_arch" , |
| 229 | Value: Twine('"') + ArchName + Twine('"')); |
| 230 | } |
| 231 | } else { |
| 232 | Builder.defineMacro(Name: "__loongarch_arch" , Value: Twine('"') + ArchName + Twine('"')); |
| 233 | } |
| 234 | |
| 235 | // Define __loongarch_tune. |
| 236 | StringRef TuneCPU = getTargetOpts().TuneCPU; |
| 237 | if (TuneCPU.empty()) |
| 238 | TuneCPU = ArchName; |
| 239 | Builder.defineMacro(Name: "__loongarch_tune" , Value: Twine('"') + TuneCPU + Twine('"')); |
| 240 | |
| 241 | if (HasFeatureLASX) { |
| 242 | Builder.defineMacro(Name: "__loongarch_simd_width" , Value: "256" ); |
| 243 | Builder.defineMacro(Name: "__loongarch_sx" , Value: Twine(1)); |
| 244 | Builder.defineMacro(Name: "__loongarch_asx" , Value: Twine(1)); |
| 245 | } else if (HasFeatureLSX) { |
| 246 | Builder.defineMacro(Name: "__loongarch_simd_width" , Value: "128" ); |
| 247 | Builder.defineMacro(Name: "__loongarch_sx" , Value: Twine(1)); |
| 248 | } |
| 249 | if (HasFeatureFrecipe) |
| 250 | Builder.defineMacro(Name: "__loongarch_frecipe" , Value: Twine(1)); |
| 251 | |
| 252 | if (HasFeatureLAM_BH) |
| 253 | Builder.defineMacro(Name: "__loongarch_lam_bh" , Value: Twine(1)); |
| 254 | |
| 255 | if (HasFeatureLAMCAS) |
| 256 | Builder.defineMacro(Name: "__loongarch_lamcas" , Value: Twine(1)); |
| 257 | |
| 258 | if (HasFeatureLD_SEQ_SA) |
| 259 | Builder.defineMacro(Name: "__loongarch_ld_seq_sa" , Value: Twine(1)); |
| 260 | |
| 261 | if (HasFeatureDiv32) |
| 262 | Builder.defineMacro(Name: "__loongarch_div32" , Value: Twine(1)); |
| 263 | |
| 264 | if (HasFeatureSCQ) |
| 265 | Builder.defineMacro(Name: "__loongarch_scq" , Value: Twine(1)); |
| 266 | |
| 267 | StringRef ABI = getABI(); |
| 268 | if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s" ) |
| 269 | Builder.defineMacro(Name: "__loongarch_lp64" ); |
| 270 | |
| 271 | if (ABI == "lp64d" || ABI == "ilp32d" ) { |
| 272 | Builder.defineMacro(Name: "__loongarch_hard_float" ); |
| 273 | Builder.defineMacro(Name: "__loongarch_double_float" ); |
| 274 | } else if (ABI == "lp64f" || ABI == "ilp32f" ) { |
| 275 | Builder.defineMacro(Name: "__loongarch_hard_float" ); |
| 276 | Builder.defineMacro(Name: "__loongarch_single_float" ); |
| 277 | } else if (ABI == "lp64s" || ABI == "ilp32s" ) { |
| 278 | Builder.defineMacro(Name: "__loongarch_soft_float" ); |
| 279 | } |
| 280 | |
| 281 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1" ); |
| 282 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2" ); |
| 283 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" ); |
| 284 | if (GRLen == 64) |
| 285 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8" ); |
| 286 | } |
| 287 | |
| 288 | static constexpr int NumBaseBuiltins = |
| 289 | LoongArch::FirstLSXBuiltin - Builtin::FirstTSBuiltin; |
| 290 | static constexpr int NumLSXBuiltins = |
| 291 | LoongArch::FirstLASXBuiltin - LoongArch::FirstLSXBuiltin; |
| 292 | static constexpr int NumLASXBuiltins = |
| 293 | LoongArch::LastTSBuiltin - LoongArch::FirstLASXBuiltin; |
| 294 | static constexpr int NumBuiltins = |
| 295 | LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin; |
| 296 | static_assert(NumBuiltins == |
| 297 | (NumBaseBuiltins + NumLSXBuiltins + NumLASXBuiltins)); |
| 298 | |
| 299 | static constexpr llvm::StringTable BuiltinBaseStrings = |
| 300 | CLANG_BUILTIN_STR_TABLE_START |
| 301 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE |
| 302 | #include "clang/Basic/BuiltinsLoongArchBase.def" |
| 303 | #undef TARGET_BUILTIN |
| 304 | ; |
| 305 | |
| 306 | static constexpr auto BuiltinBaseInfos = Builtin::MakeInfos<NumBaseBuiltins>(Infos: { |
| 307 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY |
| 308 | #include "clang/Basic/BuiltinsLoongArchBase.def" |
| 309 | #undef TARGET_BUILTIN |
| 310 | }); |
| 311 | |
| 312 | static constexpr llvm::StringTable BuiltinLSXStrings = |
| 313 | CLANG_BUILTIN_STR_TABLE_START |
| 314 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE |
| 315 | #include "clang/Basic/BuiltinsLoongArchLSX.def" |
| 316 | #undef TARGET_BUILTIN |
| 317 | ; |
| 318 | |
| 319 | static constexpr auto BuiltinLSXInfos = Builtin::MakeInfos<NumLSXBuiltins>(Infos: { |
| 320 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY |
| 321 | #include "clang/Basic/BuiltinsLoongArchLSX.def" |
| 322 | #undef TARGET_BUILTIN |
| 323 | }); |
| 324 | |
| 325 | static constexpr llvm::StringTable BuiltinLASXStrings = |
| 326 | CLANG_BUILTIN_STR_TABLE_START |
| 327 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE |
| 328 | #include "clang/Basic/BuiltinsLoongArchLASX.def" |
| 329 | #undef TARGET_BUILTIN |
| 330 | ; |
| 331 | |
| 332 | static constexpr auto BuiltinLASXInfos = Builtin::MakeInfos<NumLASXBuiltins>(Infos: { |
| 333 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY |
| 334 | #include "clang/Basic/BuiltinsLoongArchLASX.def" |
| 335 | #undef TARGET_BUILTIN |
| 336 | }); |
| 337 | |
| 338 | bool LoongArchTargetInfo::initFeatureMap( |
| 339 | llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, |
| 340 | const std::vector<std::string> &FeaturesVec) const { |
| 341 | if (getTriple().getArch() == llvm::Triple::loongarch64) |
| 342 | Features["64bit" ] = true; |
| 343 | if (getTriple().getArch() == llvm::Triple::loongarch32) |
| 344 | Features["32bit" ] = true; |
| 345 | |
| 346 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: FeaturesVec); |
| 347 | } |
| 348 | |
| 349 | /// Return true if has this feature. |
| 350 | bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { |
| 351 | bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; |
| 352 | // TODO: Handle more features. |
| 353 | return llvm::StringSwitch<bool>(Feature) |
| 354 | .Case(S: "loongarch32" , Value: !Is64Bit) |
| 355 | .Case(S: "loongarch64" , Value: Is64Bit) |
| 356 | .Case(S: "32bit" , Value: !Is64Bit) |
| 357 | .Case(S: "64bit" , Value: Is64Bit) |
| 358 | .Case(S: "lsx" , Value: HasFeatureLSX) |
| 359 | .Case(S: "lasx" , Value: HasFeatureLASX) |
| 360 | .Default(Value: false); |
| 361 | } |
| 362 | |
| 363 | llvm::SmallVector<Builtin::InfosShard> |
| 364 | LoongArchTargetInfo::getTargetBuiltins() const { |
| 365 | return { |
| 366 | {.Strings: &BuiltinBaseStrings, .Infos: BuiltinBaseInfos}, |
| 367 | {.Strings: &BuiltinLSXStrings, .Infos: BuiltinLSXInfos}, |
| 368 | {.Strings: &BuiltinLASXStrings, .Infos: BuiltinLASXInfos}, |
| 369 | }; |
| 370 | } |
| 371 | |
| 372 | bool LoongArchTargetInfo::handleTargetFeatures( |
| 373 | std::vector<std::string> &Features, DiagnosticsEngine &Diags) { |
| 374 | for (const auto &Feature : Features) { |
| 375 | if (Feature == "+d" || Feature == "+f" ) { |
| 376 | // "d" implies "f". |
| 377 | HasFeatureF = true; |
| 378 | if (Feature == "+d" ) { |
| 379 | HasFeatureD = true; |
| 380 | } |
| 381 | } else if (Feature == "+lsx" ) |
| 382 | HasFeatureLSX = true; |
| 383 | else if (Feature == "+lasx" ) |
| 384 | HasFeatureLASX = true; |
| 385 | else if (Feature == "-ual" ) |
| 386 | HasUnalignedAccess = false; |
| 387 | else if (Feature == "+frecipe" ) |
| 388 | HasFeatureFrecipe = true; |
| 389 | else if (Feature == "+lam-bh" ) |
| 390 | HasFeatureLAM_BH = true; |
| 391 | else if (Feature == "+lamcas" ) |
| 392 | HasFeatureLAMCAS = true; |
| 393 | else if (Feature == "+ld-seq-sa" ) |
| 394 | HasFeatureLD_SEQ_SA = true; |
| 395 | else if (Feature == "+div32" ) |
| 396 | HasFeatureDiv32 = true; |
| 397 | else if (Feature == "+scq" ) |
| 398 | HasFeatureSCQ = true; |
| 399 | } |
| 400 | return true; |
| 401 | } |
| 402 | |
| 403 | enum class AttrFeatureKind { Arch, Tune, NoFeature, Feature }; |
| 404 | |
| 405 | static std::pair<AttrFeatureKind, llvm::StringRef> |
| 406 | getAttrFeatureTypeAndValue(llvm::StringRef AttrFeature) { |
| 407 | if (auto Split = AttrFeature.split(Separator: "=" ); !Split.second.empty()) { |
| 408 | if (Split.first.trim() == "arch" ) |
| 409 | return {AttrFeatureKind::Arch, Split.second.trim()}; |
| 410 | if (Split.first.trim() == "tune" ) |
| 411 | return {AttrFeatureKind::Tune, Split.second.trim()}; |
| 412 | } |
| 413 | if (AttrFeature.starts_with(Prefix: "no-" )) |
| 414 | return {AttrFeatureKind::NoFeature, AttrFeature.drop_front(N: 3)}; |
| 415 | return {AttrFeatureKind::Feature, AttrFeature}; |
| 416 | } |
| 417 | |
| 418 | ParsedTargetAttr |
| 419 | LoongArchTargetInfo::parseTargetAttr(StringRef Features) const { |
| 420 | ParsedTargetAttr Ret; |
| 421 | if (Features == "default" ) |
| 422 | return Ret; |
| 423 | SmallVector<StringRef, 1> AttrFeatures; |
| 424 | Features.split(A&: AttrFeatures, Separator: "," ); |
| 425 | |
| 426 | for (auto &Feature : AttrFeatures) { |
| 427 | auto [Kind, Value] = getAttrFeatureTypeAndValue(AttrFeature: Feature.trim()); |
| 428 | |
| 429 | switch (Kind) { |
| 430 | case AttrFeatureKind::Arch: { |
| 431 | if (llvm::LoongArch::isValidArchName(Arch: Value) || Value == "la64v1.0" || |
| 432 | Value == "la64v1.1" ) { |
| 433 | std::vector<llvm::StringRef> ArchFeatures; |
| 434 | if (llvm::LoongArch::getArchFeatures(Arch: Value, Features&: ArchFeatures)) { |
| 435 | Ret.Features.insert(position: Ret.Features.end(), first: ArchFeatures.begin(), |
| 436 | last: ArchFeatures.end()); |
| 437 | } |
| 438 | |
| 439 | if (!Ret.CPU.empty()) |
| 440 | Ret.Duplicate = "arch=" ; |
| 441 | else if (Value == "la64v1.0" || Value == "la64v1.1" ) |
| 442 | Ret.CPU = "loongarch64" ; |
| 443 | else |
| 444 | Ret.CPU = Value; |
| 445 | } else { |
| 446 | Ret.Features.push_back(x: "!arch=" + Value.str()); |
| 447 | } |
| 448 | break; |
| 449 | } |
| 450 | |
| 451 | case AttrFeatureKind::Tune: |
| 452 | if (!Ret.Tune.empty()) |
| 453 | Ret.Duplicate = "tune=" ; |
| 454 | else |
| 455 | Ret.Tune = Value; |
| 456 | break; |
| 457 | |
| 458 | case AttrFeatureKind::NoFeature: |
| 459 | Ret.Features.push_back(x: "-" + Value.str()); |
| 460 | break; |
| 461 | |
| 462 | case AttrFeatureKind::Feature: |
| 463 | Ret.Features.push_back(x: "+" + Value.str()); |
| 464 | break; |
| 465 | } |
| 466 | } |
| 467 | return Ret; |
| 468 | } |
| 469 | |
| 470 | bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const { |
| 471 | return llvm::LoongArch::isValidCPUName(TuneCPU: Name); |
| 472 | } |
| 473 | |
| 474 | void LoongArchTargetInfo::fillValidCPUList( |
| 475 | SmallVectorImpl<StringRef> &Values) const { |
| 476 | llvm::LoongArch::fillValidCPUList(Values); |
| 477 | } |
| 478 | |
| 479 | bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const { |
| 480 | return llvm::LoongArch::isValidFeatureName(Feature: Name); |
| 481 | } |
| 482 | |