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" }, .Register: "$f0" }, |
85 | {.Aliases: {"$fa1" }, .Register: "$f1" }, |
86 | {.Aliases: {"$fa2" }, .Register: "$f2" }, |
87 | {.Aliases: {"$fa3" }, .Register: "$f3" }, |
88 | {.Aliases: {"$fa4" }, .Register: "$f4" }, |
89 | {.Aliases: {"$fa5" }, .Register: "$f5" }, |
90 | {.Aliases: {"$fa6" }, .Register: "$f6" }, |
91 | {.Aliases: {"$fa7" }, .Register: "$f7" }, |
92 | {.Aliases: {"$ft0" }, .Register: "$f8" }, |
93 | {.Aliases: {"$ft1" }, .Register: "$f9" }, |
94 | {.Aliases: {"$ft2" }, .Register: "$f10" }, |
95 | {.Aliases: {"$ft3" }, .Register: "$f11" }, |
96 | {.Aliases: {"$ft4" }, .Register: "$f12" }, |
97 | {.Aliases: {"$ft5" }, .Register: "$f13" }, |
98 | {.Aliases: {"$ft6" }, .Register: "$f14" }, |
99 | {.Aliases: {"$ft7" }, .Register: "$f15" }, |
100 | {.Aliases: {"$ft8" }, .Register: "$f16" }, |
101 | {.Aliases: {"$ft9" }, .Register: "$f17" }, |
102 | {.Aliases: {"$ft10" }, .Register: "$f18" }, |
103 | {.Aliases: {"$ft11" }, .Register: "$f19" }, |
104 | {.Aliases: {"$ft12" }, .Register: "$f20" }, |
105 | {.Aliases: {"$ft13" }, .Register: "$f21" }, |
106 | {.Aliases: {"$ft14" }, .Register: "$f22" }, |
107 | {.Aliases: {"$ft15" }, .Register: "$f23" }, |
108 | {.Aliases: {"$fs0" }, .Register: "$f24" }, |
109 | {.Aliases: {"$fs1" }, .Register: "$f25" }, |
110 | {.Aliases: {"$fs2" }, .Register: "$f26" }, |
111 | {.Aliases: {"$fs3" }, .Register: "$f27" }, |
112 | {.Aliases: {"$fs4" }, .Register: "$f28" }, |
113 | {.Aliases: {"$fs5" }, .Register: "$f29" }, |
114 | {.Aliases: {"$fs6" }, .Register: "$f30" }, |
115 | {.Aliases: {"$fs7" }, .Register: "$f31" }, |
116 | }; |
117 | return llvm::ArrayRef(GCCRegAliases); |
118 | } |
119 | |
120 | bool LoongArchTargetInfo::validateAsmConstraint( |
121 | const char *&Name, TargetInfo::ConstraintInfo &Info) const { |
122 | // See the GCC definitions here: |
123 | // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html |
124 | // Note that the 'm' constraint is handled in TargetInfo. |
125 | switch (*Name) { |
126 | default: |
127 | return false; |
128 | case 'f': |
129 | // A floating-point register (if available). |
130 | Info.setAllowsRegister(); |
131 | return true; |
132 | case 'k': |
133 | // A memory operand whose address is formed by a base register and |
134 | // (optionally scaled) index register. |
135 | Info.setAllowsMemory(); |
136 | return true; |
137 | case 'l': |
138 | // A signed 16-bit constant. |
139 | Info.setRequiresImmediate(Min: -32768, Max: 32767); |
140 | return true; |
141 | case 'q': |
142 | // A general-purpose register except for $r0 and $r1 (for the csrxchg |
143 | // instruction) |
144 | Info.setAllowsRegister(); |
145 | return true; |
146 | case 'I': |
147 | // A signed 12-bit constant (for arithmetic instructions). |
148 | Info.setRequiresImmediate(Min: -2048, Max: 2047); |
149 | return true; |
150 | case 'J': |
151 | // Integer zero. |
152 | Info.setRequiresImmediate(0); |
153 | return true; |
154 | case 'K': |
155 | // An unsigned 12-bit constant (for logic instructions). |
156 | Info.setRequiresImmediate(Min: 0, Max: 4095); |
157 | return true; |
158 | case 'Z': |
159 | // ZB: An address that is held in a general-purpose register. The offset is |
160 | // zero. |
161 | // ZC: A memory operand whose address is formed by a base register |
162 | // and offset that is suitable for use in instructions with the same |
163 | // addressing mode as ll.w and sc.w. |
164 | if (Name[1] == 'C' || Name[1] == 'B') { |
165 | Info.setAllowsMemory(); |
166 | ++Name; // Skip over 'Z'. |
167 | return true; |
168 | } |
169 | return false; |
170 | } |
171 | } |
172 | |
173 | std::string |
174 | LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { |
175 | std::string R; |
176 | switch (*Constraint) { |
177 | case 'Z': |
178 | // "ZC"/"ZB" are two-character constraints; add "^" hint for later |
179 | // parsing. |
180 | R = "^" + std::string(Constraint, 2); |
181 | ++Constraint; |
182 | break; |
183 | default: |
184 | R = TargetInfo::convertConstraint(Constraint); |
185 | break; |
186 | } |
187 | return R; |
188 | } |
189 | |
190 | void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, |
191 | MacroBuilder &Builder) const { |
192 | Builder.defineMacro(Name: "__loongarch__" ); |
193 | unsigned GRLen = getRegisterWidth(); |
194 | Builder.defineMacro(Name: "__loongarch_grlen" , Value: Twine(GRLen)); |
195 | if (GRLen == 64) |
196 | Builder.defineMacro(Name: "__loongarch64" ); |
197 | |
198 | if (HasFeatureD) |
199 | Builder.defineMacro(Name: "__loongarch_frlen" , Value: "64" ); |
200 | else if (HasFeatureF) |
201 | Builder.defineMacro(Name: "__loongarch_frlen" , Value: "32" ); |
202 | else |
203 | Builder.defineMacro(Name: "__loongarch_frlen" , Value: "0" ); |
204 | |
205 | // Define __loongarch_arch. |
206 | StringRef ArchName = getCPU(); |
207 | if (ArchName == "loongarch64" ) { |
208 | if (HasFeatureLSX) { |
209 | // TODO: As more features of the V1.1 ISA are supported, a unified "v1.1" |
210 | // arch feature set will be used to include all sub-features belonging to |
211 | // the V1.1 ISA version. |
212 | if (HasFeatureFrecipe && HasFeatureLAM_BH && HasFeatureLAMCAS && |
213 | HasFeatureLD_SEQ_SA && HasFeatureDiv32 && HasFeatureSCQ) |
214 | Builder.defineMacro(Name: "__loongarch_arch" , |
215 | Value: Twine('"') + "la64v1.1" + Twine('"')); |
216 | else |
217 | Builder.defineMacro(Name: "__loongarch_arch" , |
218 | Value: Twine('"') + "la64v1.0" + Twine('"')); |
219 | } else { |
220 | Builder.defineMacro(Name: "__loongarch_arch" , |
221 | Value: Twine('"') + ArchName + Twine('"')); |
222 | } |
223 | } else { |
224 | Builder.defineMacro(Name: "__loongarch_arch" , Value: Twine('"') + ArchName + Twine('"')); |
225 | } |
226 | |
227 | // Define __loongarch_tune. |
228 | StringRef TuneCPU = getTargetOpts().TuneCPU; |
229 | if (TuneCPU.empty()) |
230 | TuneCPU = ArchName; |
231 | Builder.defineMacro(Name: "__loongarch_tune" , Value: Twine('"') + TuneCPU + Twine('"')); |
232 | |
233 | if (HasFeatureLASX) { |
234 | Builder.defineMacro(Name: "__loongarch_simd_width" , Value: "256" ); |
235 | Builder.defineMacro(Name: "__loongarch_sx" , Value: Twine(1)); |
236 | Builder.defineMacro(Name: "__loongarch_asx" , Value: Twine(1)); |
237 | } else if (HasFeatureLSX) { |
238 | Builder.defineMacro(Name: "__loongarch_simd_width" , Value: "128" ); |
239 | Builder.defineMacro(Name: "__loongarch_sx" , Value: Twine(1)); |
240 | } |
241 | if (HasFeatureFrecipe) |
242 | Builder.defineMacro(Name: "__loongarch_frecipe" , Value: Twine(1)); |
243 | |
244 | if (HasFeatureLAM_BH) |
245 | Builder.defineMacro(Name: "__loongarch_lam_bh" , Value: Twine(1)); |
246 | |
247 | if (HasFeatureLAMCAS) |
248 | Builder.defineMacro(Name: "__loongarch_lamcas" , Value: Twine(1)); |
249 | |
250 | if (HasFeatureLD_SEQ_SA) |
251 | Builder.defineMacro(Name: "__loongarch_ld_seq_sa" , Value: Twine(1)); |
252 | |
253 | if (HasFeatureDiv32) |
254 | Builder.defineMacro(Name: "__loongarch_div32" , Value: Twine(1)); |
255 | |
256 | if (HasFeatureSCQ) |
257 | Builder.defineMacro(Name: "__loongarch_scq" , Value: Twine(1)); |
258 | |
259 | StringRef ABI = getABI(); |
260 | if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s" ) |
261 | Builder.defineMacro(Name: "__loongarch_lp64" ); |
262 | |
263 | if (ABI == "lp64d" || ABI == "ilp32d" ) { |
264 | Builder.defineMacro(Name: "__loongarch_hard_float" ); |
265 | Builder.defineMacro(Name: "__loongarch_double_float" ); |
266 | } else if (ABI == "lp64f" || ABI == "ilp32f" ) { |
267 | Builder.defineMacro(Name: "__loongarch_hard_float" ); |
268 | Builder.defineMacro(Name: "__loongarch_single_float" ); |
269 | } else if (ABI == "lp64s" || ABI == "ilp32s" ) { |
270 | Builder.defineMacro(Name: "__loongarch_soft_float" ); |
271 | } |
272 | |
273 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1" ); |
274 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2" ); |
275 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" ); |
276 | if (GRLen == 64) |
277 | Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8" ); |
278 | } |
279 | |
280 | static constexpr int NumBaseBuiltins = |
281 | LoongArch::FirstLSXBuiltin - Builtin::FirstTSBuiltin; |
282 | static constexpr int NumLSXBuiltins = |
283 | LoongArch::FirstLASXBuiltin - LoongArch::FirstLSXBuiltin; |
284 | static constexpr int NumLASXBuiltins = |
285 | LoongArch::LastTSBuiltin - LoongArch::FirstLASXBuiltin; |
286 | static constexpr int NumBuiltins = |
287 | LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin; |
288 | static_assert(NumBuiltins == |
289 | (NumBaseBuiltins + NumLSXBuiltins + NumLASXBuiltins)); |
290 | |
291 | static constexpr llvm::StringTable BuiltinBaseStrings = |
292 | CLANG_BUILTIN_STR_TABLE_START |
293 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE |
294 | #include "clang/Basic/BuiltinsLoongArchBase.def" |
295 | #undef TARGET_BUILTIN |
296 | ; |
297 | |
298 | static constexpr auto BuiltinBaseInfos = Builtin::MakeInfos<NumBaseBuiltins>(Infos: { |
299 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY |
300 | #include "clang/Basic/BuiltinsLoongArchBase.def" |
301 | #undef TARGET_BUILTIN |
302 | }); |
303 | |
304 | static constexpr llvm::StringTable BuiltinLSXStrings = |
305 | CLANG_BUILTIN_STR_TABLE_START |
306 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE |
307 | #include "clang/Basic/BuiltinsLoongArchLSX.def" |
308 | #undef TARGET_BUILTIN |
309 | ; |
310 | |
311 | static constexpr auto BuiltinLSXInfos = Builtin::MakeInfos<NumLSXBuiltins>(Infos: { |
312 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY |
313 | #include "clang/Basic/BuiltinsLoongArchLSX.def" |
314 | #undef TARGET_BUILTIN |
315 | }); |
316 | |
317 | static constexpr llvm::StringTable BuiltinLASXStrings = |
318 | CLANG_BUILTIN_STR_TABLE_START |
319 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_STR_TABLE |
320 | #include "clang/Basic/BuiltinsLoongArchLASX.def" |
321 | #undef TARGET_BUILTIN |
322 | ; |
323 | |
324 | static constexpr auto BuiltinLASXInfos = Builtin::MakeInfos<NumLASXBuiltins>(Infos: { |
325 | #define TARGET_BUILTIN CLANG_TARGET_BUILTIN_ENTRY |
326 | #include "clang/Basic/BuiltinsLoongArchLASX.def" |
327 | #undef TARGET_BUILTIN |
328 | }); |
329 | |
330 | bool LoongArchTargetInfo::initFeatureMap( |
331 | llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, |
332 | const std::vector<std::string> &FeaturesVec) const { |
333 | if (getTriple().getArch() == llvm::Triple::loongarch64) |
334 | Features["64bit" ] = true; |
335 | if (getTriple().getArch() == llvm::Triple::loongarch32) |
336 | Features["32bit" ] = true; |
337 | |
338 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: FeaturesVec); |
339 | } |
340 | |
341 | /// Return true if has this feature. |
342 | bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { |
343 | bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; |
344 | // TODO: Handle more features. |
345 | return llvm::StringSwitch<bool>(Feature) |
346 | .Case(S: "loongarch32" , Value: !Is64Bit) |
347 | .Case(S: "loongarch64" , Value: Is64Bit) |
348 | .Case(S: "32bit" , Value: !Is64Bit) |
349 | .Case(S: "64bit" , Value: Is64Bit) |
350 | .Case(S: "lsx" , Value: HasFeatureLSX) |
351 | .Case(S: "lasx" , Value: HasFeatureLASX) |
352 | .Default(Value: false); |
353 | } |
354 | |
355 | llvm::SmallVector<Builtin::InfosShard> |
356 | LoongArchTargetInfo::getTargetBuiltins() const { |
357 | return { |
358 | {&BuiltinBaseStrings, BuiltinBaseInfos}, |
359 | {&BuiltinLSXStrings, BuiltinLSXInfos}, |
360 | {&BuiltinLASXStrings, BuiltinLASXInfos}, |
361 | }; |
362 | } |
363 | |
364 | bool LoongArchTargetInfo::handleTargetFeatures( |
365 | std::vector<std::string> &Features, DiagnosticsEngine &Diags) { |
366 | for (const auto &Feature : Features) { |
367 | if (Feature == "+d" || Feature == "+f" ) { |
368 | // "d" implies "f". |
369 | HasFeatureF = true; |
370 | if (Feature == "+d" ) { |
371 | HasFeatureD = true; |
372 | } |
373 | } else if (Feature == "+lsx" ) |
374 | HasFeatureLSX = true; |
375 | else if (Feature == "+lasx" ) |
376 | HasFeatureLASX = true; |
377 | else if (Feature == "-ual" ) |
378 | HasUnalignedAccess = false; |
379 | else if (Feature == "+frecipe" ) |
380 | HasFeatureFrecipe = true; |
381 | else if (Feature == "+lam-bh" ) |
382 | HasFeatureLAM_BH = true; |
383 | else if (Feature == "+lamcas" ) |
384 | HasFeatureLAMCAS = true; |
385 | else if (Feature == "+ld-seq-sa" ) |
386 | HasFeatureLD_SEQ_SA = true; |
387 | else if (Feature == "+div32" ) |
388 | HasFeatureDiv32 = true; |
389 | else if (Feature == "+scq" ) |
390 | HasFeatureSCQ = true; |
391 | } |
392 | return true; |
393 | } |
394 | |
395 | enum class AttrFeatureKind { Arch, Tune, NoFeature, Feature }; |
396 | |
397 | static std::pair<AttrFeatureKind, llvm::StringRef> |
398 | getAttrFeatureTypeAndValue(llvm::StringRef AttrFeature) { |
399 | if (auto Split = AttrFeature.split(Separator: "=" ); !Split.second.empty()) { |
400 | if (Split.first.trim() == "arch" ) |
401 | return {AttrFeatureKind::Arch, Split.second.trim()}; |
402 | if (Split.first.trim() == "tune" ) |
403 | return {AttrFeatureKind::Tune, Split.second.trim()}; |
404 | } |
405 | if (AttrFeature.starts_with(Prefix: "no-" )) |
406 | return {AttrFeatureKind::NoFeature, AttrFeature.drop_front(N: 3)}; |
407 | return {AttrFeatureKind::Feature, AttrFeature}; |
408 | } |
409 | |
410 | ParsedTargetAttr |
411 | LoongArchTargetInfo::parseTargetAttr(StringRef Features) const { |
412 | ParsedTargetAttr Ret; |
413 | if (Features == "default" ) |
414 | return Ret; |
415 | SmallVector<StringRef, 1> AttrFeatures; |
416 | Features.split(A&: AttrFeatures, Separator: "," ); |
417 | |
418 | for (auto &Feature : AttrFeatures) { |
419 | auto [Kind, Value] = getAttrFeatureTypeAndValue(AttrFeature: Feature.trim()); |
420 | |
421 | switch (Kind) { |
422 | case AttrFeatureKind::Arch: { |
423 | if (llvm::LoongArch::isValidArchName(Arch: Value) || Value == "la64v1.0" || |
424 | Value == "la64v1.1" ) { |
425 | std::vector<llvm::StringRef> ArchFeatures; |
426 | if (llvm::LoongArch::getArchFeatures(Arch: Value, Features&: ArchFeatures)) { |
427 | Ret.Features.insert(position: Ret.Features.end(), first: ArchFeatures.begin(), |
428 | last: ArchFeatures.end()); |
429 | } |
430 | |
431 | if (!Ret.CPU.empty()) |
432 | Ret.Duplicate = "arch=" ; |
433 | else if (Value == "la64v1.0" || Value == "la64v1.1" ) |
434 | Ret.CPU = "loongarch64" ; |
435 | else |
436 | Ret.CPU = Value; |
437 | } else { |
438 | Ret.Features.push_back(x: "!arch=" + Value.str()); |
439 | } |
440 | break; |
441 | } |
442 | |
443 | case AttrFeatureKind::Tune: |
444 | if (!Ret.Tune.empty()) |
445 | Ret.Duplicate = "tune=" ; |
446 | else |
447 | Ret.Tune = Value; |
448 | break; |
449 | |
450 | case AttrFeatureKind::NoFeature: |
451 | Ret.Features.push_back(x: "-" + Value.str()); |
452 | break; |
453 | |
454 | case AttrFeatureKind::Feature: |
455 | Ret.Features.push_back(x: "+" + Value.str()); |
456 | break; |
457 | } |
458 | } |
459 | return Ret; |
460 | } |
461 | |
462 | bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const { |
463 | return llvm::LoongArch::isValidCPUName(TuneCPU: Name); |
464 | } |
465 | |
466 | void LoongArchTargetInfo::fillValidCPUList( |
467 | SmallVectorImpl<StringRef> &Values) const { |
468 | llvm::LoongArch::fillValidCPUList(Values); |
469 | } |
470 | |
471 | bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const { |
472 | return llvm::LoongArch::isValidFeatureName(Feature: Name); |
473 | } |
474 | |