xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Targets/LoongArch.cpp (revision 63f537551380d2dab29fa402ad1269feae17e594)
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/TargetParser.h"
18 #include "llvm/Support/raw_ostream.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   return llvm::ArrayRef(GCCRegNames);
36 }
37 
38 ArrayRef<TargetInfo::GCCRegAlias>
39 LoongArchTargetInfo::getGCCRegAliases() const {
40   static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
41       {{"$zero"}, "$r0"},       {{"$ra"}, "$r1"},    {{"$tp"}, "$r2"},
42       {{"$sp"}, "$r3"},         {{"$a0"}, "$r4"},    {{"$a1"}, "$r5"},
43       {{"$a2"}, "$r6"},         {{"$a3"}, "$r7"},    {{"$a4"}, "$r8"},
44       {{"$a5"}, "$r9"},         {{"$a6"}, "$r10"},   {{"$a7"}, "$r11"},
45       {{"$t0"}, "$r12"},        {{"$t1"}, "$r13"},   {{"$t2"}, "$r14"},
46       {{"$t3"}, "$r15"},        {{"$t4"}, "$r16"},   {{"$t5"}, "$r17"},
47       {{"$t6"}, "$r18"},        {{"$t7"}, "$r19"},   {{"$t8"}, "$r20"},
48       {{"$fp", "$s9"}, "$r22"}, {{"$s0"}, "$r23"},   {{"$s1"}, "$r24"},
49       {{"$s2"}, "$r25"},        {{"$s3"}, "$r26"},   {{"$s4"}, "$r27"},
50       {{"$s5"}, "$r28"},        {{"$s6"}, "$r29"},   {{"$s7"}, "$r30"},
51       {{"$s8"}, "$r31"},        {{"$fa0"}, "$f0"},   {{"$fa1"}, "$f1"},
52       {{"$fa2"}, "$f2"},        {{"$fa3"}, "$f3"},   {{"$fa4"}, "$f4"},
53       {{"$fa5"}, "$f5"},        {{"$fa6"}, "$f6"},   {{"$fa7"}, "$f7"},
54       {{"$ft0"}, "$f8"},        {{"$ft1"}, "$f9"},   {{"$ft2"}, "$f10"},
55       {{"$ft3"}, "$f11"},       {{"$ft4"}, "$f12"},  {{"$ft5"}, "$f13"},
56       {{"$ft6"}, "$f14"},       {{"$ft7"}, "$f15"},  {{"$ft8"}, "$f16"},
57       {{"$ft9"}, "$f17"},       {{"$ft10"}, "$f18"}, {{"$ft11"}, "$f19"},
58       {{"$ft12"}, "$f20"},      {{"$ft13"}, "$f21"}, {{"$ft14"}, "$f22"},
59       {{"$ft15"}, "$f23"},      {{"$fs0"}, "$f24"},  {{"$fs1"}, "$f25"},
60       {{"$fs2"}, "$f26"},       {{"$fs3"}, "$f27"},  {{"$fs4"}, "$f28"},
61       {{"$fs5"}, "$f29"},       {{"$fs6"}, "$f30"},  {{"$fs7"}, "$f31"},
62   };
63   return llvm::ArrayRef(GCCRegAliases);
64 }
65 
66 bool LoongArchTargetInfo::validateAsmConstraint(
67     const char *&Name, TargetInfo::ConstraintInfo &Info) const {
68   // See the GCC definitions here:
69   // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html
70   // Note that the 'm' constraint is handled in TargetInfo.
71   switch (*Name) {
72   default:
73     return false;
74   case 'f':
75     // A floating-point register (if available).
76     Info.setAllowsRegister();
77     return true;
78   case 'k':
79     // A memory operand whose address is formed by a base register and
80     // (optionally scaled) index register.
81     Info.setAllowsMemory();
82     return true;
83   case 'l':
84     // A signed 16-bit constant.
85     Info.setRequiresImmediate(-32768, 32767);
86     return true;
87   case 'I':
88     // A signed 12-bit constant (for arithmetic instructions).
89     Info.setRequiresImmediate(-2048, 2047);
90     return true;
91   case 'J':
92     // Integer zero.
93     Info.setRequiresImmediate(0);
94     return true;
95   case 'K':
96     // An unsigned 12-bit constant (for logic instructions).
97     Info.setRequiresImmediate(0, 4095);
98     return true;
99   case 'Z':
100     // ZB: An address that is held in a general-purpose register. The offset is
101     //     zero.
102     // ZC: A memory operand whose address is formed by a base register
103     //     and offset that is suitable for use in instructions with the same
104     //     addressing mode as ll.w and sc.w.
105     if (Name[1] == 'C' || Name[1] == 'B') {
106       Info.setAllowsMemory();
107       ++Name; // Skip over 'Z'.
108       return true;
109     }
110     return false;
111   }
112 }
113 
114 std::string
115 LoongArchTargetInfo::convertConstraint(const char *&Constraint) const {
116   std::string R;
117   switch (*Constraint) {
118   case 'Z':
119     // "ZC"/"ZB" are two-character constraints; add "^" hint for later
120     // parsing.
121     R = "^" + std::string(Constraint, 2);
122     ++Constraint;
123     break;
124   default:
125     R = TargetInfo::convertConstraint(Constraint);
126     break;
127   }
128   return R;
129 }
130 
131 void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
132                                            MacroBuilder &Builder) const {
133   Builder.defineMacro("__loongarch__");
134   unsigned GRLen = getRegisterWidth();
135   Builder.defineMacro("__loongarch_grlen", Twine(GRLen));
136   if (GRLen == 64)
137     Builder.defineMacro("__loongarch64");
138 
139   if (HasFeatureD)
140     Builder.defineMacro("__loongarch_frlen", "64");
141   else if (HasFeatureF)
142     Builder.defineMacro("__loongarch_frlen", "32");
143   else
144     Builder.defineMacro("__loongarch_frlen", "0");
145 
146   // TODO: define __loongarch_arch and __loongarch_tune.
147 
148   StringRef ABI = getABI();
149   if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
150     Builder.defineMacro("__loongarch_lp64");
151 
152   if (ABI == "lp64d" || ABI == "ilp32d") {
153     Builder.defineMacro("__loongarch_hard_float");
154     Builder.defineMacro("__loongarch_double_float");
155   } else if (ABI == "lp64f" || ABI == "ilp32f") {
156     Builder.defineMacro("__loongarch_hard_float");
157     Builder.defineMacro("__loongarch_single_float");
158   } else if (ABI == "lp64s" || ABI == "ilp32s") {
159     Builder.defineMacro("__loongarch_soft_float");
160   }
161 
162   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
163   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
164   Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
165   if (GRLen == 64)
166     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
167 }
168 
169 static constexpr Builtin::Info BuiltinInfo[] = {
170 #define BUILTIN(ID, TYPE, ATTRS)                                               \
171   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
172 #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
173   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
174 #include "clang/Basic/BuiltinsLoongArch.def"
175 };
176 
177 bool LoongArchTargetInfo::initFeatureMap(
178     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
179     const std::vector<std::string> &FeaturesVec) const {
180   if (getTriple().getArch() == llvm::Triple::loongarch64)
181     Features["64bit"] = true;
182   if (getTriple().getArch() == llvm::Triple::loongarch32)
183     Features["32bit"] = true;
184 
185   return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
186 }
187 
188 /// Return true if has this feature.
189 bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {
190   bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;
191   // TODO: Handle more features.
192   return llvm::StringSwitch<bool>(Feature)
193       .Case("loongarch32", !Is64Bit)
194       .Case("loongarch64", Is64Bit)
195       .Case("32bit", !Is64Bit)
196       .Case("64bit", Is64Bit)
197       .Default(false);
198 }
199 
200 ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const {
201   return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin -
202                                          Builtin::FirstTSBuiltin);
203 }
204 
205 bool LoongArchTargetInfo::handleTargetFeatures(
206     std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
207   for (const auto &Feature : Features) {
208     if (Feature == "+d" || Feature == "+f") {
209       // "d" implies "f".
210       HasFeatureF = true;
211       if (Feature == "+d") {
212         HasFeatureD = true;
213       }
214     }
215   }
216   return true;
217 }
218