[ARM] Add knowledge of FPU subtarget features to TargetParser
authorJohn Brawn <john.brawn@arm.com>
Fri, 5 Jun 2015 13:29:24 +0000 (13:29 +0000)
committerJohn Brawn <john.brawn@arm.com>
Fri, 5 Jun 2015 13:29:24 +0000 (13:29 +0000)
Add getFPUFeatures to TargetParser, which gets the list of subtarget features
that are enabled/disabled for each FPU, and use it when handling the .fpu
directive.

No functional change in this commit, though clang will start behaving
differently once it starts using this.

Differential Revision: http://reviews.llvm.org/D10237

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239150 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCSubtargetInfo.h
include/llvm/MC/SubtargetFeature.h
include/llvm/Support/TargetParser.h
lib/MC/MCSubtargetInfo.cpp
lib/MC/SubtargetFeature.cpp
lib/Support/TargetParser.cpp
lib/Target/ARM/AsmParser/ARMAsmParser.cpp

index 1778a6d13fb86205cd06dfe931afb51e7e820e19..9f76cb750620443727cd6265132715ccc4f12fb1 100644 (file)
@@ -94,6 +94,10 @@ public:
   /// feature bits. This version will also change all implied bits.
   FeatureBitset ToggleFeature(StringRef FS);
 
   /// 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;
   /// getSchedModelForCPU - Get the machine model of a CPU.
   ///
   MCSchedModel getSchedModelForCPU(StringRef CPU) const;
index 6a631ffe79bd3046a8cc22ac5476b6e9acd19453..2fb9b4ae2503f14ee7ace7c8b55db2e0c6c24a54 100644 (file)
@@ -103,6 +103,10 @@ public:
   FeatureBitset ToggleFeature(FeatureBitset Bits, StringRef String,
                          ArrayRef<SubtargetFeatureKV> FeatureTable);
 
   FeatureBitset ToggleFeature(FeatureBitset Bits, StringRef String,
                          ArrayRef<SubtargetFeatureKV> FeatureTable);
 
+  /// Apply the feature flag and return the newly updated feature bits.
+  FeatureBitset ApplyFeatureFlag(FeatureBitset Bits, StringRef Feature,
+                                 ArrayRef<SubtargetFeatureKV> FeatureTable);
+
   /// Get feature bits of a CPU.
   FeatureBitset getFeatureBits(StringRef CPU,
                           ArrayRef<SubtargetFeatureKV> CPUTable,
   /// Get feature bits of a CPU.
   FeatureBitset getFeatureBits(StringRef CPU,
                           ArrayRef<SubtargetFeatureKV> CPUTable,
index da0ed8e20795fcf9df5ed707c1a97715c5ba95f1..92fb275fcb3797b59ed4cc1aa1ced3803be002ee 100644 (file)
 #ifndef LLVM_SUPPORT_TARGETPARSER_H
 #define LLVM_SUPPORT_TARGETPARSER_H
 
 #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 <vector>
+
 namespace llvm {
   class StringRef;
 
 namespace llvm {
   class StringRef;
 
@@ -44,6 +48,20 @@ namespace ARM {
     FK_LAST
   };
 
     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,
   // Arch names.
   enum ArchKind {
     AK_INVALID = 0,
@@ -139,6 +157,12 @@ public:
 
   // Information by ID
   static const char * getFPUName(unsigned FPUKind);
 
   // 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<const char*> &Features);
   static const char * getArchName(unsigned ArchKind);
   static   unsigned   getArchAttr(unsigned ArchKind);
   static const char * getCPUAttr(unsigned ArchKind);
   static const char * getArchName(unsigned ArchKind);
   static   unsigned   getArchAttr(unsigned ArchKind);
   static const char * getCPUAttr(unsigned ArchKind);
index 6abdd3acbc5a355a58019302f4780281074f6054..7954a02d83b2168d4974c4cb8368f694638dab20 100644 (file)
@@ -81,6 +81,11 @@ FeatureBitset MCSubtargetInfo::ToggleFeature(StringRef FS) {
   return FeatureBits;
 }
 
   return FeatureBits;
 }
 
+FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) {
+  SubtargetFeatures Features;
+  FeatureBits = Features.ApplyFeatureFlag(FeatureBits, FS, ProcFeatures);
+  return FeatureBits;
+}
 
 MCSchedModel
 MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const {
 
 MCSchedModel
 MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const {
index e976a508bc2f58e177b9f447f276ebd5bf36b2e3..76574e987cb16406564dbd8bca4cf7dd8685c150 100644 (file)
@@ -190,6 +190,38 @@ SubtargetFeatures::ToggleFeature(FeatureBitset Bits, StringRef Feature,
   return Bits;
 }
 
   return Bits;
 }
 
+FeatureBitset
+SubtargetFeatures::ApplyFeatureFlag(FeatureBitset Bits, StringRef Feature,
+                                    ArrayRef<SubtargetFeatureKV> 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.
 ///
 
 /// getFeatureBits - Get feature bits a CPU.
 ///
@@ -245,28 +277,7 @@ SubtargetFeatures::getFeatureBits(StringRef CPU,
     if (Feature == "+help")
       Help(CPUTable, FeatureTable);
 
     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;
   }
 
   return Bits;
index 9e81763603f263147e59e0f11cb23dd566e81667..c2f521f323cdbc74a3bd2f4d2a5d89a7096690f7 100644 (file)
@@ -22,27 +22,33 @@ using namespace llvm;
 
 namespace {
 
 
 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;
 // 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[] = {
 } 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
 // 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 @@ const char *ARMTargetParser::getFPUName(unsigned FPUKind) {
   return FPUNames[FPUKind].Name;
 }
 
   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<const char *> &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;
 const char *ARMTargetParser::getArchName(unsigned ArchKind) {
   if (ArchKind >= ARM::AK_LAST)
     return nullptr;
index f965cb5400d894a1a62ff4bbfd9a581d96ce606b..c7287abaac5618982ba5432c71de29d4690cfa20 100644 (file)
@@ -9181,60 +9181,6 @@ bool ARMAsmParser::parseDirectiveCPU(SMLoc L) {
 
   return false;
 }
 
   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) {
 /// parseDirectiveFPU
 ///  ::= .fpu str
 bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
@@ -9242,23 +9188,15 @@ bool ARMAsmParser::parseDirectiveFPU(SMLoc L) {
   StringRef FPU = getParser().parseStringToEndOfStatement().trim();
 
   unsigned ID = ARMTargetParser::parseFPU(FPU);
   StringRef FPU = getParser().parseStringToEndOfStatement().trim();
 
   unsigned ID = ARMTargetParser::parseFPU(FPU);
-
-  if (ID == ARM::FK_INVALID) {
+  std::vector<const char *> Features;
+  if (!ARMTargetParser::getFPUFeatures(ID, Features)) {
     Error(FPUNameLoc, "Unknown FPU name");
     return false;
   }
 
     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;
 
   getTargetStreamer().emitFPU(ID);
   return false;