Coverage Report

Created: 2024-01-17 10:31

/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
}