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