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