1 //===--- LoongArch.cpp - LoongArch 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 "LoongArch.h" 10 #include "ToolChains/CommonArgs.h" 11 #include "clang/Basic/DiagnosticDriver.h" 12 #include "clang/Driver/Driver.h" 13 #include "clang/Driver/DriverDiagnostic.h" 14 #include "clang/Driver/Options.h" 15 #include "llvm/TargetParser/LoongArchTargetParser.h" 16 17 using namespace clang::driver; 18 using namespace clang::driver::tools; 19 using namespace clang; 20 using namespace llvm::opt; 21 22 StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args, 23 const llvm::Triple &Triple) { 24 assert((Triple.getArch() == llvm::Triple::loongarch32 || 25 Triple.getArch() == llvm::Triple::loongarch64) && 26 "Unexpected triple"); 27 bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32; 28 29 // Record -mabi value for later use. 30 const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ); 31 StringRef MABIValue; 32 if (MABIArg) { 33 MABIValue = MABIArg->getValue(); 34 } 35 36 // Parse -mfpu value for later use. 37 const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ); 38 int FPU = -1; 39 if (MFPUArg) { 40 StringRef V = MFPUArg->getValue(); 41 if (V == "64") 42 FPU = 64; 43 else if (V == "32") 44 FPU = 32; 45 else if (V == "0" || V == "none") 46 FPU = 0; 47 else 48 D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V; 49 } 50 51 // Check -m*-float firstly since they have highest priority. 52 if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float, 53 options::OPT_msingle_float, 54 options::OPT_msoft_float)) { 55 StringRef ImpliedABI; 56 int ImpliedFPU = -1; 57 if (A->getOption().matches(options::OPT_mdouble_float)) { 58 ImpliedABI = IsLA32 ? "ilp32d" : "lp64d"; 59 ImpliedFPU = 64; 60 } 61 if (A->getOption().matches(options::OPT_msingle_float)) { 62 ImpliedABI = IsLA32 ? "ilp32f" : "lp64f"; 63 ImpliedFPU = 32; 64 } 65 if (A->getOption().matches(options::OPT_msoft_float)) { 66 ImpliedABI = IsLA32 ? "ilp32s" : "lp64s"; 67 ImpliedFPU = 0; 68 } 69 70 // Check `-mabi=` and `-mfpu=` settings and report if they conflict with 71 // the higher-priority settings implied by -m*-float. 72 // 73 // ImpliedABI and ImpliedFPU are guaranteed to have valid values because 74 // one of the match arms must match if execution can arrive here at all. 75 if (!MABIValue.empty() && ImpliedABI != MABIValue) 76 D.Diag(diag::warn_drv_loongarch_conflicting_implied_val) 77 << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI; 78 79 if (FPU != -1 && ImpliedFPU != FPU) 80 D.Diag(diag::warn_drv_loongarch_conflicting_implied_val) 81 << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU; 82 83 return ImpliedABI; 84 } 85 86 // If `-mabi=` is specified, use it. 87 if (!MABIValue.empty()) 88 return MABIValue; 89 90 // Select abi based on -mfpu=xx. 91 switch (FPU) { 92 case 64: 93 return IsLA32 ? "ilp32d" : "lp64d"; 94 case 32: 95 return IsLA32 ? "ilp32f" : "lp64f"; 96 case 0: 97 return IsLA32 ? "ilp32s" : "lp64s"; 98 } 99 100 // Choose a default based on the triple. 101 // Honor the explicit ABI modifier suffix in triple's environment part if 102 // present, falling back to {ILP32,LP64}D otherwise. 103 switch (Triple.getEnvironment()) { 104 case llvm::Triple::GNUSF: 105 return IsLA32 ? "ilp32s" : "lp64s"; 106 case llvm::Triple::GNUF32: 107 return IsLA32 ? "ilp32f" : "lp64f"; 108 case llvm::Triple::GNUF64: 109 // This was originally permitted (and indeed the canonical way) to 110 // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to 111 // drop the explicit suffix in favor of unmarked `-gnu` for the 112 // "general-purpose" ABIs, among other non-technical reasons. 113 // 114 // The spec change did not mention whether existing usages of "gnuf64" 115 // shall remain valid or not, so we are going to continue recognizing it 116 // for some time, until it is clear that everyone else has migrated away 117 // from it. 118 [[fallthrough]]; 119 case llvm::Triple::GNU: 120 default: 121 return IsLA32 ? "ilp32d" : "lp64d"; 122 } 123 } 124 125 void loongarch::getLoongArchTargetFeatures(const Driver &D, 126 const llvm::Triple &Triple, 127 const ArgList &Args, 128 std::vector<StringRef> &Features) { 129 StringRef ArchName; 130 if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { 131 if (!llvm::LoongArch::isValidArchName(A->getValue())) { 132 D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); 133 return; 134 } 135 ArchName = A->getValue(); 136 } 137 138 // TODO: handle -march=native and -mtune=xx. 139 140 // Select a default arch name. 141 if (ArchName.empty() && Triple.isLoongArch64()) 142 ArchName = "loongarch64"; 143 144 if (!ArchName.empty()) 145 llvm::LoongArch::getArchFeatures(ArchName, Features); 146 147 // Select floating-point features determined by -mdouble-float, 148 // -msingle-float, -msoft-float and -mfpu. 149 // Note: -m*-float wins any other options. 150 if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float, 151 options::OPT_msingle_float, 152 options::OPT_msoft_float)) { 153 if (A->getOption().matches(options::OPT_mdouble_float)) { 154 Features.push_back("+f"); 155 Features.push_back("+d"); 156 } else if (A->getOption().matches(options::OPT_msingle_float)) { 157 Features.push_back("+f"); 158 Features.push_back("-d"); 159 } else /*Soft-float*/ { 160 Features.push_back("-f"); 161 Features.push_back("-d"); 162 } 163 } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) { 164 StringRef FPU = A->getValue(); 165 if (FPU == "64") { 166 Features.push_back("+f"); 167 Features.push_back("+d"); 168 } else if (FPU == "32") { 169 Features.push_back("+f"); 170 Features.push_back("-d"); 171 } else if (FPU == "0" || FPU == "none") { 172 Features.push_back("-f"); 173 Features.push_back("-d"); 174 } else { 175 D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU; 176 } 177 } 178 179 // Select the `ual` feature determined by -m[no-]unaligned-access 180 // or the alias -m[no-]strict-align. 181 AddTargetFeature(Args, Features, options::OPT_munaligned_access, 182 options::OPT_mno_unaligned_access, "ual"); 183 184 // Accept but warn about these TargetSpecific options. 185 if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) 186 A->ignoreTargetSpecific(); 187 if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ)) 188 A->ignoreTargetSpecific(); 189 } 190