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