181ad6265SDimitry Andric //===--- CSKY.cpp - CSKY Helpers for Tools --------------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric
981ad6265SDimitry Andric #include "CSKY.h"
1081ad6265SDimitry Andric #include "ToolChains/CommonArgs.h"
1181ad6265SDimitry Andric #include "clang/Basic/CharInfo.h"
1281ad6265SDimitry Andric #include "clang/Driver/Driver.h"
1381ad6265SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
1481ad6265SDimitry Andric #include "clang/Driver/Options.h"
1581ad6265SDimitry Andric #include "llvm/ADT/StringSwitch.h"
1681ad6265SDimitry Andric #include "llvm/Option/ArgList.h"
1781ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
18*06c3fb27SDimitry Andric #include "llvm/TargetParser/CSKYTargetParser.h"
19*06c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
20*06c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.h"
2181ad6265SDimitry Andric
2281ad6265SDimitry Andric using namespace clang::driver;
2381ad6265SDimitry Andric using namespace clang::driver::tools;
2481ad6265SDimitry Andric using namespace clang;
2581ad6265SDimitry Andric using namespace llvm::opt;
2681ad6265SDimitry Andric
27bdd1243dSDimitry Andric std::optional<llvm::StringRef>
getCSKYArchName(const Driver & D,const ArgList & Args,const llvm::Triple & Triple)2881ad6265SDimitry Andric csky::getCSKYArchName(const Driver &D, const ArgList &Args,
2981ad6265SDimitry Andric const llvm::Triple &Triple) {
3081ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
3181ad6265SDimitry Andric llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseArch(A->getValue());
3281ad6265SDimitry Andric
3381ad6265SDimitry Andric if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
3481ad6265SDimitry Andric D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
35bdd1243dSDimitry Andric return std::nullopt;
3681ad6265SDimitry Andric }
37bdd1243dSDimitry Andric return std::optional<llvm::StringRef>(A->getValue());
3881ad6265SDimitry Andric }
3981ad6265SDimitry Andric
4081ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
4181ad6265SDimitry Andric llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(A->getValue());
4281ad6265SDimitry Andric if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
4381ad6265SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
44bdd1243dSDimitry Andric return std::nullopt;
4581ad6265SDimitry Andric }
46bdd1243dSDimitry Andric return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind));
4781ad6265SDimitry Andric }
4881ad6265SDimitry Andric
49bdd1243dSDimitry Andric return std::optional<llvm::StringRef>("ck810");
5081ad6265SDimitry Andric }
5181ad6265SDimitry Andric
getCSKYFloatABI(const Driver & D,const ArgList & Args)5281ad6265SDimitry Andric csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) {
5381ad6265SDimitry Andric csky::FloatABI ABI = FloatABI::Soft;
5481ad6265SDimitry Andric if (Arg *A =
5581ad6265SDimitry Andric Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
5681ad6265SDimitry Andric options::OPT_mfloat_abi_EQ)) {
5781ad6265SDimitry Andric if (A->getOption().matches(options::OPT_msoft_float)) {
5881ad6265SDimitry Andric ABI = FloatABI::Soft;
5981ad6265SDimitry Andric } else if (A->getOption().matches(options::OPT_mhard_float)) {
6081ad6265SDimitry Andric ABI = FloatABI::Hard;
6181ad6265SDimitry Andric } else {
6281ad6265SDimitry Andric ABI = llvm::StringSwitch<csky::FloatABI>(A->getValue())
6381ad6265SDimitry Andric .Case("soft", FloatABI::Soft)
6481ad6265SDimitry Andric .Case("softfp", FloatABI::SoftFP)
6581ad6265SDimitry Andric .Case("hard", FloatABI::Hard)
6681ad6265SDimitry Andric .Default(FloatABI::Invalid);
6781ad6265SDimitry Andric if (ABI == FloatABI::Invalid) {
6881ad6265SDimitry Andric D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
6981ad6265SDimitry Andric ABI = FloatABI::Soft;
7081ad6265SDimitry Andric }
7181ad6265SDimitry Andric }
7281ad6265SDimitry Andric }
7381ad6265SDimitry Andric
7481ad6265SDimitry Andric return ABI;
7581ad6265SDimitry Andric }
7681ad6265SDimitry Andric
7781ad6265SDimitry Andric // Handle -mfpu=.
7881ad6265SDimitry Andric static llvm::CSKY::CSKYFPUKind
getCSKYFPUFeatures(const Driver & D,const Arg * A,const ArgList & Args,StringRef FPU,std::vector<StringRef> & Features)7981ad6265SDimitry Andric getCSKYFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args,
8081ad6265SDimitry Andric StringRef FPU, std::vector<StringRef> &Features) {
8181ad6265SDimitry Andric
8281ad6265SDimitry Andric llvm::CSKY::CSKYFPUKind FPUID =
8381ad6265SDimitry Andric llvm::StringSwitch<llvm::CSKY::CSKYFPUKind>(FPU)
8481ad6265SDimitry Andric .Case("auto", llvm::CSKY::FK_AUTO)
8581ad6265SDimitry Andric .Case("fpv2", llvm::CSKY::FK_FPV2)
8681ad6265SDimitry Andric .Case("fpv2_divd", llvm::CSKY::FK_FPV2_DIVD)
8781ad6265SDimitry Andric .Case("fpv2_sf", llvm::CSKY::FK_FPV2_SF)
8881ad6265SDimitry Andric .Case("fpv3", llvm::CSKY::FK_FPV3)
8981ad6265SDimitry Andric .Case("fpv3_hf", llvm::CSKY::FK_FPV3_HF)
9081ad6265SDimitry Andric .Case("fpv3_hsf", llvm::CSKY::FK_FPV3_HSF)
9181ad6265SDimitry Andric .Case("fpv3_sdf", llvm::CSKY::FK_FPV3_SDF)
9281ad6265SDimitry Andric .Default(llvm::CSKY::FK_INVALID);
9381ad6265SDimitry Andric if (FPUID == llvm::CSKY::FK_INVALID) {
9481ad6265SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
9581ad6265SDimitry Andric return llvm::CSKY::FK_INVALID;
9681ad6265SDimitry Andric }
9781ad6265SDimitry Andric
9881ad6265SDimitry Andric auto RemoveTargetFPUFeature =
9981ad6265SDimitry Andric [&Features](ArrayRef<const char *> FPUFeatures) {
10081ad6265SDimitry Andric for (auto FPUFeature : FPUFeatures) {
101bdd1243dSDimitry Andric auto it = llvm::find(Features, FPUFeature);
10281ad6265SDimitry Andric if (it != Features.end())
10381ad6265SDimitry Andric Features.erase(it);
10481ad6265SDimitry Andric }
10581ad6265SDimitry Andric };
10681ad6265SDimitry Andric
10781ad6265SDimitry Andric RemoveTargetFPUFeature({"+fpuv2_sf", "+fpuv2_df", "+fdivdu", "+fpuv3_hi",
10881ad6265SDimitry Andric "+fpuv3_hf", "+fpuv3_sf", "+fpuv3_df"});
10981ad6265SDimitry Andric
11081ad6265SDimitry Andric if (!llvm::CSKY::getFPUFeatures(FPUID, Features)) {
11181ad6265SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
11281ad6265SDimitry Andric return llvm::CSKY::FK_INVALID;
11381ad6265SDimitry Andric }
11481ad6265SDimitry Andric
11581ad6265SDimitry Andric return FPUID;
11681ad6265SDimitry Andric }
11781ad6265SDimitry Andric
getCSKYTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,ArgStringList & CmdArgs,std::vector<llvm::StringRef> & Features)11881ad6265SDimitry Andric void csky::getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple,
11981ad6265SDimitry Andric const ArgList &Args, ArgStringList &CmdArgs,
12081ad6265SDimitry Andric std::vector<llvm::StringRef> &Features) {
12181ad6265SDimitry Andric llvm::StringRef archName;
12281ad6265SDimitry Andric llvm::StringRef cpuName;
12381ad6265SDimitry Andric llvm::CSKY::ArchKind ArchKind = llvm::CSKY::ArchKind::INVALID;
12481ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
12581ad6265SDimitry Andric ArchKind = llvm::CSKY::parseArch(A->getValue());
12681ad6265SDimitry Andric if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
12781ad6265SDimitry Andric D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
12881ad6265SDimitry Andric return;
12981ad6265SDimitry Andric }
13081ad6265SDimitry Andric archName = A->getValue();
13181ad6265SDimitry Andric }
13281ad6265SDimitry Andric
13381ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
13481ad6265SDimitry Andric llvm::CSKY::ArchKind Kind = llvm::CSKY::parseCPUArch(A->getValue());
13581ad6265SDimitry Andric if (Kind == llvm::CSKY::ArchKind::INVALID) {
13681ad6265SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
13781ad6265SDimitry Andric return;
13881ad6265SDimitry Andric }
13981ad6265SDimitry Andric if (!archName.empty() && Kind != ArchKind) {
14081ad6265SDimitry Andric D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
14181ad6265SDimitry Andric return;
14281ad6265SDimitry Andric }
14381ad6265SDimitry Andric cpuName = A->getValue();
14481ad6265SDimitry Andric if (archName.empty())
14581ad6265SDimitry Andric archName = llvm::CSKY::getArchName(Kind);
14681ad6265SDimitry Andric }
14781ad6265SDimitry Andric
14881ad6265SDimitry Andric if (archName.empty() && cpuName.empty()) {
14981ad6265SDimitry Andric archName = "ck810";
15081ad6265SDimitry Andric cpuName = "ck810";
15181ad6265SDimitry Andric } else if (!archName.empty() && cpuName.empty()) {
15281ad6265SDimitry Andric cpuName = archName;
15381ad6265SDimitry Andric }
15481ad6265SDimitry Andric
15581ad6265SDimitry Andric csky::FloatABI FloatABI = csky::getCSKYFloatABI(D, Args);
15681ad6265SDimitry Andric
15781ad6265SDimitry Andric if (FloatABI == csky::FloatABI::Hard) {
15881ad6265SDimitry Andric Features.push_back("+hard-float-abi");
15981ad6265SDimitry Andric Features.push_back("+hard-float");
16081ad6265SDimitry Andric } else if (FloatABI == csky::FloatABI::SoftFP) {
16181ad6265SDimitry Andric Features.push_back("+hard-float");
16281ad6265SDimitry Andric }
16381ad6265SDimitry Andric
16481ad6265SDimitry Andric uint64_t Extension = llvm::CSKY::getDefaultExtensions(cpuName);
16581ad6265SDimitry Andric llvm::CSKY::getExtensionFeatures(Extension, Features);
16681ad6265SDimitry Andric
16781ad6265SDimitry Andric if (const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ))
16881ad6265SDimitry Andric getCSKYFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
16981ad6265SDimitry Andric }
170