1*12c85518Srobert //===--- CSKY.cpp - CSKY Helpers for Tools --------------------*- C++ -*-===//
2*12c85518Srobert //
3*12c85518Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*12c85518Srobert // See https://llvm.org/LICENSE.txt for license information.
5*12c85518Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*12c85518Srobert //
7*12c85518Srobert //===----------------------------------------------------------------------===//
8*12c85518Srobert
9*12c85518Srobert #include "CSKY.h"
10*12c85518Srobert #include "ToolChains/CommonArgs.h"
11*12c85518Srobert #include "clang/Basic/CharInfo.h"
12*12c85518Srobert #include "clang/Driver/Driver.h"
13*12c85518Srobert #include "clang/Driver/DriverDiagnostic.h"
14*12c85518Srobert #include "clang/Driver/Options.h"
15*12c85518Srobert #include "llvm/ADT/StringSwitch.h"
16*12c85518Srobert #include "llvm/Option/ArgList.h"
17*12c85518Srobert #include "llvm/Support/CSKYTargetParser.h"
18*12c85518Srobert #include "llvm/Support/Host.h"
19*12c85518Srobert #include "llvm/Support/TargetParser.h"
20*12c85518Srobert #include "llvm/Support/raw_ostream.h"
21*12c85518Srobert
22*12c85518Srobert using namespace clang::driver;
23*12c85518Srobert using namespace clang::driver::tools;
24*12c85518Srobert using namespace clang;
25*12c85518Srobert using namespace llvm::opt;
26*12c85518Srobert
27*12c85518Srobert std::optional<llvm::StringRef>
getCSKYArchName(const Driver & D,const ArgList & Args,const llvm::Triple & Triple)28*12c85518Srobert csky::getCSKYArchName(const Driver &D, const ArgList &Args,
29*12c85518Srobert const llvm::Triple &Triple) {
30*12c85518Srobert if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
31*12c85518Srobert llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseArch(A->getValue());
32*12c85518Srobert
33*12c85518Srobert if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
34*12c85518Srobert D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
35*12c85518Srobert return std::nullopt;
36*12c85518Srobert }
37*12c85518Srobert return std::optional<llvm::StringRef>(A->getValue());
38*12c85518Srobert }
39*12c85518Srobert
40*12c85518Srobert if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
41*12c85518Srobert llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(A->getValue());
42*12c85518Srobert if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
43*12c85518Srobert D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
44*12c85518Srobert return std::nullopt;
45*12c85518Srobert }
46*12c85518Srobert return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind));
47*12c85518Srobert }
48*12c85518Srobert
49*12c85518Srobert return std::optional<llvm::StringRef>("ck810");
50*12c85518Srobert }
51*12c85518Srobert
getCSKYFloatABI(const Driver & D,const ArgList & Args)52*12c85518Srobert csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) {
53*12c85518Srobert csky::FloatABI ABI = FloatABI::Soft;
54*12c85518Srobert if (Arg *A =
55*12c85518Srobert Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
56*12c85518Srobert options::OPT_mfloat_abi_EQ)) {
57*12c85518Srobert if (A->getOption().matches(options::OPT_msoft_float)) {
58*12c85518Srobert ABI = FloatABI::Soft;
59*12c85518Srobert } else if (A->getOption().matches(options::OPT_mhard_float)) {
60*12c85518Srobert ABI = FloatABI::Hard;
61*12c85518Srobert } else {
62*12c85518Srobert ABI = llvm::StringSwitch<csky::FloatABI>(A->getValue())
63*12c85518Srobert .Case("soft", FloatABI::Soft)
64*12c85518Srobert .Case("softfp", FloatABI::SoftFP)
65*12c85518Srobert .Case("hard", FloatABI::Hard)
66*12c85518Srobert .Default(FloatABI::Invalid);
67*12c85518Srobert if (ABI == FloatABI::Invalid) {
68*12c85518Srobert D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
69*12c85518Srobert ABI = FloatABI::Soft;
70*12c85518Srobert }
71*12c85518Srobert }
72*12c85518Srobert }
73*12c85518Srobert
74*12c85518Srobert return ABI;
75*12c85518Srobert }
76*12c85518Srobert
77*12c85518Srobert // Handle -mfpu=.
78*12c85518Srobert static llvm::CSKY::CSKYFPUKind
getCSKYFPUFeatures(const Driver & D,const Arg * A,const ArgList & Args,StringRef FPU,std::vector<StringRef> & Features)79*12c85518Srobert getCSKYFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args,
80*12c85518Srobert StringRef FPU, std::vector<StringRef> &Features) {
81*12c85518Srobert
82*12c85518Srobert llvm::CSKY::CSKYFPUKind FPUID =
83*12c85518Srobert llvm::StringSwitch<llvm::CSKY::CSKYFPUKind>(FPU)
84*12c85518Srobert .Case("auto", llvm::CSKY::FK_AUTO)
85*12c85518Srobert .Case("fpv2", llvm::CSKY::FK_FPV2)
86*12c85518Srobert .Case("fpv2_divd", llvm::CSKY::FK_FPV2_DIVD)
87*12c85518Srobert .Case("fpv2_sf", llvm::CSKY::FK_FPV2_SF)
88*12c85518Srobert .Case("fpv3", llvm::CSKY::FK_FPV3)
89*12c85518Srobert .Case("fpv3_hf", llvm::CSKY::FK_FPV3_HF)
90*12c85518Srobert .Case("fpv3_hsf", llvm::CSKY::FK_FPV3_HSF)
91*12c85518Srobert .Case("fpv3_sdf", llvm::CSKY::FK_FPV3_SDF)
92*12c85518Srobert .Default(llvm::CSKY::FK_INVALID);
93*12c85518Srobert if (FPUID == llvm::CSKY::FK_INVALID) {
94*12c85518Srobert D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
95*12c85518Srobert return llvm::CSKY::FK_INVALID;
96*12c85518Srobert }
97*12c85518Srobert
98*12c85518Srobert auto RemoveTargetFPUFeature =
99*12c85518Srobert [&Features](ArrayRef<const char *> FPUFeatures) {
100*12c85518Srobert for (auto FPUFeature : FPUFeatures) {
101*12c85518Srobert auto it = llvm::find(Features, FPUFeature);
102*12c85518Srobert if (it != Features.end())
103*12c85518Srobert Features.erase(it);
104*12c85518Srobert }
105*12c85518Srobert };
106*12c85518Srobert
107*12c85518Srobert RemoveTargetFPUFeature({"+fpuv2_sf", "+fpuv2_df", "+fdivdu", "+fpuv3_hi",
108*12c85518Srobert "+fpuv3_hf", "+fpuv3_sf", "+fpuv3_df"});
109*12c85518Srobert
110*12c85518Srobert if (!llvm::CSKY::getFPUFeatures(FPUID, Features)) {
111*12c85518Srobert D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
112*12c85518Srobert return llvm::CSKY::FK_INVALID;
113*12c85518Srobert }
114*12c85518Srobert
115*12c85518Srobert return FPUID;
116*12c85518Srobert }
117*12c85518Srobert
getCSKYTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,ArgStringList & CmdArgs,std::vector<llvm::StringRef> & Features)118*12c85518Srobert void csky::getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple,
119*12c85518Srobert const ArgList &Args, ArgStringList &CmdArgs,
120*12c85518Srobert std::vector<llvm::StringRef> &Features) {
121*12c85518Srobert llvm::StringRef archName;
122*12c85518Srobert llvm::StringRef cpuName;
123*12c85518Srobert llvm::CSKY::ArchKind ArchKind = llvm::CSKY::ArchKind::INVALID;
124*12c85518Srobert if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
125*12c85518Srobert ArchKind = llvm::CSKY::parseArch(A->getValue());
126*12c85518Srobert if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
127*12c85518Srobert D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
128*12c85518Srobert return;
129*12c85518Srobert }
130*12c85518Srobert archName = A->getValue();
131*12c85518Srobert }
132*12c85518Srobert
133*12c85518Srobert if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
134*12c85518Srobert llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(A->getValue());
135*12c85518Srobert if (Kind == llvm::CSKY::ArchKind::INVALID) {
136*12c85518Srobert D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
137*12c85518Srobert return;
138*12c85518Srobert }
139*12c85518Srobert if (!archName.empty() && Kind != ArchKind) {
140*12c85518Srobert D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
141*12c85518Srobert return;
142*12c85518Srobert }
143*12c85518Srobert cpuName = A->getValue();
144*12c85518Srobert if (archName.empty())
145*12c85518Srobert archName = llvm::CSKY::getArchName(Kind);
146*12c85518Srobert }
147*12c85518Srobert
148*12c85518Srobert if (archName.empty() && cpuName.empty()) {
149*12c85518Srobert archName = "ck810";
150*12c85518Srobert cpuName = "ck810";
151*12c85518Srobert } else if (!archName.empty() && cpuName.empty()) {
152*12c85518Srobert cpuName = archName;
153*12c85518Srobert }
154*12c85518Srobert
155*12c85518Srobert csky::FloatABI FloatABI = csky::getCSKYFloatABI(D, Args);
156*12c85518Srobert
157*12c85518Srobert if (FloatABI == csky::FloatABI::Hard) {
158*12c85518Srobert Features.push_back("+hard-float-abi");
159*12c85518Srobert Features.push_back("+hard-float");
160*12c85518Srobert } else if (FloatABI == csky::FloatABI::SoftFP) {
161*12c85518Srobert Features.push_back("+hard-float");
162*12c85518Srobert }
163*12c85518Srobert
164*12c85518Srobert uint64_t Extension = llvm::CSKY::getDefaultExtensions(cpuName);
165*12c85518Srobert llvm::CSKY::getExtensionFeatures(Extension, Features);
166*12c85518Srobert
167*12c85518Srobert if (const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ))
168*12c85518Srobert getCSKYFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
169*12c85518Srobert }
170