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/CSKYTargetParser.h" 1881ad6265SDimitry Andric #include "llvm/Support/Host.h" 1981ad6265SDimitry Andric #include "llvm/Support/TargetParser.h" 2081ad6265SDimitry Andric #include "llvm/Support/raw_ostream.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 27*bdd1243dSDimitry Andric std::optional<llvm::StringRef> 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); 35*bdd1243dSDimitry Andric return std::nullopt; 3681ad6265SDimitry Andric } 37*bdd1243dSDimitry 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); 44*bdd1243dSDimitry Andric return std::nullopt; 4581ad6265SDimitry Andric } 46*bdd1243dSDimitry Andric return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind)); 4781ad6265SDimitry Andric } 4881ad6265SDimitry Andric 49*bdd1243dSDimitry Andric return std::optional<llvm::StringRef>("ck810"); 5081ad6265SDimitry Andric } 5181ad6265SDimitry Andric 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 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) { 101*bdd1243dSDimitry 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 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