/src/llvm-project/clang/lib/Basic/Targets/LoongArch.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
20 | | using namespace clang; |
21 | | using namespace clang::targets; |
22 | | |
23 | 0 | ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const { |
24 | 0 | static const char *const GCCRegNames[] = { |
25 | | // General purpose registers. |
26 | 0 | "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", |
27 | 0 | "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18", |
28 | 0 | "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27", |
29 | 0 | "$r28", "$r29", "$r30", "$r31", |
30 | | // Floating point registers. |
31 | 0 | "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", |
32 | 0 | "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", |
33 | 0 | "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", |
34 | 0 | "$f28", "$f29", "$f30", "$f31", |
35 | | // Condition flag registers. |
36 | 0 | "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", |
37 | | // 128-bit vector registers. |
38 | 0 | "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", "$vr7", "$vr8", |
39 | 0 | "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr14", "$vr15", "$vr16", |
40 | 0 | "$vr17", "$vr18", "$vr19", "$vr20", "$vr21", "$vr22", "$vr23", "$vr24", |
41 | 0 | "$vr25", "$vr26", "$vr27", "$vr28", "$vr29", "$vr30", "$vr31", |
42 | | // 256-bit vector registers. |
43 | 0 | "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", "$xr7", "$xr8", |
44 | 0 | "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", "$xr15", "$xr16", |
45 | 0 | "$xr17", "$xr18", "$xr19", "$xr20", "$xr21", "$xr22", "$xr23", "$xr24", |
46 | 0 | "$xr25", "$xr26", "$xr27", "$xr28", "$xr29", "$xr30", "$xr31"}; |
47 | 0 | return llvm::ArrayRef(GCCRegNames); |
48 | 0 | } |
49 | | |
50 | | ArrayRef<TargetInfo::GCCRegAlias> |
51 | 0 | LoongArchTargetInfo::getGCCRegAliases() const { |
52 | 0 | static const TargetInfo::GCCRegAlias GCCRegAliases[] = { |
53 | 0 | {{"zero", "$zero", "r0"}, "$r0"}, |
54 | 0 | {{"ra", "$ra", "r1"}, "$r1"}, |
55 | 0 | {{"tp", "$tp", "r2"}, "$r2"}, |
56 | 0 | {{"sp", "$sp", "r3"}, "$r3"}, |
57 | 0 | {{"a0", "$a0", "r4"}, "$r4"}, |
58 | 0 | {{"a1", "$a1", "r5"}, "$r5"}, |
59 | 0 | {{"a2", "$a2", "r6"}, "$r6"}, |
60 | 0 | {{"a3", "$a3", "r7"}, "$r7"}, |
61 | 0 | {{"a4", "$a4", "r8"}, "$r8"}, |
62 | 0 | {{"a5", "$a5", "r9"}, "$r9"}, |
63 | 0 | {{"a6", "$a6", "r10"}, "$r10"}, |
64 | 0 | {{"a7", "$a7", "r11"}, "$r11"}, |
65 | 0 | {{"t0", "$t0", "r12"}, "$r12"}, |
66 | 0 | {{"t1", "$t1", "r13"}, "$r13"}, |
67 | 0 | {{"t2", "$t2", "r14"}, "$r14"}, |
68 | 0 | {{"t3", "$t3", "r15"}, "$r15"}, |
69 | 0 | {{"t4", "$t4", "r16"}, "$r16"}, |
70 | 0 | {{"t5", "$t5", "r17"}, "$r17"}, |
71 | 0 | {{"t6", "$t6", "r18"}, "$r18"}, |
72 | 0 | {{"t7", "$t7", "r19"}, "$r19"}, |
73 | 0 | {{"t8", "$t8", "r20"}, "$r20"}, |
74 | 0 | {{"r21"}, "$r21"}, |
75 | 0 | {{"s9", "$s9", "r22", "fp", "$fp"}, "$r22"}, |
76 | 0 | {{"s0", "$s0", "r23"}, "$r23"}, |
77 | 0 | {{"s1", "$s1", "r24"}, "$r24"}, |
78 | 0 | {{"s2", "$s2", "r25"}, "$r25"}, |
79 | 0 | {{"s3", "$s3", "r26"}, "$r26"}, |
80 | 0 | {{"s4", "$s4", "r27"}, "$r27"}, |
81 | 0 | {{"s5", "$s5", "r28"}, "$r28"}, |
82 | 0 | {{"s6", "$s6", "r29"}, "$r29"}, |
83 | 0 | {{"s7", "$s7", "r30"}, "$r30"}, |
84 | 0 | {{"s8", "$s8", "r31"}, "$r31"}, |
85 | 0 | {{"$fa0"}, "$f0"}, |
86 | 0 | {{"$fa1"}, "$f1"}, |
87 | 0 | {{"$fa2"}, "$f2"}, |
88 | 0 | {{"$fa3"}, "$f3"}, |
89 | 0 | {{"$fa4"}, "$f4"}, |
90 | 0 | {{"$fa5"}, "$f5"}, |
91 | 0 | {{"$fa6"}, "$f6"}, |
92 | 0 | {{"$fa7"}, "$f7"}, |
93 | 0 | {{"$ft0"}, "$f8"}, |
94 | 0 | {{"$ft1"}, "$f9"}, |
95 | 0 | {{"$ft2"}, "$f10"}, |
96 | 0 | {{"$ft3"}, "$f11"}, |
97 | 0 | {{"$ft4"}, "$f12"}, |
98 | 0 | {{"$ft5"}, "$f13"}, |
99 | 0 | {{"$ft6"}, "$f14"}, |
100 | 0 | {{"$ft7"}, "$f15"}, |
101 | 0 | {{"$ft8"}, "$f16"}, |
102 | 0 | {{"$ft9"}, "$f17"}, |
103 | 0 | {{"$ft10"}, "$f18"}, |
104 | 0 | {{"$ft11"}, "$f19"}, |
105 | 0 | {{"$ft12"}, "$f20"}, |
106 | 0 | {{"$ft13"}, "$f21"}, |
107 | 0 | {{"$ft14"}, "$f22"}, |
108 | 0 | {{"$ft15"}, "$f23"}, |
109 | 0 | {{"$fs0"}, "$f24"}, |
110 | 0 | {{"$fs1"}, "$f25"}, |
111 | 0 | {{"$fs2"}, "$f26"}, |
112 | 0 | {{"$fs3"}, "$f27"}, |
113 | 0 | {{"$fs4"}, "$f28"}, |
114 | 0 | {{"$fs5"}, "$f29"}, |
115 | 0 | {{"$fs6"}, "$f30"}, |
116 | 0 | {{"$fs7"}, "$f31"}, |
117 | 0 | }; |
118 | 0 | return llvm::ArrayRef(GCCRegAliases); |
119 | 0 | } |
120 | | |
121 | | bool LoongArchTargetInfo::validateAsmConstraint( |
122 | 0 | 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 | 0 | switch (*Name) { |
127 | 0 | default: |
128 | 0 | return false; |
129 | 0 | case 'f': |
130 | | // A floating-point register (if available). |
131 | 0 | Info.setAllowsRegister(); |
132 | 0 | return true; |
133 | 0 | case 'k': |
134 | | // A memory operand whose address is formed by a base register and |
135 | | // (optionally scaled) index register. |
136 | 0 | Info.setAllowsMemory(); |
137 | 0 | return true; |
138 | 0 | case 'l': |
139 | | // A signed 16-bit constant. |
140 | 0 | Info.setRequiresImmediate(-32768, 32767); |
141 | 0 | return true; |
142 | 0 | case 'I': |
143 | | // A signed 12-bit constant (for arithmetic instructions). |
144 | 0 | Info.setRequiresImmediate(-2048, 2047); |
145 | 0 | return true; |
146 | 0 | case 'J': |
147 | | // Integer zero. |
148 | 0 | Info.setRequiresImmediate(0); |
149 | 0 | return true; |
150 | 0 | case 'K': |
151 | | // An unsigned 12-bit constant (for logic instructions). |
152 | 0 | Info.setRequiresImmediate(0, 4095); |
153 | 0 | return true; |
154 | 0 | 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 | 0 | if (Name[1] == 'C' || Name[1] == 'B') { |
161 | 0 | Info.setAllowsMemory(); |
162 | 0 | ++Name; // Skip over 'Z'. |
163 | 0 | return true; |
164 | 0 | } |
165 | 0 | return false; |
166 | 0 | } |
167 | 0 | } |
168 | | |
169 | | std::string |
170 | 0 | LoongArchTargetInfo::convertConstraint(const char *&Constraint) const { |
171 | 0 | std::string R; |
172 | 0 | switch (*Constraint) { |
173 | 0 | case 'Z': |
174 | | // "ZC"/"ZB" are two-character constraints; add "^" hint for later |
175 | | // parsing. |
176 | 0 | R = "^" + std::string(Constraint, 2); |
177 | 0 | ++Constraint; |
178 | 0 | break; |
179 | 0 | default: |
180 | 0 | R = TargetInfo::convertConstraint(Constraint); |
181 | 0 | break; |
182 | 0 | } |
183 | 0 | return R; |
184 | 0 | } |
185 | | |
186 | | void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts, |
187 | 0 | MacroBuilder &Builder) const { |
188 | 0 | Builder.defineMacro("__loongarch__"); |
189 | 0 | unsigned GRLen = getRegisterWidth(); |
190 | 0 | Builder.defineMacro("__loongarch_grlen", Twine(GRLen)); |
191 | 0 | if (GRLen == 64) |
192 | 0 | Builder.defineMacro("__loongarch64"); |
193 | |
|
194 | 0 | if (HasFeatureD) |
195 | 0 | Builder.defineMacro("__loongarch_frlen", "64"); |
196 | 0 | else if (HasFeatureF) |
197 | 0 | Builder.defineMacro("__loongarch_frlen", "32"); |
198 | 0 | else |
199 | 0 | Builder.defineMacro("__loongarch_frlen", "0"); |
200 | | |
201 | | // Define __loongarch_arch. |
202 | 0 | StringRef ArchName = getCPU(); |
203 | 0 | Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"')); |
204 | | |
205 | | // Define __loongarch_tune. |
206 | 0 | StringRef TuneCPU = getTargetOpts().TuneCPU; |
207 | 0 | if (TuneCPU.empty()) |
208 | 0 | TuneCPU = ArchName; |
209 | 0 | Builder.defineMacro("__loongarch_tune", Twine('"') + TuneCPU + Twine('"')); |
210 | |
|
211 | 0 | if (HasFeatureLSX) |
212 | 0 | Builder.defineMacro("__loongarch_sx", Twine(1)); |
213 | 0 | if (HasFeatureLASX) |
214 | 0 | Builder.defineMacro("__loongarch_asx", Twine(1)); |
215 | |
|
216 | 0 | StringRef ABI = getABI(); |
217 | 0 | if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s") |
218 | 0 | Builder.defineMacro("__loongarch_lp64"); |
219 | |
|
220 | 0 | if (ABI == "lp64d" || ABI == "ilp32d") { |
221 | 0 | Builder.defineMacro("__loongarch_hard_float"); |
222 | 0 | Builder.defineMacro("__loongarch_double_float"); |
223 | 0 | } else if (ABI == "lp64f" || ABI == "ilp32f") { |
224 | 0 | Builder.defineMacro("__loongarch_hard_float"); |
225 | 0 | Builder.defineMacro("__loongarch_single_float"); |
226 | 0 | } else if (ABI == "lp64s" || ABI == "ilp32s") { |
227 | 0 | Builder.defineMacro("__loongarch_soft_float"); |
228 | 0 | } |
229 | |
|
230 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); |
231 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); |
232 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); |
233 | 0 | if (GRLen == 64) |
234 | 0 | Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); |
235 | 0 | } |
236 | | |
237 | | static 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 | | |
245 | | bool LoongArchTargetInfo::initFeatureMap( |
246 | | llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, |
247 | 0 | const std::vector<std::string> &FeaturesVec) const { |
248 | 0 | if (getTriple().getArch() == llvm::Triple::loongarch64) |
249 | 0 | Features["64bit"] = true; |
250 | 0 | if (getTriple().getArch() == llvm::Triple::loongarch32) |
251 | 0 | Features["32bit"] = true; |
252 | |
|
253 | 0 | return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); |
254 | 0 | } |
255 | | |
256 | | /// Return true if has this feature. |
257 | 0 | bool LoongArchTargetInfo::hasFeature(StringRef Feature) const { |
258 | 0 | bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64; |
259 | | // TODO: Handle more features. |
260 | 0 | return llvm::StringSwitch<bool>(Feature) |
261 | 0 | .Case("loongarch32", !Is64Bit) |
262 | 0 | .Case("loongarch64", Is64Bit) |
263 | 0 | .Case("32bit", !Is64Bit) |
264 | 0 | .Case("64bit", Is64Bit) |
265 | 0 | .Case("lsx", HasFeatureLSX) |
266 | 0 | .Case("lasx", HasFeatureLASX) |
267 | 0 | .Default(false); |
268 | 0 | } |
269 | | |
270 | 0 | ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const { |
271 | 0 | return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - |
272 | 0 | Builtin::FirstTSBuiltin); |
273 | 0 | } |
274 | | |
275 | | bool LoongArchTargetInfo::handleTargetFeatures( |
276 | 0 | std::vector<std::string> &Features, DiagnosticsEngine &Diags) { |
277 | 0 | for (const auto &Feature : Features) { |
278 | 0 | if (Feature == "+d" || Feature == "+f") { |
279 | | // "d" implies "f". |
280 | 0 | HasFeatureF = true; |
281 | 0 | if (Feature == "+d") { |
282 | 0 | HasFeatureD = true; |
283 | 0 | } |
284 | 0 | } else if (Feature == "+lsx") |
285 | 0 | HasFeatureLSX = true; |
286 | 0 | else if (Feature == "+lasx") |
287 | 0 | HasFeatureLASX = true; |
288 | 0 | } |
289 | 0 | return true; |
290 | 0 | } |
291 | | |
292 | 0 | bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const { |
293 | 0 | return llvm::LoongArch::isValidCPUName(Name); |
294 | 0 | } |
295 | | |
296 | | void LoongArchTargetInfo::fillValidCPUList( |
297 | 0 | SmallVectorImpl<StringRef> &Values) const { |
298 | 0 | llvm::LoongArch::fillValidCPUList(Values); |
299 | 0 | } |