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 "clang/Basic/DiagnosticDriver.h"
11 #include "clang/Driver/Driver.h"
12 #include "clang/Driver/DriverDiagnostic.h"
13 #include "clang/Driver/Options.h"
14 #include "llvm/Support/LoongArchTargetParser.h"
15 
16 using namespace clang::driver;
17 using namespace clang::driver::tools;
18 using namespace clang;
19 using namespace llvm::opt;
20 
21 StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
22                                      const llvm::Triple &Triple) {
23   assert((Triple.getArch() == llvm::Triple::loongarch32 ||
24           Triple.getArch() == llvm::Triple::loongarch64) &&
25          "Unexpected triple");
26   bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
27 
28   // Check -m*-float firstly since they have highest priority.
29   if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
30                                      options::OPT_msingle_float,
31                                      options::OPT_msoft_float)) {
32     if (A->getOption().matches(options::OPT_mdouble_float))
33       return IsLA32 ? "ilp32d" : "lp64d";
34     if (A->getOption().matches(options::OPT_msingle_float))
35       return IsLA32 ? "ilp32f" : "lp64f";
36     if (A->getOption().matches(options::OPT_msoft_float))
37       return IsLA32 ? "ilp32s" : "lp64s";
38   }
39 
40   // If `-mabi=` is specified, use it.
41   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
42     return A->getValue();
43 
44   // Select abi based on -mfpu=xx.
45   if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
46     StringRef FPU = A->getValue();
47     if (FPU == "64")
48       return IsLA32 ? "ilp32d" : "lp64d";
49     if (FPU == "32")
50       return IsLA32 ? "ilp32f" : "lp64f";
51     if (FPU == "0" || FPU == "none")
52       return IsLA32 ? "ilp32s" : "lp64s";
53     D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
54   }
55 
56   // Choose a default based on the triple.
57   return IsLA32 ? "ilp32d" : "lp64d";
58 }
59 
60 void loongarch::getLoongArchTargetFeatures(const Driver &D,
61                                            const llvm::Triple &Triple,
62                                            const ArgList &Args,
63                                            std::vector<StringRef> &Features) {
64   StringRef ArchName;
65   llvm::LoongArch::ArchKind ArchKind = llvm::LoongArch::ArchKind::AK_INVALID;
66   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
67     ArchKind = llvm::LoongArch::parseArch(A->getValue());
68     if (ArchKind == llvm::LoongArch::ArchKind::AK_INVALID) {
69       D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
70       return;
71     }
72     ArchName = A->getValue();
73   }
74 
75   // TODO: handle -march=native and -mtune=xx.
76 
77   // Select a default arch name.
78   if (ArchName.empty() && Triple.getArch() == llvm::Triple::loongarch64)
79     ArchName = "loongarch64";
80 
81   if (!ArchName.empty())
82     llvm::LoongArch::getArchFeatures(ArchName, Features);
83 
84   // Select floating-point features determined by -mdouble-float,
85   // -msingle-float, -msoft-float and -mfpu.
86   // Note: -m*-float wins any other options.
87   if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
88                                      options::OPT_msingle_float,
89                                      options::OPT_msoft_float)) {
90     if (A->getOption().matches(options::OPT_mdouble_float)) {
91       Features.push_back("+f");
92       Features.push_back("+d");
93     } else if (A->getOption().matches(options::OPT_msingle_float)) {
94       Features.push_back("+f");
95       Features.push_back("-d");
96     } else /*Soft-float*/ {
97       Features.push_back("-f");
98       Features.push_back("-d");
99     }
100   } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
101     StringRef FPU = A->getValue();
102     if (FPU == "64") {
103       Features.push_back("+f");
104       Features.push_back("+d");
105     } else if (FPU == "32") {
106       Features.push_back("+f");
107       Features.push_back("-d");
108     } else if (FPU == "0" || FPU == "none") {
109       Features.push_back("-f");
110       Features.push_back("-d");
111     } else {
112       D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
113     }
114   }
115 }
116