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
22using namespace clang::driver;
23using namespace clang::driver::tools;
24using namespace clang;
25using namespace llvm::opt;
26
27std::optional<llvm::StringRef>
28csky::getCSKYArchName(const Driver &D, const ArgList &Args,
29 const llvm::Triple &Triple) {
30 if (const Arg *A = Args.getLastArg(Ids: options::OPT_march_EQ)) {
31 llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseArch(Arch: A->getValue());
32
33 if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
34 D.Diag(DiagID: 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(Ids: clang::driver::options::OPT_mcpu_EQ)) {
41 llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(CPU: A->getValue());
42 if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
43 D.Diag(DiagID: clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
44 return std::nullopt;
45 }
46 return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(AK: ArchKind));
47 }
48
49 return std::optional<llvm::StringRef>("ck810");
50}
51
52csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) {
53 csky::FloatABI ABI = FloatABI::Soft;
54 if (Arg *A =
55 Args.getLastArg(Ids: options::OPT_msoft_float, Ids: options::OPT_mhard_float,
56 Ids: options::OPT_mfloat_abi_EQ)) {
57 if (A->getOption().matches(ID: options::OPT_msoft_float)) {
58 ABI = FloatABI::Soft;
59 } else if (A->getOption().matches(ID: options::OPT_mhard_float)) {
60 ABI = FloatABI::Hard;
61 } else {
62 ABI = llvm::StringSwitch<csky::FloatABI>(A->getValue())
63 .Case(S: "soft", Value: FloatABI::Soft)
64 .Case(S: "softfp", Value: FloatABI::SoftFP)
65 .Case(S: "hard", Value: FloatABI::Hard)
66 .Default(Value: FloatABI::Invalid);
67 if (ABI == FloatABI::Invalid) {
68 D.Diag(DiagID: 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=.
78static llvm::CSKY::CSKYFPUKind
79getCSKYFPUFeatures(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(S: "auto", Value: llvm::CSKY::FK_AUTO)
85 .Case(S: "fpv2", Value: llvm::CSKY::FK_FPV2)
86 .Case(S: "fpv2_divd", Value: llvm::CSKY::FK_FPV2_DIVD)
87 .Case(S: "fpv2_sf", Value: llvm::CSKY::FK_FPV2_SF)
88 .Case(S: "fpv3", Value: llvm::CSKY::FK_FPV3)
89 .Case(S: "fpv3_hf", Value: llvm::CSKY::FK_FPV3_HF)
90 .Case(S: "fpv3_hsf", Value: llvm::CSKY::FK_FPV3_HSF)
91 .Case(S: "fpv3_sdf", Value: llvm::CSKY::FK_FPV3_SDF)
92 .Default(Value: llvm::CSKY::FK_INVALID);
93 if (FPUID == llvm::CSKY::FK_INVALID) {
94 D.Diag(DiagID: 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(Range&: Features, Val: FPUFeature);
102 if (it != Features.end())
103 Features.erase(position: 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(Kind: FPUID, Features)) {
111 D.Diag(DiagID: clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
112 return llvm::CSKY::FK_INVALID;
113 }
114
115 return FPUID;
116}
117
118void 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(Ids: options::OPT_march_EQ)) {
125 ArchKind = llvm::CSKY::parseArch(Arch: A->getValue());
126 if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
127 D.Diag(DiagID: 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(Ids: clang::driver::options::OPT_mcpu_EQ)) {
134 llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(CPU: A->getValue());
135 if (Kind == llvm::CSKY::ArchKind::INVALID) {
136 D.Diag(DiagID: clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
137 return;
138 }
139 if (!archName.empty() && Kind != ArchKind) {
140 D.Diag(DiagID: 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(AK: 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(x: "+hard-float-abi");
159 Features.push_back(x: "+hard-float");
160 } else if (FloatABI == csky::FloatABI::SoftFP) {
161 Features.push_back(x: "+hard-float");
162 }
163
164 uint64_t Extension = llvm::CSKY::getDefaultExtensions(CPU: cpuName);
165 llvm::CSKY::getExtensionFeatures(Extensions: Extension, Features);
166
167 if (const Arg *FPUArg = Args.getLastArg(Ids: options::OPT_mfpu_EQ))
168 getCSKYFPUFeatures(D, A: FPUArg, Args, FPU: FPUArg->getValue(), Features);
169}
170