simon_tatham created this revision. simon_tatham added reviewers: dmgreen, samparker, SjoerdMeijer. Herald added subscribers: llvm-commits, cfe-commits, hiraditya, kristof.beyls, javed.absar. Herald added projects: clang, LLVM.
Now, when clang processes an argument of the form "-march=foo+x+y+z", then instead of calling getArchExtFeature() for each of the extension names "x", "y", "z" and appending the returned string to its list of low-level subtarget features, it will call appendArchExtFeatures() which does the appending itself. The difference is that appendArchExtFeatures can add _more_ than one low-level feature name to the output feature list if it has to, and also, it gets told some information about what base architecture and CPU the extension is going to go with, which means that "+fp" can now mean something different for different CPUs. Namely, "+fp" now selects whatever the _default_ FPU is for the selected CPU and/or architecture, as defined in the ARM_ARCH or ARM_CPU_NAME macros in ARMTargetParser.def. On the clang side, I adjust DecodeARMFeatures to call the new appendArchExtFeatures function in place of getArchExtFeature. This means DecodeARMFeatures needs to be passed a CPU name and an ArchKind, which meant changing its call sites to make those available, and also sawing getLLVMArchSuffixForARM in half so that you can get an ArchKind enum value out of it instead of a string. Also, I add support here for the extension name "+fp.dp", which will automatically look through the FPU list for something that looks just like the default FPU except for also supporting double precision. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D60697 Files: clang/lib/Driver/ToolChains/Arch/ARM.cpp clang/lib/Driver/ToolChains/Arch/ARM.h llvm/include/llvm/Support/ARMTargetParser.h llvm/lib/Support/ARMTargetParser.cpp
Index: llvm/lib/Support/ARMTargetParser.cpp =================================================================== --- llvm/lib/Support/ARMTargetParser.cpp +++ llvm/lib/Support/ARMTargetParser.cpp @@ -473,22 +473,68 @@ return StringRef(); } -StringRef ARM::getArchExtFeature(StringRef ArchExt) { - if (ArchExt.startswith("no")) { - StringRef ArchExtBase(ArchExt.substr(2)); - for (const auto AE : ARCHExtNames) { - if (AE.NegFeature && ArchExtBase == AE.getName()) - return StringRef(AE.NegFeature); - } +static bool wasNegated(StringRef &Name) { + if (Name.startswith("no")) { + Name = Name.substr(2); + return true; } + return false; +} + +StringRef ARM::getArchExtFeature(StringRef ArchExt) { + bool Negated = wasNegated(ArchExt); for (const auto AE : ARCHExtNames) { if (AE.Feature && ArchExt == AE.getName()) - return StringRef(AE.Feature); + return StringRef(Negated ? AE.NegFeature : AE.Feature); } return StringRef(); } +bool ARM::appendArchExtFeatures( + StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, + std::vector<StringRef> &Features) { + StringRef StandardFeature = getArchExtFeature(ArchExt); + if (!StandardFeature.empty()) { + Features.push_back(StandardFeature); + return true; + } + + bool Negated = wasNegated(ArchExt); + if (ArchExt == "fp" || ArchExt == "fp.dp") { + unsigned FPUKind; + if (Negated) { + FPUKind = ARM::FK_NONE; + } else { + FPUKind = getDefaultFPU(CPU, AK); + if (FPUKind == ARM::FK_NONE) + return false; + if (ArchExt == "fp.dp") { + // Enable a double-precision-capable FPU in cases where the + // default one is single-precision only. + const FPUName &DefaultFPU = FPUNames[FPUKind]; + if (DefaultFPU.Restriction != FPURestriction::SP_D16) + return false; // meaningless for this arch + + FPUKind = ARM::FK_INVALID; + for (const FPUName &CandidateFPU : FPUNames) { + if (CandidateFPU.FPUVer == DefaultFPU.FPUVer && + CandidateFPU.NeonSupport == DefaultFPU.NeonSupport && + CandidateFPU.Restriction == FPURestriction::D16) { + FPUKind = CandidateFPU.ID; + break; + } + } + } + } + if (FPUKind == ARM::FK_INVALID) + return false; + return ARM::getFPUFeatures(FPUKind, Features); + } + + return false; +} + StringRef ARM::getHWDivName(unsigned HWDivKind) { for (const auto D : HWDivNames) { if (HWDivKind == D.ID) Index: llvm/include/llvm/Support/ARMTargetParser.h =================================================================== --- llvm/include/llvm/Support/ARMTargetParser.h +++ llvm/include/llvm/Support/ARMTargetParser.h @@ -233,6 +233,8 @@ StringRef getSubArch(ArchKind AK); StringRef getArchExtName(unsigned ArchExtKind); StringRef getArchExtFeature(StringRef ArchExt); +bool appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK, StringRef ArchExt, + std::vector<StringRef> &Features); StringRef getHWDivName(unsigned HWDivKind); // Information by Name Index: clang/lib/Driver/ToolChains/Arch/ARM.h =================================================================== --- clang/lib/Driver/ToolChains/Arch/ARM.h +++ clang/lib/Driver/ToolChains/Arch/ARM.h @@ -13,6 +13,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" +#include "llvm/Support/TargetParser.h" #include <string> #include <vector> @@ -25,6 +26,8 @@ const llvm::Triple &Triple); const std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); StringRef getARMCPUForMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +llvm::ARM::ArchKind getLLVMArchKindForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple); StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch, const llvm::Triple &Triple); Index: clang/lib/Driver/ToolChains/Arch/ARM.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -72,15 +72,13 @@ // Decode ARM features from string like +[no]featureA+[no]featureB+... static bool DecodeARMFeatures(const Driver &D, StringRef text, + StringRef CPU, llvm::ARM::ArchKind ArchKind, std::vector<StringRef> &Features) { SmallVector<StringRef, 8> Split; text.split(Split, StringRef("+"), -1, false); for (StringRef Feature : Split) { - StringRef FeatureName = llvm::ARM::getArchExtFeature(Feature); - if (!FeatureName.empty()) - Features.push_back(FeatureName); - else + if (!appendArchExtFeatures(CPU, ArchKind, Feature, Features)) return false; } return true; @@ -105,8 +103,10 @@ std::pair<StringRef, StringRef> Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); - if (llvm::ARM::parseArch(MArch) == llvm::ARM::ArchKind::INVALID || - (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(MArch); + if (ArchKind == llvm::ARM::ArchKind::INVALID || + (Split.second.size() && !DecodeARMFeatures( + D, Split.second, "generic", ArchKind, Features))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -118,8 +118,11 @@ std::pair<StringRef, StringRef> Split = CPUName.split("+"); std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); - if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() || - (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) + llvm::ARM::ArchKind ArchKind = + arm::getLLVMArchKindForARM(CPU, ArchName, Triple); + if (ArchKind == llvm::ARM::ArchKind::INVALID || + (Split.second.size() && !DecodeARMFeatures( + D, Split.second, CPU, ArchKind, Features))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -615,11 +618,12 @@ return getARMCPUForMArch(Arch, Triple); } -/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular -/// CPU (or Arch, if CPU is generic). -// FIXME: This is redundant with -mcpu, why does LLVM use this. -StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple) { +/// getLLVMArchSuffixForARM - Get the LLVM ArchKind value to use for a +/// particular CPU (or Arch, if CPU is generic). This is needed to +/// pass to functions like llvm::ARM::getDefaultFPU which need an +/// ArchKind as well as a CPU name. +llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { llvm::ARM::ArchKind ArchKind; if (CPU == "generic") { std::string ARMArch = tools::arm::getARMArch(Arch, Triple); @@ -635,6 +639,15 @@ ? llvm::ARM::ArchKind::ARMV7K : llvm::ARM::parseCPUArch(CPU); } + return ArchKind; +} + +/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular +/// CPU (or Arch, if CPU is generic). +// FIXME: This is redundant with -mcpu, why does LLVM use this. +StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { + llvm::ARM::ArchKind ArchKind = getLLVMArchKindForARM(CPU, Arch, Triple); if (ArchKind == llvm::ARM::ArchKind::INVALID) return ""; return llvm::ARM::getSubArch(ArchKind);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits