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
19using namespace clang;
20using namespace clang::targets;
21
22ArrayRef<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
49ArrayRef<TargetInfo::GCCRegAlias>
50LoongArchTargetInfo::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
120bool 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
173std::string
174LoongArchTargetInfo::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
190void 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
280static constexpr int NumBaseBuiltins =
281 LoongArch::FirstLSXBuiltin - Builtin::FirstTSBuiltin;
282static constexpr int NumLSXBuiltins =
283 LoongArch::FirstLASXBuiltin - LoongArch::FirstLSXBuiltin;
284static constexpr int NumLASXBuiltins =
285 LoongArch::LastTSBuiltin - LoongArch::FirstLASXBuiltin;
286static constexpr int NumBuiltins =
287 LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin;
288static_assert(NumBuiltins ==
289 (NumBaseBuiltins + NumLSXBuiltins + NumLASXBuiltins));
290
291static 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
298static 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
304static 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
311static 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
317static 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
324static 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
330bool 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.
342bool 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
355llvm::SmallVector<Builtin::InfosShard>
356LoongArchTargetInfo::getTargetBuiltins() const {
357 return {
358 {&BuiltinBaseStrings, BuiltinBaseInfos},
359 {&BuiltinLSXStrings, BuiltinLSXInfos},
360 {&BuiltinLASXStrings, BuiltinLASXInfos},
361 };
362}
363
364bool 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
395enum class AttrFeatureKind { Arch, Tune, NoFeature, Feature };
396
397static std::pair<AttrFeatureKind, llvm::StringRef>
398getAttrFeatureTypeAndValue(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
410ParsedTargetAttr
411LoongArchTargetInfo::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
462bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const {
463 return llvm::LoongArch::isValidCPUName(TuneCPU: Name);
464}
465
466void LoongArchTargetInfo::fillValidCPUList(
467 SmallVectorImpl<StringRef> &Values) const {
468 llvm::LoongArch::fillValidCPUList(Values);
469}
470
471bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const {
472 return llvm::LoongArch::isValidFeatureName(Feature: Name);
473}
474

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/lib/Basic/Targets/LoongArch.cpp