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