xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1bdd1243dSDimitry Andric //===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- C++ -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric 
9bdd1243dSDimitry Andric #include "LoongArch.h"
10*06c3fb27SDimitry Andric #include "ToolChains/CommonArgs.h"
11bdd1243dSDimitry Andric #include "clang/Basic/DiagnosticDriver.h"
12bdd1243dSDimitry Andric #include "clang/Driver/Driver.h"
13bdd1243dSDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
14bdd1243dSDimitry Andric #include "clang/Driver/Options.h"
15*06c3fb27SDimitry Andric #include "llvm/TargetParser/LoongArchTargetParser.h"
16bdd1243dSDimitry Andric 
17bdd1243dSDimitry Andric using namespace clang::driver;
18bdd1243dSDimitry Andric using namespace clang::driver::tools;
19bdd1243dSDimitry Andric using namespace clang;
20bdd1243dSDimitry Andric using namespace llvm::opt;
21bdd1243dSDimitry Andric 
22bdd1243dSDimitry Andric StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
23bdd1243dSDimitry Andric                                      const llvm::Triple &Triple) {
24bdd1243dSDimitry Andric   assert((Triple.getArch() == llvm::Triple::loongarch32 ||
25bdd1243dSDimitry Andric           Triple.getArch() == llvm::Triple::loongarch64) &&
26bdd1243dSDimitry Andric          "Unexpected triple");
27bdd1243dSDimitry Andric   bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
28bdd1243dSDimitry Andric 
29*06c3fb27SDimitry Andric   // Record -mabi value for later use.
30*06c3fb27SDimitry Andric   const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ);
31*06c3fb27SDimitry Andric   StringRef MABIValue;
32*06c3fb27SDimitry Andric   if (MABIArg) {
33*06c3fb27SDimitry Andric     MABIValue = MABIArg->getValue();
34*06c3fb27SDimitry Andric   }
35*06c3fb27SDimitry Andric 
36*06c3fb27SDimitry Andric   // Parse -mfpu value for later use.
37*06c3fb27SDimitry Andric   const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
38*06c3fb27SDimitry Andric   int FPU = -1;
39*06c3fb27SDimitry Andric   if (MFPUArg) {
40*06c3fb27SDimitry Andric     StringRef V = MFPUArg->getValue();
41*06c3fb27SDimitry Andric     if (V == "64")
42*06c3fb27SDimitry Andric       FPU = 64;
43*06c3fb27SDimitry Andric     else if (V == "32")
44*06c3fb27SDimitry Andric       FPU = 32;
45*06c3fb27SDimitry Andric     else if (V == "0" || V == "none")
46*06c3fb27SDimitry Andric       FPU = 0;
47*06c3fb27SDimitry Andric     else
48*06c3fb27SDimitry Andric       D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V;
49*06c3fb27SDimitry Andric   }
50*06c3fb27SDimitry Andric 
51bdd1243dSDimitry Andric   // Check -m*-float firstly since they have highest priority.
52bdd1243dSDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
53bdd1243dSDimitry Andric                                      options::OPT_msingle_float,
54bdd1243dSDimitry Andric                                      options::OPT_msoft_float)) {
55*06c3fb27SDimitry Andric     StringRef ImpliedABI;
56*06c3fb27SDimitry Andric     int ImpliedFPU = -1;
57*06c3fb27SDimitry Andric     if (A->getOption().matches(options::OPT_mdouble_float)) {
58*06c3fb27SDimitry Andric       ImpliedABI = IsLA32 ? "ilp32d" : "lp64d";
59*06c3fb27SDimitry Andric       ImpliedFPU = 64;
60*06c3fb27SDimitry Andric     }
61*06c3fb27SDimitry Andric     if (A->getOption().matches(options::OPT_msingle_float)) {
62*06c3fb27SDimitry Andric       ImpliedABI = IsLA32 ? "ilp32f" : "lp64f";
63*06c3fb27SDimitry Andric       ImpliedFPU = 32;
64*06c3fb27SDimitry Andric     }
65*06c3fb27SDimitry Andric     if (A->getOption().matches(options::OPT_msoft_float)) {
66*06c3fb27SDimitry Andric       ImpliedABI = IsLA32 ? "ilp32s" : "lp64s";
67*06c3fb27SDimitry Andric       ImpliedFPU = 0;
68*06c3fb27SDimitry Andric     }
69*06c3fb27SDimitry Andric 
70*06c3fb27SDimitry Andric     // Check `-mabi=` and `-mfpu=` settings and report if they conflict with
71*06c3fb27SDimitry Andric     // the higher-priority settings implied by -m*-float.
72*06c3fb27SDimitry Andric     //
73*06c3fb27SDimitry Andric     // ImpliedABI and ImpliedFPU are guaranteed to have valid values because
74*06c3fb27SDimitry Andric     // one of the match arms must match if execution can arrive here at all.
75*06c3fb27SDimitry Andric     if (!MABIValue.empty() && ImpliedABI != MABIValue)
76*06c3fb27SDimitry Andric       D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
77*06c3fb27SDimitry Andric           << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI;
78*06c3fb27SDimitry Andric 
79*06c3fb27SDimitry Andric     if (FPU != -1 && ImpliedFPU != FPU)
80*06c3fb27SDimitry Andric       D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
81*06c3fb27SDimitry Andric           << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU;
82*06c3fb27SDimitry Andric 
83*06c3fb27SDimitry Andric     return ImpliedABI;
84bdd1243dSDimitry Andric   }
85bdd1243dSDimitry Andric 
86bdd1243dSDimitry Andric   // If `-mabi=` is specified, use it.
87*06c3fb27SDimitry Andric   if (!MABIValue.empty())
88*06c3fb27SDimitry Andric     return MABIValue;
89bdd1243dSDimitry Andric 
90bdd1243dSDimitry Andric   // Select abi based on -mfpu=xx.
91*06c3fb27SDimitry Andric   switch (FPU) {
92*06c3fb27SDimitry Andric   case 64:
93bdd1243dSDimitry Andric     return IsLA32 ? "ilp32d" : "lp64d";
94*06c3fb27SDimitry Andric   case 32:
95bdd1243dSDimitry Andric     return IsLA32 ? "ilp32f" : "lp64f";
96*06c3fb27SDimitry Andric   case 0:
97bdd1243dSDimitry Andric     return IsLA32 ? "ilp32s" : "lp64s";
98bdd1243dSDimitry Andric   }
99bdd1243dSDimitry Andric 
100bdd1243dSDimitry Andric   // Choose a default based on the triple.
101*06c3fb27SDimitry Andric   // Honor the explicit ABI modifier suffix in triple's environment part if
102*06c3fb27SDimitry Andric   // present, falling back to {ILP32,LP64}D otherwise.
103*06c3fb27SDimitry Andric   switch (Triple.getEnvironment()) {
104*06c3fb27SDimitry Andric   case llvm::Triple::GNUSF:
105*06c3fb27SDimitry Andric     return IsLA32 ? "ilp32s" : "lp64s";
106*06c3fb27SDimitry Andric   case llvm::Triple::GNUF32:
107*06c3fb27SDimitry Andric     return IsLA32 ? "ilp32f" : "lp64f";
108*06c3fb27SDimitry Andric   case llvm::Triple::GNUF64:
109*06c3fb27SDimitry Andric     // This was originally permitted (and indeed the canonical way) to
110*06c3fb27SDimitry Andric     // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to
111*06c3fb27SDimitry Andric     // drop the explicit suffix in favor of unmarked `-gnu` for the
112*06c3fb27SDimitry Andric     // "general-purpose" ABIs, among other non-technical reasons.
113*06c3fb27SDimitry Andric     //
114*06c3fb27SDimitry Andric     // The spec change did not mention whether existing usages of "gnuf64"
115*06c3fb27SDimitry Andric     // shall remain valid or not, so we are going to continue recognizing it
116*06c3fb27SDimitry Andric     // for some time, until it is clear that everyone else has migrated away
117*06c3fb27SDimitry Andric     // from it.
118*06c3fb27SDimitry Andric     [[fallthrough]];
119*06c3fb27SDimitry Andric   case llvm::Triple::GNU:
120*06c3fb27SDimitry Andric   default:
121bdd1243dSDimitry Andric     return IsLA32 ? "ilp32d" : "lp64d";
122bdd1243dSDimitry Andric   }
123*06c3fb27SDimitry Andric }
124bdd1243dSDimitry Andric 
125bdd1243dSDimitry Andric void loongarch::getLoongArchTargetFeatures(const Driver &D,
126bdd1243dSDimitry Andric                                            const llvm::Triple &Triple,
127bdd1243dSDimitry Andric                                            const ArgList &Args,
128bdd1243dSDimitry Andric                                            std::vector<StringRef> &Features) {
129bdd1243dSDimitry Andric   StringRef ArchName;
130bdd1243dSDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
131*06c3fb27SDimitry Andric     if (!llvm::LoongArch::isValidArchName(A->getValue())) {
132bdd1243dSDimitry Andric       D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
133bdd1243dSDimitry Andric       return;
134bdd1243dSDimitry Andric     }
135bdd1243dSDimitry Andric     ArchName = A->getValue();
136bdd1243dSDimitry Andric   }
137bdd1243dSDimitry Andric 
138bdd1243dSDimitry Andric   // TODO: handle -march=native and -mtune=xx.
139bdd1243dSDimitry Andric 
140bdd1243dSDimitry Andric   // Select a default arch name.
141*06c3fb27SDimitry Andric   if (ArchName.empty() && Triple.isLoongArch64())
142bdd1243dSDimitry Andric     ArchName = "loongarch64";
143bdd1243dSDimitry Andric 
144bdd1243dSDimitry Andric   if (!ArchName.empty())
145bdd1243dSDimitry Andric     llvm::LoongArch::getArchFeatures(ArchName, Features);
146bdd1243dSDimitry Andric 
147bdd1243dSDimitry Andric   // Select floating-point features determined by -mdouble-float,
148bdd1243dSDimitry Andric   // -msingle-float, -msoft-float and -mfpu.
149bdd1243dSDimitry Andric   // Note: -m*-float wins any other options.
150bdd1243dSDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
151bdd1243dSDimitry Andric                                      options::OPT_msingle_float,
152bdd1243dSDimitry Andric                                      options::OPT_msoft_float)) {
153bdd1243dSDimitry Andric     if (A->getOption().matches(options::OPT_mdouble_float)) {
154bdd1243dSDimitry Andric       Features.push_back("+f");
155bdd1243dSDimitry Andric       Features.push_back("+d");
156bdd1243dSDimitry Andric     } else if (A->getOption().matches(options::OPT_msingle_float)) {
157bdd1243dSDimitry Andric       Features.push_back("+f");
158bdd1243dSDimitry Andric       Features.push_back("-d");
159bdd1243dSDimitry Andric     } else /*Soft-float*/ {
160bdd1243dSDimitry Andric       Features.push_back("-f");
161bdd1243dSDimitry Andric       Features.push_back("-d");
162bdd1243dSDimitry Andric     }
163bdd1243dSDimitry Andric   } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
164bdd1243dSDimitry Andric     StringRef FPU = A->getValue();
165bdd1243dSDimitry Andric     if (FPU == "64") {
166bdd1243dSDimitry Andric       Features.push_back("+f");
167bdd1243dSDimitry Andric       Features.push_back("+d");
168bdd1243dSDimitry Andric     } else if (FPU == "32") {
169bdd1243dSDimitry Andric       Features.push_back("+f");
170bdd1243dSDimitry Andric       Features.push_back("-d");
171bdd1243dSDimitry Andric     } else if (FPU == "0" || FPU == "none") {
172bdd1243dSDimitry Andric       Features.push_back("-f");
173bdd1243dSDimitry Andric       Features.push_back("-d");
174bdd1243dSDimitry Andric     } else {
175bdd1243dSDimitry Andric       D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
176bdd1243dSDimitry Andric     }
177bdd1243dSDimitry Andric   }
178*06c3fb27SDimitry Andric 
179*06c3fb27SDimitry Andric   // Select the `ual` feature determined by -m[no-]unaligned-access
180*06c3fb27SDimitry Andric   // or the alias -m[no-]strict-align.
181*06c3fb27SDimitry Andric   AddTargetFeature(Args, Features, options::OPT_munaligned_access,
182*06c3fb27SDimitry Andric                    options::OPT_mno_unaligned_access, "ual");
183*06c3fb27SDimitry Andric 
184*06c3fb27SDimitry Andric   // Accept but warn about these TargetSpecific options.
185*06c3fb27SDimitry Andric   if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
186*06c3fb27SDimitry Andric     A->ignoreTargetSpecific();
187*06c3fb27SDimitry Andric   if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
188*06c3fb27SDimitry Andric     A->ignoreTargetSpecific();
189bdd1243dSDimitry Andric }
190