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