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"
1006c3fb27SDimitry 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"
158a4dda33SDimitry Andric #include "llvm/TargetParser/Host.h"
1606c3fb27SDimitry Andric #include "llvm/TargetParser/LoongArchTargetParser.h"
17bdd1243dSDimitry Andric
18bdd1243dSDimitry Andric using namespace clang::driver;
19bdd1243dSDimitry Andric using namespace clang::driver::tools;
20bdd1243dSDimitry Andric using namespace clang;
21bdd1243dSDimitry Andric using namespace llvm::opt;
22bdd1243dSDimitry Andric
getLoongArchABI(const Driver & D,const ArgList & Args,const llvm::Triple & Triple)23bdd1243dSDimitry Andric StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
24bdd1243dSDimitry Andric const llvm::Triple &Triple) {
25bdd1243dSDimitry Andric assert((Triple.getArch() == llvm::Triple::loongarch32 ||
26bdd1243dSDimitry Andric Triple.getArch() == llvm::Triple::loongarch64) &&
27bdd1243dSDimitry Andric "Unexpected triple");
28bdd1243dSDimitry Andric bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
29bdd1243dSDimitry Andric
3006c3fb27SDimitry Andric // Record -mabi value for later use.
3106c3fb27SDimitry Andric const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ);
3206c3fb27SDimitry Andric StringRef MABIValue;
3306c3fb27SDimitry Andric if (MABIArg) {
3406c3fb27SDimitry Andric MABIValue = MABIArg->getValue();
3506c3fb27SDimitry Andric }
3606c3fb27SDimitry Andric
3706c3fb27SDimitry Andric // Parse -mfpu value for later use.
3806c3fb27SDimitry Andric const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
3906c3fb27SDimitry Andric int FPU = -1;
4006c3fb27SDimitry Andric if (MFPUArg) {
4106c3fb27SDimitry Andric StringRef V = MFPUArg->getValue();
4206c3fb27SDimitry Andric if (V == "64")
4306c3fb27SDimitry Andric FPU = 64;
4406c3fb27SDimitry Andric else if (V == "32")
4506c3fb27SDimitry Andric FPU = 32;
4606c3fb27SDimitry Andric else if (V == "0" || V == "none")
4706c3fb27SDimitry Andric FPU = 0;
4806c3fb27SDimitry Andric else
4906c3fb27SDimitry Andric D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V;
5006c3fb27SDimitry Andric }
5106c3fb27SDimitry Andric
52bdd1243dSDimitry Andric // Check -m*-float firstly since they have highest priority.
53bdd1243dSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
54bdd1243dSDimitry Andric options::OPT_msingle_float,
55bdd1243dSDimitry Andric options::OPT_msoft_float)) {
5606c3fb27SDimitry Andric StringRef ImpliedABI;
5706c3fb27SDimitry Andric int ImpliedFPU = -1;
5806c3fb27SDimitry Andric if (A->getOption().matches(options::OPT_mdouble_float)) {
5906c3fb27SDimitry Andric ImpliedABI = IsLA32 ? "ilp32d" : "lp64d";
6006c3fb27SDimitry Andric ImpliedFPU = 64;
6106c3fb27SDimitry Andric }
6206c3fb27SDimitry Andric if (A->getOption().matches(options::OPT_msingle_float)) {
6306c3fb27SDimitry Andric ImpliedABI = IsLA32 ? "ilp32f" : "lp64f";
6406c3fb27SDimitry Andric ImpliedFPU = 32;
6506c3fb27SDimitry Andric }
6606c3fb27SDimitry Andric if (A->getOption().matches(options::OPT_msoft_float)) {
6706c3fb27SDimitry Andric ImpliedABI = IsLA32 ? "ilp32s" : "lp64s";
6806c3fb27SDimitry Andric ImpliedFPU = 0;
6906c3fb27SDimitry Andric }
7006c3fb27SDimitry Andric
7106c3fb27SDimitry Andric // Check `-mabi=` and `-mfpu=` settings and report if they conflict with
7206c3fb27SDimitry Andric // the higher-priority settings implied by -m*-float.
7306c3fb27SDimitry Andric //
7406c3fb27SDimitry Andric // ImpliedABI and ImpliedFPU are guaranteed to have valid values because
7506c3fb27SDimitry Andric // one of the match arms must match if execution can arrive here at all.
7606c3fb27SDimitry Andric if (!MABIValue.empty() && ImpliedABI != MABIValue)
7706c3fb27SDimitry Andric D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
7806c3fb27SDimitry Andric << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI;
7906c3fb27SDimitry Andric
8006c3fb27SDimitry Andric if (FPU != -1 && ImpliedFPU != FPU)
8106c3fb27SDimitry Andric D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
8206c3fb27SDimitry Andric << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU;
8306c3fb27SDimitry Andric
8406c3fb27SDimitry Andric return ImpliedABI;
85bdd1243dSDimitry Andric }
86bdd1243dSDimitry Andric
87bdd1243dSDimitry Andric // If `-mabi=` is specified, use it.
8806c3fb27SDimitry Andric if (!MABIValue.empty())
8906c3fb27SDimitry Andric return MABIValue;
90bdd1243dSDimitry Andric
91bdd1243dSDimitry Andric // Select abi based on -mfpu=xx.
9206c3fb27SDimitry Andric switch (FPU) {
9306c3fb27SDimitry Andric case 64:
94bdd1243dSDimitry Andric return IsLA32 ? "ilp32d" : "lp64d";
9506c3fb27SDimitry Andric case 32:
96bdd1243dSDimitry Andric return IsLA32 ? "ilp32f" : "lp64f";
9706c3fb27SDimitry Andric case 0:
98bdd1243dSDimitry Andric return IsLA32 ? "ilp32s" : "lp64s";
99bdd1243dSDimitry Andric }
100bdd1243dSDimitry Andric
101bdd1243dSDimitry Andric // Choose a default based on the triple.
10206c3fb27SDimitry Andric // Honor the explicit ABI modifier suffix in triple's environment part if
10306c3fb27SDimitry Andric // present, falling back to {ILP32,LP64}D otherwise.
10406c3fb27SDimitry Andric switch (Triple.getEnvironment()) {
10506c3fb27SDimitry Andric case llvm::Triple::GNUSF:
10606c3fb27SDimitry Andric return IsLA32 ? "ilp32s" : "lp64s";
10706c3fb27SDimitry Andric case llvm::Triple::GNUF32:
10806c3fb27SDimitry Andric return IsLA32 ? "ilp32f" : "lp64f";
10906c3fb27SDimitry Andric case llvm::Triple::GNUF64:
11006c3fb27SDimitry Andric // This was originally permitted (and indeed the canonical way) to
11106c3fb27SDimitry Andric // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to
11206c3fb27SDimitry Andric // drop the explicit suffix in favor of unmarked `-gnu` for the
11306c3fb27SDimitry Andric // "general-purpose" ABIs, among other non-technical reasons.
11406c3fb27SDimitry Andric //
11506c3fb27SDimitry Andric // The spec change did not mention whether existing usages of "gnuf64"
11606c3fb27SDimitry Andric // shall remain valid or not, so we are going to continue recognizing it
11706c3fb27SDimitry Andric // for some time, until it is clear that everyone else has migrated away
11806c3fb27SDimitry Andric // from it.
11906c3fb27SDimitry Andric [[fallthrough]];
12006c3fb27SDimitry Andric case llvm::Triple::GNU:
12106c3fb27SDimitry Andric default:
122bdd1243dSDimitry Andric return IsLA32 ? "ilp32d" : "lp64d";
123bdd1243dSDimitry Andric }
12406c3fb27SDimitry Andric }
125bdd1243dSDimitry Andric
getLoongArchTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & Features)126bdd1243dSDimitry Andric void loongarch::getLoongArchTargetFeatures(const Driver &D,
127bdd1243dSDimitry Andric const llvm::Triple &Triple,
128bdd1243dSDimitry Andric const ArgList &Args,
129bdd1243dSDimitry Andric std::vector<StringRef> &Features) {
1308a4dda33SDimitry Andric std::string ArchName;
1318a4dda33SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
132bdd1243dSDimitry Andric ArchName = A->getValue();
1338a4dda33SDimitry Andric ArchName = postProcessTargetCPUString(ArchName, Triple);
134bdd1243dSDimitry Andric llvm::LoongArch::getArchFeatures(ArchName, Features);
135bdd1243dSDimitry Andric
136bdd1243dSDimitry Andric // Select floating-point features determined by -mdouble-float,
137bdd1243dSDimitry Andric // -msingle-float, -msoft-float and -mfpu.
138bdd1243dSDimitry Andric // Note: -m*-float wins any other options.
139bdd1243dSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
140bdd1243dSDimitry Andric options::OPT_msingle_float,
141bdd1243dSDimitry Andric options::OPT_msoft_float)) {
142bdd1243dSDimitry Andric if (A->getOption().matches(options::OPT_mdouble_float)) {
143bdd1243dSDimitry Andric Features.push_back("+f");
144bdd1243dSDimitry Andric Features.push_back("+d");
145bdd1243dSDimitry Andric } else if (A->getOption().matches(options::OPT_msingle_float)) {
146bdd1243dSDimitry Andric Features.push_back("+f");
147bdd1243dSDimitry Andric Features.push_back("-d");
148bdd1243dSDimitry Andric } else /*Soft-float*/ {
149bdd1243dSDimitry Andric Features.push_back("-f");
150bdd1243dSDimitry Andric Features.push_back("-d");
151bdd1243dSDimitry Andric }
152bdd1243dSDimitry Andric } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
153bdd1243dSDimitry Andric StringRef FPU = A->getValue();
154bdd1243dSDimitry Andric if (FPU == "64") {
155bdd1243dSDimitry Andric Features.push_back("+f");
156bdd1243dSDimitry Andric Features.push_back("+d");
157bdd1243dSDimitry Andric } else if (FPU == "32") {
158bdd1243dSDimitry Andric Features.push_back("+f");
159bdd1243dSDimitry Andric Features.push_back("-d");
160bdd1243dSDimitry Andric } else if (FPU == "0" || FPU == "none") {
161bdd1243dSDimitry Andric Features.push_back("-f");
162bdd1243dSDimitry Andric Features.push_back("-d");
163bdd1243dSDimitry Andric } else {
164bdd1243dSDimitry Andric D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
165bdd1243dSDimitry Andric }
166bdd1243dSDimitry Andric }
16706c3fb27SDimitry Andric
16806c3fb27SDimitry Andric // Select the `ual` feature determined by -m[no-]unaligned-access
16906c3fb27SDimitry Andric // or the alias -m[no-]strict-align.
17006c3fb27SDimitry Andric AddTargetFeature(Args, Features, options::OPT_munaligned_access,
17106c3fb27SDimitry Andric options::OPT_mno_unaligned_access, "ual");
17206c3fb27SDimitry Andric
17306c3fb27SDimitry Andric // Accept but warn about these TargetSpecific options.
17406c3fb27SDimitry Andric if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
17506c3fb27SDimitry Andric A->ignoreTargetSpecific();
17606c3fb27SDimitry Andric if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
17706c3fb27SDimitry Andric A->ignoreTargetSpecific();
178*5f757f3fSDimitry Andric
179*5f757f3fSDimitry Andric // Select lsx feature determined by -m[no-]lsx.
180*5f757f3fSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
181*5f757f3fSDimitry Andric // LSX depends on 64-bit FPU.
182*5f757f3fSDimitry Andric // -m*-float and -mfpu=none/0/32 conflict with -mlsx.
183*5f757f3fSDimitry Andric if (A->getOption().matches(options::OPT_mlsx)) {
184*5f757f3fSDimitry Andric if (llvm::find(Features, "-d") != Features.end())
185*5f757f3fSDimitry Andric D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lsx);
186*5f757f3fSDimitry Andric else /*-mlsx*/
187*5f757f3fSDimitry Andric Features.push_back("+lsx");
188*5f757f3fSDimitry Andric } else /*-mno-lsx*/ {
189*5f757f3fSDimitry Andric Features.push_back("-lsx");
190*5f757f3fSDimitry Andric }
191*5f757f3fSDimitry Andric }
192*5f757f3fSDimitry Andric
193*5f757f3fSDimitry Andric // Select lasx feature determined by -m[no-]lasx.
194*5f757f3fSDimitry Andric if (const Arg *A =
195*5f757f3fSDimitry Andric Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) {
196*5f757f3fSDimitry Andric // LASX depends on 64-bit FPU and LSX.
197*5f757f3fSDimitry Andric // -mno-lsx conflicts with -mlasx.
198*5f757f3fSDimitry Andric if (A->getOption().matches(options::OPT_mlasx)) {
199*5f757f3fSDimitry Andric if (llvm::find(Features, "-d") != Features.end())
200*5f757f3fSDimitry Andric D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lasx);
201*5f757f3fSDimitry Andric else if (llvm::find(Features, "-lsx") != Features.end())
202*5f757f3fSDimitry Andric D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
203*5f757f3fSDimitry Andric else { /*-mlasx*/
204*5f757f3fSDimitry Andric Features.push_back("+lsx");
205*5f757f3fSDimitry Andric Features.push_back("+lasx");
206*5f757f3fSDimitry Andric }
207*5f757f3fSDimitry Andric } else /*-mno-lasx*/
208*5f757f3fSDimitry Andric Features.push_back("-lasx");
209*5f757f3fSDimitry Andric }
210bdd1243dSDimitry Andric }
2118a4dda33SDimitry Andric
postProcessTargetCPUString(const std::string & CPU,const llvm::Triple & Triple)2128a4dda33SDimitry Andric std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
2138a4dda33SDimitry Andric const llvm::Triple &Triple) {
2148a4dda33SDimitry Andric std::string CPUString = CPU;
2158a4dda33SDimitry Andric if (CPUString == "native") {
2168a4dda33SDimitry Andric CPUString = llvm::sys::getHostCPUName();
2178a4dda33SDimitry Andric if (CPUString == "generic")
2188a4dda33SDimitry Andric CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
2198a4dda33SDimitry Andric }
2208a4dda33SDimitry Andric if (CPUString.empty())
2218a4dda33SDimitry Andric CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
2228a4dda33SDimitry Andric return CPUString;
2238a4dda33SDimitry Andric }
2248a4dda33SDimitry Andric
getLoongArchTargetCPU(const llvm::opt::ArgList & Args,const llvm::Triple & Triple)2258a4dda33SDimitry Andric std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
2268a4dda33SDimitry Andric const llvm::Triple &Triple) {
2278a4dda33SDimitry Andric std::string CPU;
2288a4dda33SDimitry Andric // If we have -march, use that.
2298a4dda33SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
2308a4dda33SDimitry Andric CPU = A->getValue();
2318a4dda33SDimitry Andric return postProcessTargetCPUString(CPU, Triple);
2328a4dda33SDimitry Andric }
233