[llvm] 2567d25 - [llvm-readobj][NFC] Use compact enums (except for ELF) (#206075)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 27 22:15:15 PDT 2026


Author: Alexis Engelke
Date: 2026-06-28T07:15:11+02:00
New Revision: 2567d2518dd2c55fd27b1618c65875e530842486

URL: https://github.com/llvm/llvm-project/commit/2567d2518dd2c55fd27b1618c65875e530842486
DIFF: https://github.com/llvm/llvm-project/commit/2567d2518dd2c55fd27b1618c65875e530842486.diff

LOG: [llvm-readobj][NFC] Use compact enums (except for ELF) (#206075)

In principle straight-forward replacement, but clang-format is
deliberately non-helpful here..

ELFDumper is a separate patch due to the size of the changes.

Added: 
    

Modified: 
    llvm/tools/llvm-objdump/COFFDump.cpp
    llvm/tools/llvm-readobj/COFFDumper.cpp
    llvm/tools/llvm-readobj/MachODumper.cpp
    llvm/tools/llvm-readobj/WasmDumper.cpp
    llvm/tools/llvm-readobj/Win64EHDumper.cpp
    llvm/tools/llvm-readobj/XCOFFDumper.cpp
    llvm/tools/llvm-readobj/llvm-readobj.h

Removed: 
    


################################################################################
diff  --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp
index a93a5bebf45a8..581943390a0a3 100644
--- a/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -62,33 +62,32 @@ objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {
   return std::make_unique<COFFDumper>(Obj);
 }
 
-constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
-    {"PE32", uint16_t(COFF::PE32Header::PE32)},
-    {"PE32+", uint16_t(COFF::PE32Header::PE32_PLUS)},
+constexpr EnumStringDef<uint16_t> PEHeaderMagicDefs[] = {
+    {{"PE32"}, uint16_t(COFF::PE32Header::PE32)},
+    {{"PE32+"}, uint16_t(COFF::PE32Header::PE32_PLUS)},
 };
-
-constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
-    {"unspecified", COFF::IMAGE_SUBSYSTEM_UNKNOWN},
-    {"NT native", COFF::IMAGE_SUBSYSTEM_NATIVE},
-    {"Windows GUI", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI},
-    {"Windows CUI", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI},
-    {"POSIX CUI", COFF::IMAGE_SUBSYSTEM_POSIX_CUI},
-    {"Wince CUI", COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI},
-    {"EFI application", COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION},
-    {"EFI boot service driver", COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER},
-    {"EFI runtime driver", COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER},
-    {"SAL runtime driver", COFF::IMAGE_SUBSYSTEM_EFI_ROM},
-    {"XBOX", COFF::IMAGE_SUBSYSTEM_XBOX},
+constexpr auto PEHeaderMagic = BUILD_ENUM_STRINGS(PEHeaderMagicDefs);
+
+constexpr EnumStringDef<COFF::WindowsSubsystem> PEWindowsSubsystemDefs[] = {
+    {{"unspecified"}, COFF::IMAGE_SUBSYSTEM_UNKNOWN},
+    {{"NT native"}, COFF::IMAGE_SUBSYSTEM_NATIVE},
+    {{"Windows GUI"}, COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI},
+    {{"Windows CUI"}, COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI},
+    {{"POSIX CUI"}, COFF::IMAGE_SUBSYSTEM_POSIX_CUI},
+    {{"Wince CUI"}, COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI},
+    {{"EFI application"}, COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION},
+    {{"EFI boot service driver"},
+     COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER},
+    {{"EFI runtime driver"}, COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER},
+    {{"SAL runtime driver"}, COFF::IMAGE_SUBSYSTEM_EFI_ROM},
+    {{"XBOX"}, COFF::IMAGE_SUBSYSTEM_XBOX},
 };
+constexpr auto PEWindowsSubsystem = BUILD_ENUM_STRINGS(PEWindowsSubsystemDefs);
 
 template <typename T, typename TEnum>
-static void printOptionalEnumName(T Value,
-                                  ArrayRef<EnumEntry<TEnum>> EnumValues) {
-  for (const EnumEntry<TEnum> &I : EnumValues)
-    if (I.Value == Value) {
-      outs() << "\t(" << I.Name << ')';
-      return;
-    }
+static void printOptionalEnumName(T Value, EnumStrings<TEnum> EnumValues) {
+  if (StringRef Name = EnumValues.toString(Value); !Name.empty())
+    outs() << "\t(" << Name << ')';
 }
 
 template <class PEHeader>
@@ -105,7 +104,7 @@ void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
   };
 
   printU16("Magic", Hdr.Magic, "%04x");
-  printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
+  printOptionalEnumName(Hdr.Magic, EnumStrings(PEHeaderMagic));
   outs() << '\n';
   print("MajorLinkerVersion", Hdr.MajorLinkerVersion);
   print("MinorLinkerVersion", Hdr.MinorLinkerVersion);
@@ -130,7 +129,7 @@ void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
   printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");
   printU32("CheckSum", Hdr.CheckSum, "%08x\n");
   printU16("Subsystem", Hdr.Subsystem, "%08x");
-  printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));
+  printOptionalEnumName(Hdr.Subsystem, EnumStrings(PEWindowsSubsystem));
   outs() << '\n';
 
   printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");

diff  --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 55e106d8ea6ac..6ac6837bf37ff 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -17,6 +17,7 @@
 #include "Win64EHDumper.h"
 #include "llvm-readobj.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Enum.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/COFF.h"
@@ -340,82 +341,87 @@ void COFFDumper::printBinaryBlockWithRelocs(StringRef Label,
   }
 }
 
-const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = {
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN  ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64EC  ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64X   ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16   ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU  ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC  ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP   ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)
+constexpr EnumStringDef<COFF::MachineTypes> ImageFileMachineTypeDefs[] = {
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64EC),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64X),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2)};
+constexpr auto ImageFileMachineType =
+    BUILD_ENUM_STRINGS(ImageFileMachineTypeDefs);
+
+constexpr EnumStringDef<COFF::Characteristics> ImageFileCharacteristicsDefs[] =
+    {LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY),
+     LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI)};
+constexpr auto ImageFileCharacteristics =
+    BUILD_ENUM_STRINGS(ImageFileCharacteristicsDefs);
+
+constexpr EnumStringDef<COFF::WindowsSubsystem> PEWindowsSubsystemDefs[] = {
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX),
 };
-
-const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = {
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED        ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE          ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM                 ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL                    ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI      )
-};
-
-const EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_UNKNOWN                ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_NATIVE                 ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_GUI            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CUI            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_POSIX_CUI              ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_WINDOWS_CE_GUI         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_APPLICATION        ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER     ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_EFI_ROM                ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SUBSYSTEM_XBOX                   ),
-};
-
-const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY      ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH               ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND              ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER           ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF             ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
+constexpr auto PEWindowsSubsystem = BUILD_ENUM_STRINGS(PEWindowsSubsystemDefs);
+
+constexpr EnumStringDef<COFF::DLLCharacteristics> PEDLLCharacteristicsDefs[] = {
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER),
+    LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF),
+    LLVM_READOBJ_ENUM_ENT(COFF,
+                          IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
 };
+constexpr auto PEDLLCharacteristics =
+    BUILD_ENUM_STRINGS(PEDLLCharacteristicsDefs);
 
 // clang-format off
-static const EnumEntry<COFF::ExtendedDLLCharacteristics>
-    PEExtendedDLLCharacteristics[] = {
+constexpr EnumStringDef<COFF::ExtendedDLLCharacteristics> PEExtendedDLLCharacteristicsDefs[] = {
         LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT                                ),
         LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE                    ),
         LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE),
@@ -425,145 +431,154 @@ static const EnumEntry<COFF::ExtendedDLLCharacteristics>
         LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_FORWARD_CFI_COMPAT                        ),
         LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE                       ),
 };
+constexpr auto PEExtendedDLLCharacteristics = BUILD_ENUM_STRINGS(PEExtendedDLLCharacteristicsDefs);
 // clang-format on
 
-static const EnumEntry<COFF::SectionCharacteristics>
-ImageSectionCharacteristics[] = {
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD           ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD           ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE              ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA  ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER             ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO              ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL                 ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT             ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD           ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES          ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES          ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES          ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES          ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES        ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES        ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES        ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE       ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED        ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED         ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED            ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE           ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ              ),
-  LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE             )
+constexpr EnumStringDef<COFF::SectionCharacteristics>
+    ImageSectionCharacteristicsDefs[] = {
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)};
+constexpr auto ImageSectionCharacteristics =
+    BUILD_ENUM_STRINGS(ImageSectionCharacteristicsDefs);
+
+constexpr EnumStringDef<COFF::SymbolBaseType> ImageSymTypeDefs[] = {
+    {{"Null"}, COFF::IMAGE_SYM_TYPE_NULL},
+    {{"Void"}, COFF::IMAGE_SYM_TYPE_VOID},
+    {{"Char"}, COFF::IMAGE_SYM_TYPE_CHAR},
+    {{"Short"}, COFF::IMAGE_SYM_TYPE_SHORT},
+    {{"Int"}, COFF::IMAGE_SYM_TYPE_INT},
+    {{"Long"}, COFF::IMAGE_SYM_TYPE_LONG},
+    {{"Float"}, COFF::IMAGE_SYM_TYPE_FLOAT},
+    {{"Double"}, COFF::IMAGE_SYM_TYPE_DOUBLE},
+    {{"Struct"}, COFF::IMAGE_SYM_TYPE_STRUCT},
+    {{"Union"}, COFF::IMAGE_SYM_TYPE_UNION},
+    {{"Enum"}, COFF::IMAGE_SYM_TYPE_ENUM},
+    {{"MOE"}, COFF::IMAGE_SYM_TYPE_MOE},
+    {{"Byte"}, COFF::IMAGE_SYM_TYPE_BYTE},
+    {{"Word"}, COFF::IMAGE_SYM_TYPE_WORD},
+    {{"UInt"}, COFF::IMAGE_SYM_TYPE_UINT},
+    {{"DWord"}, COFF::IMAGE_SYM_TYPE_DWORD},
 };
+constexpr auto ImageSymType = BUILD_ENUM_STRINGS(ImageSymTypeDefs);
 
-const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = {
-  { "Null"  , COFF::IMAGE_SYM_TYPE_NULL   },
-  { "Void"  , COFF::IMAGE_SYM_TYPE_VOID   },
-  { "Char"  , COFF::IMAGE_SYM_TYPE_CHAR   },
-  { "Short" , COFF::IMAGE_SYM_TYPE_SHORT  },
-  { "Int"   , COFF::IMAGE_SYM_TYPE_INT    },
-  { "Long"  , COFF::IMAGE_SYM_TYPE_LONG   },
-  { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT  },
-  { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE },
-  { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT },
-  { "Union" , COFF::IMAGE_SYM_TYPE_UNION  },
-  { "Enum"  , COFF::IMAGE_SYM_TYPE_ENUM   },
-  { "MOE"   , COFF::IMAGE_SYM_TYPE_MOE    },
-  { "Byte"  , COFF::IMAGE_SYM_TYPE_BYTE   },
-  { "Word"  , COFF::IMAGE_SYM_TYPE_WORD   },
-  { "UInt"  , COFF::IMAGE_SYM_TYPE_UINT   },
-  { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD  }
+constexpr EnumStringDef<COFF::SymbolComplexType> ImageSymDTypeDefs[] = {
+    {{"Null"}, COFF::IMAGE_SYM_DTYPE_NULL},
+    {{"Pointer"}, COFF::IMAGE_SYM_DTYPE_POINTER},
+    {{"Function"}, COFF::IMAGE_SYM_DTYPE_FUNCTION},
+    {{"Array"}, COFF::IMAGE_SYM_DTYPE_ARRAY},
 };
-
-const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = {
-  { "Null"    , COFF::IMAGE_SYM_DTYPE_NULL     },
-  { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER  },
-  { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION },
-  { "Array"   , COFF::IMAGE_SYM_DTYPE_ARRAY    }
+constexpr auto ImageSymDType = BUILD_ENUM_STRINGS(ImageSymDTypeDefs);
+
+constexpr EnumStringDef<COFF::SymbolStorageClass> ImageSymClassDefs[] = {
+    {{"EndOfFunction"}, COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION},
+    {{"Null"}, COFF::IMAGE_SYM_CLASS_NULL},
+    {{"Automatic"}, COFF::IMAGE_SYM_CLASS_AUTOMATIC},
+    {{"External"}, COFF::IMAGE_SYM_CLASS_EXTERNAL},
+    {{"Static"}, COFF::IMAGE_SYM_CLASS_STATIC},
+    {{"Register"}, COFF::IMAGE_SYM_CLASS_REGISTER},
+    {{"ExternalDef"}, COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF},
+    {{"Label"}, COFF::IMAGE_SYM_CLASS_LABEL},
+    {{"UndefinedLabel"}, COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL},
+    {{"MemberOfStruct"}, COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT},
+    {{"Argument"}, COFF::IMAGE_SYM_CLASS_ARGUMENT},
+    {{"StructTag"}, COFF::IMAGE_SYM_CLASS_STRUCT_TAG},
+    {{"MemberOfUnion"}, COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION},
+    {{"UnionTag"}, COFF::IMAGE_SYM_CLASS_UNION_TAG},
+    {{"TypeDefinition"}, COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION},
+    {{"UndefinedStatic"}, COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC},
+    {{"EnumTag"}, COFF::IMAGE_SYM_CLASS_ENUM_TAG},
+    {{"MemberOfEnum"}, COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM},
+    {{"RegisterParam"}, COFF::IMAGE_SYM_CLASS_REGISTER_PARAM},
+    {{"BitField"}, COFF::IMAGE_SYM_CLASS_BIT_FIELD},
+    {{"Block"}, COFF::IMAGE_SYM_CLASS_BLOCK},
+    {{"Function"}, COFF::IMAGE_SYM_CLASS_FUNCTION},
+    {{"EndOfStruct"}, COFF::IMAGE_SYM_CLASS_END_OF_STRUCT},
+    {{"File"}, COFF::IMAGE_SYM_CLASS_FILE},
+    {{"Section"}, COFF::IMAGE_SYM_CLASS_SECTION},
+    {{"WeakExternal"}, COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL},
+    {{"CLRToken"}, COFF::IMAGE_SYM_CLASS_CLR_TOKEN},
 };
-
-const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = {
-  { "EndOfFunction"  , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION  },
-  { "Null"           , COFF::IMAGE_SYM_CLASS_NULL             },
-  { "Automatic"      , COFF::IMAGE_SYM_CLASS_AUTOMATIC        },
-  { "External"       , COFF::IMAGE_SYM_CLASS_EXTERNAL         },
-  { "Static"         , COFF::IMAGE_SYM_CLASS_STATIC           },
-  { "Register"       , COFF::IMAGE_SYM_CLASS_REGISTER         },
-  { "ExternalDef"    , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF     },
-  { "Label"          , COFF::IMAGE_SYM_CLASS_LABEL            },
-  { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL  },
-  { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT },
-  { "Argument"       , COFF::IMAGE_SYM_CLASS_ARGUMENT         },
-  { "StructTag"      , COFF::IMAGE_SYM_CLASS_STRUCT_TAG       },
-  { "MemberOfUnion"  , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION  },
-  { "UnionTag"       , COFF::IMAGE_SYM_CLASS_UNION_TAG        },
-  { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION  },
-  { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC },
-  { "EnumTag"        , COFF::IMAGE_SYM_CLASS_ENUM_TAG         },
-  { "MemberOfEnum"   , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM   },
-  { "RegisterParam"  , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM   },
-  { "BitField"       , COFF::IMAGE_SYM_CLASS_BIT_FIELD        },
-  { "Block"          , COFF::IMAGE_SYM_CLASS_BLOCK            },
-  { "Function"       , COFF::IMAGE_SYM_CLASS_FUNCTION         },
-  { "EndOfStruct"    , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT    },
-  { "File"           , COFF::IMAGE_SYM_CLASS_FILE             },
-  { "Section"        , COFF::IMAGE_SYM_CLASS_SECTION          },
-  { "WeakExternal"   , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL    },
-  { "CLRToken"       , COFF::IMAGE_SYM_CLASS_CLR_TOKEN        }
-};
-
-const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
-  { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES },
-  { "Any"         , COFF::IMAGE_COMDAT_SELECT_ANY          },
-  { "SameSize"    , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE    },
-  { "ExactMatch"  , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH  },
-  { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE  },
-  { "Largest"     , COFF::IMAGE_COMDAT_SELECT_LARGEST      },
-  { "Newest"      , COFF::IMAGE_COMDAT_SELECT_NEWEST       }
+constexpr auto ImageSymClass = BUILD_ENUM_STRINGS(ImageSymClassDefs);
+
+constexpr EnumStringDef<COFF::COMDATType> ImageCOMDATSelectDefs[] = {
+    {{"NoDuplicates"}, COFF::IMAGE_COMDAT_SELECT_NODUPLICATES},
+    {{"Any"}, COFF::IMAGE_COMDAT_SELECT_ANY},
+    {{"SameSize"}, COFF::IMAGE_COMDAT_SELECT_SAME_SIZE},
+    {{"ExactMatch"}, COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH},
+    {{"Associative"}, COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE},
+    {{"Largest"}, COFF::IMAGE_COMDAT_SELECT_LARGEST},
+    {{"Newest"}, COFF::IMAGE_COMDAT_SELECT_NEWEST},
 };
-
-const EnumEntry<COFF::DebugType> ImageDebugType[] = {
-    {"Unknown", COFF::IMAGE_DEBUG_TYPE_UNKNOWN},
-    {"COFF", COFF::IMAGE_DEBUG_TYPE_COFF},
-    {"CodeView", COFF::IMAGE_DEBUG_TYPE_CODEVIEW},
-    {"FPO", COFF::IMAGE_DEBUG_TYPE_FPO},
-    {"Misc", COFF::IMAGE_DEBUG_TYPE_MISC},
-    {"Exception", COFF::IMAGE_DEBUG_TYPE_EXCEPTION},
-    {"Fixup", COFF::IMAGE_DEBUG_TYPE_FIXUP},
-    {"OmapToSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC},
-    {"OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC},
-    {"Borland", COFF::IMAGE_DEBUG_TYPE_BORLAND},
-    {"Reserved10", COFF::IMAGE_DEBUG_TYPE_RESERVED10},
-    {"CLSID", COFF::IMAGE_DEBUG_TYPE_CLSID},
-    {"VCFeature", COFF::IMAGE_DEBUG_TYPE_VC_FEATURE},
-    {"POGO", COFF::IMAGE_DEBUG_TYPE_POGO},
-    {"ILTCG", COFF::IMAGE_DEBUG_TYPE_ILTCG},
-    {"MPX", COFF::IMAGE_DEBUG_TYPE_MPX},
-    {"Repro", COFF::IMAGE_DEBUG_TYPE_REPRO},
-    {"ExtendedDLLCharacteristics",
+constexpr auto ImageCOMDATSelect = BUILD_ENUM_STRINGS(ImageCOMDATSelectDefs);
+
+constexpr EnumStringDef<COFF::DebugType> ImageDebugTypeDefs[] = {
+    {{"Unknown"}, COFF::IMAGE_DEBUG_TYPE_UNKNOWN},
+    {{"COFF"}, COFF::IMAGE_DEBUG_TYPE_COFF},
+    {{"CodeView"}, COFF::IMAGE_DEBUG_TYPE_CODEVIEW},
+    {{"FPO"}, COFF::IMAGE_DEBUG_TYPE_FPO},
+    {{"Misc"}, COFF::IMAGE_DEBUG_TYPE_MISC},
+    {{"Exception"}, COFF::IMAGE_DEBUG_TYPE_EXCEPTION},
+    {{"Fixup"}, COFF::IMAGE_DEBUG_TYPE_FIXUP},
+    {{"OmapToSrc"}, COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC},
+    {{"OmapFromSrc"}, COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC},
+    {{"Borland"}, COFF::IMAGE_DEBUG_TYPE_BORLAND},
+    {{"Reserved10"}, COFF::IMAGE_DEBUG_TYPE_RESERVED10},
+    {{"CLSID"}, COFF::IMAGE_DEBUG_TYPE_CLSID},
+    {{"VCFeature"}, COFF::IMAGE_DEBUG_TYPE_VC_FEATURE},
+    {{"POGO"}, COFF::IMAGE_DEBUG_TYPE_POGO},
+    {{"ILTCG"}, COFF::IMAGE_DEBUG_TYPE_ILTCG},
+    {{"MPX"}, COFF::IMAGE_DEBUG_TYPE_MPX},
+    {{"Repro"}, COFF::IMAGE_DEBUG_TYPE_REPRO},
+    {{"ExtendedDLLCharacteristics"},
      COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS},
 };
-
-static const EnumEntry<COFF::WeakExternalCharacteristics>
-WeakExternalCharacteristics[] = {
-  { "NoLibrary"       , COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY },
-  { "Library"         , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY   },
-  { "Alias"           , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS     },
-  { "AntiDependency"  , COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY  },
+constexpr auto ImageDebugType = BUILD_ENUM_STRINGS(ImageDebugTypeDefs);
+
+constexpr EnumStringDef<COFF::WeakExternalCharacteristics>
+    WeakExternalCharacteristicsDefs[] = {
+        {{"NoLibrary"}, COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY},
+        {{"Library"}, COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY},
+        {{"Alias"}, COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS},
+        {{"AntiDependency"}, COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY},
 };
+constexpr auto WeakExternalCharacteristics =
+    BUILD_ENUM_STRINGS(WeakExternalCharacteristicsDefs);
 
-const EnumEntry<uint32_t> SubSectionTypes[] = {
+constexpr EnumStringDef<uint32_t> SubSectionTypesDefs[] = {
     LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols),
     LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, Lines),
     LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable),
@@ -578,21 +593,25 @@ const EnumEntry<uint32_t> SubSectionTypes[] = {
     LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput),
     LLVM_READOBJ_ENUM_CLASS_ENT(DebugSubsectionKind, CoffSymbolRVA),
 };
+constexpr auto SubSectionTypes = BUILD_ENUM_STRINGS(SubSectionTypesDefs);
 
-const EnumEntry<uint32_t> FrameDataFlags[] = {
+constexpr EnumStringDef<uint32_t> FrameDataFlagsDefs[] = {
     LLVM_READOBJ_ENUM_ENT(FrameData, HasSEH),
     LLVM_READOBJ_ENUM_ENT(FrameData, HasEH),
     LLVM_READOBJ_ENUM_ENT(FrameData, IsFunctionStart),
 };
+constexpr auto FrameDataFlags = BUILD_ENUM_STRINGS(FrameDataFlagsDefs);
 
-const EnumEntry<uint8_t> FileChecksumKindNames[] = {
-  LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, None),
-  LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, MD5),
-  LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
-  LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
+constexpr EnumStringDef<uint8_t> FileChecksumKindNamesDefs[] = {
+    LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, None),
+    LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, MD5),
+    LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
+    LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
 };
+constexpr auto FileChecksumKindNames =
+    BUILD_ENUM_STRINGS(FileChecksumKindNamesDefs);
 
-const EnumEntry<uint32_t> PELoadConfigGuardFlags[] = {
+constexpr EnumStringDef<uint32_t> PELoadConfigGuardFlagsDefs[] = {
     LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CF_INSTRUMENTED),
     LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CFW_INSTRUMENTED),
     LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags, CF_FUNCTION_TABLE_PRESENT),
@@ -637,6 +656,8 @@ const EnumEntry<uint32_t> PELoadConfigGuardFlags[] = {
     LLVM_READOBJ_ENUM_CLASS_ENT(COFF::GuardFlags,
                                 CF_FUNCTION_TABLE_SIZE_19BYTES),
 };
+constexpr auto PELoadConfigGuardFlags =
+    BUILD_ENUM_STRINGS(PELoadConfigGuardFlagsDefs);
 
 template <typename T>
 static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
@@ -682,7 +703,8 @@ void COFFDumper::printFileHeaders() {
 
   {
     DictScope D(W, "ImageFileHeader");
-    W.printEnum("Machine", Obj->getMachine(), ArrayRef(ImageFileMachineType));
+    W.printEnum("Machine", Obj->getMachine(),
+                EnumStrings(ImageFileMachineType));
     W.printNumber("SectionCount", Obj->getNumberOfSections());
     W.printHex   ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp());
     W.printHex   ("PointerToSymbolTable", Obj->getPointerToSymbolTable());
@@ -690,7 +712,7 @@ void COFFDumper::printFileHeaders() {
     W.printNumber("StringTableSize", Obj->getStringTableSize());
     W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader());
     W.printFlags("Characteristics", Obj->getCharacteristics(),
-                 ArrayRef(ImageFileCharacteristics));
+                 EnumStrings(ImageFileCharacteristics));
   }
 
   // Print PE header. This header does not exist if this is an object file and
@@ -752,9 +774,9 @@ void COFFDumper::printPEHeader(const PEHeader *Hdr) {
   W.printNumber("SizeOfImage", Hdr->SizeOfImage);
   W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
   W.printHex   ("CheckSum", Hdr->CheckSum);
-  W.printEnum("Subsystem", Hdr->Subsystem, ArrayRef(PEWindowsSubsystem));
+  W.printEnum("Subsystem", Hdr->Subsystem, EnumStrings(PEWindowsSubsystem));
   W.printFlags("Characteristics", Hdr->DLLCharacteristics,
-               ArrayRef(PEDLLCharacteristics));
+               EnumStrings(PEDLLCharacteristics));
   W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
   W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
   W.printNumber("SizeOfHeapReserve", Hdr->SizeOfHeapReserve);
@@ -789,7 +811,7 @@ void COFFDumper::printCOFFDebugDirectory() {
     W.printHex("TimeDateStamp", FormattedTime, D.TimeDateStamp);
     W.printHex("MajorVersion", D.MajorVersion);
     W.printHex("MinorVersion", D.MinorVersion);
-    W.printEnum("Type", D.Type, ArrayRef(ImageDebugType));
+    W.printEnum("Type", D.Type, EnumStrings(ImageDebugType));
     W.printHex("SizeOfData", D.SizeOfData);
     W.printHex("AddressOfRawData", D.AddressOfRawData);
     W.printHex("PointerToRawData", D.PointerToRawData);
@@ -824,7 +846,7 @@ void COFFDumper::printCOFFDebugDirectory() {
         // but that might change in the future
         uint16_t Characteristics = RawData[0];
         W.printFlags("ExtendedCharacteristics", Characteristics,
-                     ArrayRef(PEExtendedDLLCharacteristics));
+                     EnumStrings(PEExtendedDLLCharacteristics));
       }
       W.printBinaryBlock("RawData", RawData);
     }
@@ -1079,7 +1101,8 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
   W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch);
   W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable);
   W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount);
-  W.printFlags("GuardFlags", Conf->GuardFlags, ArrayRef(PELoadConfigGuardFlags),
+  W.printFlags("GuardFlags", Conf->GuardFlags,
+               EnumStrings(PELoadConfigGuardFlags),
                (uint32_t)COFF::GuardFlags::CF_FUNCTION_TABLE_SIZE_MASK);
 
   Tables.GuardFidTableVA = Conf->GuardCFFunctionTable;
@@ -1225,7 +1248,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
       W.printHex("IgnoredSubsectionKind", SubType);
       SubType &= ~SubsectionIgnoreFlag;
     }
-    W.printEnum("SubSectionType", SubType, ArrayRef(SubSectionTypes));
+    W.printEnum("SubSectionType", SubType, EnumStrings(SubSectionTypes));
     W.printHex("SubSectionSize", SubSectionSize);
 
     // Get the contents of the subsection.
@@ -1323,7 +1346,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
         W.printHex("MaxStackSize", FD.MaxStackSize);
         W.printHex("PrologSize", FD.PrologSize);
         W.printHex("SavedRegsSize", FD.SavedRegsSize);
-        W.printFlags("Flags", FD.Flags, ArrayRef(FrameDataFlags));
+        W.printFlags("Flags", FD.Flags, EnumStrings(FrameDataFlags));
 
         // The FrameFunc string is a small RPN program. It can be broken up into
         // statements that end in the '=' operator, which assigns the value on
@@ -1442,7 +1465,7 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) {
     W.printHex("Filename", Filename, FC.FileNameOffset);
     W.printHex("ChecksumSize", FC.Checksum.size());
     W.printEnum("ChecksumKind", uint8_t(FC.Kind),
-                ArrayRef(FileChecksumKindNames));
+                EnumStrings(FileChecksumKindNames));
 
     W.printBinary("ChecksumBytes", FC.Checksum);
   }
@@ -1582,7 +1605,7 @@ void COFFDumper::printSectionHeaders() {
     W.printNumber("RelocationCount", Section->NumberOfRelocations);
     W.printNumber("LineNumberCount", Section->NumberOfLinenumbers);
     W.printFlags("Characteristics", Section->Characteristics,
-                 ArrayRef(ImageSectionCharacteristics),
+                 EnumStrings(ImageSectionCharacteristics),
                  COFF::SectionCharacteristics(0x00F00000));
 
     if (opts::SectionRelocations) {
@@ -1719,10 +1742,11 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
   W.printString("Name", SymbolName);
   W.printNumber("Value", Symbol.getValue());
   W.printNumber("Section", SectionName, Symbol.getSectionNumber());
-  W.printEnum("BaseType", Symbol.getBaseType(), ArrayRef(ImageSymType));
-  W.printEnum("ComplexType", Symbol.getComplexType(), ArrayRef(ImageSymDType));
+  W.printEnum("BaseType", Symbol.getBaseType(), EnumStrings(ImageSymType));
+  W.printEnum("ComplexType", Symbol.getComplexType(),
+              EnumStrings(ImageSymDType));
   W.printEnum("StorageClass", Symbol.getStorageClass(),
-              ArrayRef(ImageSymClass));
+              EnumStrings(ImageSymClass));
   W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols());
 
   for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) {
@@ -1745,7 +1769,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
       DictScope AS(W, "AuxWeakExternal");
       W.printNumber("Linked", getSymbolName(Aux->TagIndex), Aux->TagIndex);
       W.printEnum("Search", Aux->Characteristics,
-                  ArrayRef(WeakExternalCharacteristics));
+                  EnumStrings(WeakExternalCharacteristics));
 
     } else if (Symbol.isFileRecord()) {
       const char *FileName;
@@ -1770,7 +1794,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
       W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
       W.printHex("Checksum", Aux->CheckSum);
       W.printNumber("Number", AuxNumber);
-      W.printEnum("Selection", Aux->Selection, ArrayRef(ImageCOMDATSelect));
+      W.printEnum("Selection", Aux->Selection, EnumStrings(ImageCOMDATSelect));
 
       if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
           && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
@@ -1827,7 +1851,7 @@ void COFFDumper::printUnwindInfo() {
   }
   default:
     W.printEnum("unsupported Image Machine", Obj->getMachine(),
-                ArrayRef(ImageFileMachineType));
+                EnumStrings(ImageFileMachineType));
     break;
   }
 }
@@ -2555,6 +2579,6 @@ void COFFDumper::printCOFFTLSDirectory(
   W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks);
   W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill);
   W.printFlags("Characteristics", TlsTable->Characteristics,
-               ArrayRef(ImageSectionCharacteristics),
+               EnumStrings(ImageSectionCharacteristics),
                COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK));
 }

diff  --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp
index 41afd112b1a6a..f5b3cf203204f 100644
--- a/llvm/tools/llvm-readobj/MachODumper.cpp
+++ b/llvm/tools/llvm-readobj/MachODumper.cpp
@@ -87,74 +87,79 @@ std::unique_ptr<ObjDumper> createMachODumper(const object::MachOObjectFile &Obj,
 
 } // namespace llvm
 
-const EnumEntry<uint32_t> MachOMagics[] = {
-  { "Magic",      MachO::MH_MAGIC    },
-  { "Cigam",      MachO::MH_CIGAM    },
-  { "Magic64",    MachO::MH_MAGIC_64 },
-  { "Cigam64",    MachO::MH_CIGAM_64 },
-  { "FatMagic",   MachO::FAT_MAGIC   },
-  { "FatCigam",   MachO::FAT_CIGAM   },
+constexpr EnumStringDef<uint32_t> MachOMagicsDefs[] = {
+    {{"Magic"}, MachO::MH_MAGIC},      {{"Cigam"}, MachO::MH_CIGAM},
+    {{"Magic64"}, MachO::MH_MAGIC_64}, {{"Cigam64"}, MachO::MH_CIGAM_64},
+    {{"FatMagic"}, MachO::FAT_MAGIC},  {{"FatCigam"}, MachO::FAT_CIGAM},
 };
-
-const EnumEntry<uint32_t> MachOHeaderFileTypes[] = {
-  { "Relocatable",          MachO::MH_OBJECT      },
-  { "Executable",           MachO::MH_EXECUTE     },
-  { "FixedVMLibrary",       MachO::MH_FVMLIB      },
-  { "Core",                 MachO::MH_CORE        },
-  { "PreloadedExecutable",  MachO::MH_PRELOAD     },
-  { "DynamicLibrary",       MachO::MH_DYLIB       },
-  { "DynamicLinker",        MachO::MH_DYLINKER    },
-  { "Bundle",               MachO::MH_BUNDLE      },
-  { "DynamicLibraryStub",   MachO::MH_DYLIB_STUB  },
-  { "DWARFSymbol",          MachO::MH_DSYM        },
-  { "KextBundle",           MachO::MH_KEXT_BUNDLE },
+constexpr auto MachOMagics = BUILD_ENUM_STRINGS(MachOMagicsDefs);
+
+constexpr EnumStringDef<uint32_t> MachOHeaderFileTypesDefs[] = {
+    {{"Relocatable"}, MachO::MH_OBJECT},
+    {{"Executable"}, MachO::MH_EXECUTE},
+    {{"FixedVMLibrary"}, MachO::MH_FVMLIB},
+    {{"Core"}, MachO::MH_CORE},
+    {{"PreloadedExecutable"}, MachO::MH_PRELOAD},
+    {{"DynamicLibrary"}, MachO::MH_DYLIB},
+    {{"DynamicLinker"}, MachO::MH_DYLINKER},
+    {{"Bundle"}, MachO::MH_BUNDLE},
+    {{"DynamicLibraryStub"}, MachO::MH_DYLIB_STUB},
+    {{"DWARFSymbol"}, MachO::MH_DSYM},
+    {{"KextBundle"}, MachO::MH_KEXT_BUNDLE},
 };
+constexpr auto MachOHeaderFileTypes =
+    BUILD_ENUM_STRINGS(MachOHeaderFileTypesDefs);
 
 // clang-format off
-const EnumEntry<uint32_t> MachOHeaderCpuTypes[] = {
-  { "Any"          ,  static_cast<uint32_t>(MachO::CPU_TYPE_ANY) },
-  { "X86"          ,  MachO::CPU_TYPE_X86       },
-  { "X86-64"       ,  MachO::CPU_TYPE_X86_64    },
-  { "Mc98000"      ,  MachO::CPU_TYPE_MC98000   },
-  { "Arm"          ,  MachO::CPU_TYPE_ARM       },
-  { "Arm64"        ,  MachO::CPU_TYPE_ARM64     },
-  { "Arm64 (ILP32)",  MachO::CPU_TYPE_ARM64_32  },
-  { "Sparc"        ,  MachO::CPU_TYPE_SPARC     },
-  { "PowerPC"      ,  MachO::CPU_TYPE_POWERPC   },
-  { "PowerPC64"    ,  MachO::CPU_TYPE_POWERPC64 },
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuTypesDefs[] = {
+  { {"Any"}          ,  static_cast<uint32_t>(MachO::CPU_TYPE_ANY) },
+  { {"X86"}          ,  MachO::CPU_TYPE_X86       },
+  { {"X86-64"}       ,  MachO::CPU_TYPE_X86_64    },
+  { {"Mc98000"}      ,  MachO::CPU_TYPE_MC98000   },
+  { {"Arm"}          ,  MachO::CPU_TYPE_ARM       },
+  { {"Arm64"}        ,  MachO::CPU_TYPE_ARM64     },
+  { {"Arm64 (ILP32)"},  MachO::CPU_TYPE_ARM64_32  },
+  { {"Sparc"}        ,  MachO::CPU_TYPE_SPARC     },
+  { {"PowerPC"}      ,  MachO::CPU_TYPE_POWERPC   },
+  { {"PowerPC64"}    ,  MachO::CPU_TYPE_POWERPC64 },
 };
+constexpr auto MachOHeaderCpuTypes = BUILD_ENUM_STRINGS(MachOHeaderCpuTypesDefs);
 // clang-format on
 
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX86[] = {
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP),
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesX86Defs[] = {
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP),
 };
+constexpr auto MachOHeaderCpuSubtypesX86 =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesX86Defs);
 
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX64[] = {
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H),
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesX64Defs[] = {
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H),
 };
+constexpr auto MachOHeaderCpuSubtypesX64 =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesX64Defs);
 
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = {
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesARMDefs[] = {
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL),
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T),
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6),
@@ -171,131 +176,143 @@ const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = {
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V8M_BASE),
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V8_1M_MAIN),
 };
+constexpr auto MachOHeaderCpuSubtypesARM =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesARMDefs);
 
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64_32[] = {
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesARM64_32Defs[] = {
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_32_V8),
 };
+constexpr auto MachOHeaderCpuSubtypesARM64_32 =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesARM64_32Defs);
 
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64[] = {
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesARM64Defs[] = {
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL),
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_V8),
     LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64E),
 };
+constexpr auto MachOHeaderCpuSubtypesARM64 =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesARM64Defs);
 
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = {
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL),
-};
-
-const EnumEntry<uint32_t> MachOHeaderCpuSubtypesPPC[] = {
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450),
-  LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970),
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesSPARCDefs[] = {
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL),
 };
-
-const EnumEntry<uint32_t> MachOHeaderFlags[] = {
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION),
-  LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),
-};
-
-const EnumEntry<unsigned> MachOSectionTypes[] = {
-  { "Regular"                        , MachO::S_REGULAR },
-  { "ZeroFill"                       , MachO::S_ZEROFILL },
-  { "CStringLiterals"                , MachO::S_CSTRING_LITERALS },
-  { "4ByteLiterals"                  , MachO::S_4BYTE_LITERALS },
-  { "8ByteLiterals"                  , MachO::S_8BYTE_LITERALS },
-  { "LiteralPointers"                , MachO::S_LITERAL_POINTERS },
-  { "NonLazySymbolPointers"          , MachO::S_NON_LAZY_SYMBOL_POINTERS },
-  { "LazySymbolPointers"             , MachO::S_LAZY_SYMBOL_POINTERS },
-  { "SymbolStubs"                    , MachO::S_SYMBOL_STUBS },
-  { "ModInitFuncPointers"            , MachO::S_MOD_INIT_FUNC_POINTERS },
-  { "ModTermFuncPointers"            , MachO::S_MOD_TERM_FUNC_POINTERS },
-  { "Coalesced"                      , MachO::S_COALESCED },
-  { "GBZeroFill"                     , MachO::S_GB_ZEROFILL },
-  { "Interposing"                    , MachO::S_INTERPOSING },
-  { "16ByteLiterals"                 , MachO::S_16BYTE_LITERALS },
-  { "DTraceDOF"                      , MachO::S_DTRACE_DOF },
-  { "LazyDylibSymbolPointers"        , MachO::S_LAZY_DYLIB_SYMBOL_POINTERS },
-  { "ThreadLocalRegular"             , MachO::S_THREAD_LOCAL_REGULAR },
-  { "ThreadLocalZerofill"            , MachO::S_THREAD_LOCAL_ZEROFILL },
-  { "ThreadLocalVariables"           , MachO::S_THREAD_LOCAL_VARIABLES },
-  { "ThreadLocalVariablePointers"    , MachO::S_THREAD_LOCAL_VARIABLE_POINTERS },
-  { "ThreadLocalInitFunctionPointers", MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS }
+constexpr auto MachOHeaderCpuSubtypesSPARC =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesSPARCDefs);
+
+constexpr EnumStringDef<uint32_t> MachOHeaderCpuSubtypesPPCDefs[] = {
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450),
+    LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970),
 };
-
-const EnumEntry<unsigned> MachOSectionAttributes[] = {
-  { "LocReloc"         , 1 <<  0 /*S_ATTR_LOC_RELOC          */ },
-  { "ExtReloc"         , 1 <<  1 /*S_ATTR_EXT_RELOC          */ },
-  { "SomeInstructions" , 1 <<  2 /*S_ATTR_SOME_INSTRUCTIONS  */ },
-  { "Debug"            , 1 << 17 /*S_ATTR_DEBUG              */ },
-  { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ },
-  { "LiveSupport"      , 1 << 19 /*S_ATTR_LIVE_SUPPORT       */ },
-  { "NoDeadStrip"      , 1 << 20 /*S_ATTR_NO_DEAD_STRIP      */ },
-  { "StripStaticSyms"  , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS  */ },
-  { "NoTOC"            , 1 << 22 /*S_ATTR_NO_TOC             */ },
-  { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS  */ },
+constexpr auto MachOHeaderCpuSubtypesPPC =
+    BUILD_ENUM_STRINGS(MachOHeaderCpuSubtypesPPCDefs);
+
+constexpr EnumStringDef<uint32_t> MachOHeaderFlagsDefs[] = {
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION),
+    LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),
 };
-
-const EnumEntry<unsigned> MachOSymbolRefTypes[] = {
-  { "UndefinedNonLazy",                     0 },
-  { "ReferenceFlagUndefinedLazy",           1 },
-  { "ReferenceFlagDefined",                 2 },
-  { "ReferenceFlagPrivateDefined",          3 },
-  { "ReferenceFlagPrivateUndefinedNonLazy", 4 },
-  { "ReferenceFlagPrivateUndefinedLazy",    5 }
+constexpr auto MachOHeaderFlags = BUILD_ENUM_STRINGS(MachOHeaderFlagsDefs);
+
+constexpr EnumStringDef<unsigned> MachOSectionTypesDefs[] = {
+    {{"Regular"}, MachO::S_REGULAR},
+    {{"ZeroFill"}, MachO::S_ZEROFILL},
+    {{"CStringLiterals"}, MachO::S_CSTRING_LITERALS},
+    {{"4ByteLiterals"}, MachO::S_4BYTE_LITERALS},
+    {{"8ByteLiterals"}, MachO::S_8BYTE_LITERALS},
+    {{"LiteralPointers"}, MachO::S_LITERAL_POINTERS},
+    {{"NonLazySymbolPointers"}, MachO::S_NON_LAZY_SYMBOL_POINTERS},
+    {{"LazySymbolPointers"}, MachO::S_LAZY_SYMBOL_POINTERS},
+    {{"SymbolStubs"}, MachO::S_SYMBOL_STUBS},
+    {{"ModInitFuncPointers"}, MachO::S_MOD_INIT_FUNC_POINTERS},
+    {{"ModTermFuncPointers"}, MachO::S_MOD_TERM_FUNC_POINTERS},
+    {{"Coalesced"}, MachO::S_COALESCED},
+    {{"GBZeroFill"}, MachO::S_GB_ZEROFILL},
+    {{"Interposing"}, MachO::S_INTERPOSING},
+    {{"16ByteLiterals"}, MachO::S_16BYTE_LITERALS},
+    {{"DTraceDOF"}, MachO::S_DTRACE_DOF},
+    {{"LazyDylibSymbolPointers"}, MachO::S_LAZY_DYLIB_SYMBOL_POINTERS},
+    {{"ThreadLocalRegular"}, MachO::S_THREAD_LOCAL_REGULAR},
+    {{"ThreadLocalZerofill"}, MachO::S_THREAD_LOCAL_ZEROFILL},
+    {{"ThreadLocalVariables"}, MachO::S_THREAD_LOCAL_VARIABLES},
+    {{"ThreadLocalVariablePointers"}, MachO::S_THREAD_LOCAL_VARIABLE_POINTERS},
+    {{"ThreadLocalInitFunctionPointers"},
+     MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS}};
+constexpr auto MachOSectionTypes = BUILD_ENUM_STRINGS(MachOSectionTypesDefs);
+
+constexpr EnumStringDef<unsigned> MachOSectionAttributesDefs[] = {
+    {{"LocReloc"}, 1 << 0 /*S_ATTR_LOC_RELOC*/},
+    {{"ExtReloc"}, 1 << 1 /*S_ATTR_EXT_RELOC*/},
+    {{"SomeInstructions"}, 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS*/},
+    {{"Debug"}, 1 << 17 /*S_ATTR_DEBUG*/},
+    {{"SelfModifyingCode"}, 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/},
+    {{"LiveSupport"}, 1 << 19 /*S_ATTR_LIVE_SUPPORT*/},
+    {{"NoDeadStrip"}, 1 << 20 /*S_ATTR_NO_DEAD_STRIP*/},
+    {{"StripStaticSyms"}, 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS*/},
+    {{"NoTOC"}, 1 << 22 /*S_ATTR_NO_TOC*/},
+    {{"PureInstructions"}, 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS*/},
 };
-
-const EnumEntry<unsigned> MachOSymbolFlags[] = {
-  { "ThumbDef",               0x8 },
-  { "ReferencedDynamically", 0x10 },
-  { "NoDeadStrip",           0x20 },
-  { "WeakRef",               0x40 },
-  { "WeakDef",               0x80 },
-  { "SymbolResolver",       0x100 },
-  { "AltEntry",             0x200 },
-  { "ColdFunc",             0x400 },
+constexpr auto MachOSectionAttributes =
+    BUILD_ENUM_STRINGS(MachOSectionAttributesDefs);
+
+constexpr EnumStringDef<unsigned> MachOSymbolRefTypesDefs[] = {
+    {{"UndefinedNonLazy"}, 0},
+    {{"ReferenceFlagUndefinedLazy"}, 1},
+    {{"ReferenceFlagDefined"}, 2},
+    {{"ReferenceFlagPrivateDefined"}, 3},
+    {{"ReferenceFlagPrivateUndefinedNonLazy"}, 4},
+    {{"ReferenceFlagPrivateUndefinedLazy"}, 5}};
+constexpr auto MachOSymbolRefTypes =
+    BUILD_ENUM_STRINGS(MachOSymbolRefTypesDefs);
+
+constexpr EnumStringDef<unsigned> MachOSymbolFlagsDefs[] = {
+    {{"ThumbDef"}, 0x8},     {{"ReferencedDynamically"}, 0x10},
+    {{"NoDeadStrip"}, 0x20}, {{"WeakRef"}, 0x40},
+    {{"WeakDef"}, 0x80},     {{"SymbolResolver"}, 0x100},
+    {{"AltEntry"}, 0x200},   {{"ColdFunc"}, 0x400},
 };
+constexpr auto MachOSymbolFlags = BUILD_ENUM_STRINGS(MachOSymbolFlagsDefs);
 
-const EnumEntry<unsigned> MachOSymbolTypes[] = {
-  { "Undef",           0x0 },
-  { "Abs",             0x2 },
-  { "Indirect",        0xA },
-  { "PreboundUndef",   0xC },
-  { "Section",         0xE }
-};
+constexpr EnumStringDef<unsigned> MachOSymbolTypesDefs[] = {
+    {{"Undef"}, 0x0},
+    {{"Abs"}, 0x2},
+    {{"Indirect"}, 0xA},
+    {{"PreboundUndef"}, 0xC},
+    {{"Section"}, 0xE}};
+constexpr auto MachOSymbolTypes = BUILD_ENUM_STRINGS(MachOSymbolTypesDefs);
 
 namespace {
   struct MachOSection {
@@ -441,40 +458,42 @@ void MachODumper::printFileHeaders() {
 
 template<class MachHeader>
 void MachODumper::printFileHeaders(const MachHeader &Header) {
-  W.printEnum("Magic", Header.magic, ArrayRef(MachOMagics));
-  W.printEnum("CpuType", Header.cputype, ArrayRef(MachOHeaderCpuTypes));
+  W.printEnum("Magic", Header.magic, EnumStrings(MachOMagics));
+  W.printEnum("CpuType", Header.cputype, EnumStrings(MachOHeaderCpuTypes));
   uint32_t subtype = Header.cpusubtype & ~MachO::CPU_SUBTYPE_MASK;
   switch (Header.cputype) {
   case MachO::CPU_TYPE_X86:
-    W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesX86));
+    W.printEnum("CpuSubType", subtype, EnumStrings(MachOHeaderCpuSubtypesX86));
     break;
   case MachO::CPU_TYPE_X86_64:
-    W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesX64));
+    W.printEnum("CpuSubType", subtype, EnumStrings(MachOHeaderCpuSubtypesX64));
     break;
   case MachO::CPU_TYPE_ARM:
-    W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesARM));
+    W.printEnum("CpuSubType", subtype, EnumStrings(MachOHeaderCpuSubtypesARM));
     break;
   case MachO::CPU_TYPE_POWERPC:
-    W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesPPC));
+    W.printEnum("CpuSubType", subtype, EnumStrings(MachOHeaderCpuSubtypesPPC));
     break;
   case MachO::CPU_TYPE_SPARC:
-    W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesSPARC));
+    W.printEnum("CpuSubType", subtype,
+                EnumStrings(MachOHeaderCpuSubtypesSPARC));
     break;
   case MachO::CPU_TYPE_ARM64:
-    W.printEnum("CpuSubType", subtype, ArrayRef(MachOHeaderCpuSubtypesARM64));
+    W.printEnum("CpuSubType", subtype,
+                EnumStrings(MachOHeaderCpuSubtypesARM64));
     break;
   case MachO::CPU_TYPE_ARM64_32:
     W.printEnum("CpuSubType", subtype,
-                ArrayRef(MachOHeaderCpuSubtypesARM64_32));
+                EnumStrings(MachOHeaderCpuSubtypesARM64_32));
     break;
   case MachO::CPU_TYPE_POWERPC64:
   default:
     W.printHex("CpuSubType", subtype);
   }
-  W.printEnum("FileType", Header.filetype, ArrayRef(MachOHeaderFileTypes));
+  W.printEnum("FileType", Header.filetype, EnumStrings(MachOHeaderFileTypes));
   W.printNumber("NumOfLoadCommands", Header.ncmds);
   W.printNumber("SizeOfLoadCommands", Header.sizeofcmds);
-  W.printFlags("Flags", Header.flags, ArrayRef(MachOHeaderFlags));
+  W.printFlags("Flags", Header.flags, EnumStrings(MachOHeaderFlags));
 }
 
 void MachODumper::printSectionHeaders() { return printSectionHeaders(Obj); }
@@ -504,9 +523,9 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {
     W.printNumber("Alignment", MOSection.Alignment);
     W.printHex("RelocationOffset", MOSection.RelocationTableOffset);
     W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries);
-    W.printEnum("Type", MOSection.Flags & 0xFF, ArrayRef(MachOSectionTypes));
+    W.printEnum("Type", MOSection.Flags & 0xFF, EnumStrings(MachOSectionTypes));
     W.printFlags("Attributes", MOSection.Flags >> 8,
-                 ArrayRef(MachOSectionAttributes));
+                 EnumStrings(MachOSectionAttributes));
     W.printHex("Reserved1", MOSection.Reserved1);
     W.printHex("Reserved2", MOSection.Reserved2);
     if (Obj->is64Bit())
@@ -709,13 +728,13 @@ void MachODumper::printSymbol(const SymbolRef &Symbol, ScopedPrinter &W) {
     if (MOSymbol.Type & MachO::N_EXT)
       W.startLine() << "Extern\n";
     W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE),
-                ArrayRef(MachOSymbolTypes));
+                EnumStrings(MachOSymbolTypes));
   }
   W.printHex("Section", SectionName, MOSymbol.SectionIndex);
   W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0x7),
-              ArrayRef(MachOSymbolRefTypes));
+              EnumStrings(MachOSymbolRefTypes));
   W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0x7),
-               ArrayRef(MachOSymbolFlags));
+               EnumStrings(MachOSymbolFlags));
   W.printHex("Value", MOSymbol.Value);
 }
 

diff  --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp
index 5d7639b0b70fd..dfacc4f53944c 100644
--- a/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -20,17 +20,16 @@ using namespace object;
 
 namespace {
 
-const EnumEntry<unsigned> WasmSymbolTypes[] = {
-#define ENUM_ENTRY(X)                                                          \
-  { #X, wasm::WASM_SYMBOL_TYPE_##X }
+constexpr EnumStringDef<unsigned> WasmSymbolTypeDefs[] = {
+#define ENUM_ENTRY(X) {{#X}, wasm::WASM_SYMBOL_TYPE_##X}
     ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL),
     ENUM_ENTRY(SECTION),  ENUM_ENTRY(TAG),  ENUM_ENTRY(TABLE),
 #undef ENUM_ENTRY
 };
+constexpr auto WasmSymbolTypes = BUILD_ENUM_STRINGS(WasmSymbolTypeDefs);
 
-const EnumEntry<uint32_t> WasmSectionTypes[] = {
-#define ENUM_ENTRY(X)                                                          \
-  { #X, wasm::WASM_SEC_##X }
+constexpr EnumStringDef<uint32_t> WasmSectionTypeDefs[] = {
+#define ENUM_ENTRY(X) {{#X}, wasm::WASM_SEC_##X}
     ENUM_ENTRY(CUSTOM),   ENUM_ENTRY(TYPE),      ENUM_ENTRY(IMPORT),
     ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE),     ENUM_ENTRY(MEMORY),
     ENUM_ENTRY(GLOBAL),   ENUM_ENTRY(TAG),       ENUM_ENTRY(EXPORT),
@@ -38,21 +37,18 @@ const EnumEntry<uint32_t> WasmSectionTypes[] = {
     ENUM_ENTRY(DATA),     ENUM_ENTRY(DATACOUNT),
 #undef ENUM_ENTRY
 };
-
-const EnumEntry<unsigned> WasmSymbolFlags[] = {
-#define ENUM_ENTRY(X)                                                          \
-  { #X, wasm::WASM_SYMBOL_##X }
-  ENUM_ENTRY(BINDING_GLOBAL),
-  ENUM_ENTRY(BINDING_WEAK),
-  ENUM_ENTRY(BINDING_LOCAL),
-  ENUM_ENTRY(VISIBILITY_DEFAULT),
-  ENUM_ENTRY(VISIBILITY_HIDDEN),
-  ENUM_ENTRY(UNDEFINED),
-  ENUM_ENTRY(EXPORTED),
-  ENUM_ENTRY(EXPLICIT_NAME),
-  ENUM_ENTRY(NO_STRIP),
+constexpr auto WasmSectionTypes = BUILD_ENUM_STRINGS(WasmSectionTypeDefs);
+
+constexpr EnumStringDef<unsigned> WasmSymbolFlagDefs[] = {
+#define ENUM_ENTRY(X) {{#X}, wasm::WASM_SYMBOL_##X}
+    ENUM_ENTRY(BINDING_GLOBAL),    ENUM_ENTRY(BINDING_WEAK),
+    ENUM_ENTRY(BINDING_LOCAL),     ENUM_ENTRY(VISIBILITY_DEFAULT),
+    ENUM_ENTRY(VISIBILITY_HIDDEN), ENUM_ENTRY(UNDEFINED),
+    ENUM_ENTRY(EXPORTED),          ENUM_ENTRY(EXPLICIT_NAME),
+    ENUM_ENTRY(NO_STRIP),
 #undef ENUM_ENTRY
 };
+constexpr auto WasmSymbolFlags = BUILD_ENUM_STRINGS(WasmSymbolFlagDefs);
 
 class WasmDumper : public ObjDumper {
 public:
@@ -156,7 +152,7 @@ void WasmDumper::printSectionHeaders() {
   for (const SectionRef &Section : Obj->sections()) {
     const WasmSection &WasmSec = Obj->getWasmSection(Section);
     DictScope SectionD(W, "Section");
-    W.printEnum("Type", WasmSec.Type, ArrayRef(WasmSectionTypes));
+    W.printEnum("Type", WasmSec.Type, EnumStrings(WasmSectionTypes));
     W.printNumber("Size", static_cast<uint64_t>(WasmSec.Content.size()));
     W.printNumber("Offset", WasmSec.Offset);
     switch (WasmSec.Type) {
@@ -221,8 +217,8 @@ void WasmDumper::printSymbol(const SymbolRef &Sym) {
   DictScope D(W, "Symbol");
   WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl());
   W.printString("Name", Symbol.Info.Name);
-  W.printEnum("Type", Symbol.Info.Kind, ArrayRef(WasmSymbolTypes));
-  W.printFlags("Flags", Symbol.Info.Flags, ArrayRef(WasmSymbolFlags));
+  W.printEnum("Type", Symbol.Info.Kind, EnumStrings(WasmSymbolTypes));
+  W.printFlags("Flags", Symbol.Info.Flags, EnumStrings(WasmSymbolFlags));
 
   if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) {
     if (Symbol.Info.ImportName) {

diff  --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp
index 635d64a76e213..1091103d0a778 100644
--- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -8,6 +8,7 @@
 
 #include "Win64EHDumper.h"
 #include "llvm-readobj.h"
+#include "llvm/ADT/Enum.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
@@ -19,37 +20,40 @@ using namespace llvm::object;
 using namespace llvm::Win64EH;
 
 // clang-format off
-const EnumEntry<unsigned> UnwindFlags[] = {
-  { "ExceptionHandler", UNW_ExceptionHandler },
-  { "TerminateHandler", UNW_TerminateHandler },
-  { "ChainInfo"       , UNW_ChainInfo        },
-  { "Large"           , UNW_FlagLarge        }
+constexpr EnumStringDef<unsigned> UnwindFlagDefs[] = {
+  {{"ExceptionHandler"}, UNW_ExceptionHandler},
+  {{"TerminateHandler"}, UNW_TerminateHandler},
+  {{"ChainInfo"}       , UNW_ChainInfo       },
+  {{"Large"}           , UNW_FlagLarge       }
 };
+constexpr auto UnwindFlags = BUILD_ENUM_STRINGS(UnwindFlagDefs);
 
-const EnumEntry<unsigned> EpilogFlags[] = {
-  { "ParentFragmentTransfer", EPILOG_PARENT_FRAGMENT_TRANSFER },
-  { "Large"                 , EPILOG_INFO_LARGE               }
+constexpr EnumStringDef<unsigned> EpilogFlagDefs[] = {
+  {{"ParentFragmentTransfer"}, EPILOG_PARENT_FRAGMENT_TRANSFER},
+  {{"Large"}                 , EPILOG_INFO_LARGE              }
 };
-// clang-format on
-
-const EnumEntry<unsigned> UnwindOpInfo[] = {
-  { "RAX",  0 },
-  { "RCX",  1 },
-  { "RDX",  2 },
-  { "RBX",  3 },
-  { "RSP",  4 },
-  { "RBP",  5 },
-  { "RSI",  6 },
-  { "RDI",  7 },
-  { "R8",   8 },
-  { "R9",   9 },
-  { "R10", 10 },
-  { "R11", 11 },
-  { "R12", 12 },
-  { "R13", 13 },
-  { "R14", 14 },
-  { "R15", 15 }
+constexpr auto EpilogFlags = BUILD_ENUM_STRINGS(EpilogFlagDefs);
+
+constexpr EnumStringDef<unsigned> UnwindOpInfoDefs[] = {
+  {{"RAX"},  0},
+  {{"RCX"},  1},
+  {{"RDX"},  2},
+  {{"RBX"},  3},
+  {{"RSP"},  4},
+  {{"RBP"},  5},
+  {{"RSI"},  6},
+  {{"RDI"},  7},
+  {{"R8"},   8},
+  {{"R9"},   9},
+  {{"R10"}, 10},
+  {{"R11"}, 11},
+  {{"R12"}, 12},
+  {{"R13"}, 13},
+  {{"R14"}, 14},
+  {{"R15"}, 15}
 };
+constexpr auto UnwindOpInfo = BUILD_ENUM_STRINGS(UnwindOpInfoDefs);
+// clang-format on
 
 static uint64_t getOffsetOfLSDA(const UnwindInfo& UI) {
   return static_cast<const char*>(UI.getLanguageSpecificData())
@@ -346,11 +350,11 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section,
                              off_t Offset, const UnwindInfo &UI) {
   DictScope UIS(SW, "UnwindInfo");
   SW.printNumber("Version", UI.getVersion());
-  SW.printFlags("Flags", UI.getFlags(), ArrayRef(UnwindFlags));
+  SW.printFlags("Flags", UI.getFlags(), EnumStrings(UnwindFlags));
   SW.printNumber("PrologSize", UI.PrologSize);
   if (UI.getFrameRegister()) {
     SW.printEnum("FrameRegister", UI.getFrameRegister(),
-                 ArrayRef(UnwindOpInfo));
+                 EnumStrings(UnwindOpInfo));
     SW.printHex("FrameOffset", UI.getFrameOffset());
   } else {
     SW.printString("FrameRegister", StringRef("-"));
@@ -518,7 +522,7 @@ void Dumper::printUnwindInfoV3(const Context &Ctx,
   const DecodedUnwindInfoV3 &Info = *InfoOrErr;
 
   SW.printNumber("Version", Info.Version);
-  SW.printFlags("Flags", Info.Flags, ArrayRef(UnwindFlags));
+  SW.printFlags("Flags", Info.Flags, EnumStrings(UnwindFlags));
   SW.printHex("SizeOfProlog", Info.SizeOfProlog);
   SW.printNumber("PayloadWords", Info.PayloadWords);
   SW.printNumber("NumberOfOps", Info.NumberOfOps);
@@ -557,7 +561,7 @@ void Dumper::printUnwindInfoV3(const Context &Ctx,
     const DecodedEpilogV3 &Epi = Info.Epilogs[I];
 
     DictScope ES(SW, formatv("Epilog [{0}]", I).str());
-    SW.printFlags("Flags", Epi.Flags, ArrayRef(EpilogFlags));
+    SW.printFlags("Flags", Epi.Flags, EnumStrings(EpilogFlags));
     // Format the signed EpilogOffset as hex with explicit sign so negative
     // tail-relative offsets remain readable (e.g. "-0x14" rather than
     // "0xFFFFFFEC").

diff  --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
index 03764e9ba483d..2aae7c4cac15c 100644
--- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -205,9 +205,8 @@ void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) {
   }
 }
 
-const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::StorageClass> SymStorageClassDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(C_NULL),  ECase(C_AUTO),    ECase(C_EXT),     ECase(C_STAT),
     ECase(C_REG),   ECase(C_EXTDEF),  ECase(C_LABEL),   ECase(C_ULABEL),
     ECase(C_MOS),   ECase(C_ARG),     ECase(C_STRTAG),  ECase(C_MOU),
@@ -223,6 +222,7 @@ const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
     ECase(C_STTLS), ECase(C_EFCN)
 #undef ECase
 };
+constexpr auto SymStorageClass = BUILD_ENUM_STRINGS(SymStorageClassDefs);
 
 template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
 void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) {
@@ -258,7 +258,7 @@ void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) {
     W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType);
     W.printEnum("StorageClass",
                 static_cast<uint8_t>(LoadSecSymEntPtr->StorageClass),
-                ArrayRef(SymStorageClass));
+                EnumStrings(SymStorageClass));
     W.printHex("ImportFileID", LoadSecSymEntPtr->ImportFileID);
     W.printNumber("ParameterTypeCheck", LoadSecSymEntPtr->ParameterTypeCheck);
   }
@@ -274,9 +274,8 @@ void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) {
                                     LoaderSectionHeader32>(LoaderSectionAddr);
 }
 
-const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::RelocationType> RelocationTypeNameclassDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(R_POS),    ECase(R_RL),     ECase(R_RLA),    ECase(R_NEG),
     ECase(R_REL),    ECase(R_TOC),    ECase(R_TRL),    ECase(R_TRLA),
     ECase(R_GL),     ECase(R_TCL),    ECase(R_REF),    ECase(R_BA),
@@ -285,6 +284,8 @@ const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
     ECase(R_TLSML),  ECase(R_TOCU),   ECase(R_TOCL)
 #undef ECase
 };
+constexpr auto RelocationTypeNameclass =
+    BUILD_ENUM_STRINGS(RelocationTypeNameclassDefs);
 
 // From the XCOFF specification: there are five implicit external symbols, one
 // each for the .text, .data, .bss, .tdata, and .tbss sections. These symbols
@@ -334,7 +335,7 @@ void XCOFFDumper::printLoaderSectionRelocationEntry(
     W.printNumber("FixupBitValue", IsFixupIndicated(Info) ? 1 : 0);
     W.printNumber("Length", GetRelocatedLength(Info));
     W.printEnum("Type", static_cast<uint8_t>(Type),
-                ArrayRef(RelocationTypeNameclass));
+                EnumStrings(RelocationTypeNameclass));
     W.printNumber("SectionNumber", LoaderSecRelEntPtr->SectionNum);
   } else {
     W.startLine() << format_hex(LoaderSecRelEntPtr->VirtualAddr,
@@ -475,7 +476,8 @@ template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
     W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No");
     W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
     W.printNumber("Length", Reloc.getRelocatedLength());
-    W.printEnum("Type", (uint8_t)Reloc.Type, ArrayRef(RelocationTypeNameclass));
+    W.printEnum("Type", (uint8_t)Reloc.Type,
+                EnumStrings(RelocationTypeNameclass));
   } else {
     raw_ostream &OS = W.startLine();
     OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " "
@@ -516,20 +518,20 @@ void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) {
   }
 }
 
-const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::CFileStringType> FileStringTypeDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
 #undef ECase
 };
+constexpr auto FileStringType = BUILD_ENUM_STRINGS(FileStringTypeDefs);
 
-const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::SymbolAuxType> SymAuxTypeDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE),
     ECase(AUX_CSECT),  ECase(AUX_SECT)
 #undef ECase
 };
+constexpr auto SymAuxType = BUILD_ENUM_STRINGS(SymAuxTypeDefs);
 
 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
   assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) &&
@@ -541,17 +543,16 @@ void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
   W.printString("Name", FileName);
   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
-              ArrayRef(FileStringType));
+              EnumStrings(FileStringType));
   if (Obj.is64Bit()) {
     W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
-                ArrayRef(SymAuxType));
+                EnumStrings(SymAuxType));
   }
 }
 
-static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
-    {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::StorageMappingClass>
+    CsectStorageMappingClassDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
         ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB),   ECase(XMC_GL),
         ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264),
         ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW),   ECase(XMC_TC0),
@@ -560,13 +561,16 @@ static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
         ECase(XMC_TE)
 #undef ECase
 };
+constexpr auto CsectStorageMappingClass =
+    BUILD_ENUM_STRINGS(CsectStorageMappingClassDefs);
 
-const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::SymbolType> CsectSymbolTypeClassDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
 #undef ECase
 };
+constexpr auto CsectSymbolTypeClass =
+    BUILD_ENUM_STRINGS(CsectSymbolTypeClassDefs);
 
 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
   assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) &&
@@ -582,14 +586,14 @@ void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) {
   // Print out symbol alignment and type.
   W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2());
   W.printEnum("SymbolType", AuxEntRef.getSymbolType(),
-              ArrayRef(CsectSymbolTypeClass));
+              EnumStrings(CsectSymbolTypeClass));
   W.printEnum("StorageMappingClass",
               static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
-              ArrayRef(CsectStorageMappingClass));
+              EnumStrings(CsectStorageMappingClass));
 
   if (Obj.is64Bit()) {
     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
-                ArrayRef(SymAuxType));
+                EnumStrings(SymAuxType));
   } else {
     W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32());
     W.printHex("StabSectNum", AuxEntRef.getStabSectNum32());
@@ -621,7 +625,7 @@ void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) {
   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
-              ArrayRef(SymAuxType));
+              EnumStrings(SymAuxType));
 }
 
 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) {
@@ -646,7 +650,7 @@ void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) {
   W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
-              ArrayRef(SymAuxType));
+              EnumStrings(SymAuxType));
 }
 
 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) {
@@ -667,7 +671,7 @@ void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) {
                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
   W.printHex("LineNumber", AuxEntPtr->LineNum);
   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
-              ArrayRef(SymAuxType));
+              EnumStrings(SymAuxType));
 }
 
 template <typename T>
@@ -679,7 +683,7 @@ void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
   W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
   if (Obj.is64Bit())
     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
-                ArrayRef(SymAuxType));
+                EnumStrings(SymAuxType));
 }
 
 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
@@ -717,16 +721,15 @@ static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
   }
 }
 
-const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::CFileLangId> CFileLangIdClassDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(TB_C), ECase(TB_Fortran), ECase(TB_CPLUSPLUS)
 #undef ECase
 };
+constexpr auto CFileLangIdClass = BUILD_ENUM_STRINGS(CFileLangIdClassDefs);
 
-const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::CFileCpuId> CFileCpuIdClassDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(TCPU_INVALID), ECase(TCPU_PPC),  ECase(TCPU_PPC64), ECase(TCPU_COM),
     ECase(TCPU_PWR),     ECase(TCPU_ANY),  ECase(TCPU_601),   ECase(TCPU_603),
     ECase(TCPU_604),     ECase(TCPU_620),  ECase(TCPU_A35),   ECase(TCPU_970),
@@ -735,6 +738,7 @@ const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
     ECase(TCPU_PWRX)
 #undef ECase
 };
+constexpr auto CFileCpuIdClass = BUILD_ENUM_STRINGS(CFileCpuIdClassDefs);
 
 template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) {
   const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress);
@@ -776,14 +780,14 @@ void XCOFFDumper::printSymbol(const SymbolRef &S) {
   W.printString("Section", SectionName);
   if (SymbolClass == XCOFF::C_FILE) {
     W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(),
-                ArrayRef(CFileLangIdClass));
+                EnumStrings(CFileLangIdClass));
     W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
-                ArrayRef(CFileCpuIdClass));
+                EnumStrings(CFileCpuIdClass));
   } else
     W.printHex("Type", SymbolEntRef.getSymbolType());
 
   W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
-              ArrayRef(SymStorageClass));
+              EnumStrings(SymStorageClass));
   W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
 
   if (NumberOfAuxEntries == 0)
@@ -792,8 +796,7 @@ void XCOFFDumper::printSymbol(const SymbolRef &S) {
   auto checkNumOfAux = [=] {
     if (NumberOfAuxEntries > 1)
       reportUniqueWarning("the " +
-                          enumToString(static_cast<uint8_t>(SymbolClass),
-                                       ArrayRef(SymStorageClass)) +
+                          EnumStrings(SymStorageClass).toString(SymbolClass) +
                           " symbol at index " + Twine(SymbolIdx) +
                           " should not have more than 1 "
                           "auxiliary entry");
@@ -987,9 +990,8 @@ void XCOFFDumper::printNeededLibraries() {
   }
 }
 
-const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::SectionTypeFlags> SectionTypeFlagsNamesDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
     ECase(STYP_PAD),    ECase(STYP_DWARF), ECase(STYP_TEXT),
     ECase(STYP_DATA),   ECase(STYP_BSS),   ECase(STYP_EXCEPT),
     ECase(STYP_INFO),   ECase(STYP_TDATA), ECase(STYP_TBSS),
@@ -997,17 +999,20 @@ const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
     ECase(STYP_OVRFLO)
 #undef ECase
 };
+constexpr auto SectionTypeFlagsNames =
+    BUILD_ENUM_STRINGS(SectionTypeFlagsNamesDefs);
 
-const EnumEntry<XCOFF::DwarfSectionSubtypeFlags>
-    DWARFSectionSubtypeFlagsNames[] = {
-#define ECase(X)                                                               \
-  { #X, XCOFF::X }
+constexpr EnumStringDef<XCOFF::DwarfSectionSubtypeFlags>
+    DWARFSectionSubtypeFlagsNamesDefs[] = {
+#define ECase(X) {{#X}, XCOFF::X}
         ECase(SSUBTYP_DWINFO),  ECase(SSUBTYP_DWLINE),  ECase(SSUBTYP_DWPBNMS),
         ECase(SSUBTYP_DWPBTYP), ECase(SSUBTYP_DWARNGE), ECase(SSUBTYP_DWABREV),
         ECase(SSUBTYP_DWSTR),   ECase(SSUBTYP_DWRNGES), ECase(SSUBTYP_DWLOC),
         ECase(SSUBTYP_DWFRAME), ECase(SSUBTYP_DWMAC)
 #undef ECase
 };
+constexpr auto DWARFSectionSubtypeFlagsNames =
+    BUILD_ENUM_STRINGS(DWARFSectionSubtypeFlagsNamesDefs);
 
 template <typename T>
 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const {
@@ -1225,10 +1230,10 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
     if (Sec.isReservedSectionType())
       W.printHex("Flags", "Reserved", SectionType);
     else {
-      W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames));
+      W.printEnum("Type", SectionType, EnumStrings(SectionTypeFlagsNames));
       if (SectionType == XCOFF::STYP_DWARF) {
         W.printEnum("DWARFSubType", SectionSubtype,
-                    ArrayRef(DWARFSectionSubtypeFlagsNames));
+                    EnumStrings(DWARFSectionSubtypeFlagsNames));
       }
     }
   }

diff  --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h
index a8047b9136a01..f46526b4b7aac 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.h
+++ b/llvm/tools/llvm-readobj/llvm-readobj.h
@@ -45,10 +45,9 @@ enum OutputStyleTy { LLVM, GNU, JSON, UNKNOWN };
 extern OutputStyleTy Output;
 } // namespace opts
 
-#define LLVM_READOBJ_ENUM_ENT(ns, enum) \
-  { #enum, ns::enum }
+#define LLVM_READOBJ_ENUM_ENT(ns, enum) {{#enum}, ns::enum}
 
-#define LLVM_READOBJ_ENUM_CLASS_ENT(enum_class, enum) \
-  { #enum, std::underlying_type_t<enum_class>(enum_class::enum) }
+#define LLVM_READOBJ_ENUM_CLASS_ENT(enum_class, enum)                          \
+  {{#enum}, std::underlying_type_t<enum_class>(enum_class::enum)}
 
 #endif


        


More information about the llvm-commits mailing list