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