clang  19.0.0git
LoongArch.cpp
Go to the documentation of this file.
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"
12 #include "clang/Driver/Driver.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 
127  const llvm::Triple &Triple,
128  const ArgList &Args,
129  std::vector<StringRef> &Features) {
130  std::string ArchName;
131  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
132  ArchName = A->getValue();
133  ArchName = postProcessTargetCPUString(ArchName, Triple);
134  llvm::LoongArch::getArchFeatures(ArchName, Features);
135 
136  // Select floating-point features determined by -mdouble-float,
137  // -msingle-float, -msoft-float and -mfpu.
138  // Note: -m*-float wins any other options.
139  if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
140  options::OPT_msingle_float,
141  options::OPT_msoft_float)) {
142  if (A->getOption().matches(options::OPT_mdouble_float)) {
143  Features.push_back("+f");
144  Features.push_back("+d");
145  } else if (A->getOption().matches(options::OPT_msingle_float)) {
146  Features.push_back("+f");
147  Features.push_back("-d");
148  } else /*Soft-float*/ {
149  Features.push_back("-f");
150  Features.push_back("-d");
151  }
152  } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
153  StringRef FPU = A->getValue();
154  if (FPU == "64") {
155  Features.push_back("+f");
156  Features.push_back("+d");
157  } else if (FPU == "32") {
158  Features.push_back("+f");
159  Features.push_back("-d");
160  } else if (FPU == "0" || FPU == "none") {
161  Features.push_back("-f");
162  Features.push_back("-d");
163  } else {
164  D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
165  }
166  }
167 
168  // Select the `ual` feature determined by -m[no-]strict-align.
169  AddTargetFeature(Args, Features, options::OPT_mno_strict_align,
170  options::OPT_mstrict_align, "ual");
171 
172  // Accept but warn about these TargetSpecific options.
173  if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
174  A->ignoreTargetSpecific();
175  if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
176  A->ignoreTargetSpecific();
177 
178  // Select lsx feature determined by -m[no-]lsx.
179  if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
180  // LSX depends on 64-bit FPU.
181  // -m*-float and -mfpu=none/0/32 conflict with -mlsx.
182  if (A->getOption().matches(options::OPT_mlsx)) {
183  if (llvm::find(Features, "-d") != Features.end())
184  D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
185  else /*-mlsx*/
186  Features.push_back("+lsx");
187  } else /*-mno-lsx*/ {
188  Features.push_back("-lsx");
189  }
190  }
191 
192  // Select lasx feature determined by -m[no-]lasx.
193  if (const Arg *A =
194  Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) {
195  // LASX depends on 64-bit FPU and LSX.
196  // -mno-lsx conflicts with -mlasx.
197  if (A->getOption().matches(options::OPT_mlasx)) {
198  if (llvm::find(Features, "-d") != Features.end())
199  D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
200  else if (llvm::find(Features, "-lsx") != Features.end())
201  D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
202  else { /*-mlasx*/
203  Features.push_back("+lsx");
204  Features.push_back("+lasx");
205  }
206  } else /*-mno-lasx*/
207  Features.push_back("-lasx");
208  }
209 }
210 
211 std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
212  const llvm::Triple &Triple) {
213  std::string CPUString = CPU;
214  if (CPUString == "native") {
215  CPUString = llvm::sys::getHostCPUName();
216  if (CPUString == "generic")
217  CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
218  }
219  if (CPUString.empty())
220  CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
221  return CPUString;
222 }
223 
224 std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
225  const llvm::Triple &Triple) {
226  std::string CPU;
227  // If we have -march, use that.
228  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
229  CPU = A->getValue();
230  return postProcessTargetCPUString(CPU, Triple);
231 }
#define V(N, I)
Definition: ASTContext.h:3299
static bool getArchFeatures(const Driver &D, StringRef Arch, std::vector< StringRef > &Features, const ArgList &Args)
Definition: RISCV.cpp:29
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:146
StringRef getLoongArchABI(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
std::string getLoongArchTargetCPU(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: LoongArch.cpp:224
std::string postProcessTargetCPUString(const std::string &CPU, const llvm::Triple &Triple)
Definition: LoongArch.cpp:211
void getLoongArchTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< llvm::StringRef > &Features)
void AddTargetFeature(const llvm::opt::ArgList &Args, std::vector< StringRef > &Features, llvm::opt::OptSpecifier OnOpt, llvm::opt::OptSpecifier OffOpt, StringRef FeatureName)
The JSON file list parser is used to communicate input to InstallAPI.