Skip to content

[Hexagon] NFC: Reduce the amount of version-specific code #145812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

quic-akaryaki
Copy link
Contributor

There is a lot of redundant code that needs to be modified when new Hexagon versions are added. Reduce the amount of this redundancy.

  • compute ELF flags and attributes based on version feature names;
  • simplify EnableHVX option handling by using arch features instead of arch version enums;
  • simplify completeHVXFeatures() by using features;
  • delete several unused or redundant functions and constants: isCPUValid, getCpu, getHexagonCPUSuffix;
  • do not set HexagonArchVersion in initializeSubtargetDependencies, it is set in ParseSubtargetFeatures;

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:Hexagon clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 25, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 25, 2025

@llvm/pr-subscribers-backend-hexagon

Author: Alexey Karyakin (quic-akaryaki)

Changes

There is a lot of redundant code that needs to be modified when new Hexagon versions are added. Reduce the amount of this redundancy.

  • compute ELF flags and attributes based on version feature names;
  • simplify EnableHVX option handling by using arch features instead of arch version enums;
  • simplify completeHVXFeatures() by using features;
  • delete several unused or redundant functions and constants: isCPUValid, getCpu, getHexagonCPUSuffix;
  • do not set HexagonArchVersion in initializeSubtargetDependencies, it is set in ParseSubtargetFeatures;

Patch is 21.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/145812.diff

7 Files Affected:

  • (modified) clang/lib/Basic/Targets/Hexagon.cpp (+15-26)
  • (modified) clang/lib/Basic/Targets/Hexagon.h (+5-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonDepArch.h (-20)
  • (modified) llvm/lib/Target/Hexagon/HexagonSubtarget.cpp (+1-7)
  • (modified) llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp (+4-3)
  • (modified) llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp (+137-171)
  • (modified) llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h (+5-2)
diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp
index 06dcac03baa5b..9fff20bf0f417 100644
--- a/clang/lib/Basic/Targets/Hexagon.cpp
+++ b/clang/lib/Basic/Targets/Hexagon.cpp
@@ -18,6 +18,19 @@
 using namespace clang;
 using namespace clang::targets;
 
+namespace {
+
+constexpr llvm::StringLiteral CpuValsTextArray[] = {
+    "hexagonv5",  "hexagonv55",  "hexagonv60",  "hexagonv62", "hexagonv65",
+    "hexagonv66", "hexagonv67",  "hexagonv67t", "hexagonv68", "hexagonv69",
+    "hexagonv71", "hexagonv71t", "hexagonv73",  "hexagonv75", "hexagonv79",
+};
+
+} // namespace
+
+const llvm::ArrayRef<llvm::StringLiteral>
+    HexagonTargetInfo::CpuValsText(CpuValsTextArray);
+
 void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   Builder.defineMacro("__qdsp6__", "1");
@@ -239,22 +252,6 @@ bool HexagonTargetInfo::hasFeature(StringRef Feature) const {
       .Default(false);
 }
 
-struct CPUSuffix {
-  llvm::StringLiteral Name;
-  llvm::StringLiteral Suffix;
-};
-
-static constexpr CPUSuffix Suffixes[] = {
-    {{"hexagonv5"}, {"5"}},   {{"hexagonv55"}, {"55"}},
-    {{"hexagonv60"}, {"60"}}, {{"hexagonv62"}, {"62"}},
-    {{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}},
-    {{"hexagonv67"}, {"67"}}, {{"hexagonv67t"}, {"67t"}},
-    {{"hexagonv68"}, {"68"}}, {{"hexagonv69"}, {"69"}},
-    {{"hexagonv71"}, {"71"}}, {{"hexagonv71t"}, {"71t"}},
-    {{"hexagonv73"}, {"73"}}, {{"hexagonv75"}, {"75"}},
-    {{"hexagonv79"}, {"79"}},
-};
-
 std::optional<unsigned> HexagonTargetInfo::getHexagonCPURev(StringRef Name) {
   StringRef Arch = Name;
   Arch.consume_front("hexagonv");
@@ -267,18 +264,10 @@ std::optional<unsigned> HexagonTargetInfo::getHexagonCPURev(StringRef Name) {
   return std::nullopt;
 }
 
-const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) {
-  const CPUSuffix *Item = llvm::find_if(
-      Suffixes, [Name](const CPUSuffix &S) { return S.Name == Name; });
-  if (Item == std::end(Suffixes))
-    return nullptr;
-  return Item->Suffix.data();
-}
-
 void HexagonTargetInfo::fillValidCPUList(
     SmallVectorImpl<StringRef> &Values) const {
-  for (const CPUSuffix &Suffix : Suffixes)
-    Values.push_back(Suffix.Name);
+  for (const llvm::StringLiteral &I : CpuValsText)
+    Values.push_back(I);
 }
 
 llvm::SmallVector<Builtin::InfosShard>
diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h
index a65663ca09eee..f9a6de39d022b 100644
--- a/clang/lib/Basic/Targets/Hexagon.h
+++ b/clang/lib/Basic/Targets/Hexagon.h
@@ -25,6 +25,7 @@ namespace targets {
 // Hexagon abstract base class
 class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo {
 
+  static const llvm::ArrayRef<llvm::StringLiteral> CpuValsText;
   static const char *const GCCRegNames[];
   static const TargetInfo::GCCRegAlias GCCRegAliases[];
   std::string CPU;
@@ -115,11 +116,13 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo {
 
   std::string_view getClobbers() const override { return ""; }
 
-  static const char *getHexagonCPUSuffix(StringRef Name);
   static std::optional<unsigned> getHexagonCPURev(StringRef Name);
 
   bool isValidCPUName(StringRef Name) const override {
-    return getHexagonCPUSuffix(Name);
+    // All the valid CPU architectures and micro-architectures must
+    // return true.
+    return std::any_of(std::begin(CpuValsText), std::end(CpuValsText),
+                       [Name](StringRef V) { return V == Name; });
   }
 
   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
diff --git a/llvm/lib/Target/Hexagon/HexagonDepArch.h b/llvm/lib/Target/Hexagon/HexagonDepArch.h
index 89845348a9e31..6f851a042ca20 100644
--- a/llvm/lib/Target/Hexagon/HexagonDepArch.h
+++ b/llvm/lib/Target/Hexagon/HexagonDepArch.h
@@ -32,26 +32,6 @@ enum class ArchEnum {
   V79
 };
 
-inline std::optional<Hexagon::ArchEnum> getCpu(StringRef CPU) {
-  return StringSwitch<std::optional<Hexagon::ArchEnum>>(CPU)
-      .Case("generic", Hexagon::ArchEnum::V5)
-      .Case("hexagonv5", Hexagon::ArchEnum::V5)
-      .Case("hexagonv55", Hexagon::ArchEnum::V55)
-      .Case("hexagonv60", Hexagon::ArchEnum::V60)
-      .Case("hexagonv62", Hexagon::ArchEnum::V62)
-      .Case("hexagonv65", Hexagon::ArchEnum::V65)
-      .Case("hexagonv66", Hexagon::ArchEnum::V66)
-      .Case("hexagonv67", Hexagon::ArchEnum::V67)
-      .Case("hexagonv67t", Hexagon::ArchEnum::V67)
-      .Case("hexagonv68", Hexagon::ArchEnum::V68)
-      .Case("hexagonv69", Hexagon::ArchEnum::V69)
-      .Case("hexagonv71", Hexagon::ArchEnum::V71)
-      .Case("hexagonv71t", Hexagon::ArchEnum::V71)
-      .Case("hexagonv73", Hexagon::ArchEnum::V73)
-      .Case("hexagonv75", Hexagon::ArchEnum::V75)
-      .Case("hexagonv79", Hexagon::ArchEnum::V79)
-      .Default(std::nullopt);
-}
 } // namespace Hexagon
 } // namespace llvm
 
diff --git a/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp b/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
index ecc1b5d2ebe35..ebaee73c51ec6 100644
--- a/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
@@ -88,12 +88,6 @@ HexagonSubtarget::HexagonSubtarget(const Triple &TT, StringRef CPU,
 
 HexagonSubtarget &
 HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
-  std::optional<Hexagon::ArchEnum> ArchVer = Hexagon::getCpu(CPUString);
-  if (ArchVer)
-    HexagonArchVersion = *ArchVer;
-  else
-    llvm_unreachable("Unrecognized Hexagon processor version");
-
   UseHVX128BOps = false;
   UseHVX64BOps = false;
   UseAudioOps = false;
@@ -163,7 +157,7 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
   FeatureBitset FeatureBits = getFeatureBits();
   if (HexagonDisableDuplex)
     setFeatureBits(FeatureBits.reset(Hexagon::FeatureDuplex));
-  setFeatureBits(Hexagon_MC::completeHVXFeatures(FeatureBits));
+  SetFeatureBitsTransitively(Hexagon_MC::completeHVXFeatures(FeatureBits));
 
   return *this;
 }
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
index 13ecc231a70b2..df86d2a3a54c0 100644
--- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
@@ -195,11 +195,12 @@ static unsigned featureToArchVersion(unsigned Feature) {
 
 void HexagonTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
   auto Features = STI.getFeatureBits();
-  unsigned Arch = featureToArchVersion(Hexagon_MC::getArchVersion(Features));
-  std::optional<unsigned> HVXArch = Hexagon_MC::getHVXVersion(Features);
+  unsigned Arch = Hexagon_MC::getArchVersionAttribute(Features).value_or(0);
+  std::optional<unsigned> HVXArch =
+      Hexagon_MC::getHVXVersionAttribute(Features);
   emitAttribute(HexagonAttrs::ARCH, Arch);
   if (HVXArch)
-    emitAttribute(HexagonAttrs::HVXARCH, featureToArchVersion(*HVXArch));
+    emitAttribute(HexagonAttrs::HVXARCH, *HVXArch);
   if (Features.test(Hexagon::ExtensionHVXIEEEFP))
     emitAttribute(HexagonAttrs::HVXIEEEFP, 1);
   if (Features.test(Hexagon::ExtensionHVXQFloat))
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
index 980df819b2c26..01ef334bed01b 100644
--- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
@@ -128,6 +128,59 @@ static cl::opt<bool> EnableHexagonCabac
 
 static constexpr StringRef DefaultArch = "hexagonv68";
 
+static const FeatureBitset HexagonArchFeatures = {
+    llvm::Hexagon::ArchV5,  llvm::Hexagon::ArchV55, llvm::Hexagon::ArchV60,
+    llvm::Hexagon::ArchV62, llvm::Hexagon::ArchV65, llvm::Hexagon::ArchV66,
+    llvm::Hexagon::ArchV67, llvm::Hexagon::ArchV68, llvm::Hexagon::ArchV69,
+    llvm::Hexagon::ArchV71, llvm::Hexagon::ArchV73, llvm::Hexagon::ArchV75,
+    llvm::Hexagon::ArchV79,
+};
+
+static const FeatureBitset HVXFeatures = {
+    llvm::Hexagon::ExtensionHVX,
+    llvm::Hexagon::ExtensionHVX64B,
+    llvm::Hexagon::ExtensionHVX128B,
+};
+
+static const FeatureBitset HVXVersionFeatures = {
+    llvm::Hexagon::ExtensionHVXV60, llvm::Hexagon::ExtensionHVXV62,
+    llvm::Hexagon::ExtensionHVXV65, llvm::Hexagon::ExtensionHVXV66,
+    llvm::Hexagon::ExtensionHVXV67, llvm::Hexagon::ExtensionHVXV68,
+    llvm::Hexagon::ExtensionHVXV69, llvm::Hexagon::ExtensionHVXV71,
+    llvm::Hexagon::ExtensionHVXV73, llvm::Hexagon::ExtensionHVXV75,
+    llvm::Hexagon::ExtensionHVXV79,
+
+};
+
+static const std::unordered_map<unsigned, unsigned> HexagonDefaultHVXVersion = {
+    {llvm::Hexagon::ArchV60, llvm::Hexagon::ExtensionHVXV60},
+    {llvm::Hexagon::ArchV62, llvm::Hexagon::ExtensionHVXV62},
+    {llvm::Hexagon::ArchV65, llvm::Hexagon::ExtensionHVXV65},
+    {llvm::Hexagon::ArchV66, llvm::Hexagon::ExtensionHVXV66},
+    {llvm::Hexagon::ArchV67, llvm::Hexagon::ExtensionHVXV67},
+    {llvm::Hexagon::ArchV68, llvm::Hexagon::ExtensionHVXV68},
+    {llvm::Hexagon::ArchV69, llvm::Hexagon::ExtensionHVXV69},
+    {llvm::Hexagon::ArchV71, llvm::Hexagon::ExtensionHVXV71},
+    {llvm::Hexagon::ArchV73, llvm::Hexagon::ExtensionHVXV73},
+    {llvm::Hexagon::ArchV75, llvm::Hexagon::ExtensionHVXV75},
+    {llvm::Hexagon::ArchV79, llvm::Hexagon::ExtensionHVXV79},
+
+};
+
+// An enum must be used as a command option type, therefore we need to convert
+// it. Note that no mapping exists for NoArch and Generic, the users must filter
+// these values.
+static const std::map<llvm::Hexagon::ArchEnum, unsigned>
+    HexagonArchEnumToNumber = {
+        {llvm::Hexagon::ArchEnum::V5, 5},   {llvm::Hexagon::ArchEnum::V55, 55},
+        {llvm::Hexagon::ArchEnum::V60, 60}, {llvm::Hexagon::ArchEnum::V62, 62},
+        {llvm::Hexagon::ArchEnum::V65, 65}, {llvm::Hexagon::ArchEnum::V66, 66},
+        {llvm::Hexagon::ArchEnum::V67, 67}, {llvm::Hexagon::ArchEnum::V68, 68},
+        {llvm::Hexagon::ArchEnum::V69, 69}, {llvm::Hexagon::ArchEnum::V71, 71},
+        {llvm::Hexagon::ArchEnum::V73, 73}, {llvm::Hexagon::ArchEnum::V75, 75},
+        {llvm::Hexagon::ArchEnum::V79, 79},
+};
+
 static StringRef HexagonGetArchVariant() {
   if (MV5)
     return "hexagonv5";
@@ -163,6 +216,37 @@ static StringRef HexagonGetArchVariant() {
   return "";
 }
 
+/// Return the set feature with a highest number from FS. Return {} if FS is
+/// empty.
+static std::optional<unsigned> top_feature(const FeatureBitset &FS) {
+  std::optional<unsigned> F;
+  for (unsigned I = 0; I != FS.size(); ++I)
+    if (FS.test(I))
+      F = I;
+  return F;
+}
+
+/// Convert feature to its name.
+static llvm::StringRef HexagonFeatureName(unsigned F) {
+  for (const auto &I : HexagonFeatureKV)
+    if (I.Value == F)
+      return I.Key;
+  return "";
+}
+
+/// Extract the trailing decimal number from the name of a feature F.
+static std::optional<unsigned>
+extractFeatureVersionSuffix(unsigned F, llvm::StringRef Prefix,
+                            unsigned Radix = 10) {
+  llvm::StringRef FeatureName = HexagonFeatureName(F);
+  if (FeatureName.consume_front(Prefix)) {
+    unsigned Number;
+    if (!FeatureName.getAsInteger(Radix, Number))
+      return Number;
+  }
+  return {};
+}
+
 StringRef Hexagon_MC::selectHexagonCPU(StringRef CPU) {
   StringRef ArchV = HexagonGetArchVariant();
   if (!ArchV.empty() && !CPU.empty()) {
@@ -420,68 +504,31 @@ static bool LLVM_ATTRIBUTE_UNUSED checkFeature(MCSubtargetInfo* STI, uint64_t F)
 
 namespace {
 std::string selectHexagonFS(StringRef CPU, StringRef FS) {
-  SmallVector<StringRef, 3> Result;
+  SmallVector<std::string> Result;
   if (!FS.empty())
-    Result.push_back(FS);
-
-  switch (EnableHVX) {
-  case Hexagon::ArchEnum::V5:
-  case Hexagon::ArchEnum::V55:
-    break;
-  case Hexagon::ArchEnum::V60:
-    Result.push_back("+hvxv60");
-    break;
-  case Hexagon::ArchEnum::V62:
-    Result.push_back("+hvxv62");
-    break;
-  case Hexagon::ArchEnum::V65:
-    Result.push_back("+hvxv65");
-    break;
-  case Hexagon::ArchEnum::V66:
-    Result.push_back("+hvxv66");
-    break;
-  case Hexagon::ArchEnum::V67:
-    Result.push_back("+hvxv67");
-    break;
-  case Hexagon::ArchEnum::V68:
-    Result.push_back("+hvxv68");
-    break;
-  case Hexagon::ArchEnum::V69:
-    Result.push_back("+hvxv69");
-    break;
-  case Hexagon::ArchEnum::V71:
-    Result.push_back("+hvxv71");
-    break;
-  case Hexagon::ArchEnum::V73:
-    Result.push_back("+hvxv73");
-    break;
-  case Hexagon::ArchEnum::V75:
-    Result.push_back("+hvxv75");
-    break;
-  case Hexagon::ArchEnum::V79:
-    Result.push_back("+hvxv79");
-    break;
-
-  case Hexagon::ArchEnum::Generic: {
-    Result.push_back(StringSwitch<StringRef>(CPU)
-                         .Case("hexagonv60", "+hvxv60")
-                         .Case("hexagonv62", "+hvxv62")
-                         .Case("hexagonv65", "+hvxv65")
-                         .Case("hexagonv66", "+hvxv66")
-                         .Case("hexagonv67", "+hvxv67")
-                         .Case("hexagonv67t", "+hvxv67")
-                         .Case("hexagonv68", "+hvxv68")
-                         .Case("hexagonv69", "+hvxv69")
-                         .Case("hexagonv71", "+hvxv71")
-                         .Case("hexagonv71t", "+hvxv71")
-                         .Case("hexagonv73", "+hvxv73")
-                         .Case("hexagonv75", "+hvxv75")
-                         .Case("hexagonv79", "+hvxv79"));
-    break;
-  }
-  case Hexagon::ArchEnum::NoArch:
-    // Sentinel if -mhvx isn't specified
-    break;
+    Result.push_back(FS.str());
+
+  if (EnableHVX != Hexagon::ArchEnum::NoArch) {
+    std::string HVXFeature;
+    if (EnableHVX == Hexagon::ArchEnum::Generic) {
+      // Set the default HVX version for a given processor if -mhvx option with
+      // no value is specified.
+      for (const auto &P : HexagonSubTypeKV)
+        if (CPU == P.Key) {
+          if (auto Arch = top_feature(P.Implies & HexagonArchFeatures)) {
+            auto It = HexagonDefaultHVXVersion.find(*Arch);
+            if (It != HexagonDefaultHVXVersion.end())
+              HVXFeature = HexagonFeatureName(It->second);
+          }
+          break;
+        }
+    } else {
+      auto It = HexagonArchEnumToNumber.find(EnableHVX);
+      if (It != HexagonArchEnumToNumber.end())
+        HVXFeature = "hvxv" + std::to_string(It->second);
+    }
+    if (!HVXFeature.empty())
+      Result.push_back("+" + HVXFeature);
   }
   if (EnableHvxIeeeFp)
     Result.push_back("+hvx-ieee-fp");
@@ -492,10 +539,6 @@ std::string selectHexagonFS(StringRef CPU, StringRef FS) {
 }
 }
 
-static bool isCPUValid(StringRef CPU) {
-  return Hexagon::getCpu(CPU).has_value();
-}
-
 namespace {
 std::pair<std::string, std::string> selectCPUAndFS(StringRef CPU,
                                                    StringRef FS) {
@@ -522,74 +565,13 @@ FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) {
   using namespace Hexagon;
   // Make sure that +hvx-length turns hvx on, and that "hvx" alone
   // turns on hvxvNN, corresponding to the existing ArchVNN.
-  FeatureBitset FB = S;
-  unsigned CpuArch = ArchV5;
-  for (unsigned F :
-       {ArchV79, ArchV75, ArchV73, ArchV71, ArchV69, ArchV68, ArchV67, ArchV66,
-        ArchV65, ArchV62, ArchV60, ArchV55, ArchV5}) {
-    if (!FB.test(F))
-      continue;
-    CpuArch = F;
-    break;
-  }
-  bool UseHvx = false;
-  for (unsigned F : {ExtensionHVX, ExtensionHVX64B, ExtensionHVX128B}) {
-    if (!FB.test(F))
-      continue;
-    UseHvx = true;
-    break;
-  }
-  bool HasHvxVer = false;
-  for (unsigned F :
-       {ExtensionHVXV60, ExtensionHVXV62, ExtensionHVXV65, ExtensionHVXV66,
-        ExtensionHVXV67, ExtensionHVXV68, ExtensionHVXV69, ExtensionHVXV71,
-        ExtensionHVXV73, ExtensionHVXV75, ExtensionHVXV79}) {
-    if (!FB.test(F))
-      continue;
-    HasHvxVer = true;
-    UseHvx = true;
-    break;
-  }
-
-  if (!UseHvx || HasHvxVer)
-    return FB;
-
-  // HasHvxVer is false, and UseHvx is true.
-  switch (CpuArch) {
-  case ArchV79:
-    FB.set(ExtensionHVXV79);
-    [[fallthrough]];
-  case ArchV75:
-    FB.set(ExtensionHVXV75);
-    [[fallthrough]];
-  case ArchV73:
-    FB.set(ExtensionHVXV73);
-    [[fallthrough]];
-  case ArchV71:
-    FB.set(ExtensionHVXV71);
-    [[fallthrough]];
-  case ArchV69:
-    FB.set(ExtensionHVXV69);
-    [[fallthrough]];
-  case ArchV68:
-    FB.set(ExtensionHVXV68);
-    [[fallthrough]];
-  case ArchV67:
-    FB.set(ExtensionHVXV67);
-    [[fallthrough]];
-  case ArchV66:
-    FB.set(ExtensionHVXV66);
-    [[fallthrough]];
-  case ArchV65:
-    FB.set(ExtensionHVXV65);
-    [[fallthrough]];
-  case ArchV62:
-    FB.set(ExtensionHVXV62);
-    [[fallthrough]];
-  case ArchV60:
-    FB.set(ExtensionHVXV60);
-    break;
-  }
+  FeatureBitset FB;
+  if ((S & HVXFeatures).any() && (S & HVXVersionFeatures).none())
+    if (auto Arch = top_feature(S & HexagonArchFeatures)) {
+      auto It = HexagonDefaultHVXVersion.find(*Arch);
+      if (It != HexagonDefaultHVXVersion.end())
+        FB.set(It->second);
+    }
   return FB;
 }
 
@@ -608,7 +590,7 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT,
   if (CPU == "help")
     exit(0);
 
-  if (!isCPUValid(CPUName.str())) {
+  if (!X->isCPUStringValid(CPUName)) {
     errs() << "error: invalid CPU \"" << CPUName.str().c_str()
            << "\" specified\n";
     return nullptr;
@@ -627,7 +609,7 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT,
     X->setFeatureBits(Features.reset(Hexagon::FeatureDuplex));
   }
 
-  X->setFeatureBits(completeHVXFeatures(X->getFeatureBits()));
+  X->SetFeatureBitsTransitively(completeHVXFeatures(X->getFeatureBits()));
 
   // The Z-buffer instructions are grandfathered in for current
   // architectures but omitted for new ones.  Future instruction
@@ -654,48 +636,32 @@ void Hexagon_MC::addArchSubtarget(MCSubtargetInfo const *STI, StringRef FS) {
 }
 
 std::optional<unsigned>
-Hexagon_MC::getHVXVersion(const FeatureBitset &Features) {
-  for (auto Arch : {Hexagon::ExtensionHVXV79, Hexagon::ExtensionHVXV75,
-                    Hexagon::ExtensionHVXV73, Hexagon::ExtensionHVXV71,
-                    Hexagon::ExtensionHVXV69, Hexagon::ExtensionHVXV68,
-                    Hexagon::ExtensionHVXV67, Hexagon::ExtensionHVXV66,
-                    Hexagon::ExtensionHVXV65, Hexagon::ExtensionHVXV62,
-                    Hexagon::ExtensionHVXV60})
-    if (Features.test(Arch))
-      return Arch;
+Hexagon_MC::getArchVersionAttribute(const FeatureBitset &FS) {
+  if (std::optional<unsigned> F = top_feature(FS & HexagonArchFeatures))
+    return extractFeatureVersionSuffix(*F, "v");
   return {};
 }
 
-unsigned Hexagon_MC::getArchVersion(const FeatureBitset &Features) {
-  for (auto Arch :
-       {Hexagon::ArchV79, Hexagon::ArchV75, Hexagon::ArchV73, Hexagon::ArchV71,
-        Hexagon::ArchV69, Hexagon::ArchV68, Hexagon::ArchV67, Hexagon::ArchV66,
-        Hexagon::ArchV65, Hexagon::ArchV62, Hexagon::ArchV60, Hexagon::ArchV55,
-        Hexagon::ArchV5})
-    if (Features.test(Arch))
-      return Arch;
-  llvm_unreachable("Expected arch v5-v79");
-  return 0;
+std::optional<unsigned>
+Hexagon_MC::getHVXVersionAttribute(const FeatureBitset &FS) {
+  if (std::optional<unsigned> F = top_feature(FS & HVXVersionFeatures))
+    return extractFeatureVersionSuffix(*F, "hvxv");
+  return {};
 }
 
 unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) {
-  return StringSwitch<unsigned>(STI.getCPU())
-      .Case("generic", llvm::ELF::EF_HEXAGON_MACH_V5)
-      .Case("hexagonv5", llvm::ELF::EF_HEXAGON_MACH_V5)
-      .Case("hexagonv55", llvm::ELF::EF_HEXAGON_MACH_V55)
-      .Case("hexagonv60", llvm::ELF::EF_HEXAGON_MACH_V60)
-      .Case("hexagonv62", llvm::ELF::EF_HEXAGON_MACH_V62)
-      .Case("hexagonv65", llvm::ELF::EF_HEXAGON_MACH_V65)
-      .Case("hexagonv66", llvm::ELF::EF_HEXAGON_MACH_V66)
-      .Case("hexagonv67", llvm::ELF::EF_HEXAGON_MACH_V67)
-      .Case("hexagonv67t", llvm::ELF::EF_HEXAGON_MACH_V67T)
-      .Case("hexagonv68", llvm::ELF::EF_HEXAGON_MACH_V68)
-      .Case("hexagonv69", llvm::ELF::EF_HEXAGON_MACH_V69)
-      .Case("hexagonv71", llvm::ELF::EF_HEXAGON_MACH_V71)
-      .Case("hexagonv71t", llvm::ELF::EF_HEXAGON_MACH_V71T)
-      .C...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jun 25, 2025

@llvm/pr-subscribers-clang

Author: Alexey Karyakin (quic-akaryaki)

Changes

There is a lot of redundant code that needs to be modified when new Hexagon versions are added. Reduce the amount of this redundancy.

  • compute ELF flags and attributes based on version feature names;
  • simplify EnableHVX option handling by using arch features instead of arch version enums;
  • simplify completeHVXFeatures() by using features;
  • delete several unused or redundant functions and constants: isCPUValid, getCpu, getHexagonCPUSuffix;
  • do not set HexagonArchVersion in initializeSubtargetDependencies, it is set in ParseSubtargetFeatures;

Patch is 21.77 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/145812.diff

7 Files Affected:

  • (modified) clang/lib/Basic/Targets/Hexagon.cpp (+15-26)
  • (modified) clang/lib/Basic/Targets/Hexagon.h (+5-2)
  • (modified) llvm/lib/Target/Hexagon/HexagonDepArch.h (-20)
  • (modified) llvm/lib/Target/Hexagon/HexagonSubtarget.cpp (+1-7)
  • (modified) llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp (+4-3)
  • (modified) llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp (+137-171)
  • (modified) llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.h (+5-2)
diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp
index 06dcac03baa5b..9fff20bf0f417 100644
--- a/clang/lib/Basic/Targets/Hexagon.cpp
+++ b/clang/lib/Basic/Targets/Hexagon.cpp
@@ -18,6 +18,19 @@
 using namespace clang;
 using namespace clang::targets;
 
+namespace {
+
+constexpr llvm::StringLiteral CpuValsTextArray[] = {
+    "hexagonv5",  "hexagonv55",  "hexagonv60",  "hexagonv62", "hexagonv65",
+    "hexagonv66", "hexagonv67",  "hexagonv67t", "hexagonv68", "hexagonv69",
+    "hexagonv71", "hexagonv71t", "hexagonv73",  "hexagonv75", "hexagonv79",
+};
+
+} // namespace
+
+const llvm::ArrayRef<llvm::StringLiteral>
+    HexagonTargetInfo::CpuValsText(CpuValsTextArray);
+
 void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   Builder.defineMacro("__qdsp6__", "1");
@@ -239,22 +252,6 @@ bool HexagonTargetInfo::hasFeature(StringRef Feature) const {
       .Default(false);
 }
 
-struct CPUSuffix {
-  llvm::StringLiteral Name;
-  llvm::StringLiteral Suffix;
-};
-
-static constexpr CPUSuffix Suffixes[] = {
-    {{"hexagonv5"}, {"5"}},   {{"hexagonv55"}, {"55"}},
-    {{"hexagonv60"}, {"60"}}, {{"hexagonv62"}, {"62"}},
-    {{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}},
-    {{"hexagonv67"}, {"67"}}, {{"hexagonv67t"}, {"67t"}},
-    {{"hexagonv68"}, {"68"}}, {{"hexagonv69"}, {"69"}},
-    {{"hexagonv71"}, {"71"}}, {{"hexagonv71t"}, {"71t"}},
-    {{"hexagonv73"}, {"73"}}, {{"hexagonv75"}, {"75"}},
-    {{"hexagonv79"}, {"79"}},
-};
-
 std::optional<unsigned> HexagonTargetInfo::getHexagonCPURev(StringRef Name) {
   StringRef Arch = Name;
   Arch.consume_front("hexagonv");
@@ -267,18 +264,10 @@ std::optional<unsigned> HexagonTargetInfo::getHexagonCPURev(StringRef Name) {
   return std::nullopt;
 }
 
-const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) {
-  const CPUSuffix *Item = llvm::find_if(
-      Suffixes, [Name](const CPUSuffix &S) { return S.Name == Name; });
-  if (Item == std::end(Suffixes))
-    return nullptr;
-  return Item->Suffix.data();
-}
-
 void HexagonTargetInfo::fillValidCPUList(
     SmallVectorImpl<StringRef> &Values) const {
-  for (const CPUSuffix &Suffix : Suffixes)
-    Values.push_back(Suffix.Name);
+  for (const llvm::StringLiteral &I : CpuValsText)
+    Values.push_back(I);
 }
 
 llvm::SmallVector<Builtin::InfosShard>
diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h
index a65663ca09eee..f9a6de39d022b 100644
--- a/clang/lib/Basic/Targets/Hexagon.h
+++ b/clang/lib/Basic/Targets/Hexagon.h
@@ -25,6 +25,7 @@ namespace targets {
 // Hexagon abstract base class
 class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo {
 
+  static const llvm::ArrayRef<llvm::StringLiteral> CpuValsText;
   static const char *const GCCRegNames[];
   static const TargetInfo::GCCRegAlias GCCRegAliases[];
   std::string CPU;
@@ -115,11 +116,13 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo {
 
   std::string_view getClobbers() const override { return ""; }
 
-  static const char *getHexagonCPUSuffix(StringRef Name);
   static std::optional<unsigned> getHexagonCPURev(StringRef Name);
 
   bool isValidCPUName(StringRef Name) const override {
-    return getHexagonCPUSuffix(Name);
+    // All the valid CPU architectures and micro-architectures must
+    // return true.
+    return std::any_of(std::begin(CpuValsText), std::end(CpuValsText),
+                       [Name](StringRef V) { return V == Name; });
   }
 
   void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
diff --git a/llvm/lib/Target/Hexagon/HexagonDepArch.h b/llvm/lib/Target/Hexagon/HexagonDepArch.h
index 89845348a9e31..6f851a042ca20 100644
--- a/llvm/lib/Target/Hexagon/HexagonDepArch.h
+++ b/llvm/lib/Target/Hexagon/HexagonDepArch.h
@@ -32,26 +32,6 @@ enum class ArchEnum {
   V79
 };
 
-inline std::optional<Hexagon::ArchEnum> getCpu(StringRef CPU) {
-  return StringSwitch<std::optional<Hexagon::ArchEnum>>(CPU)
-      .Case("generic", Hexagon::ArchEnum::V5)
-      .Case("hexagonv5", Hexagon::ArchEnum::V5)
-      .Case("hexagonv55", Hexagon::ArchEnum::V55)
-      .Case("hexagonv60", Hexagon::ArchEnum::V60)
-      .Case("hexagonv62", Hexagon::ArchEnum::V62)
-      .Case("hexagonv65", Hexagon::ArchEnum::V65)
-      .Case("hexagonv66", Hexagon::ArchEnum::V66)
-      .Case("hexagonv67", Hexagon::ArchEnum::V67)
-      .Case("hexagonv67t", Hexagon::ArchEnum::V67)
-      .Case("hexagonv68", Hexagon::ArchEnum::V68)
-      .Case("hexagonv69", Hexagon::ArchEnum::V69)
-      .Case("hexagonv71", Hexagon::ArchEnum::V71)
-      .Case("hexagonv71t", Hexagon::ArchEnum::V71)
-      .Case("hexagonv73", Hexagon::ArchEnum::V73)
-      .Case("hexagonv75", Hexagon::ArchEnum::V75)
-      .Case("hexagonv79", Hexagon::ArchEnum::V79)
-      .Default(std::nullopt);
-}
 } // namespace Hexagon
 } // namespace llvm
 
diff --git a/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp b/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
index ecc1b5d2ebe35..ebaee73c51ec6 100644
--- a/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp
@@ -88,12 +88,6 @@ HexagonSubtarget::HexagonSubtarget(const Triple &TT, StringRef CPU,
 
 HexagonSubtarget &
 HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
-  std::optional<Hexagon::ArchEnum> ArchVer = Hexagon::getCpu(CPUString);
-  if (ArchVer)
-    HexagonArchVersion = *ArchVer;
-  else
-    llvm_unreachable("Unrecognized Hexagon processor version");
-
   UseHVX128BOps = false;
   UseHVX64BOps = false;
   UseAudioOps = false;
@@ -163,7 +157,7 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) {
   FeatureBitset FeatureBits = getFeatureBits();
   if (HexagonDisableDuplex)
     setFeatureBits(FeatureBits.reset(Hexagon::FeatureDuplex));
-  setFeatureBits(Hexagon_MC::completeHVXFeatures(FeatureBits));
+  SetFeatureBitsTransitively(Hexagon_MC::completeHVXFeatures(FeatureBits));
 
   return *this;
 }
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
index 13ecc231a70b2..df86d2a3a54c0 100644
--- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCELFStreamer.cpp
@@ -195,11 +195,12 @@ static unsigned featureToArchVersion(unsigned Feature) {
 
 void HexagonTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
   auto Features = STI.getFeatureBits();
-  unsigned Arch = featureToArchVersion(Hexagon_MC::getArchVersion(Features));
-  std::optional<unsigned> HVXArch = Hexagon_MC::getHVXVersion(Features);
+  unsigned Arch = Hexagon_MC::getArchVersionAttribute(Features).value_or(0);
+  std::optional<unsigned> HVXArch =
+      Hexagon_MC::getHVXVersionAttribute(Features);
   emitAttribute(HexagonAttrs::ARCH, Arch);
   if (HVXArch)
-    emitAttribute(HexagonAttrs::HVXARCH, featureToArchVersion(*HVXArch));
+    emitAttribute(HexagonAttrs::HVXARCH, *HVXArch);
   if (Features.test(Hexagon::ExtensionHVXIEEEFP))
     emitAttribute(HexagonAttrs::HVXIEEEFP, 1);
   if (Features.test(Hexagon::ExtensionHVXQFloat))
diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
index 980df819b2c26..01ef334bed01b 100644
--- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
+++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCTargetDesc.cpp
@@ -128,6 +128,59 @@ static cl::opt<bool> EnableHexagonCabac
 
 static constexpr StringRef DefaultArch = "hexagonv68";
 
+static const FeatureBitset HexagonArchFeatures = {
+    llvm::Hexagon::ArchV5,  llvm::Hexagon::ArchV55, llvm::Hexagon::ArchV60,
+    llvm::Hexagon::ArchV62, llvm::Hexagon::ArchV65, llvm::Hexagon::ArchV66,
+    llvm::Hexagon::ArchV67, llvm::Hexagon::ArchV68, llvm::Hexagon::ArchV69,
+    llvm::Hexagon::ArchV71, llvm::Hexagon::ArchV73, llvm::Hexagon::ArchV75,
+    llvm::Hexagon::ArchV79,
+};
+
+static const FeatureBitset HVXFeatures = {
+    llvm::Hexagon::ExtensionHVX,
+    llvm::Hexagon::ExtensionHVX64B,
+    llvm::Hexagon::ExtensionHVX128B,
+};
+
+static const FeatureBitset HVXVersionFeatures = {
+    llvm::Hexagon::ExtensionHVXV60, llvm::Hexagon::ExtensionHVXV62,
+    llvm::Hexagon::ExtensionHVXV65, llvm::Hexagon::ExtensionHVXV66,
+    llvm::Hexagon::ExtensionHVXV67, llvm::Hexagon::ExtensionHVXV68,
+    llvm::Hexagon::ExtensionHVXV69, llvm::Hexagon::ExtensionHVXV71,
+    llvm::Hexagon::ExtensionHVXV73, llvm::Hexagon::ExtensionHVXV75,
+    llvm::Hexagon::ExtensionHVXV79,
+
+};
+
+static const std::unordered_map<unsigned, unsigned> HexagonDefaultHVXVersion = {
+    {llvm::Hexagon::ArchV60, llvm::Hexagon::ExtensionHVXV60},
+    {llvm::Hexagon::ArchV62, llvm::Hexagon::ExtensionHVXV62},
+    {llvm::Hexagon::ArchV65, llvm::Hexagon::ExtensionHVXV65},
+    {llvm::Hexagon::ArchV66, llvm::Hexagon::ExtensionHVXV66},
+    {llvm::Hexagon::ArchV67, llvm::Hexagon::ExtensionHVXV67},
+    {llvm::Hexagon::ArchV68, llvm::Hexagon::ExtensionHVXV68},
+    {llvm::Hexagon::ArchV69, llvm::Hexagon::ExtensionHVXV69},
+    {llvm::Hexagon::ArchV71, llvm::Hexagon::ExtensionHVXV71},
+    {llvm::Hexagon::ArchV73, llvm::Hexagon::ExtensionHVXV73},
+    {llvm::Hexagon::ArchV75, llvm::Hexagon::ExtensionHVXV75},
+    {llvm::Hexagon::ArchV79, llvm::Hexagon::ExtensionHVXV79},
+
+};
+
+// An enum must be used as a command option type, therefore we need to convert
+// it. Note that no mapping exists for NoArch and Generic, the users must filter
+// these values.
+static const std::map<llvm::Hexagon::ArchEnum, unsigned>
+    HexagonArchEnumToNumber = {
+        {llvm::Hexagon::ArchEnum::V5, 5},   {llvm::Hexagon::ArchEnum::V55, 55},
+        {llvm::Hexagon::ArchEnum::V60, 60}, {llvm::Hexagon::ArchEnum::V62, 62},
+        {llvm::Hexagon::ArchEnum::V65, 65}, {llvm::Hexagon::ArchEnum::V66, 66},
+        {llvm::Hexagon::ArchEnum::V67, 67}, {llvm::Hexagon::ArchEnum::V68, 68},
+        {llvm::Hexagon::ArchEnum::V69, 69}, {llvm::Hexagon::ArchEnum::V71, 71},
+        {llvm::Hexagon::ArchEnum::V73, 73}, {llvm::Hexagon::ArchEnum::V75, 75},
+        {llvm::Hexagon::ArchEnum::V79, 79},
+};
+
 static StringRef HexagonGetArchVariant() {
   if (MV5)
     return "hexagonv5";
@@ -163,6 +216,37 @@ static StringRef HexagonGetArchVariant() {
   return "";
 }
 
+/// Return the set feature with a highest number from FS. Return {} if FS is
+/// empty.
+static std::optional<unsigned> top_feature(const FeatureBitset &FS) {
+  std::optional<unsigned> F;
+  for (unsigned I = 0; I != FS.size(); ++I)
+    if (FS.test(I))
+      F = I;
+  return F;
+}
+
+/// Convert feature to its name.
+static llvm::StringRef HexagonFeatureName(unsigned F) {
+  for (const auto &I : HexagonFeatureKV)
+    if (I.Value == F)
+      return I.Key;
+  return "";
+}
+
+/// Extract the trailing decimal number from the name of a feature F.
+static std::optional<unsigned>
+extractFeatureVersionSuffix(unsigned F, llvm::StringRef Prefix,
+                            unsigned Radix = 10) {
+  llvm::StringRef FeatureName = HexagonFeatureName(F);
+  if (FeatureName.consume_front(Prefix)) {
+    unsigned Number;
+    if (!FeatureName.getAsInteger(Radix, Number))
+      return Number;
+  }
+  return {};
+}
+
 StringRef Hexagon_MC::selectHexagonCPU(StringRef CPU) {
   StringRef ArchV = HexagonGetArchVariant();
   if (!ArchV.empty() && !CPU.empty()) {
@@ -420,68 +504,31 @@ static bool LLVM_ATTRIBUTE_UNUSED checkFeature(MCSubtargetInfo* STI, uint64_t F)
 
 namespace {
 std::string selectHexagonFS(StringRef CPU, StringRef FS) {
-  SmallVector<StringRef, 3> Result;
+  SmallVector<std::string> Result;
   if (!FS.empty())
-    Result.push_back(FS);
-
-  switch (EnableHVX) {
-  case Hexagon::ArchEnum::V5:
-  case Hexagon::ArchEnum::V55:
-    break;
-  case Hexagon::ArchEnum::V60:
-    Result.push_back("+hvxv60");
-    break;
-  case Hexagon::ArchEnum::V62:
-    Result.push_back("+hvxv62");
-    break;
-  case Hexagon::ArchEnum::V65:
-    Result.push_back("+hvxv65");
-    break;
-  case Hexagon::ArchEnum::V66:
-    Result.push_back("+hvxv66");
-    break;
-  case Hexagon::ArchEnum::V67:
-    Result.push_back("+hvxv67");
-    break;
-  case Hexagon::ArchEnum::V68:
-    Result.push_back("+hvxv68");
-    break;
-  case Hexagon::ArchEnum::V69:
-    Result.push_back("+hvxv69");
-    break;
-  case Hexagon::ArchEnum::V71:
-    Result.push_back("+hvxv71");
-    break;
-  case Hexagon::ArchEnum::V73:
-    Result.push_back("+hvxv73");
-    break;
-  case Hexagon::ArchEnum::V75:
-    Result.push_back("+hvxv75");
-    break;
-  case Hexagon::ArchEnum::V79:
-    Result.push_back("+hvxv79");
-    break;
-
-  case Hexagon::ArchEnum::Generic: {
-    Result.push_back(StringSwitch<StringRef>(CPU)
-                         .Case("hexagonv60", "+hvxv60")
-                         .Case("hexagonv62", "+hvxv62")
-                         .Case("hexagonv65", "+hvxv65")
-                         .Case("hexagonv66", "+hvxv66")
-                         .Case("hexagonv67", "+hvxv67")
-                         .Case("hexagonv67t", "+hvxv67")
-                         .Case("hexagonv68", "+hvxv68")
-                         .Case("hexagonv69", "+hvxv69")
-                         .Case("hexagonv71", "+hvxv71")
-                         .Case("hexagonv71t", "+hvxv71")
-                         .Case("hexagonv73", "+hvxv73")
-                         .Case("hexagonv75", "+hvxv75")
-                         .Case("hexagonv79", "+hvxv79"));
-    break;
-  }
-  case Hexagon::ArchEnum::NoArch:
-    // Sentinel if -mhvx isn't specified
-    break;
+    Result.push_back(FS.str());
+
+  if (EnableHVX != Hexagon::ArchEnum::NoArch) {
+    std::string HVXFeature;
+    if (EnableHVX == Hexagon::ArchEnum::Generic) {
+      // Set the default HVX version for a given processor if -mhvx option with
+      // no value is specified.
+      for (const auto &P : HexagonSubTypeKV)
+        if (CPU == P.Key) {
+          if (auto Arch = top_feature(P.Implies & HexagonArchFeatures)) {
+            auto It = HexagonDefaultHVXVersion.find(*Arch);
+            if (It != HexagonDefaultHVXVersion.end())
+              HVXFeature = HexagonFeatureName(It->second);
+          }
+          break;
+        }
+    } else {
+      auto It = HexagonArchEnumToNumber.find(EnableHVX);
+      if (It != HexagonArchEnumToNumber.end())
+        HVXFeature = "hvxv" + std::to_string(It->second);
+    }
+    if (!HVXFeature.empty())
+      Result.push_back("+" + HVXFeature);
   }
   if (EnableHvxIeeeFp)
     Result.push_back("+hvx-ieee-fp");
@@ -492,10 +539,6 @@ std::string selectHexagonFS(StringRef CPU, StringRef FS) {
 }
 }
 
-static bool isCPUValid(StringRef CPU) {
-  return Hexagon::getCpu(CPU).has_value();
-}
-
 namespace {
 std::pair<std::string, std::string> selectCPUAndFS(StringRef CPU,
                                                    StringRef FS) {
@@ -522,74 +565,13 @@ FeatureBitset Hexagon_MC::completeHVXFeatures(const FeatureBitset &S) {
   using namespace Hexagon;
   // Make sure that +hvx-length turns hvx on, and that "hvx" alone
   // turns on hvxvNN, corresponding to the existing ArchVNN.
-  FeatureBitset FB = S;
-  unsigned CpuArch = ArchV5;
-  for (unsigned F :
-       {ArchV79, ArchV75, ArchV73, ArchV71, ArchV69, ArchV68, ArchV67, ArchV66,
-        ArchV65, ArchV62, ArchV60, ArchV55, ArchV5}) {
-    if (!FB.test(F))
-      continue;
-    CpuArch = F;
-    break;
-  }
-  bool UseHvx = false;
-  for (unsigned F : {ExtensionHVX, ExtensionHVX64B, ExtensionHVX128B}) {
-    if (!FB.test(F))
-      continue;
-    UseHvx = true;
-    break;
-  }
-  bool HasHvxVer = false;
-  for (unsigned F :
-       {ExtensionHVXV60, ExtensionHVXV62, ExtensionHVXV65, ExtensionHVXV66,
-        ExtensionHVXV67, ExtensionHVXV68, ExtensionHVXV69, ExtensionHVXV71,
-        ExtensionHVXV73, ExtensionHVXV75, ExtensionHVXV79}) {
-    if (!FB.test(F))
-      continue;
-    HasHvxVer = true;
-    UseHvx = true;
-    break;
-  }
-
-  if (!UseHvx || HasHvxVer)
-    return FB;
-
-  // HasHvxVer is false, and UseHvx is true.
-  switch (CpuArch) {
-  case ArchV79:
-    FB.set(ExtensionHVXV79);
-    [[fallthrough]];
-  case ArchV75:
-    FB.set(ExtensionHVXV75);
-    [[fallthrough]];
-  case ArchV73:
-    FB.set(ExtensionHVXV73);
-    [[fallthrough]];
-  case ArchV71:
-    FB.set(ExtensionHVXV71);
-    [[fallthrough]];
-  case ArchV69:
-    FB.set(ExtensionHVXV69);
-    [[fallthrough]];
-  case ArchV68:
-    FB.set(ExtensionHVXV68);
-    [[fallthrough]];
-  case ArchV67:
-    FB.set(ExtensionHVXV67);
-    [[fallthrough]];
-  case ArchV66:
-    FB.set(ExtensionHVXV66);
-    [[fallthrough]];
-  case ArchV65:
-    FB.set(ExtensionHVXV65);
-    [[fallthrough]];
-  case ArchV62:
-    FB.set(ExtensionHVXV62);
-    [[fallthrough]];
-  case ArchV60:
-    FB.set(ExtensionHVXV60);
-    break;
-  }
+  FeatureBitset FB;
+  if ((S & HVXFeatures).any() && (S & HVXVersionFeatures).none())
+    if (auto Arch = top_feature(S & HexagonArchFeatures)) {
+      auto It = HexagonDefaultHVXVersion.find(*Arch);
+      if (It != HexagonDefaultHVXVersion.end())
+        FB.set(It->second);
+    }
   return FB;
 }
 
@@ -608,7 +590,7 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT,
   if (CPU == "help")
     exit(0);
 
-  if (!isCPUValid(CPUName.str())) {
+  if (!X->isCPUStringValid(CPUName)) {
     errs() << "error: invalid CPU \"" << CPUName.str().c_str()
            << "\" specified\n";
     return nullptr;
@@ -627,7 +609,7 @@ MCSubtargetInfo *Hexagon_MC::createHexagonMCSubtargetInfo(const Triple &TT,
     X->setFeatureBits(Features.reset(Hexagon::FeatureDuplex));
   }
 
-  X->setFeatureBits(completeHVXFeatures(X->getFeatureBits()));
+  X->SetFeatureBitsTransitively(completeHVXFeatures(X->getFeatureBits()));
 
   // The Z-buffer instructions are grandfathered in for current
   // architectures but omitted for new ones.  Future instruction
@@ -654,48 +636,32 @@ void Hexagon_MC::addArchSubtarget(MCSubtargetInfo const *STI, StringRef FS) {
 }
 
 std::optional<unsigned>
-Hexagon_MC::getHVXVersion(const FeatureBitset &Features) {
-  for (auto Arch : {Hexagon::ExtensionHVXV79, Hexagon::ExtensionHVXV75,
-                    Hexagon::ExtensionHVXV73, Hexagon::ExtensionHVXV71,
-                    Hexagon::ExtensionHVXV69, Hexagon::ExtensionHVXV68,
-                    Hexagon::ExtensionHVXV67, Hexagon::ExtensionHVXV66,
-                    Hexagon::ExtensionHVXV65, Hexagon::ExtensionHVXV62,
-                    Hexagon::ExtensionHVXV60})
-    if (Features.test(Arch))
-      return Arch;
+Hexagon_MC::getArchVersionAttribute(const FeatureBitset &FS) {
+  if (std::optional<unsigned> F = top_feature(FS & HexagonArchFeatures))
+    return extractFeatureVersionSuffix(*F, "v");
   return {};
 }
 
-unsigned Hexagon_MC::getArchVersion(const FeatureBitset &Features) {
-  for (auto Arch :
-       {Hexagon::ArchV79, Hexagon::ArchV75, Hexagon::ArchV73, Hexagon::ArchV71,
-        Hexagon::ArchV69, Hexagon::ArchV68, Hexagon::ArchV67, Hexagon::ArchV66,
-        Hexagon::ArchV65, Hexagon::ArchV62, Hexagon::ArchV60, Hexagon::ArchV55,
-        Hexagon::ArchV5})
-    if (Features.test(Arch))
-      return Arch;
-  llvm_unreachable("Expected arch v5-v79");
-  return 0;
+std::optional<unsigned>
+Hexagon_MC::getHVXVersionAttribute(const FeatureBitset &FS) {
+  if (std::optional<unsigned> F = top_feature(FS & HVXVersionFeatures))
+    return extractFeatureVersionSuffix(*F, "hvxv");
+  return {};
 }
 
 unsigned Hexagon_MC::GetELFFlags(const MCSubtargetInfo &STI) {
-  return StringSwitch<unsigned>(STI.getCPU())
-      .Case("generic", llvm::ELF::EF_HEXAGON_MACH_V5)
-      .Case("hexagonv5", llvm::ELF::EF_HEXAGON_MACH_V5)
-      .Case("hexagonv55", llvm::ELF::EF_HEXAGON_MACH_V55)
-      .Case("hexagonv60", llvm::ELF::EF_HEXAGON_MACH_V60)
-      .Case("hexagonv62", llvm::ELF::EF_HEXAGON_MACH_V62)
-      .Case("hexagonv65", llvm::ELF::EF_HEXAGON_MACH_V65)
-      .Case("hexagonv66", llvm::ELF::EF_HEXAGON_MACH_V66)
-      .Case("hexagonv67", llvm::ELF::EF_HEXAGON_MACH_V67)
-      .Case("hexagonv67t", llvm::ELF::EF_HEXAGON_MACH_V67T)
-      .Case("hexagonv68", llvm::ELF::EF_HEXAGON_MACH_V68)
-      .Case("hexagonv69", llvm::ELF::EF_HEXAGON_MACH_V69)
-      .Case("hexagonv71", llvm::ELF::EF_HEXAGON_MACH_V71)
-      .Case("hexagonv71t", llvm::ELF::EF_HEXAGON_MACH_V71T)
-      .C...
[truncated]

There is a lot of redundant code that needs to be modified when new
Hexagon versions are added. Reduce the amount of this redundancy.

- compute ELF flags and attributes based on version feature names;
- simplify EnableHVX option handling by using arch features instead of
  arch version enums;
- simplify completeHVXFeatures() by using features;
- delete several unused or redundant functions and constants:
  isCPUValid, getCpu, getHexagonCPUSuffix;
- do not set HexagonArchVersion in initializeSubtargetDependencies,
  it is set in ParseSubtargetFeatures;

Signed-off-by: Alexey Karyakin <[email protected]>
@quic-akaryaki quic-akaryaki force-pushed the hexagon-versioning-cleanup branch from f43559d to a84ed78 Compare June 26, 2025 01:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:Hexagon clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants