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