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 | |