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