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>
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 
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
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 
95   if (!llvm::CSKY::getFPUFeatures(FPUID, Features)) {
96     D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
97     return llvm::CSKY::FK_INVALID;
98   }
99 
100   return FPUID;
101 }
102 
103 void csky::getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple,
104                                  const ArgList &Args, ArgStringList &CmdArgs,
105                                  std::vector<llvm::StringRef> &Features) {
106   llvm::StringRef archName;
107   llvm::StringRef cpuName;
108   llvm::CSKY::ArchKind ArchKind = llvm::CSKY::ArchKind::INVALID;
109   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
110     ArchKind = llvm::CSKY::parseArch(A->getValue());
111     if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
112       D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
113       return;
114     }
115     archName = A->getValue();
116   }
117 
118   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
119     llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(A->getValue());
120     if (Kind == llvm::CSKY::ArchKind::INVALID) {
121       D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
122       return;
123     }
124     if (!archName.empty() && Kind != ArchKind) {
125       D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
126       return;
127     }
128     cpuName = A->getValue();
129   }
130 
131   if (archName.empty() && cpuName.empty()) {
132     archName = "ck810";
133     cpuName = "ck810";
134   } else if (!archName.empty() && cpuName.empty()) {
135     cpuName = archName;
136   }
137 
138   csky::FloatABI FloatABI = csky::getCSKYFloatABI(D, Args);
139 
140   if (FloatABI == csky::FloatABI::Hard) {
141     Features.push_back("+hard-float-abi");
142     Features.push_back("+hard-float");
143   } else if (FloatABI == csky::FloatABI::SoftFP) {
144     Features.push_back("+hard-float");
145   }
146 
147   if (const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ))
148     getCSKYFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
149   else if (FloatABI != csky::FloatABI::Soft && archName.empty())
150     llvm::CSKY::getFPUFeatures(llvm::CSKY::FK_AUTO, Features);
151 
152   uint64_t Extension = llvm::CSKY::getDefaultExtensions(cpuName);
153   llvm::CSKY::getExtensionFeatures(Extension, Features);
154 }
155