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
20using namespace clang;
21using namespace clang::targets;
22
23ArrayRef<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
50ArrayRef<TargetInfo::GCCRegAlias>
51LoongArchTargetInfo::getGCCRegAliases() const {
52 static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
53 {.Aliases: {"zero", "$zero", "r0"}, .Register: "$r0"},
54 {.Aliases: {"ra", "$ra", "r1"}, .Register: "$r1"},
55 {.Aliases: {"tp", "$tp", "r2"}, .Register: "$r2"},
56 {.Aliases: {"sp", "$sp", "r3"}, .Register: "$r3"},
57 {.Aliases: {"a0", "$a0", "r4"}, .Register: "$r4"},
58 {.Aliases: {"a1", "$a1", "r5"}, .Register: "$r5"},
59 {.Aliases: {"a2", "$a2", "r6"}, .Register: "$r6"},
60 {.Aliases: {"a3", "$a3", "r7"}, .Register: "$r7"},
61 {.Aliases: {"a4", "$a4", "r8"}, .Register: "$r8"},
62 {.Aliases: {"a5", "$a5", "r9"}, .Register: "$r9"},
63 {.Aliases: {"a6", "$a6", "r10"}, .Register: "$r10"},
64 {.Aliases: {"a7", "$a7", "r11"}, .Register: "$r11"},
65 {.Aliases: {"t0", "$t0", "r12"}, .Register: "$r12"},
66 {.Aliases: {"t1", "$t1", "r13"}, .Register: "$r13"},
67 {.Aliases: {"t2", "$t2", "r14"}, .Register: "$r14"},
68 {.Aliases: {"t3", "$t3", "r15"}, .Register: "$r15"},
69 {.Aliases: {"t4", "$t4", "r16"}, .Register: "$r16"},
70 {.Aliases: {"t5", "$t5", "r17"}, .Register: "$r17"},
71 {.Aliases: {"t6", "$t6", "r18"}, .Register: "$r18"},
72 {.Aliases: {"t7", "$t7", "r19"}, .Register: "$r19"},
73 {.Aliases: {"t8", "$t8", "r20"}, .Register: "$r20"},
74 {.Aliases: {"r21"}, .Register: "$r21"},
75 {.Aliases: {"s9", "$s9", "r22", "fp", "$fp"}, .Register: "$r22"},
76 {.Aliases: {"s0", "$s0", "r23"}, .Register: "$r23"},
77 {.Aliases: {"s1", "$s1", "r24"}, .Register: "$r24"},
78 {.Aliases: {"s2", "$s2", "r25"}, .Register: "$r25"},
79 {.Aliases: {"s3", "$s3", "r26"}, .Register: "$r26"},
80 {.Aliases: {"s4", "$s4", "r27"}, .Register: "$r27"},
81 {.Aliases: {"s5", "$s5", "r28"}, .Register: "$r28"},
82 {.Aliases: {"s6", "$s6", "r29"}, .Register: "$r29"},
83 {.Aliases: {"s7", "$s7", "r30"}, .Register: "$r30"},
84 {.Aliases: {"s8", "$s8", "r31"}, .Register: "$r31"},
85 {.Aliases: {"$fa0"}, .Register: "$f0"},
86 {.Aliases: {"$fa1"}, .Register: "$f1"},
87 {.Aliases: {"$fa2"}, .Register: "$f2"},
88 {.Aliases: {"$fa3"}, .Register: "$f3"},
89 {.Aliases: {"$fa4"}, .Register: "$f4"},
90 {.Aliases: {"$fa5"}, .Register: "$f5"},
91 {.Aliases: {"$fa6"}, .Register: "$f6"},
92 {.Aliases: {"$fa7"}, .Register: "$f7"},
93 {.Aliases: {"$ft0"}, .Register: "$f8"},
94 {.Aliases: {"$ft1"}, .Register: "$f9"},
95 {.Aliases: {"$ft2"}, .Register: "$f10"},
96 {.Aliases: {"$ft3"}, .Register: "$f11"},
97 {.Aliases: {"$ft4"}, .Register: "$f12"},
98 {.Aliases: {"$ft5"}, .Register: "$f13"},
99 {.Aliases: {"$ft6"}, .Register: "$f14"},
100 {.Aliases: {"$ft7"}, .Register: "$f15"},
101 {.Aliases: {"$ft8"}, .Register: "$f16"},
102 {.Aliases: {"$ft9"}, .Register: "$f17"},
103 {.Aliases: {"$ft10"}, .Register: "$f18"},
104 {.Aliases: {"$ft11"}, .Register: "$f19"},
105 {.Aliases: {"$ft12"}, .Register: "$f20"},
106 {.Aliases: {"$ft13"}, .Register: "$f21"},
107 {.Aliases: {"$ft14"}, .Register: "$f22"},
108 {.Aliases: {"$ft15"}, .Register: "$f23"},
109 {.Aliases: {"$fs0"}, .Register: "$f24"},
110 {.Aliases: {"$fs1"}, .Register: "$f25"},
111 {.Aliases: {"$fs2"}, .Register: "$f26"},
112 {.Aliases: {"$fs3"}, .Register: "$f27"},
113 {.Aliases: {"$fs4"}, .Register: "$f28"},
114 {.Aliases: {"$fs5"}, .Register: "$f29"},
115 {.Aliases: {"$fs6"}, .Register: "$f30"},
116 {.Aliases: {"$fs7"}, .Register: "$f31"},
117 };
118 return llvm::ArrayRef(GCCRegAliases);
119}
120
121bool 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(Min: -32768, Max: 32767);
141 return true;
142 case 'I':
143 // A signed 12-bit constant (for arithmetic instructions).
144 Info.setRequiresImmediate(Min: -2048, Max: 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(Min: 0, Max: 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
169std::string
170LoongArchTargetInfo::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
186void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
187 MacroBuilder &Builder) const {
188 Builder.defineMacro(Name: "__loongarch__");
189 unsigned GRLen = getRegisterWidth();
190 Builder.defineMacro(Name: "__loongarch_grlen", Value: Twine(GRLen));
191 if (GRLen == 64)
192 Builder.defineMacro(Name: "__loongarch64");
193
194 if (HasFeatureD)
195 Builder.defineMacro(Name: "__loongarch_frlen", Value: "64");
196 else if (HasFeatureF)
197 Builder.defineMacro(Name: "__loongarch_frlen", Value: "32");
198 else
199 Builder.defineMacro(Name: "__loongarch_frlen", Value: "0");
200
201 // Define __loongarch_arch.
202 StringRef ArchName = getCPU();
203 Builder.defineMacro(Name: "__loongarch_arch", Value: Twine('"') + ArchName + Twine('"'));
204
205 // Define __loongarch_tune.
206 StringRef TuneCPU = getTargetOpts().TuneCPU;
207 if (TuneCPU.empty())
208 TuneCPU = ArchName;
209 Builder.defineMacro(Name: "__loongarch_tune", Value: Twine('"') + TuneCPU + Twine('"'));
210
211 if (HasFeatureLSX)
212 Builder.defineMacro(Name: "__loongarch_sx", Value: Twine(1));
213 if (HasFeatureLASX)
214 Builder.defineMacro(Name: "__loongarch_asx", Value: Twine(1));
215
216 StringRef ABI = getABI();
217 if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
218 Builder.defineMacro(Name: "__loongarch_lp64");
219
220 if (ABI == "lp64d" || ABI == "ilp32d") {
221 Builder.defineMacro(Name: "__loongarch_hard_float");
222 Builder.defineMacro(Name: "__loongarch_double_float");
223 } else if (ABI == "lp64f" || ABI == "ilp32f") {
224 Builder.defineMacro(Name: "__loongarch_hard_float");
225 Builder.defineMacro(Name: "__loongarch_single_float");
226 } else if (ABI == "lp64s" || ABI == "ilp32s") {
227 Builder.defineMacro(Name: "__loongarch_soft_float");
228 }
229
230 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
231 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
232 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
233 if (GRLen == 64)
234 Builder.defineMacro(Name: "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
235}
236
237static constexpr Builtin::Info BuiltinInfo[] = {
238#define BUILTIN(ID, TYPE, ATTRS) \
239 {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
240#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
241 {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
242#include "clang/Basic/BuiltinsLoongArch.def"
243};
244
245bool LoongArchTargetInfo::initFeatureMap(
246 llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
247 const std::vector<std::string> &FeaturesVec) const {
248 if (getTriple().getArch() == llvm::Triple::loongarch64)
249 Features["64bit"] = true;
250 if (getTriple().getArch() == llvm::Triple::loongarch32)
251 Features["32bit"] = true;
252
253 return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec: FeaturesVec);
254}
255
256/// Return true if has this feature.
257bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {
258 bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;
259 // TODO: Handle more features.
260 return llvm::StringSwitch<bool>(Feature)
261 .Case(S: "loongarch32", Value: !Is64Bit)
262 .Case(S: "loongarch64", Value: Is64Bit)
263 .Case(S: "32bit", Value: !Is64Bit)
264 .Case(S: "64bit", Value: Is64Bit)
265 .Case(S: "lsx", Value: HasFeatureLSX)
266 .Case(S: "lasx", Value: HasFeatureLASX)
267 .Default(Value: false);
268}
269
270ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const {
271 return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin -
272 Builtin::FirstTSBuiltin);
273}
274
275bool LoongArchTargetInfo::handleTargetFeatures(
276 std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
277 for (const auto &Feature : Features) {
278 if (Feature == "+d" || Feature == "+f") {
279 // "d" implies "f".
280 HasFeatureF = true;
281 if (Feature == "+d") {
282 HasFeatureD = true;
283 }
284 } else if (Feature == "+lsx")
285 HasFeatureLSX = true;
286 else if (Feature == "+lasx")
287 HasFeatureLASX = true;
288 else if (Feature == "-ual")
289 HasUnalignedAccess = false;
290 }
291 return true;
292}
293
294bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const {
295 return llvm::LoongArch::isValidCPUName(TuneCPU: Name);
296}
297
298void LoongArchTargetInfo::fillValidCPUList(
299 SmallVectorImpl<StringRef> &Values) const {
300 llvm::LoongArch::fillValidCPUList(Values);
301}
302

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