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