Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
35294 views
1
//===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- C++ -*-===//
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
#include "LoongArch.h"
10
#include "ToolChains/CommonArgs.h"
11
#include "clang/Basic/DiagnosticDriver.h"
12
#include "clang/Driver/Driver.h"
13
#include "clang/Driver/DriverDiagnostic.h"
14
#include "clang/Driver/Options.h"
15
#include "llvm/TargetParser/Host.h"
16
#include "llvm/TargetParser/LoongArchTargetParser.h"
17
18
using namespace clang::driver;
19
using namespace clang::driver::tools;
20
using namespace clang;
21
using namespace llvm::opt;
22
23
StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
24
const llvm::Triple &Triple) {
25
assert((Triple.getArch() == llvm::Triple::loongarch32 ||
26
Triple.getArch() == llvm::Triple::loongarch64) &&
27
"Unexpected triple");
28
bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
29
30
// Record -mabi value for later use.
31
const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ);
32
StringRef MABIValue;
33
if (MABIArg) {
34
MABIValue = MABIArg->getValue();
35
}
36
37
// Parse -mfpu value for later use.
38
const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
39
int FPU = -1;
40
if (MFPUArg) {
41
StringRef V = MFPUArg->getValue();
42
if (V == "64")
43
FPU = 64;
44
else if (V == "32")
45
FPU = 32;
46
else if (V == "0" || V == "none")
47
FPU = 0;
48
else
49
D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V;
50
}
51
52
// Check -m*-float firstly since they have highest priority.
53
if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
54
options::OPT_msingle_float,
55
options::OPT_msoft_float)) {
56
StringRef ImpliedABI;
57
int ImpliedFPU = -1;
58
if (A->getOption().matches(options::OPT_mdouble_float)) {
59
ImpliedABI = IsLA32 ? "ilp32d" : "lp64d";
60
ImpliedFPU = 64;
61
}
62
if (A->getOption().matches(options::OPT_msingle_float)) {
63
ImpliedABI = IsLA32 ? "ilp32f" : "lp64f";
64
ImpliedFPU = 32;
65
}
66
if (A->getOption().matches(options::OPT_msoft_float)) {
67
ImpliedABI = IsLA32 ? "ilp32s" : "lp64s";
68
ImpliedFPU = 0;
69
}
70
71
// Check `-mabi=` and `-mfpu=` settings and report if they conflict with
72
// the higher-priority settings implied by -m*-float.
73
//
74
// ImpliedABI and ImpliedFPU are guaranteed to have valid values because
75
// one of the match arms must match if execution can arrive here at all.
76
if (!MABIValue.empty() && ImpliedABI != MABIValue)
77
D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
78
<< MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI;
79
80
if (FPU != -1 && ImpliedFPU != FPU)
81
D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
82
<< MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU;
83
84
return ImpliedABI;
85
}
86
87
// If `-mabi=` is specified, use it.
88
if (!MABIValue.empty())
89
return MABIValue;
90
91
// Select abi based on -mfpu=xx.
92
switch (FPU) {
93
case 64:
94
return IsLA32 ? "ilp32d" : "lp64d";
95
case 32:
96
return IsLA32 ? "ilp32f" : "lp64f";
97
case 0:
98
return IsLA32 ? "ilp32s" : "lp64s";
99
}
100
101
// Choose a default based on the triple.
102
// Honor the explicit ABI modifier suffix in triple's environment part if
103
// present, falling back to {ILP32,LP64}D otherwise.
104
switch (Triple.getEnvironment()) {
105
case llvm::Triple::GNUSF:
106
return IsLA32 ? "ilp32s" : "lp64s";
107
case llvm::Triple::GNUF32:
108
return IsLA32 ? "ilp32f" : "lp64f";
109
case llvm::Triple::GNUF64:
110
// This was originally permitted (and indeed the canonical way) to
111
// represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to
112
// drop the explicit suffix in favor of unmarked `-gnu` for the
113
// "general-purpose" ABIs, among other non-technical reasons.
114
//
115
// The spec change did not mention whether existing usages of "gnuf64"
116
// shall remain valid or not, so we are going to continue recognizing it
117
// for some time, until it is clear that everyone else has migrated away
118
// from it.
119
[[fallthrough]];
120
case llvm::Triple::GNU:
121
default:
122
return IsLA32 ? "ilp32d" : "lp64d";
123
}
124
}
125
126
void loongarch::getLoongArchTargetFeatures(const Driver &D,
127
const llvm::Triple &Triple,
128
const ArgList &Args,
129
std::vector<StringRef> &Features) {
130
// Enable the `lsx` feature on 64-bit LoongArch by default.
131
if (Triple.isLoongArch64() &&
132
(!Args.hasArgNoClaim(clang::driver::options::OPT_march_EQ)))
133
Features.push_back("+lsx");
134
135
std::string ArchName;
136
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
137
ArchName = A->getValue();
138
ArchName = postProcessTargetCPUString(ArchName, Triple);
139
llvm::LoongArch::getArchFeatures(ArchName, Features);
140
141
// Select floating-point features determined by -mdouble-float,
142
// -msingle-float, -msoft-float and -mfpu.
143
// Note: -m*-float wins any other options.
144
if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
145
options::OPT_msingle_float,
146
options::OPT_msoft_float)) {
147
if (A->getOption().matches(options::OPT_mdouble_float)) {
148
Features.push_back("+f");
149
Features.push_back("+d");
150
} else if (A->getOption().matches(options::OPT_msingle_float)) {
151
Features.push_back("+f");
152
Features.push_back("-d");
153
Features.push_back("-lsx");
154
} else /*Soft-float*/ {
155
Features.push_back("-f");
156
Features.push_back("-d");
157
Features.push_back("-lsx");
158
}
159
} else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
160
StringRef FPU = A->getValue();
161
if (FPU == "64") {
162
Features.push_back("+f");
163
Features.push_back("+d");
164
} else if (FPU == "32") {
165
Features.push_back("+f");
166
Features.push_back("-d");
167
Features.push_back("-lsx");
168
} else if (FPU == "0" || FPU == "none") {
169
Features.push_back("-f");
170
Features.push_back("-d");
171
Features.push_back("-lsx");
172
} else {
173
D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
174
}
175
}
176
177
// Select the `ual` feature determined by -m[no-]strict-align.
178
AddTargetFeature(Args, Features, options::OPT_mno_strict_align,
179
options::OPT_mstrict_align, "ual");
180
181
// Accept but warn about these TargetSpecific options.
182
if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
183
A->ignoreTargetSpecific();
184
if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
185
A->ignoreTargetSpecific();
186
if (Arg *A = Args.getLastArgNoClaim(options::OPT_msimd_EQ))
187
A->ignoreTargetSpecific();
188
189
// Select lsx/lasx feature determined by -msimd=.
190
// Option -msimd= precedes -m[no-]lsx and -m[no-]lasx.
191
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
192
StringRef MSIMD = A->getValue();
193
if (MSIMD == "lsx") {
194
// Option -msimd=lsx depends on 64-bit FPU.
195
// -m*-float and -mfpu=none/0/32 conflict with -msimd=lsx.
196
if (llvm::find(Features, "-d") != Features.end())
197
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
198
else
199
Features.push_back("+lsx");
200
} else if (MSIMD == "lasx") {
201
// Option -msimd=lasx depends on 64-bit FPU and LSX.
202
// -m*-float, -mfpu=none/0/32 and -mno-lsx conflict with -msimd=lasx.
203
if (llvm::find(Features, "-d") != Features.end())
204
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
205
else if (llvm::find(Features, "-lsx") != Features.end())
206
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
207
208
// The command options do not contain -mno-lasx.
209
if (!Args.getLastArg(options::OPT_mno_lasx)) {
210
Features.push_back("+lsx");
211
Features.push_back("+lasx");
212
}
213
} else if (MSIMD == "none") {
214
if (llvm::find(Features, "+lsx") != Features.end())
215
Features.push_back("-lsx");
216
if (llvm::find(Features, "+lasx") != Features.end())
217
Features.push_back("-lasx");
218
} else {
219
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
220
}
221
}
222
223
// Select lsx feature determined by -m[no-]lsx.
224
if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
225
// LSX depends on 64-bit FPU.
226
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
227
if (A->getOption().matches(options::OPT_mlsx)) {
228
if (llvm::find(Features, "-d") != Features.end())
229
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
230
else /*-mlsx*/
231
Features.push_back("+lsx");
232
} else /*-mno-lsx*/ {
233
Features.push_back("-lsx");
234
}
235
}
236
237
// Select lasx feature determined by -m[no-]lasx.
238
if (const Arg *A =
239
Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) {
240
// LASX depends on 64-bit FPU and LSX.
241
// -mno-lsx conflicts with -mlasx.
242
if (A->getOption().matches(options::OPT_mlasx)) {
243
if (llvm::find(Features, "-d") != Features.end())
244
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
245
else { /*-mlasx*/
246
Features.push_back("+lsx");
247
Features.push_back("+lasx");
248
}
249
} else /*-mno-lasx*/
250
Features.push_back("-lasx");
251
}
252
}
253
254
std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
255
const llvm::Triple &Triple) {
256
std::string CPUString = CPU;
257
if (CPUString == "native") {
258
CPUString = llvm::sys::getHostCPUName();
259
if (CPUString == "generic")
260
CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
261
}
262
if (CPUString.empty())
263
CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
264
return CPUString;
265
}
266
267
std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
268
const llvm::Triple &Triple) {
269
std::string CPU;
270
std::string Arch;
271
// If we have -march, use that.
272
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
273
Arch = A->getValue();
274
if (Arch == "la64v1.0" || Arch == "la64v1.1")
275
CPU = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
276
else
277
CPU = Arch;
278
}
279
return postProcessTargetCPUString(CPU, Triple);
280
}
281
282