Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
35294 views
//===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "LoongArch.h"9#include "ToolChains/CommonArgs.h"10#include "clang/Basic/DiagnosticDriver.h"11#include "clang/Driver/Driver.h"12#include "clang/Driver/DriverDiagnostic.h"13#include "clang/Driver/Options.h"14#include "llvm/TargetParser/Host.h"15#include "llvm/TargetParser/LoongArchTargetParser.h"1617using namespace clang::driver;18using namespace clang::driver::tools;19using namespace clang;20using namespace llvm::opt;2122StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,23const llvm::Triple &Triple) {24assert((Triple.getArch() == llvm::Triple::loongarch32 ||25Triple.getArch() == llvm::Triple::loongarch64) &&26"Unexpected triple");27bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;2829// Record -mabi value for later use.30const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ);31StringRef MABIValue;32if (MABIArg) {33MABIValue = MABIArg->getValue();34}3536// Parse -mfpu value for later use.37const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ);38int FPU = -1;39if (MFPUArg) {40StringRef V = MFPUArg->getValue();41if (V == "64")42FPU = 64;43else if (V == "32")44FPU = 32;45else if (V == "0" || V == "none")46FPU = 0;47else48D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V;49}5051// Check -m*-float firstly since they have highest priority.52if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,53options::OPT_msingle_float,54options::OPT_msoft_float)) {55StringRef ImpliedABI;56int ImpliedFPU = -1;57if (A->getOption().matches(options::OPT_mdouble_float)) {58ImpliedABI = IsLA32 ? "ilp32d" : "lp64d";59ImpliedFPU = 64;60}61if (A->getOption().matches(options::OPT_msingle_float)) {62ImpliedABI = IsLA32 ? "ilp32f" : "lp64f";63ImpliedFPU = 32;64}65if (A->getOption().matches(options::OPT_msoft_float)) {66ImpliedABI = IsLA32 ? "ilp32s" : "lp64s";67ImpliedFPU = 0;68}6970// Check `-mabi=` and `-mfpu=` settings and report if they conflict with71// the higher-priority settings implied by -m*-float.72//73// ImpliedABI and ImpliedFPU are guaranteed to have valid values because74// one of the match arms must match if execution can arrive here at all.75if (!MABIValue.empty() && ImpliedABI != MABIValue)76D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)77<< MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI;7879if (FPU != -1 && ImpliedFPU != FPU)80D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)81<< MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU;8283return ImpliedABI;84}8586// If `-mabi=` is specified, use it.87if (!MABIValue.empty())88return MABIValue;8990// Select abi based on -mfpu=xx.91switch (FPU) {92case 64:93return IsLA32 ? "ilp32d" : "lp64d";94case 32:95return IsLA32 ? "ilp32f" : "lp64f";96case 0:97return IsLA32 ? "ilp32s" : "lp64s";98}99100// Choose a default based on the triple.101// Honor the explicit ABI modifier suffix in triple's environment part if102// present, falling back to {ILP32,LP64}D otherwise.103switch (Triple.getEnvironment()) {104case llvm::Triple::GNUSF:105return IsLA32 ? "ilp32s" : "lp64s";106case llvm::Triple::GNUF32:107return IsLA32 ? "ilp32f" : "lp64f";108case llvm::Triple::GNUF64:109// This was originally permitted (and indeed the canonical way) to110// represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to111// drop the explicit suffix in favor of unmarked `-gnu` for the112// "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 it116// for some time, until it is clear that everyone else has migrated away117// from it.118[[fallthrough]];119case llvm::Triple::GNU:120default:121return IsLA32 ? "ilp32d" : "lp64d";122}123}124125void loongarch::getLoongArchTargetFeatures(const Driver &D,126const llvm::Triple &Triple,127const ArgList &Args,128std::vector<StringRef> &Features) {129// Enable the `lsx` feature on 64-bit LoongArch by default.130if (Triple.isLoongArch64() &&131(!Args.hasArgNoClaim(clang::driver::options::OPT_march_EQ)))132Features.push_back("+lsx");133134std::string ArchName;135if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))136ArchName = A->getValue();137ArchName = postProcessTargetCPUString(ArchName, Triple);138llvm::LoongArch::getArchFeatures(ArchName, Features);139140// Select floating-point features determined by -mdouble-float,141// -msingle-float, -msoft-float and -mfpu.142// Note: -m*-float wins any other options.143if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,144options::OPT_msingle_float,145options::OPT_msoft_float)) {146if (A->getOption().matches(options::OPT_mdouble_float)) {147Features.push_back("+f");148Features.push_back("+d");149} else if (A->getOption().matches(options::OPT_msingle_float)) {150Features.push_back("+f");151Features.push_back("-d");152Features.push_back("-lsx");153} else /*Soft-float*/ {154Features.push_back("-f");155Features.push_back("-d");156Features.push_back("-lsx");157}158} else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {159StringRef FPU = A->getValue();160if (FPU == "64") {161Features.push_back("+f");162Features.push_back("+d");163} else if (FPU == "32") {164Features.push_back("+f");165Features.push_back("-d");166Features.push_back("-lsx");167} else if (FPU == "0" || FPU == "none") {168Features.push_back("-f");169Features.push_back("-d");170Features.push_back("-lsx");171} else {172D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;173}174}175176// Select the `ual` feature determined by -m[no-]strict-align.177AddTargetFeature(Args, Features, options::OPT_mno_strict_align,178options::OPT_mstrict_align, "ual");179180// Accept but warn about these TargetSpecific options.181if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))182A->ignoreTargetSpecific();183if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))184A->ignoreTargetSpecific();185if (Arg *A = Args.getLastArgNoClaim(options::OPT_msimd_EQ))186A->ignoreTargetSpecific();187188// Select lsx/lasx feature determined by -msimd=.189// Option -msimd= precedes -m[no-]lsx and -m[no-]lasx.190if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {191StringRef MSIMD = A->getValue();192if (MSIMD == "lsx") {193// Option -msimd=lsx depends on 64-bit FPU.194// -m*-float and -mfpu=none/0/32 conflict with -msimd=lsx.195if (llvm::find(Features, "-d") != Features.end())196D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;197else198Features.push_back("+lsx");199} else if (MSIMD == "lasx") {200// Option -msimd=lasx depends on 64-bit FPU and LSX.201// -m*-float, -mfpu=none/0/32 and -mno-lsx conflict with -msimd=lasx.202if (llvm::find(Features, "-d") != Features.end())203D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;204else if (llvm::find(Features, "-lsx") != Features.end())205D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);206207// The command options do not contain -mno-lasx.208if (!Args.getLastArg(options::OPT_mno_lasx)) {209Features.push_back("+lsx");210Features.push_back("+lasx");211}212} else if (MSIMD == "none") {213if (llvm::find(Features, "+lsx") != Features.end())214Features.push_back("-lsx");215if (llvm::find(Features, "+lasx") != Features.end())216Features.push_back("-lasx");217} else {218D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;219}220}221222// Select lsx feature determined by -m[no-]lsx.223if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {224// LSX depends on 64-bit FPU.225// -m*-float and -mfpu=none/0/32 conflict with -mlsx.226if (A->getOption().matches(options::OPT_mlsx)) {227if (llvm::find(Features, "-d") != Features.end())228D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;229else /*-mlsx*/230Features.push_back("+lsx");231} else /*-mno-lsx*/ {232Features.push_back("-lsx");233}234}235236// Select lasx feature determined by -m[no-]lasx.237if (const Arg *A =238Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) {239// LASX depends on 64-bit FPU and LSX.240// -mno-lsx conflicts with -mlasx.241if (A->getOption().matches(options::OPT_mlasx)) {242if (llvm::find(Features, "-d") != Features.end())243D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;244else { /*-mlasx*/245Features.push_back("+lsx");246Features.push_back("+lasx");247}248} else /*-mno-lasx*/249Features.push_back("-lasx");250}251}252253std::string loongarch::postProcessTargetCPUString(const std::string &CPU,254const llvm::Triple &Triple) {255std::string CPUString = CPU;256if (CPUString == "native") {257CPUString = llvm::sys::getHostCPUName();258if (CPUString == "generic")259CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());260}261if (CPUString.empty())262CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());263return CPUString;264}265266std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,267const llvm::Triple &Triple) {268std::string CPU;269std::string Arch;270// If we have -march, use that.271if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {272Arch = A->getValue();273if (Arch == "la64v1.0" || Arch == "la64v1.1")274CPU = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());275else276CPU = Arch;277}278return postProcessTargetCPUString(CPU, Triple);279}280281282