Index: llvm/trunk/include/llvm/MC/MCSubtargetInfo.h =================================================================== --- llvm/trunk/include/llvm/MC/MCSubtargetInfo.h +++ llvm/trunk/include/llvm/MC/MCSubtargetInfo.h @@ -94,6 +94,10 @@ /// feature bits. This version will also change all implied bits. FeatureBitset ToggleFeature(StringRef FS); + /// Apply a feature flag and return the re-computed feature bits, including + /// all feature bits implied by the flag. + FeatureBitset ApplyFeatureFlag(StringRef FS); + /// getSchedModelForCPU - Get the machine model of a CPU. /// MCSchedModel getSchedModelForCPU(StringRef CPU) const; Index: llvm/trunk/include/llvm/MC/SubtargetFeature.h =================================================================== --- llvm/trunk/include/llvm/MC/SubtargetFeature.h +++ llvm/trunk/include/llvm/MC/SubtargetFeature.h @@ -103,6 +103,10 @@ FeatureBitset ToggleFeature(FeatureBitset Bits, StringRef String, ArrayRef FeatureTable); + /// Apply the feature flag and return the newly updated feature bits. + FeatureBitset ApplyFeatureFlag(FeatureBitset Bits, StringRef Feature, + ArrayRef FeatureTable); + /// Get feature bits of a CPU. FeatureBitset getFeatureBits(StringRef CPU, ArrayRef CPUTable, Index: llvm/trunk/include/llvm/Support/TargetParser.h =================================================================== --- llvm/trunk/include/llvm/Support/TargetParser.h +++ llvm/trunk/include/llvm/Support/TargetParser.h @@ -15,6 +15,10 @@ #ifndef LLVM_SUPPORT_TARGETPARSER_H #define LLVM_SUPPORT_TARGETPARSER_H +// FIXME: vector is used because that's what clang uses for subtarget feature +// lists, but SmallVector would probably be better +#include + namespace llvm { class StringRef; @@ -44,6 +48,20 @@ FK_LAST }; + // An FPU name implies one of three levels of Neon support: + enum NeonSupportLevel { + NS_None = 0, //< No Neon + NS_Neon, //< Neon + NS_Crypto //< Neon with Crypto + }; + + // An FPU name restricts the FPU in one of three ways: + enum FPURestriction { + FR_None = 0, //< No restriction + FR_D16, //< Only 16 D registers + FR_SP_D16 //< Only single-precision instructions, with 16 D registers + }; + // Arch names. enum ArchKind { AK_INVALID = 0, @@ -139,6 +157,12 @@ // Information by ID static const char * getFPUName(unsigned FPUKind); + static unsigned getFPUVersion(unsigned FPUKind); + static unsigned getFPUNeonSupportLevel(unsigned FPUKind); + static unsigned getFPURestriction(unsigned FPUKind); + // FIXME: This should be moved to TargetTuple once it exists + static bool getFPUFeatures(unsigned FPUKind, + std::vector &Features); static const char * getArchName(unsigned ArchKind); static unsigned getArchAttr(unsigned ArchKind); static const char * getCPUAttr(unsigned ArchKind); Index: llvm/trunk/lib/MC/MCSubtargetInfo.cpp =================================================================== --- llvm/trunk/lib/MC/MCSubtargetInfo.cpp +++ llvm/trunk/lib/MC/MCSubtargetInfo.cpp @@ -81,6 +81,11 @@ return FeatureBits; } +FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) { + SubtargetFeatures Features; + FeatureBits = Features.ApplyFeatureFlag(FeatureBits, FS, ProcFeatures); + return FeatureBits; +} MCSchedModel MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const { Index: llvm/trunk/lib/MC/SubtargetFeature.cpp =================================================================== --- llvm/trunk/lib/MC/SubtargetFeature.cpp +++ llvm/trunk/lib/MC/SubtargetFeature.cpp @@ -190,6 +190,38 @@ return Bits; } +FeatureBitset +SubtargetFeatures::ApplyFeatureFlag(FeatureBitset Bits, StringRef Feature, + ArrayRef FeatureTable) { + + assert(hasFlag(Feature)); + + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable); + // If there is a match + if (FeatureEntry) { + // Enable/disable feature in bits + if (isEnabled(Feature)) { + Bits |= FeatureEntry->Value; + + // For each feature that this implies, set it. + SetImpliedBits(Bits, FeatureEntry, FeatureTable); + } else { + Bits &= ~FeatureEntry->Value; + + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, FeatureEntry, FeatureTable); + } + } else { + errs() << "'" << Feature + << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } + + return Bits; +} + /// getFeatureBits - Get feature bits a CPU. /// @@ -245,28 +277,7 @@ if (Feature == "+help") Help(CPUTable, FeatureTable); - // Find feature in table. - const SubtargetFeatureKV *FeatureEntry = - Find(StripFlag(Feature), FeatureTable); - // If there is a match - if (FeatureEntry) { - // Enable/disable feature in bits - if (isEnabled(Feature)) { - Bits |= FeatureEntry->Value; - - // For each feature that this implies, set it. - SetImpliedBits(Bits, FeatureEntry, FeatureTable); - } else { - Bits &= ~FeatureEntry->Value; - - // For each feature that implies this, clear it. - ClearImpliedBits(Bits, FeatureEntry, FeatureTable); - } - } else { - errs() << "'" << Feature - << "' is not a recognized feature for this target" - << " (ignoring feature)\n"; - } + Bits = ApplyFeatureFlag(Bits, Feature, FeatureTable); } return Bits; Index: llvm/trunk/lib/Support/TargetParser.cpp =================================================================== --- llvm/trunk/lib/Support/TargetParser.cpp +++ llvm/trunk/lib/Support/TargetParser.cpp @@ -22,27 +22,33 @@ namespace { -// List of canonical FPU names (use getFPUSynonym). +// List of canonical FPU names (use getFPUSynonym) and which architectural +// features they correspond to (use getFPUFeatures). // FIXME: TableGen this. struct { const char * Name; ARM::FPUKind ID; + unsigned FPUVersion; //< Corresponds directly to the FP arch version number. + ARM::NeonSupportLevel NeonSupport; + ARM::FPURestriction Restriction; } FPUNames[] = { - { "invalid", ARM::FK_INVALID }, - { "vfp", ARM::FK_VFP }, - { "vfpv2", ARM::FK_VFPV2 }, - { "vfpv3", ARM::FK_VFPV3 }, - { "vfpv3-d16", ARM::FK_VFPV3_D16 }, - { "vfpv4", ARM::FK_VFPV4 }, - { "vfpv4-d16", ARM::FK_VFPV4_D16 }, - { "fpv5-d16", ARM::FK_FPV5_D16 }, - { "fp-armv8", ARM::FK_FP_ARMV8 }, - { "neon", ARM::FK_NEON }, - { "neon-vfpv4", ARM::FK_NEON_VFPV4 }, - { "neon-fp-armv8", ARM::FK_NEON_FP_ARMV8 }, - { "crypto-neon-fp-armv8", ARM::FK_CRYPTO_NEON_FP_ARMV8 }, - { "softvfp", ARM::FK_SOFTVFP } + { "invalid", ARM::FK_INVALID, 0, ARM::NS_None, ARM::FR_None}, + { "vfp", ARM::FK_VFP, 2, ARM::NS_None, ARM::FR_None}, + { "vfpv2", ARM::FK_VFPV2, 2, ARM::NS_None, ARM::FR_None}, + { "vfpv3", ARM::FK_VFPV3, 3, ARM::NS_None, ARM::FR_None}, + { "vfpv3-d16", ARM::FK_VFPV3_D16, 3, ARM::NS_None, ARM::FR_D16}, + { "vfpv4", ARM::FK_VFPV4, 4, ARM::NS_None, ARM::FR_None}, + { "vfpv4-d16", ARM::FK_VFPV4_D16, 4, ARM::NS_None, ARM::FR_D16}, + { "fpv5-d16", ARM::FK_FPV5_D16, 5, ARM::NS_None, ARM::FR_D16}, + { "fp-armv8", ARM::FK_FP_ARMV8, 5, ARM::NS_None, ARM::FR_None}, + { "neon", ARM::FK_NEON, 3, ARM::NS_Neon, ARM::FR_None}, + { "neon-vfpv4", ARM::FK_NEON_VFPV4, 4, ARM::NS_Neon, ARM::FR_None}, + { "neon-fp-armv8", ARM::FK_NEON_FP_ARMV8, 5, ARM::NS_Neon, ARM::FR_None}, + { "crypto-neon-fp-armv8", + ARM::FK_CRYPTO_NEON_FP_ARMV8, 5, ARM::NS_Crypto, ARM::FR_None}, + { "softvfp", ARM::FK_SOFTVFP, 0, ARM::NS_None, ARM::FR_None}, }; + // List of canonical arch names (use getArchSynonym). // This table also provides the build attribute fields for CPU arch // and Arch ID, according to the Addenda to the ARM ABI, chapters @@ -226,6 +232,95 @@ return FPUNames[FPUKind].Name; } +unsigned ARMTargetParser::getFPUVersion(unsigned FPUKind) { + if (FPUKind >= ARM::FK_LAST) + return 0; + return FPUNames[FPUKind].FPUVersion; +} + +unsigned getFPUNeonSupportLevel(unsigned FPUKind) { + if (FPUKind >= ARM::FK_LAST) + return 0; + return FPUNames[FPUKind].NeonSupport; +} + +unsigned getFPURestriction(unsigned FPUKind) { + if (FPUKind >= ARM::FK_LAST) + return 0; + return FPUNames[FPUKind].Restriction; +} + +bool ARMTargetParser::getFPUFeatures(unsigned FPUKind, + std::vector &Features) { + + if (FPUKind >= ARM::FK_LAST || FPUKind == ARM::FK_INVALID) + return false; + + // fp-only-sp and d16 subtarget features are independent of each other, so we + // must enable/disable both. + switch (FPUNames[FPUKind].Restriction) { + case ARM::FR_SP_D16: + Features.push_back("+fp-only-sp"); + Features.push_back("+d16"); + break; + case ARM::FR_D16: + Features.push_back("-fp-only-sp"); + Features.push_back("+d16"); + break; + case ARM::FR_None: + Features.push_back("-fp-only-sp"); + Features.push_back("-d16"); + break; + } + + // FPU version subtarget features are inclusive of lower-numbered ones, so + // enable the one corresponding to this version and disable all that are + // higher. + switch (FPUNames[FPUKind].FPUVersion) { + case 5: + Features.push_back("+fp-armv8"); + break; + case 4: + Features.push_back("+vfp4"); + Features.push_back("-fp-armv8"); + break; + case 3: + Features.push_back("+vfp3"); + Features.push_back("-vfp4"); + Features.push_back("-fp-armv8"); + break; + case 2: + Features.push_back("+vfp2"); + Features.push_back("-vfp3"); + Features.push_back("-vfp4"); + Features.push_back("-fp-armv8"); + break; + case 0: + Features.push_back("-vfp2"); + Features.push_back("-vfp3"); + Features.push_back("-vfp4"); + Features.push_back("-fp-armv8"); + break; + } + + // crypto includes neon, so we handle this similarly to FPU version. + switch (FPUNames[FPUKind].NeonSupport) { + case ARM::NS_Crypto: + Features.push_back("+crypto"); + break; + case ARM::NS_Neon: + Features.push_back("+neon"); + Features.push_back("-crypto"); + break; + case ARM::NS_None: + Features.push_back("-neon"); + Features.push_back("-crypto"); + break; + } + + return true; +} + const char *ARMTargetParser::getArchName(unsigned ArchKind) { if (ArchKind >= ARM::AK_LAST) return nullptr; Index: llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -9181,60 +9181,6 @@ return false; } - -// FIXME: This is duplicated in getARMFPUFeatures() in -// tools/clang/lib/Driver/Tools.cpp -static const struct { - const unsigned ID; - const FeatureBitset Enabled; - const FeatureBitset Disabled; -} FPUs[] = { - {/* ID */ ARM::FK_VFP, - /* Enabled */ {ARM::FeatureVFP2}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_VFPV2, - /* Enabled */ {ARM::FeatureVFP2}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_VFPV3, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureD16}}, - {/* ID */ ARM::FK_VFPV3_D16, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureD16}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_VFPV4, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureD16}}, - {/* ID */ ARM::FK_VFPV4_D16, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureD16}, - /* Disabled */ {ARM::FeatureNEON}}, - {/* ID */ ARM::FK_FPV5_D16, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8, ARM::FeatureD16}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureCrypto}}, - {/* ID */ ARM::FK_FP_ARMV8, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8}, - /* Disabled */ {ARM::FeatureNEON, ARM::FeatureCrypto, ARM::FeatureD16}}, - {/* ID */ ARM::FK_NEON, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureNEON}, - /* Disabled */ {ARM::FeatureD16}}, - {/* ID */ ARM::FK_NEON_VFPV4, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureNEON}, - /* Disabled */ {ARM::FeatureD16}}, - {/* ID */ ARM::FK_NEON_FP_ARMV8, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8, ARM::FeatureNEON}, - /* Disabled */ {ARM::FeatureCrypto, ARM::FeatureD16}}, - {/* ID */ ARM::FK_CRYPTO_NEON_FP_ARMV8, - /* Enabled */ {ARM::FeatureVFP2, ARM::FeatureVFP3, ARM::FeatureVFP4, - ARM::FeatureFPARMv8, ARM::FeatureNEON, - ARM::FeatureCrypto}, - /* Disabled */ {ARM::FeatureD16}}, - {ARM::FK_SOFTVFP, {}, {}}, -}; - /// parseDirectiveFPU /// ::= .fpu str bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { @@ -9242,23 +9188,15 @@ StringRef FPU = getParser().parseStringToEndOfStatement().trim(); unsigned ID = ARMTargetParser::parseFPU(FPU); - - if (ID == ARM::FK_INVALID) { + std::vector Features; + if (!ARMTargetParser::getFPUFeatures(ID, Features)) { Error(FPUNameLoc, "Unknown FPU name"); return false; } - for (const auto &Entry : FPUs) { - if (Entry.ID != ID) - continue; - - // Need to toggle features that should be on but are off and that - // should off but are on. - FeatureBitset Toggle = (Entry.Enabled & ~STI.getFeatureBits()) | - (Entry.Disabled & STI.getFeatureBits()); - setAvailableFeatures(ComputeAvailableFeatures(STI.ToggleFeature(Toggle))); - break; - } + for (auto Feature : Features) + STI.ApplyFeatureFlag(Feature); + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); getTargetStreamer().emitFPU(ID); return false;