[llvm] [TableGen] Use StringTable for searchable tables (PR #206252)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 27 22:32:40 PDT 2026


https://github.com/aengelke updated https://github.com/llvm/llvm-project/pull/206252

>From ec5f42dc5f077185bfc272598d0ba91fc6238cbb Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Sat, 27 Jun 2026 13:49:24 +0000
Subject: [PATCH 1/2] [spr] initial version

Created using spr 1.3.8-wip
---
 .../AArch64/AsmParser/AArch64AsmParser.cpp    |  50 +++--
 .../MCTargetDesc/AArch64InstPrinter.cpp       |  67 +++----
 .../Target/AArch64/Utils/AArch64BaseInfo.h    |  37 ++--
 .../AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp |   2 +-
 llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h |   5 +-
 .../ARM/MCTargetDesc/ARMInstPrinter.cpp       |  12 +-
 llvm/lib/Target/ARM/Utils/ARMBaseInfo.h       |   7 +-
 .../Target/RISCV/AsmParser/RISCVAsmParser.cpp |   9 +-
 .../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h |   5 +-
 .../RISCV/MCTargetDesc/RISCVInstPrinter.cpp   |   2 +-
 llvm/lib/Target/RISCV/RISCVSubtarget.h        |   3 +-
 .../SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp      |  13 +-
 .../Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h |   3 +-
 llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp       | 179 ++++++++++--------
 .../Sparc/MCTargetDesc/SparcInstPrinter.cpp   |   4 +-
 .../Sparc/MCTargetDesc/SparcMCTargetDesc.h    |   7 +-
 .../TableGen/generic-tables-return-range.td   |   5 +-
 llvm/test/TableGen/generic-tables.td          |  24 +--
 .../utils/TableGen/SearchableTableEmitter.cpp |  93 +++++++--
 19 files changed, 317 insertions(+), 210 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 6a6b73b8a4c88..a0cf7024ff89d 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1576,11 +1576,12 @@ class AArch64Operand : public MCParsedAsmOperand {
       // Lookup the immediate from table of supported immediates.
       auto *Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmEnum);
       assert(Desc && "Unknown enum value");
+      StringRef DescRepr = AArch64ExactFPImm::getExactFPImmStr(Desc->Repr);
 
       // Calculate its FP value.
       APFloat RealVal(APFloat::IEEEdouble());
       auto StatusOrErr =
-          RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero);
+          RealVal.convertFromString(DescRepr, APFloat::rmTowardZero);
       if (errorToBool(StatusOrErr.takeError()) || *StatusOrErr != APFloat::opOK)
         llvm_unreachable("FP immediate is not exact");
 
@@ -3216,7 +3217,8 @@ ParseStatus AArch64AsmParser::tryParseRPRFMOperand(OperandVector &Operands) {
 
     auto RPRFM = AArch64RPRFM::lookupRPRFMByEncoding(MCE->getValue());
     Operands.push_back(AArch64Operand::CreatePrefetch(
-        prfop, RPRFM ? RPRFM->Name : "", S, getContext()));
+        prfop, RPRFM ? AArch64RPRFM::getRPRFMStr(RPRFM->Name) : "", S,
+        getContext()));
     return ParseStatus::Success;
   }
 
@@ -3251,9 +3253,10 @@ ParseStatus AArch64AsmParser::tryParsePrefetch(OperandVector &Operands) {
   auto LookupByEncoding = [](unsigned E) {
     if (IsSVEPrefetch) {
       if (auto Res = AArch64SVEPRFM::lookupSVEPRFMByEncoding(E))
-        return std::optional<StringRef>(Res->Name);
+        return std::optional<StringRef>(
+            AArch64SVEPRFM::getSVEPRFMStr(Res->Name));
     } else if (auto Res = AArch64PRFM::lookupPRFMByEncoding(E))
-      return std::optional<StringRef>(Res->Name);
+      return std::optional<StringRef>(AArch64PRFM::getPRFMStr(Res->Name));
     return std::optional<StringRef>();
   };
   unsigned MaxVal = IsSVEPrefetch ? 15 : 31;
@@ -4056,7 +4059,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!IC)
       return TokError("invalid operand for IC instruction");
     else if (!IC->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("IC " + std::string(IC->Name) + " requires: ");
+      std::string Str("IC " + std::string(AArch64IC::getICStr(IC->Name)) +
+                      " requires: ");
       setRequiredFeatureString(IC->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4067,7 +4071,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!DC)
       return TokError("invalid operand for DC instruction");
     else if (!DC->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("DC " + std::string(DC->Name) + " requires: ");
+      std::string Str("DC " + std::string(AArch64DC::getDCStr(DC->Name)) +
+                      " requires: ");
       setRequiredFeatureString(DC->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4077,7 +4082,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!AT)
       return TokError("invalid operand for AT instruction");
     else if (!AT->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("AT " + std::string(AT->Name) + " requires: ");
+      std::string Str("AT " + std::string(AArch64AT::getATStr(AT->Name)) +
+                      " requires: ");
       setRequiredFeatureString(AT->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4087,7 +4093,9 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!TLBI)
       return TokError("invalid operand for TLBI instruction");
     else if (!TLBI->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("TLBI " + std::string(TLBI->Name) + " requires: ");
+      std::string Str("TLBI " +
+                      std::string(AArch64TLBI::getTLBIStr(TLBI->Name)) +
+                      " requires: ");
       setRequiredFeatureString(TLBI->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4100,7 +4108,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!GIC)
       return TokError("invalid operand for GIC instruction");
     else if (!GIC->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("GIC " + std::string(GIC->Name) + " requires: ");
+      std::string Str("GIC " + std::string(AArch64GIC::getGICStr(GIC->Name)) +
+                      " requires: ");
       setRequiredFeatureString(GIC->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4111,7 +4120,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!GSB)
       return TokError("invalid operand for GSB instruction");
     else if (!GSB->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("GSB " + std::string(GSB->Name) + " requires: ");
+      std::string Str("GSB " + std::string(AArch64GSB::getGSBStr(GSB->Name)) +
+                      " requires: ");
       setRequiredFeatureString(GSB->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4122,7 +4132,9 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     if (!PLBI)
       return TokError("invalid operand for PLBI instruction");
     else if (!PLBI->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("PLBI " + std::string(PLBI->Name) + " requires: ");
+      std::string Str("PLBI " +
+                      std::string(AArch64PLBI::getPLBIStr(PLBI->Name)) +
+                      " requires: ");
       setRequiredFeatureString(PLBI->getRequiredFeatures(), Str);
       return TokError(Str);
     }
@@ -4217,7 +4229,9 @@ bool AArch64AsmParser::parseSyslAlias(StringRef Name, SMLoc NameLoc,
     if (!GICR)
       return Error(S2, "invalid operand for GICR instruction");
     else if (!GICR->haveFeatures(getSTI().getFeatureBits())) {
-      std::string Str("GICR " + std::string(GICR->Name) + " requires: ");
+      std::string Str("GICR " +
+                      std::string(AArch64GICR::getGICRStr(GICR->Name)) +
+                      " requires: ");
       setRequiredFeatureString(GICR->getRequiredFeatures(), Str);
       return Error(S2, Str);
     }
@@ -4305,9 +4319,9 @@ ParseStatus AArch64AsmParser::tryParseBarrierOperand(OperandVector &Operands) {
     if (Value < 0 || Value > 15)
       return Error(ExprLoc, "barrier operand out of range");
     auto DB = AArch64DB::lookupDBByEncoding(Value);
-    Operands.push_back(AArch64Operand::CreateBarrier(Value, DB ? DB->Name : "",
-                                                     ExprLoc, getContext(),
-                                                     false /*hasnXSModifier*/));
+    StringRef DBStr = DB ? AArch64DB::getDBStr(DB->Name) : "";
+    Operands.push_back(AArch64Operand::CreateBarrier(
+        Value, DBStr, ExprLoc, getContext(), false /*hasnXSModifier*/));
     return ParseStatus::Success;
   }
 
@@ -4363,9 +4377,9 @@ AArch64AsmParser::tryParseBarriernXSOperand(OperandVector &Operands) {
     if (Value != 16 && Value != 20 && Value != 24 && Value != 28)
       return Error(ExprLoc, "barrier operand out of range");
     auto DB = AArch64DBnXS::lookupDBnXSByImmValue(Value);
-    Operands.push_back(AArch64Operand::CreateBarrier(DB->Encoding, DB->Name,
-                                                     ExprLoc, getContext(),
-                                                     true /*hasnXSModifier*/));
+    StringRef DBName = AArch64DBnXS::getDBnXSStr(DB->Name);
+    Operands.push_back(AArch64Operand::CreateBarrier(
+        DB->Encoding, DBName, ExprLoc, getContext(), true /*hasnXSModifier*/));
     return ParseStatus::Success;
   }
 
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 9134203a2da2a..2783b559c8f5c 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -879,7 +879,7 @@ bool AArch64InstPrinter::printRangePrefetchAlias(const MCInst *MI,
 
   O << "\trprfm ";
   if (auto RPRFM = AArch64RPRFM::lookupRPRFMByEncoding(RPRFOp))
-    O << RPRFM->Name << ", ";
+    O << AArch64RPRFM::getRPRFMStr(RPRFM->Name) << ", ";
   else
     O << "#" << formatImm(RPRFOp) << ", ";
   O << getRegisterName(Rm);
@@ -962,7 +962,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
 
       NeedsReg = IC->NeedsReg;
       Ins = "ic\t";
-      Name = std::string(IC->Name);
+      Name = std::string(AArch64IC::getICStr(IC->Name));
     }
     break;
     // DC aliases
@@ -974,7 +974,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
 
       NeedsReg = true;
       Ins = "dc\t";
-      Name = std::string(DC->Name);
+      Name = std::string(AArch64DC::getDCStr(DC->Name));
     }
     break;
     // AT aliases
@@ -985,7 +985,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
 
       NeedsReg = true;
       Ins = "at\t";
-      Name = std::string(AT->Name);
+      Name = std::string(AArch64AT::getATStr(AT->Name));
     }
     break;
     // Overlaps with AT and DC
@@ -995,11 +995,11 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
       if (AT && AT->haveFeatures(STI.getFeatureBits())) {
         NeedsReg = true;
         Ins = "at\t";
-        Name = std::string(AT->Name);
+        Name = std::string(AArch64AT::getATStr(AT->Name));
       } else if (DC && DC->haveFeatures(STI.getFeatureBits())) {
         NeedsReg = true;
         Ins = "dc\t";
-        Name = std::string(DC->Name);
+        Name = std::string(AArch64DC::getDCStr(DC->Name));
       } else {
         return false;
       }
@@ -1016,7 +1016,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
         STI.hasFeature(AArch64::FeatureTLBID))
       OptionalReg = TLBI->RegUse == REG_OPTIONAL;
     Ins = "tlbi\t";
-    Name = std::string(TLBI->Name);
+    Name = std::string(AArch64TLBI::getTLBIStr(TLBI->Name));
   } else if (CnVal == 12) {
     if (CmVal != 0) {
       // GIC aliases
@@ -1026,7 +1026,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
 
       NeedsReg = GIC->NeedsReg;
       Ins = "gic\t";
-      Name = std::string(GIC->Name);
+      Name = std::string(AArch64GIC::getGICStr(GIC->Name));
     } else {
       // GSB aliases
       const AArch64GSB::GSB *GSB = AArch64GSB::lookupGSBByEncoding(Encoding);
@@ -1035,7 +1035,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
 
       NeedsReg = false;
       Ins = "gsb\t";
-      Name = std::string(GSB->Name);
+      Name = std::string(AArch64GSB::getGSBStr(GSB->Name));
     }
   } else if (CnVal == 10) {
     // PLBI aliases
@@ -1048,7 +1048,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
         STI.hasFeature(AArch64::FeatureTLBID))
       OptionalReg = PLBI->RegUse == REG_OPTIONAL;
     Ins = "plbi\t";
-    Name = std::string(PLBI->Name);
+    Name = std::string(AArch64PLBI::getPLBIStr(PLBI->Name));
   } else
     return false;
 
@@ -1110,7 +1110,7 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
         return false;
 
       Ins = "gicr";
-      Name = std::string(GICR->Name);
+      Name = std::string(AArch64GICR::getGICRStr(GICR->Name));
     } else
       return false;
   } else
@@ -1159,7 +1159,7 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
       return false;
 
     Ins = "tlbip\t";
-    Name = std::string(TLBIP->Name);
+    Name = std::string(AArch64TLBIP::getTLBIPStr(TLBIP->Name));
   } else
     return false;
 
@@ -1237,7 +1237,7 @@ void AArch64InstPrinter::printSVCROp(const MCInst *MI, unsigned OpNum,
   unsigned svcrop = MO.getImm();
   const auto *SVCR = AArch64SVCR::lookupSVCRByEncoding(svcrop);
   assert(SVCR && "Unexpected SVCR operand!");
-  O << SVCR->Name;
+  O << AArch64SVCR::getSVCRStr(SVCR->Name);
 }
 
 void AArch64InstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
@@ -1543,7 +1543,7 @@ void AArch64InstPrinter::printRPRFMOperand(const MCInst *MI, unsigned OpNum,
                                            raw_ostream &O) {
   unsigned prfop = MI->getOperand(OpNum).getImm();
   if (auto PRFM = AArch64RPRFM::lookupRPRFMByEncoding(prfop)) {
-    O << PRFM->Name;
+    O << AArch64RPRFM::getRPRFMStr(PRFM->Name);
     return;
   }
 
@@ -1557,13 +1557,13 @@ void AArch64InstPrinter::printPrefetchOp(const MCInst *MI, unsigned OpNum,
   unsigned prfop = MI->getOperand(OpNum).getImm();
   if (IsSVEPrefetch) {
     if (auto PRFM = AArch64SVEPRFM::lookupSVEPRFMByEncoding(prfop)) {
-      O << PRFM->Name;
+      O << AArch64SVEPRFM::getSVEPRFMStr(PRFM->Name);
       return;
     }
   } else {
     auto PRFM = AArch64PRFM::lookupPRFMByEncoding(prfop);
     if (PRFM && PRFM->haveFeatures(STI.getFeatureBits())) {
-      O << PRFM->Name;
+      O << AArch64PRFM::getPRFMStr(PRFM->Name);
       return;
     }
   }
@@ -1577,7 +1577,7 @@ void AArch64InstPrinter::printPSBHintOp(const MCInst *MI, unsigned OpNum,
   unsigned psbhintop = MI->getOperand(OpNum).getImm();
   auto PSB = AArch64PSBHint::lookupPSBByEncoding(psbhintop);
   if (PSB)
-    O << PSB->Name;
+    O << AArch64PSBHint::getPSBStr(PSB->Name);
   else
     markup(O, Markup::Immediate) << '#' << formatImm(psbhintop);
 }
@@ -1588,7 +1588,7 @@ void AArch64InstPrinter::printBTIHintOp(const MCInst *MI, unsigned OpNum,
   unsigned btihintop = MI->getOperand(OpNum).getImm() ^ 32;
   auto BTI = AArch64BTIHint::lookupBTIByEncoding(btihintop);
   if (BTI)
-    O << BTI->Name;
+    O << AArch64BTIHint::getBTIStr(BTI->Name);
   else
     markup(O, Markup::Immediate) << '#' << formatImm(btihintop);
 }
@@ -1601,7 +1601,7 @@ void AArch64InstPrinter::printCMHPriorityHintOp(const MCInst *MI,
   auto PHint =
       AArch64CMHPriorityHint::lookupCMHPriorityHintByEncoding(priorityhint_op);
   if (PHint)
-    O << PHint->Name;
+    O << AArch64CMHPriorityHint::getCMHPriorityHintStr(PHint->Name);
   else
     markup(O, Markup::Immediate) << '#' << formatImm(priorityhint_op);
 }
@@ -1612,7 +1612,7 @@ void AArch64InstPrinter::printTIndexHintOp(const MCInst *MI, unsigned OpNum,
   unsigned tindexhintop = MI->getOperand(OpNum).getImm();
   auto TIndex = AArch64TIndexHint::lookupTIndexByEncoding(tindexhintop);
   if (TIndex)
-    O << TIndex->Name;
+    O << AArch64TIndexHint::getTIndexStr(TIndex->Name);
   else
     markup(O, Markup::Immediate) << '#' << formatImm(tindexhintop);
 }
@@ -1965,13 +1965,13 @@ void AArch64InstPrinter::printBarrierOption(const MCInst *MI, unsigned OpNo,
   StringRef Name;
   if (Opcode == AArch64::ISB) {
     auto ISB = AArch64ISB::lookupISBByEncoding(Val);
-    Name = ISB ? ISB->Name : "";
+    Name = ISB ? AArch64ISB::getISBStr(ISB->Name) : "";
   } else if (Opcode == AArch64::TSB) {
     auto TSB = AArch64TSB::lookupTSBByEncoding(Val);
-    Name = TSB ? TSB->Name : "";
+    Name = TSB ? AArch64TSB::getTSBStr(TSB->Name) : "";
   } else {
     auto DB = AArch64DB::lookupDBByEncoding(Val);
-    Name = DB ? DB->Name : "";
+    Name = DB ? AArch64DB::getDBStr(DB->Name) : "";
   }
   if (!Name.empty())
     O << Name;
@@ -1987,7 +1987,7 @@ void AArch64InstPrinter::printBarriernXSOption(const MCInst *MI, unsigned OpNo,
 
   StringRef Name;
   auto DB = AArch64DBnXS::lookupDBnXSByEncoding(Val);
-  Name = DB ? DB->Name : "";
+  Name = DB ? AArch64DBnXS::getDBnXSStr(DB->Name) : "";
 
   if (!Name.empty())
     O << Name;
@@ -2038,7 +2038,7 @@ void AArch64InstPrinter::printMRSSystemRegister(const MCInst *MI, unsigned OpNo,
   const AArch64SysReg::SysReg *Reg = lookupSysReg(Val, true /*Read*/, STI);
 
   if (Reg)
-    O << Reg->Name;
+    O << AArch64SysReg::getSysRegStr(Reg->Name);
   else
     O << AArch64SysReg::genericRegisterString(Val);
 }
@@ -2065,7 +2065,7 @@ void AArch64InstPrinter::printMSRSystemRegister(const MCInst *MI, unsigned OpNo,
   const AArch64SysReg::SysReg *Reg = lookupSysReg(Val, false /*Read*/, STI);
 
   if (Reg)
-    O << Reg->Name;
+    O << AArch64SysReg::getSysRegStr(Reg->Name);
   else
     O << AArch64SysReg::genericRegisterString(Val);
 }
@@ -2078,9 +2078,9 @@ void AArch64InstPrinter::printSystemPStateField(const MCInst *MI, unsigned OpNo,
   auto PStateImm15 = AArch64PState::lookupPStateImm0_15ByEncoding(Val);
   auto PStateImm1 = AArch64PState::lookupPStateImm0_1ByEncoding(Val);
   if (PStateImm15 && PStateImm15->haveFeatures(STI.getFeatureBits()))
-    O << PStateImm15->Name;
+    O << AArch64PState::getPStateImm0_15Str(PStateImm15->Name);
   else if (PStateImm1 && PStateImm1->haveFeatures(STI.getFeatureBits()))
-    O << PStateImm1->Name;
+    O << AArch64PState::getPStateImm0_1Str(PStateImm1->Name);
   else
     O << "#" << formatImm(Val);
 }
@@ -2106,7 +2106,7 @@ void AArch64InstPrinter::printSVEPattern(const MCInst *MI, unsigned OpNum,
                                          raw_ostream &O) {
   unsigned Val = MI->getOperand(OpNum).getImm();
   if (auto Pat = AArch64SVEPredPattern::lookupSVEPREDPATByEncoding(Val))
-    O << Pat->Name;
+    O << AArch64SVEPredPattern::getSVEPREDPATStr(Pat->Name);
   else
     markup(O, Markup::Immediate) << '#' << formatImm(Val);
 }
@@ -2121,7 +2121,7 @@ void AArch64InstPrinter::printSVEVecLenSpecifier(const MCInst *MI,
     llvm_unreachable("Invalid vector length specifier");
   if (auto Pat =
           AArch64SVEVecLenSpecifier::lookupSVEVECLENSPECIFIERByEncoding(Val))
-    O << Pat->Name;
+    O << AArch64SVEVecLenSpecifier::getSVEVECLENSPECIFIERStr(Pat->Name);
   else
     llvm_unreachable("Invalid vector length specifier");
 }
@@ -2234,8 +2234,9 @@ void AArch64InstPrinter::printExactFPImm(const MCInst *MI, unsigned OpNum,
   auto *Imm0Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs0);
   auto *Imm1Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs1);
   unsigned Val = MI->getOperand(OpNum).getImm();
-  markup(O, Markup::Immediate)
-      << "#" << (Val ? Imm1Desc->Repr : Imm0Desc->Repr);
+  markup(O, Markup::Immediate) << "#"
+                               << AArch64ExactFPImm::getExactFPImmStr(
+                                      Val ? Imm1Desc->Repr : Imm0Desc->Repr);
 }
 
 void AArch64InstPrinter::printGPR64as32(const MCInst *MI, unsigned OpNum,
@@ -2267,7 +2268,7 @@ void AArch64InstPrinter::printPHintOp(const MCInst *MI, unsigned OpNum,
   unsigned Op = MI->getOperand(OpNum).getImm();
   auto PH = AArch64PHint::lookupPHintByEncoding(Op);
   if (PH)
-    O << PH->Name;
+    O << AArch64PHint::getPHintStr(PH->Name);
   else
     markup(O, Markup::Immediate) << '#' << formatImm(Op);
 }
diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
index 1f18af709bd93..bd7faa42449b7 100644
--- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
+++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
@@ -24,6 +24,7 @@
 #include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
 
@@ -419,12 +420,13 @@ inline static bool isValidCBCond(AArch64CC::CondCode Code) {
 } // end namespace AArch64CC
 
 struct SysAlias {
-  const char *Name;
+  StringTable::Offset Name;
   uint16_t Encoding;
   FeatureBitset FeaturesRequired;
 
-  constexpr SysAlias(const char *N, uint16_t E) : Name(N), Encoding(E) {}
-  constexpr SysAlias(const char *N, uint16_t E, FeatureBitset F)
+  constexpr SysAlias(StringTable::Offset N, uint16_t E)
+      : Name(N), Encoding(E) {}
+  constexpr SysAlias(StringTable::Offset N, uint16_t E, FeatureBitset F)
       : Name(N), Encoding(E), FeaturesRequired(F) {}
 
   bool haveFeatures(FeatureBitset ActiveFeatures) const {
@@ -440,25 +442,27 @@ struct SysAlias {
 
 struct SysAliasReg : SysAlias {
   bool NeedsReg;
-  constexpr SysAliasReg(const char *N, uint16_t E, bool R)
+  constexpr SysAliasReg(StringTable::Offset N, uint16_t E, bool R)
       : SysAlias(N, E), NeedsReg(R) {}
-  constexpr SysAliasReg(const char *N, uint16_t E, bool R, FeatureBitset F)
+  constexpr SysAliasReg(StringTable::Offset N, uint16_t E, bool R,
+                        FeatureBitset F)
       : SysAlias(N, E, F), NeedsReg(R) {}
 };
 
 struct SysAliasOptionalReg : SysAlias {
   SysAliasRegUse RegUse;
-  constexpr SysAliasOptionalReg(const char *N, uint16_t E, SysAliasRegUse R)
+  constexpr SysAliasOptionalReg(StringTable::Offset N, uint16_t E,
+                                SysAliasRegUse R)
       : SysAlias(N, E), RegUse(R) {}
-  constexpr SysAliasOptionalReg(const char *N, uint16_t E, SysAliasRegUse R,
-                                FeatureBitset F)
+  constexpr SysAliasOptionalReg(StringTable::Offset N, uint16_t E,
+                                SysAliasRegUse R, FeatureBitset F)
       : SysAlias(N, E, F), RegUse(R) {}
 };
 
 struct TLBIPSysAlias : SysAliasOptionalReg {
   bool AllowWithTLBID;
 
-  constexpr TLBIPSysAlias(const char *N, uint16_t E, SysAliasRegUse R,
+  constexpr TLBIPSysAlias(StringTable::Offset N, uint16_t E, SysAliasRegUse R,
                           FeatureBitset F, bool AllowWithTLBID)
       : SysAliasOptionalReg(N, E, R, F), AllowWithTLBID(AllowWithTLBID) {}
 
@@ -472,9 +476,10 @@ struct TLBIPSysAlias : SysAliasOptionalReg {
 
 struct SysAliasImm : SysAlias {
   uint16_t ImmValue;
-  constexpr SysAliasImm(const char *N, uint16_t E, uint16_t I)
+  constexpr SysAliasImm(StringTable::Offset N, uint16_t E, uint16_t I)
       : SysAlias(N, E), ImmValue(I) {}
-  constexpr SysAliasImm(const char *N, uint16_t E, uint16_t I, FeatureBitset F)
+  constexpr SysAliasImm(StringTable::Offset N, uint16_t E, uint16_t I,
+                        FeatureBitset F)
       : SysAlias(N, E, F), ImmValue(I) {}
 };
 
@@ -579,7 +584,7 @@ struct RPRFM : SysAlias {
 
 namespace AArch64SVEPredPattern {
   struct SVEPREDPAT {
-    const char *Name;
+    StringTable::Offset Name;
     uint16_t Encoding;
   };
 #define GET_SVEPREDPATValues_DECL
@@ -589,7 +594,7 @@ namespace AArch64SVEPredPattern {
 
 namespace AArch64SVEVecLenSpecifier {
   struct SVEVECLENSPECIFIER {
-    const char *Name;
+    StringTable::Offset Name;
     uint16_t Encoding;
   };
 #define GET_SVEVECLENSPECIFIERValues_DECL
@@ -677,7 +682,7 @@ LLVM_DECLARE_ENUM_AS_BITMASK(TailFoldingOpts,
 namespace AArch64ExactFPImm {
 struct ExactFPImm {
   int Enum;
-  const char *Repr;
+  StringTable::Offset Repr;
 };
 #define GET_ExactFPImmValues_DECL
 #define GET_ExactFPImmsList_DECL
@@ -711,7 +716,7 @@ namespace AArch64PSBHint {
 
 namespace AArch64PHint {
 struct PHint {
-  const char *Name;
+  StringTable::Offset Name;
   unsigned Encoding;
   FeatureBitset FeaturesRequired;
 
@@ -844,7 +849,7 @@ AArch64StringToVectorLayout(StringRef LayoutStr) {
 
 namespace AArch64SysReg {
   struct SysReg {
-    const char Name[32];
+    StringTable::Offset Name;
     unsigned Encoding;
     bool Readable;
     bool Writeable;
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
index f0ca0727cf3e0..9687f31b298ad 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp
@@ -274,7 +274,7 @@ void AMDGPUInstPrinter::printDim(const MCInst *MI, unsigned OpNo,
 
   const AMDGPU::MIMGDimInfo *DimInfo = AMDGPU::getMIMGDimInfoByEncoding(Dim);
   if (DimInfo)
-    O << DimInfo->AsmSuffix;
+    O << AMDGPU::getMIMGDimInfoStr(DimInfo->AsmSuffix);
   else
     O << Dim;
 }
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index 1623dc72d2810..fcc5209210791 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
@@ -12,6 +12,7 @@
 #include "AMDGPUSubtarget.h"
 #include "SIDefines.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Module.h"
@@ -414,12 +415,14 @@ struct MIMGDimInfo {
   bool MSAA;
   bool DA;
   uint8_t Encoding;
-  const char *AsmSuffix;
+  StringTable::Offset AsmSuffix;
 };
 
 LLVM_READONLY
 const MIMGDimInfo *getMIMGDimInfo(unsigned DimEnum);
 
+LLVM_READONLY StringRef getMIMGDimInfoStr(StringTable::Offset);
+
 LLVM_READONLY
 const MIMGDimInfo *getMIMGDimInfoByEncoding(uint8_t DimEnc);
 
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp
index 400cf2ce28b65..cea173231f3bc 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp
@@ -917,8 +917,8 @@ void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum,
     if (Opcode == ARM::t2MSR_M && FeatureBits[ARM::FeatureDSP]) {
       auto TheReg =ARMSysReg::lookupMClassSysRegBy12bitSYSmValue(SYSm);
       if (TheReg && TheReg->isInRequiredFeatures({ARM::FeatureDSP})) {
-          O << TheReg->Name;
-          return;
+        O << ARMSysReg::getMClassSysRegStr(TheReg->Name);
+        return;
       }
     }
 
@@ -929,14 +929,14 @@ void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum,
       // alias for MSR APSR_nzcvq.
       auto TheReg = ARMSysReg::lookupMClassSysRegAPSRNonDeprecated(SYSm);
       if (TheReg) {
-          O << TheReg->Name;
-          return;
+        O << ARMSysReg::getMClassSysRegStr(TheReg->Name);
+        return;
       }
     }
 
     auto TheReg = ARMSysReg::lookupMClassSysRegBy8bitSYSmValue(SYSm);
     if (TheReg) {
-      O << TheReg->Name;
+      O << ARMSysReg::getMClassSysRegStr(TheReg->Name);
       return;
     }
 
@@ -991,7 +991,7 @@ void ARMInstPrinter::printBankedRegOperand(const MCInst *MI, unsigned OpNum,
   uint32_t Banked = MI->getOperand(OpNum).getImm();
   auto TheReg = ARMBankedReg::lookupBankedRegByEncoding(Banked);
   assert(TheReg && "invalid banked register operand");
-  std::string Name = TheReg->Name;
+  std::string Name = ARMBankedReg::getBankedRegStr(TheReg->Name).str();
 
   uint32_t isSPSR = (Banked & 0x20) >> 5;
   if (isSPSR)
diff --git a/llvm/lib/Target/ARM/Utils/ARMBaseInfo.h b/llvm/lib/Target/ARM/Utils/ARMBaseInfo.h
index dc4f811e075c6..7172d64051f5f 100644
--- a/llvm/lib/Target/ARM/Utils/ARMBaseInfo.h
+++ b/llvm/lib/Target/ARM/Utils/ARMBaseInfo.h
@@ -16,10 +16,11 @@
 #ifndef LLVM_LIB_TARGET_ARM_UTILS_ARMBASEINFO_H
 #define LLVM_LIB_TARGET_ARM_UTILS_ARMBASEINFO_H
 
+#include "MCTargetDesc/ARMMCTargetDesc.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
-#include "MCTargetDesc/ARMMCTargetDesc.h"
 
 namespace llvm {
 
@@ -189,7 +190,7 @@ inline static unsigned ARMCondCodeFromString(StringRef CC) {
 // System Registers
 namespace ARMSysReg {
   struct MClassSysReg {
-    const char Name[32];
+    StringTable::Offset Name;
     uint16_t M1Encoding12;
     uint16_t M2M3Encoding8;
     uint16_t Encoding;
@@ -225,7 +226,7 @@ namespace ARMSysReg {
 // Banked Registers
 namespace ARMBankedReg {
   struct BankedReg {
-    const char *Name;
+    StringTable::Offset Name;
     uint16_t Encoding;
   };
 #define GET_BankedRegsList_DECL
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index e68f783b9ffdc..384efaae0a025 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -2027,7 +2027,8 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) {
           if (Reg.IsAltName || Reg.IsDeprecatedName)
             continue;
           if (Reg.haveRequiredFeatures(STI->getFeatureBits()))
-            return RISCVOperand::createSysReg(Reg.Name, S, Imm);
+            return RISCVOperand::createSysReg(
+                RISCVSysReg::getSysRegStr(Reg.Name), S, Imm);
         }
         // Accept an immediate representing an un-named Sys Reg if the range is
         // valid, regardless of the required features.
@@ -2072,7 +2073,7 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) {
           if (Reg.IsAltName || Reg.IsDeprecatedName)
             continue;
           Warning(S, "'" + Identifier + "' is a deprecated alias for '" +
-                         Reg.Name + "'");
+                         RISCVSysReg::getSysRegStr(Reg.Name) + "'");
         }
       }
 
@@ -2084,7 +2085,9 @@ ParseStatus RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) {
             llvm::find_if(AllFeatures, [&](const auto &Feature) {
               return SysReg->FeaturesRequired[Feature.Value];
             });
-        auto ErrorMsg = std::string("system register '") + SysReg->Name + "' ";
+        std::string ErrorMsg =
+            std::string("system register '") +
+            std::string(RISCVSysReg::getSysRegStr(SysReg->Name)) + "' ";
         if (SysReg->IsRV32Only && FeatureBits[RISCV::Feature64Bit]) {
           ErrorMsg += "is RV32 only";
           if (Feature != std::end(AllFeatures))
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index 2e50e4223f4a4..adf5d5d8b3759 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/MC/MCInstrDesc.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/TargetParser/RISCVTargetParser.h"
@@ -624,7 +625,7 @@ int getLoadFPImm(APFloat FPImm);
 
 namespace RISCVSysReg {
 struct SysReg {
-  const char Name[32];
+  StringTable::Offset Name;
   unsigned Encoding;
   // FIXME: add these additional fields when needed.
   // Privilege Access: Read, Write, Read-Only.
@@ -658,7 +659,7 @@ struct SysReg {
 
 namespace RISCVInsnOpcode {
 struct RISCVOpcode {
-  char Name[10];
+  StringTable::Offset Name;
   uint8_t Value;
 };
 
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
index 52c59d25a7ee9..475ffb44f4931 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
@@ -137,7 +137,7 @@ void RISCVInstPrinter::printCSRSystemRegister(const MCInst *MI, unsigned OpNo,
     if (Reg.IsAltName || Reg.IsDeprecatedName)
       continue;
     if (Reg.haveRequiredFeatures(STI.getFeatureBits())) {
-      markup(O, Markup::Register) << Reg.Name;
+      markup(O, Markup::Register) << RISCVSysReg::getSysRegStr(Reg.Name);
       return;
     }
   }
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 0971ae85a5634..c782445b4c1d3 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -18,6 +18,7 @@
 #include "RISCVFrameLowering.h"
 #include "RISCVISelLowering.h"
 #include "RISCVInstrInfo.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/CodeGen/GlobalISel/CallLowering.h"
 #include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h"
 #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
@@ -42,7 +43,7 @@ class StringRef;
 namespace RISCVTuneInfoTable {
 
 struct RISCVTuneInfo {
-  const char *Name;
+  StringTable::Offset Name;
   uint8_t PrefFunctionAlignment;
   uint8_t PrefLoopAlignment;
 
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
index 4daac32d84215..efad2df822812 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp
@@ -15,13 +15,14 @@
 #include "SPIRVBaseInfo.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringTable.h"
 
 namespace llvm {
 namespace SPIRV {
 struct SymbolicOperand {
   OperandCategory::OperandCategory Category;
   uint32_t Value;
-  StringRef Mnemonic;
+  StringTable::Offset Mnemonic;
   uint32_t MinVersion;
   uint32_t MaxVersion;
 };
@@ -69,7 +70,7 @@ getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category,
       SPIRV::lookupSymbolicOperandByCategoryAndValue(Category, Value);
   // Value that encodes just one enum value.
   if (Lookup)
-    return Lookup->Mnemonic.str();
+    return SPIRV::getSymbolicOperandStr(Lookup->Mnemonic).str();
   if (Category != SPIRV::OperandCategory::ImageOperandOperand &&
       Category != SPIRV::OperandCategory::FPFastMathModeOperand &&
       Category != SPIRV::OperandCategory::SelectionControlOperand &&
@@ -90,7 +91,8 @@ getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category,
   while (EnumValueInCategory && EnumValueInCategory->Category == Category) {
     if ((EnumValueInCategory->Value != 0) &&
         (Value & EnumValueInCategory->Value)) {
-      Name += Separator + EnumValueInCategory->Mnemonic.str();
+      Name += Separator +
+              SPIRV::getSymbolicOperandStr(EnumValueInCategory->Mnemonic).str();
       Separator = "|";
     }
     if (++EnumValueInCategory == TableEnd)
@@ -205,7 +207,8 @@ std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue) {
           SPIRV::OperandCategory::BuiltInOperand, BuiltInValue);
 
   if (Lookup)
-    return "__spirv_BuiltIn" + Lookup->Mnemonic.str();
+    return "__spirv_BuiltIn" +
+           SPIRV::getSymbolicOperandStr(Lookup->Mnemonic).str();
   return "UNKNOWN_BUILTIN";
 }
 
@@ -263,6 +266,6 @@ std::string getExtInstName(SPIRV::InstructionSet::InstructionSet Set,
   if (!Lookup)
     return "UNKNOWN_EXT_INST";
 
-  return Lookup->Name.str();
+  return SPIRV::getExtendedBuiltinStr(Lookup->Name).str();
 }
 } // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
index d57b38a5fa35c..160fcf8133920 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/Support/VersionTuple.h"
 #include <string>
 
@@ -239,7 +240,7 @@ namespace FPEncoding {
 } // namespace FPEncoding
 
 struct ExtendedBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   uint32_t Number;
 };
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 89683be4d5309..69c8c9f9818e3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -16,6 +16,7 @@
 #include "SPIRVSubtarget.h"
 #include "SPIRVUtils.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/IntrinsicsSPIRV.h"
 #include <regex>
@@ -30,11 +31,13 @@ namespace SPIRV {
 #include "SPIRVGenTables.inc"
 
 struct DemangledBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   BuiltinGroup Group;
   uint8_t MinNumArgs;
   uint8_t MaxNumArgs;
+
+  StringRef name() const;
 };
 
 #define GET_DemangledBuiltins_DECL
@@ -59,7 +62,7 @@ struct IncomingCall {
 };
 
 struct NativeBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   uint32_t Opcode;
 };
@@ -68,7 +71,7 @@ struct NativeBuiltin {
 #define GET_NativeBuiltins_IMPL
 
 struct GroupBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   uint32_t Opcode;
   uint32_t GroupOperation;
   bool IsElect;
@@ -87,7 +90,7 @@ struct GroupBuiltin {
 #define GET_GroupBuiltins_IMPL
 
 struct IntelSubgroupsBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   uint32_t Opcode;
   bool IsBlock;
   bool IsWrite;
@@ -98,14 +101,14 @@ struct IntelSubgroupsBuiltin {
 #define GET_IntelSubgroupsBuiltins_IMPL
 
 struct AtomicFloatingBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   uint32_t Opcode;
 };
 
 #define GET_AtomicFloatingBuiltins_DECL
 #define GET_AtomicFloatingBuiltins_IMPL
 struct GroupUniformBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   uint32_t Opcode;
   bool IsLogical;
 };
@@ -114,7 +117,7 @@ struct GroupUniformBuiltin {
 #define GET_GroupUniformBuiltins_IMPL
 
 struct GetBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   BuiltIn::BuiltIn Value;
 };
@@ -124,7 +127,7 @@ using namespace BuiltIn;
 #define GET_GetBuiltins_IMPL
 
 struct ImageQueryBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   uint32_t Component;
 };
@@ -133,7 +136,7 @@ struct ImageQueryBuiltin {
 #define GET_ImageQueryBuiltins_IMPL
 
 struct IntegerDotProductBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   uint32_t Opcode;
   bool IsSwapReq;
 };
@@ -142,7 +145,7 @@ struct IntegerDotProductBuiltin {
 #define GET_IntegerDotProductBuiltins_IMPL
 
 struct ConvertBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   bool IsDestinationSigned;
   bool IsSaturated;
@@ -153,7 +156,7 @@ struct ConvertBuiltin {
 };
 
 struct VectorLoadStoreBuiltin {
-  StringRef Name;
+  StringTable::Offset Name;
   InstructionSet::InstructionSet Set;
   uint32_t Number;
   uint32_t ElementCount;
@@ -174,6 +177,11 @@ using namespace InstructionSet;
 #define GET_CLMemoryFenceFlags_DECL
 #define GET_ExtendedBuiltins_DECL
 #include "SPIRVGenTables.inc"
+
+// Defined here to reference declarations from tablegen.
+StringRef DemangledBuiltin::name() const {
+  return getDemangledBuiltinStr(Name);
+}
 } // namespace SPIRV
 
 //===----------------------------------------------------------------------===//
@@ -719,7 +727,7 @@ static bool buildAtomicCompareExchangeInst(
     return buildOpFromWrapper(MIRBuilder, Opcode, Call,
                               GR->getSPIRVTypeID(Call->ReturnType));
 
-  bool IsCmpxchg = Call->Builtin->Name.contains("cmpxchg");
+  bool IsCmpxchg = Call->Builtin->name().contains("cmpxchg");
   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
 
   Register ObjectPtr = Call->Arguments[0];   // Pointer (volatile A *object.)
@@ -937,7 +945,7 @@ static bool buildBarrierInst(const SPIRV::IncomingCall *Call, unsigned Opcode,
   if ((Opcode == SPIRV::OpControlBarrierArriveINTEL ||
        Opcode == SPIRV::OpControlBarrierWaitINTEL) &&
       !ST->canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(Builtin->name()) +
                           ": the builtin requires the following SPIR-V "
                           "extension: SPV_INTEL_split_barrier";
     report_fatal_error(DiagMsg.c_str(), false);
@@ -1016,7 +1024,7 @@ static bool buildExtendedBitOpsInst(const SPIRV::IncomingCall *Call,
        Opcode == SPIRV::OpBitFieldSExtract ||
        Opcode == SPIRV::OpBitFieldUExtract || Opcode == SPIRV::OpBitReverse) &&
       !ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions)) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(Builtin->name()) +
                           ": the builtin requires the following SPIR-V "
                           "extension: SPV_KHR_bit_instructions";
     report_fatal_error(DiagMsg.c_str(), false);
@@ -1237,7 +1245,7 @@ static bool generateExtInst(const SPIRV::IncomingCall *Call,
   // Lookup the extended instruction number in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   uint32_t Number =
-      SPIRV::lookupExtendedBuiltin(Builtin->Name, Builtin->Set)->Number;
+      SPIRV::lookupExtendedBuiltin(Builtin->name(), Builtin->Set)->Number;
   // fmin_common and fmax_common are now deprecated, and we should use fmin and
   // fmax with NotInf and NotNaN flags instead. Keep original number to add
   // later the NoNans and NoInfs flags.
@@ -1317,7 +1325,7 @@ static bool generateRelationalInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   Register CompareRegister;
   SPIRVTypeInst RelationType = nullptr;
@@ -1365,7 +1373,7 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call,
                               SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   const SPIRV::GroupBuiltin *GroupBuiltin =
-      SPIRV::lookupGroupBuiltin(Builtin->Name);
+      SPIRV::lookupGroupBuiltin(Builtin->name());
 
   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
   if (Call->isSpirvOp()) {
@@ -1440,8 +1448,9 @@ static bool generateGroupInst(const SPIRV::IncomingCall *Call,
     std::tie(GroupResultRegister, GroupResultType) =
         buildBoolRegister(MIRBuilder, Call->ReturnType, GR);
 
-  auto Scope = Builtin->Name.starts_with("sub_group") ? SPIRV::Scope::Subgroup
-                                                      : SPIRV::Scope::Workgroup;
+  auto Scope = Builtin->name().starts_with("sub_group")
+                   ? SPIRV::Scope::Subgroup
+                   : SPIRV::Scope::Workgroup;
   Register ScopeRegister = buildConstantIntReg32(Scope, MIRBuilder, GR);
 
   Register VecReg;
@@ -1505,17 +1514,17 @@ static bool generateIntelSubgroupsInst(const SPIRV::IncomingCall *Call,
   MachineFunction &MF = MIRBuilder.getMF();
   const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget());
   const SPIRV::IntelSubgroupsBuiltin *IntelSubgroups =
-      SPIRV::lookupIntelSubgroupsBuiltin(Builtin->Name);
+      SPIRV::lookupIntelSubgroupsBuiltin(Builtin->name());
 
   if (IntelSubgroups->IsMedia &&
       !ST->canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(Builtin->name()) +
                           ": the builtin requires the following SPIR-V "
                           "extension: SPV_INTEL_media_block_io";
     report_fatal_error(DiagMsg.c_str(), false);
   } else if (!IntelSubgroups->IsMedia &&
              !ST->canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(Builtin->name()) +
                           ": the builtin requires the following SPIR-V "
                           "extension: SPV_INTEL_subgroups";
     report_fatal_error(DiagMsg.c_str(), false);
@@ -1580,13 +1589,13 @@ static bool generateGroupUniformInst(const SPIRV::IncomingCall *Call,
   const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget());
   if (!ST->canUseExtension(
           SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(Builtin->name()) +
                           ": the builtin requires the following SPIR-V "
                           "extension: SPV_KHR_uniform_group_instructions";
     report_fatal_error(DiagMsg.c_str(), false);
   }
   const SPIRV::GroupUniformBuiltin *GroupUniform =
-      SPIRV::lookupGroupUniformBuiltin(Builtin->Name);
+      SPIRV::lookupGroupUniformBuiltin(Builtin->name());
   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
 
   Register GroupResultReg = Call->ReturnRegister;
@@ -1623,7 +1632,7 @@ static bool generateKernelClockInst(const SPIRV::IncomingCall *Call,
   MachineFunction &MF = MIRBuilder.getMF();
   const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget());
   if (!ST->canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock)) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(Builtin->name()) +
                           ": the builtin requires the following SPIR-V "
                           "extension: SPV_KHR_shader_clock";
     report_fatal_error(DiagMsg.c_str(), false);
@@ -1631,7 +1640,7 @@ static bool generateKernelClockInst(const SPIRV::IncomingCall *Call,
 
   Register ResultReg = Call->ReturnRegister;
 
-  if (Builtin->Name == "__spirv_ReadClockKHR") {
+  if (Builtin->name() == "__spirv_ReadClockKHR") {
     MIRBuilder.buildInstr(SPIRV::OpReadClockKHR)
         .addDef(ResultReg)
         .addUse(GR->getSPIRVTypeID(Call->ReturnType))
@@ -1639,7 +1648,7 @@ static bool generateKernelClockInst(const SPIRV::IncomingCall *Call,
   } else {
     // Deduce the `Scope` operand from the builtin function name.
     SPIRV::Scope::Scope ScopeArg =
-        StringSwitch<SPIRV::Scope::Scope>(Builtin->Name)
+        StringSwitch<SPIRV::Scope::Scope>(Builtin->name())
             .EndsWith("device", SPIRV::Scope::Scope::Device)
             .EndsWith("work_group", SPIRV::Scope::Scope::Workgroup)
             .EndsWith("sub_group", SPIRV::Scope::Scope::Subgroup);
@@ -1784,7 +1793,7 @@ static bool generateBuiltinVar(const SPIRV::IncomingCall *Call,
   // Lookup the builtin variable record.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   SPIRV::BuiltIn::BuiltIn Value =
-      SPIRV::lookupGetBuiltin(Builtin->Name, Builtin->Set)->Value;
+      SPIRV::lookupGetBuiltin(Builtin->name(), Builtin->Set)->Value;
 
   if (Value == SPIRV::BuiltIn::GlobalInvocationId)
     return genWorkgroupQuery(Call, MIRBuilder, GR, Value, 0);
@@ -1808,7 +1817,7 @@ static bool generateAtomicInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   switch (Opcode) {
   case SPIRV::OpStore:
@@ -1850,7 +1859,7 @@ static bool generateAtomicFloatingInst(const SPIRV::IncomingCall *Call,
                                        SPIRVGlobalRegistry *GR) {
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
-  unsigned Opcode = SPIRV::lookupAtomicFloatingBuiltin(Builtin->Name)->Opcode;
+  unsigned Opcode = SPIRV::lookupAtomicFloatingBuiltin(Builtin->name())->Opcode;
 
   switch (Opcode) {
   case SPIRV::OpAtomicFAddEXT:
@@ -1868,7 +1877,7 @@ static bool generateBarrierInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return buildBarrierInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -1879,7 +1888,7 @@ static bool generateCastToPtrInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   if (Opcode == SPIRV::OpGenericCastToPtrExplicit) {
     SPIRV::StorageClass::StorageClass ResSC =
@@ -1921,7 +1930,7 @@ static bool generateDotOrFMulInst(const StringRef DemangledCall,
        ST->isAtLeastSPIRVVer(VersionTuple(1, 6)))) {
     const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
     const SPIRV::IntegerDotProductBuiltin *IntDot =
-        SPIRV::lookupIntegerDotProductBuiltin(Builtin->Name);
+        SPIRV::lookupIntegerDotProductBuiltin(Builtin->name());
     if (IntDot) {
       OC = IntDot->Opcode;
       IsSwapReq = IntDot->IsSwapReq;
@@ -1986,7 +1995,7 @@ static bool generateWaveInst(const SPIRV::IncomingCall *Call,
                              SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   SPIRV::BuiltIn::BuiltIn Value =
-      SPIRV::lookupGetBuiltin(Builtin->Name, Builtin->Set)->Value;
+      SPIRV::lookupGetBuiltin(Builtin->name(), Builtin->Set)->Value;
 
   // For now, we only support a single Wave intrinsic with a single return type.
   assert(Call->ReturnType->getOpcode() == SPIRV::OpTypeInt);
@@ -2030,7 +2039,7 @@ static bool generateICarryBorrowInst(const SPIRV::IncomingCall *Call,
                                      SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   Register SRetReg = Call->Arguments[0];
   SPIRVTypeInst PtrRetType = GR->getSPIRVTypeForVReg(SRetReg);
@@ -2077,7 +2086,7 @@ static bool generateMulExtendedInst(const SPIRV::IncomingCall *Call,
                                     SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
   assert((Opcode == SPIRV::OpUMulExtended || Opcode == SPIRV::OpSMulExtended) &&
          "Expected OpUMulExtended or OpSMulExtended");
 
@@ -2141,7 +2150,7 @@ static bool generateArithmeticInst(const SPIRV::IncomingCall *Call,
                                    SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   auto MIB = MIRBuilder.buildInstr(Opcode)
                  .addDef(Call->ReturnRegister)
@@ -2156,7 +2165,7 @@ static bool generateGetQueryInst(const SPIRV::IncomingCall *Call,
                                  SPIRVGlobalRegistry *GR) {
   // Lookup the builtin record.
   SPIRV::BuiltIn::BuiltIn Value =
-      SPIRV::lookupGetBuiltin(Call->Builtin->Name, Call->Builtin->Set)->Value;
+      SPIRV::lookupGetBuiltin(Call->Builtin->name(), Call->Builtin->Set)->Value;
   const bool IsDefaultOne = (Value == SPIRV::BuiltIn::GlobalSize ||
                              Value == SPIRV::BuiltIn::NumWorkgroups ||
                              Value == SPIRV::BuiltIn::WorkgroupSize ||
@@ -2170,7 +2179,7 @@ static bool generateImageSizeQueryInst(const SPIRV::IncomingCall *Call,
   // Lookup the image size query component number in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   uint32_t Component =
-      SPIRV::lookupImageQueryBuiltin(Builtin->Name, Builtin->Set)->Component;
+      SPIRV::lookupImageQueryBuiltin(Builtin->name(), Builtin->Set)->Component;
   // Query result may either be a vector or a scalar. If return type is not a
   // vector, expect only a single size component. Otherwise get the number of
   // expected components.
@@ -2252,7 +2261,7 @@ static bool generateImageMiscQueryInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   Register Image = Call->Arguments[0];
   SPIRV::Dim::Dim ImageDimensionality = static_cast<SPIRV::Dim::Dim>(
@@ -2412,7 +2421,7 @@ static bool generateSampleImageInst(const StringRef DemangledCall,
                                     MachineIRBuilder &MIRBuilder,
                                     SPIRVGlobalRegistry *GR) {
   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
-  if (Call->Builtin->Name.contains_insensitive(
+  if (Call->Builtin->name().contains_insensitive(
           "__translate_sampler_initializer")) {
     // Build sampler literal.
     uint64_t Bitmask = getIConstVal(Call->Arguments[0], MRI);
@@ -2421,7 +2430,8 @@ static bool generateSampleImageInst(const StringRef DemangledCall,
         getSamplerParamFromBitmask(Bitmask),
         getSamplerFilterModeFromBitmask(Bitmask), MIRBuilder);
     return Sampler.isValid();
-  } else if (Call->Builtin->Name.contains_insensitive("__spirv_SampledImage")) {
+  } else if (Call->Builtin->name().contains_insensitive(
+                 "__spirv_SampledImage")) {
     // Create OpSampledImage.
     Register Image = Call->Arguments[0];
     SPIRVTypeInst ImageType = GR->getSPIRVTypeForVReg(Image);
@@ -2437,7 +2447,7 @@ static bool generateSampleImageInst(const StringRef DemangledCall,
         .addUse(Image)
         .addUse(Call->Arguments[1]); // Sampler.
     return true;
-  } else if (Call->Builtin->Name.contains_insensitive(
+  } else if (Call->Builtin->name().contains_insensitive(
                  "__spirv_ImageSampleExplicitLod")) {
     // Sample an image using an explicit level of detail.
     std::string ReturnType = DemangledCall.str();
@@ -2494,7 +2504,7 @@ static bool generateCoopMatrInst(const SPIRV::IncomingCall *Call,
                                  SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
   bool IsSet = Opcode != SPIRV::OpCooperativeMatrixStoreKHR &&
                Opcode != SPIRV::OpCooperativeMatrixStoreCheckedINTEL &&
                Opcode != SPIRV::OpCooperativeMatrixPrefetchINTEL;
@@ -2561,7 +2571,7 @@ static bool generateSpecConstantInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
   const MachineRegisterInfo *MRI = MIRBuilder.getMRI();
 
   switch (Opcode) {
@@ -2616,7 +2626,7 @@ static bool generateExtendedBitOpsInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return buildExtendedBitOpsInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -2627,7 +2637,7 @@ static bool generateBindlessImageINTELInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return buildBindlessImageINTELInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -2637,7 +2647,7 @@ static bool generateBlockingPipesInst(const SPIRV::IncomingCall *Call,
                                       SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
   return buildOpFromWrapper(MIRBuilder, Opcode, Call, Register(0));
 }
 
@@ -2707,7 +2717,7 @@ static bool generateAPFixedPointInst(const SPIRV::IncomingCall *Call,
                                      SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return buildAPFixedPointInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -2719,7 +2729,7 @@ generateTernaryBitwiseFunctionINTELInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return buildTernaryBitwiseFunctionINTELInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -2729,7 +2739,7 @@ static bool generateImageChannelDataTypeInst(const SPIRV::IncomingCall *Call,
                                              SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return buildImageChannelDataTypeInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -2740,7 +2750,7 @@ static bool generate2DBlockIOINTELInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   return build2DBlockIOINTELInst(Call, Opcode, MIRBuilder, GR);
 }
@@ -2750,10 +2760,10 @@ static bool generatePipeInst(const SPIRV::IncomingCall *Call,
                              SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   unsigned Scope = SPIRV::Scope::Workgroup;
-  if (Builtin->Name.contains("sub_group"))
+  if (Builtin->name().contains("sub_group"))
     Scope = SPIRV::Scope::Subgroup;
 
   return buildPipeInst(Call, Opcode, Scope, MIRBuilder, GR);
@@ -2764,7 +2774,7 @@ static bool generatePredicatedLoadStoreInst(const SPIRV::IncomingCall *Call,
                                             SPIRVGlobalRegistry *GR) {
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   bool IsSet = Opcode != SPIRV::OpPredicatedStoreINTEL;
   unsigned ArgSz = Call->Arguments.size();
@@ -2831,7 +2841,7 @@ static bool buildNDRange(const SPIRV::IncomingCall *Call,
   // The dimension is encoded in the function name as "ndrange_XD" where X is
   // 1, 2, or 3.
   unsigned Dimension = 0;
-  Call->Builtin->Name.substr(8, 1).getAsInteger(10, Dimension);
+  Call->Builtin->name().substr(8, 1).getAsInteger(10, Dimension);
   assert(Dimension <= 3 && Dimension >= 1);
 
   // Determine the work size type based on the dimension. For missing arguments,
@@ -2948,8 +2958,8 @@ static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call,
   // We also may expect __spirv_EnqueueKernel
 
   bool IsSpirvOp = Call->isSpirvOp();
-  bool HasEvents = Call->Builtin->Name.contains("_events") || IsSpirvOp;
-  bool HasVarArgs = Call->Builtin->Name.contains("_varargs") || IsSpirvOp;
+  bool HasEvents = Call->Builtin->name().contains("_events") || IsSpirvOp;
+  bool HasVarArgs = Call->Builtin->name().contains("_varargs") || IsSpirvOp;
 
   const unsigned NumArgs = Call->Arguments.size();
   const unsigned BaseArgIdx = 0;
@@ -3091,7 +3101,7 @@ static bool generateEnqueueInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   switch (Opcode) {
   case SPIRV::OpRetainEvent:
@@ -3131,7 +3141,7 @@ static bool generateAsyncCopy(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
 
   bool IsSet = Opcode == SPIRV::OpGroupAsyncCopy;
   Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType);
@@ -3182,12 +3192,12 @@ static bool generateConvertInst(const StringRef DemangledCall,
                                 SPIRVGlobalRegistry *GR) {
   // Lookup the conversion builtin in the TableGen records.
   const SPIRV::ConvertBuiltin *Builtin =
-      SPIRV::lookupConvertBuiltin(Call->Builtin->Name, Call->Builtin->Set);
+      SPIRV::lookupConvertBuiltin(Call->Builtin->name(), Call->Builtin->Set);
 
   if (!Builtin && Call->isSpirvOp()) {
     const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
     unsigned Opcode =
-        SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+        SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
     return buildOpFromWrapper(MIRBuilder, Opcode, Call,
                               GR->getSPIRVTypeID(Call->ReturnType));
   }
@@ -3281,8 +3291,9 @@ static bool generateConvertInst(const StringRef DemangledCall,
     }
   }
 
+  StringRef BuiltinName = SPIRV::getConvertBuiltinStr(Builtin->Name);
   if (!NeedExtMsg.empty()) {
-    std::string DiagMsg = std::string(Builtin->Name) +
+    std::string DiagMsg = std::string(BuiltinName) +
                           ": the builtin requires the following SPIR-V "
                           "extension: " +
                           NeedExtMsg;
@@ -3290,7 +3301,7 @@ static bool generateConvertInst(const StringRef DemangledCall,
   }
   if (!IsRightComponentsNumber) {
     std::string DiagMsg =
-        std::string(Builtin->Name) +
+        std::string(BuiltinName) +
         ": result and argument must have the same number of components";
     report_fatal_error(DiagMsg.c_str(), false);
   }
@@ -3309,7 +3320,7 @@ static bool generateVectorLoadStoreInst(const SPIRV::IncomingCall *Call,
                                         SPIRVGlobalRegistry *GR) {
   // Lookup the vector load/store builtin in the TableGen records.
   const SPIRV::VectorLoadStoreBuiltin *Builtin =
-      SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->Name,
+      SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->name(),
                                           Call->Builtin->Set);
   // Build extended instruction.
   auto MIB =
@@ -3320,7 +3331,8 @@ static bool generateVectorLoadStoreInst(const SPIRV::IncomingCall *Call,
           .addImm(Builtin->Number);
   for (auto Argument : Call->Arguments)
     MIB.addUse(Argument);
-  if (Builtin->Name.contains("load") && Builtin->ElementCount > 1)
+  StringRef BuiltinName = SPIRV::getVectorLoadStoreBuiltinStr(Builtin->Name);
+  if (BuiltinName.contains("load") && Builtin->ElementCount > 1)
     MIB.addImm(Builtin->ElementCount);
 
   // Rounding mode should be passed as a last argument in the MI for builtins
@@ -3336,7 +3348,7 @@ static bool generateAFPInst(const SPIRV::IncomingCall *Call,
   const auto *Builtin = Call->Builtin;
   auto *MRI = MIRBuilder.getMRI();
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
   const Type *RetTy = GR->getTypeForSPIRVType(Call->ReturnType);
   bool IsVoid = RetTy->isVoidTy();
   auto MIB = MIRBuilder.buildInstr(Opcode);
@@ -3379,7 +3391,7 @@ static bool generateLoadStoreInst(const SPIRV::IncomingCall *Call,
   // Lookup the instruction opcode in the TableGen records.
   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
   unsigned Opcode =
-      SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+      SPIRV::lookupNativeBuiltin(Builtin->name(), Builtin->Set)->Opcode;
   bool IsLoad = Opcode == SPIRV::OpLoad;
   // Build the instruction.
   auto MIB = MIRBuilder.buildInstr(Opcode);
@@ -3432,39 +3444,41 @@ mapBuiltinToOpcode(const StringRef DemangledCall,
   case SPIRV::LoadStore:
   case SPIRV::CoopMatr:
   case SPIRV::Arithmetic:
-    if (const auto *R =
-            SPIRV::lookupNativeBuiltin(Call->Builtin->Name, Call->Builtin->Set))
+    if (const auto *R = SPIRV::lookupNativeBuiltin(Call->Builtin->name(),
+                                                   Call->Builtin->Set))
       return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
     break;
   case SPIRV::Extended:
-    if (const auto *R = SPIRV::lookupExtendedBuiltin(Call->Builtin->Name,
+    if (const auto *R = SPIRV::lookupExtendedBuiltin(Call->Builtin->name(),
                                                      Call->Builtin->Set))
       return std::make_tuple(Call->Builtin->Group, 0, R->Number);
     break;
   case SPIRV::VectorLoadStore:
-    if (const auto *R = SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->Name,
-                                                            Call->Builtin->Set))
+    if (const auto *R = SPIRV::lookupVectorLoadStoreBuiltin(
+            Call->Builtin->name(), Call->Builtin->Set))
       return std::make_tuple(SPIRV::Extended, 0, R->Number);
     break;
   case SPIRV::Group:
-    if (const auto *R = SPIRV::lookupGroupBuiltin(Call->Builtin->Name))
+    if (const auto *R = SPIRV::lookupGroupBuiltin(Call->Builtin->name()))
       return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
     break;
   case SPIRV::AtomicFloating:
-    if (const auto *R = SPIRV::lookupAtomicFloatingBuiltin(Call->Builtin->Name))
+    if (const auto *R =
+            SPIRV::lookupAtomicFloatingBuiltin(Call->Builtin->name()))
       return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
     break;
   case SPIRV::IntelSubgroups:
-    if (const auto *R = SPIRV::lookupIntelSubgroupsBuiltin(Call->Builtin->Name))
+    if (const auto *R =
+            SPIRV::lookupIntelSubgroupsBuiltin(Call->Builtin->name()))
       return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
     break;
   case SPIRV::GroupUniform:
-    if (const auto *R = SPIRV::lookupGroupUniformBuiltin(Call->Builtin->Name))
+    if (const auto *R = SPIRV::lookupGroupUniformBuiltin(Call->Builtin->name()))
       return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
     break;
   case SPIRV::IntegerDot:
     if (const auto *R =
-            SPIRV::lookupIntegerDotProductBuiltin(Call->Builtin->Name))
+            SPIRV::lookupIntegerDotProductBuiltin(Call->Builtin->name()))
       return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
     break;
   case SPIRV::WriteImage:
@@ -3675,7 +3689,7 @@ Type *parseBuiltinCallArgumentBaseType(const StringRef DemangledCall,
 }
 
 struct BuiltinType {
-  StringRef Name;
+  StringTable::Offset Name;
   uint32_t Opcode;
 };
 
@@ -3683,8 +3697,8 @@ struct BuiltinType {
 #define GET_BuiltinTypes_IMPL
 
 struct OpenCLType {
-  StringRef Name;
-  StringRef SpirvTypeLiteral;
+  StringTable::Offset Name;
+  StringTable::Offset SpirvTypeLiteral;
 };
 
 #define GET_OpenCLTypes_DECL
@@ -3866,7 +3880,8 @@ TargetExtType *parseBuiltinTypeNameToTargetExtType(std::string TypeName,
     if (!OCLTypeRecord)
       report_fatal_error("Missing TableGen record for OpenCL type: " +
                          NameWithParameters);
-    NameWithParameters = OCLTypeRecord->SpirvTypeLiteral;
+    NameWithParameters =
+        SPIRV::getOpenCLTypeStr(OCLTypeRecord->SpirvTypeLiteral);
     // Continue with the SPIR-V builtin type...
   }
 
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
index b6d34c6e61bb7..77d74f06ea5da 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp
@@ -248,7 +248,7 @@ void SparcInstPrinter::printASITag(const MCInst *MI, int opNum,
   unsigned Imm = MI->getOperand(opNum).getImm();
   auto ASITag = SparcASITag::lookupASITagByEncoding(Imm);
   if (isV9(STI) && ASITag)
-    O << '#' << ASITag->Name;
+    O << '#' << SparcASITag::getASITagStr(ASITag->Name);
   else
     O << Imm;
 }
@@ -259,7 +259,7 @@ void SparcInstPrinter::printPrefetchTag(const MCInst *MI, int opNum,
   unsigned Imm = MI->getOperand(opNum).getImm();
   auto PrefetchTag = SparcPrefetchTag::lookupPrefetchTagByEncoding(Imm);
   if (PrefetchTag)
-    O << '#' << PrefetchTag->Name;
+    O << '#' << SparcPrefetchTag::getPrefetchTagStr(PrefetchTag->Name);
   else
     O << Imm;
 }
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
index b523366e6adaa..4b4742214303e 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
@@ -14,6 +14,7 @@
 #define LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCTARGETDESC_H
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/Support/DataTypes.h"
 
 #include <memory>
@@ -41,8 +42,8 @@ createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI);
 // Defines symbolic names for Sparc v9 ASI tag names.
 namespace SparcASITag {
 struct ASITag {
-  const char *Name;
-  const char *AltName;
+  StringTable::Offset Name;
+  StringTable::Offset AltName;
   unsigned Encoding;
 };
 
@@ -53,7 +54,7 @@ struct ASITag {
 // Defines symbolic names for Sparc v9 prefetch tag names.
 namespace SparcPrefetchTag {
 struct PrefetchTag {
-  const char *Name;
+  StringTable::Offset Name;
   unsigned Encoding;
 };
 
diff --git a/llvm/test/TableGen/generic-tables-return-range.td b/llvm/test/TableGen/generic-tables-return-range.td
index 5b3c0509c2eb7..86a5ad542d9b7 100644
--- a/llvm/test/TableGen/generic-tables-return-range.td
+++ b/llvm/test/TableGen/generic-tables-return-range.td
@@ -29,12 +29,13 @@ def : SysReg<"csr2", 0x7C0>;
 
 // CHECK: #ifdef GET_List1_DECL
 // CHECK-NEXT: llvm::iterator_range<const SysReg *> lookupSysRegByEncoding(uint16_t Encoding);
+// CHECK-NEXT: StringRef getSysRegStr(StringTable::Offset);
 // CHECK-NEXT: #endif
 
 // CHECK: #ifdef GET_List1_IMPL
 // CHECK-NEXT: constexpr SysReg List1[] = {
-// CHECK-NEXT:   { "csr1", 0x7C0,  {Feature1}  }, // 0
-// CHECK-NEXT:   { "csr2", 0x7C0,  {Feature2}  }, // 1
+// CHECK-NEXT:   { {{[0-9]+}} /* "csr1" */, 0x7C0,  {Feature1}  }, // 0
+// CHECK-NEXT:   { {{[0-9]+}} /* "csr2" */, 0x7C0,  {Feature2}  }, // 1
 // CHECK-NEXT:  };
 
 // CHECK: llvm::iterator_range<const SysReg *> lookupSysRegByEncoding(uint16_t Encoding) {
diff --git a/llvm/test/TableGen/generic-tables.td b/llvm/test/TableGen/generic-tables.td
index ca29dcff75c0e..82c74cfc26b3b 100644
--- a/llvm/test/TableGen/generic-tables.td
+++ b/llvm/test/TableGen/generic-tables.td
@@ -24,11 +24,11 @@ include "llvm/TableGen/SearchableTable.td"
 
 // CHECK-LABEL: GET_ATable_IMPL
 // CHECK: constexpr AEntry ATable[] = {
-// CHECK-NOT:   { "aaa"
-// CHECK:       { "baz", 0x2, 0x6, 0xFFFFFFFF00000000 },
-// CHECK:       { "foo", 0x4, 0x4, 0x100000000 },
-// CHECK:       { "foobar", 0x4, 0x5, 0x100000000 },
-// CHECK:       { "bar", 0x5, 0x3, 0x100000000 },
+// CHECK-NOT:   "aaa"
+// CHECK:       { {{[0-9]+}} /* "baz" */, 0x2, 0x6, 0xFFFFFFFF00000000 },
+// CHECK:       { {{[0-9]+}} /* "foo" */, 0x4, 0x4, 0x100000000 },
+// CHECK:       { {{[0-9]+}} /* "foobar" */, 0x4, 0x5, 0x100000000 },
+// CHECK:       { {{[0-9]+}} /* "bar" */, 0x5, 0x3, 0x100000000 },
 // CHECK: };
 
 // CHECK: const AEntry *lookupATableByValues(uint8_t Val1, uint16_t Val2) {
@@ -61,10 +61,10 @@ def ATable : GenericTable {
 
 // CHECK-LABEL: GET_BTable_IMPL
 // CHECK: constexpr BTypeName BTable[] = {
-// CHECK:   { "BAlice", 0xAC, false,  },
-// CHECK:   { "BBob", 0x14, false, Bob == 13 },
-// CHECK:   { "BCharlie", 0x80, true, Charlie == 42 },
-// CHECK:   { "BEve", 0x4C, true, Eve == 108 },
+// CHECK:   { {{[0-9]+}} /* "BAlice" */, 0xAC, false,  },
+// CHECK:   { {{[0-9]+}} /* "BBob" */, 0x14, false, Bob == 13 },
+// CHECK:   { {{[0-9]+}} /* "BCharlie" */, 0x80, true, Charlie == 42 },
+// CHECK:   { {{[0-9]+}} /* "BEve" */, 0x4C, true, Eve == 108 },
 // CHECK:  };
 // CHECK: const BTypeName *lookupBTableByName(StringRef Name) {
 // CHECK:   return &BTable[Idx->_index];
@@ -118,9 +118,9 @@ def lookupBTableByNameAndFlag : SearchIndex {
 
 // CHECK: const CEntry *lookupCEntry(StringRef Name, unsigned Kind) {
 // CHECK: Index[] = {
-// CHECK:   { "ALICE", CBar, 1 },
-// CHECK:   { "ALICE", CFoo, 0 },
-// CHECK:   { "BOB", CBaz, 2 },
+// CHECK:   { {{[0-9]+}} /* "ALICE" */, CBar, 1 },
+// CHECK:   { {{[0-9]+}} /* "ALICE" */, CFoo, 0 },
+// CHECK:   { {{[0-9]+}} /* "BOB" */, CBaz, 2 },
 
 class CEnum;
 
diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index e100682bbcec3..5646d0512563f 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -22,6 +22,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringToOffsetTable.h"
 #include "llvm/TableGen/TableGenBackend.h"
 #include <set>
 #include <string>
@@ -172,7 +173,7 @@ class SearchableTableEmitter {
                                   const GenericField &Field, TypeContext Ctx) {
     if (isa<StringRecTy>(Field.RecType)) {
       if (Ctx == TypeInStaticStruct)
-        return "const char *";
+        return "unsigned";
       if (Ctx == TypeInTempStruct)
         return "std::string";
       return "StringRef";
@@ -207,7 +208,8 @@ class SearchableTableEmitter {
   void emitLookupDeclaration(const GenericTable &Table,
                              const SearchIndex &Index, raw_ostream &OS);
   void emitLookupFunction(const GenericTable &Table, const SearchIndex &Index,
-                          bool IsPrimary, raw_ostream &OS);
+                          bool IsPrimary, StringToOffsetTable &StrTab,
+                          raw_ostream &OS);
   void emitIfdef(StringRef Guard, raw_ostream &OS);
 
   bool parseFieldType(GenericField &Field, const Init *II);
@@ -352,6 +354,7 @@ void SearchableTableEmitter::emitGenericEnum(const GenericEnum &Enum,
 void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
                                                 const SearchIndex &Index,
                                                 bool IsPrimary,
+                                                StringToOffsetTable &StrTab,
                                                 raw_ostream &OS) {
   OS << "\n";
   emitLookupDeclaration(Table, Index, OS);
@@ -396,11 +399,20 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
       OS << "    { ";
       ListSeparator LS;
       for (const auto &Field : Index.Fields) {
-        std::string Repr = primaryRepresentation(
-            Index.Loc, Field, EntryRec->getValueInit(Field.Name));
+        const Init *Value = EntryRec->getValueInit(Field.Name);
+        std::string Repr = primaryRepresentation(Index.Loc, Field, Value);
         if (isa<StringRecTy>(Field.RecType))
           Repr = StringRef(Repr).upper();
-        OS << LS << Repr;
+        if (isa<StringRecTy>(Field.RecType)) {
+          // TODO: if most strings are lower-case already, we can save space by
+          // converting all strings to lower case instead.
+          OS << LS
+             << StrTab.GetOrAddStringOffset(
+                    StringRef(Value->getAsUnquotedString()).upper())
+             << " /* " << Repr << " */";
+        } else {
+          OS << LS << Repr;
+        }
       }
       OS << ", " << EntryIndex << " },\n";
     }
@@ -479,11 +491,20 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
   OS << "    bool operator()(const " << IndexTypeName
      << " &LHS, const KeyType &RHS) const {\n";
 
-  auto emitComparator = [&]() {
+  auto emitComparator = [&](bool LHSIsKey, bool RHSIsKey) {
     for (const auto &Field : Index.Fields) {
       if (isa<StringRecTy>(Field.RecType)) {
-        OS << "      int Cmp" << Field.Name << " = StringRef(LHS." << Field.Name
-           << ").compare(RHS." << Field.Name << ");\n";
+        if (LHSIsKey)
+          OS << "      StringRef LHSStr = LHS." << Field.Name << ";\n";
+        else
+          OS << "      StringRef LHSStr = " << Table.Name << "Strings[LHS."
+             << Field.Name << "];\n";
+        if (RHSIsKey)
+          OS << "      StringRef RHSStr = RHS." << Field.Name << ";\n";
+        else
+          OS << "      StringRef RHSStr = " << Table.Name << "Strings[RHS."
+             << Field.Name << "];\n";
+        OS << "      int Cmp" << Field.Name << " = LHSStr.compare(RHSStr);\n";
         OS << "      if (Cmp" << Field.Name << " < 0) return true;\n";
         OS << "      if (Cmp" << Field.Name << " > 0) return false;\n";
       } else if (Field.Enum) {
@@ -507,12 +528,12 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
     OS << "      return false;\n";
     OS << "    }\n";
   };
-  emitComparator();
+  emitComparator(false, true);
   bool ShouldReturnRange = Index.ReturnRange;
   if (ShouldReturnRange) {
     OS << "    bool operator()(const KeyType &LHS, const " << IndexTypeName
        << " &RHS) const {\n";
-    emitComparator();
+    emitComparator(true, false);
   }
 
   OS << "  };\n";
@@ -525,8 +546,13 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
 
   if (!ShouldReturnRange) {
     OS << "  if (Idx == Table.end()";
-    for (const auto &Field : Index.Fields)
-      OS << " ||\n      Key." << Field.Name << " != Idx->" << Field.Name;
+    for (const auto &Field : Index.Fields) {
+      OS << " ||\n      Key." << Field.Name << " != ";
+      if (isa<StringRecTy>(Field.RecType))
+        OS << Table.Name << "Strings[Idx->" << Field.Name << "]";
+      else
+        OS << "Idx->" << Field.Name;
+    }
   }
 
   if (ShouldReturnRange) {
@@ -571,31 +597,62 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
     OS << ";\n";
   }
 
+  bool HasStrings = false;
+  for (const auto &Field : Table.Fields)
+    HasStrings |= isa<StringRecTy>(Field.RecType);
+  if (HasStrings)
+    OS << "StringRef get" << Table.CppTypeName << "Str(StringTable::Offset);\n";
+
   OS << "#endif\n\n";
 
   emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL").str(), OS);
 
+  StringToOffsetTable StrTab;
+
   // The primary data table contains all the fields defined for this map.
   OS << "constexpr " << Table.CppTypeName << " " << Table.Name << "[] = {\n";
   for (const auto &[Idx, Entry] : enumerate(Table.Entries)) {
     OS << "  { ";
 
     ListSeparator LS;
-    for (const auto &Field : Table.Fields)
-      OS << LS
-         << primaryRepresentation(Table.Locs[0], Field,
-                                  Entry->getValueInit(Field.Name));
+    for (const auto &Field : Table.Fields) {
+      OS << LS;
+      const Init *Value = Entry->getValueInit(Field.Name);
+      if (const auto *SI = dyn_cast<StringInit>(Value);
+          SI && !Field.IsCode && !SI->hasCodeFormat()) {
+        OS << StrTab.GetOrAddStringOffset(Value->getAsUnquotedString())
+           << " /* " << primaryRepresentation(Table.Locs[0], Field, Value)
+           << " */";
+      } else {
+        OS << primaryRepresentation(Table.Locs[0], Field, Value);
+      }
+    }
 
     OS << " }, // " << Idx << "\n";
   }
   OS << " };\n";
 
+  // Emit into string first so we can put the string table before the function.
+  // The lookup function might add more strings.
+  std::string LookupFunction;
+  raw_string_ostream LFOS(LookupFunction);
   // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary
   // search can be performed by "Thing".
   if (Table.PrimaryKey)
-    emitLookupFunction(Table, *Table.PrimaryKey, /*IsPrimary=*/true, OS);
+    emitLookupFunction(Table, *Table.PrimaryKey, /*IsPrimary=*/true, StrTab,
+                       LFOS);
   for (const auto &Index : Table.Indices)
-    emitLookupFunction(Table, *Index, /*IsPrimary=*/false, OS);
+    emitLookupFunction(Table, *Index, /*IsPrimary=*/false, StrTab, LFOS);
+
+  if (HasStrings) {
+    StrTab.EmitStringTableDef(OS, Table.Name + Twine("Strings"));
+    OS << "\nStringRef get" << Table.CppTypeName
+       << "Str(StringTable::Offset Offset) {\n";
+    OS << "  return " << Table.Name << "Strings[Offset];\n";
+    OS << "}\n";
+  }
+
+  OS << LookupFunction;
 
   OS << "#endif\n\n";
 }

>From 2fa14779dfd73e56f3f79075172fabad7690c1a4 Mon Sep 17 00:00:00 2001
From: Alexis Engelke <engelke at in.tum.de>
Date: Sun, 28 Jun 2026 05:32:01 +0000
Subject: [PATCH 2/2] feedback

Created using spr 1.3.8-wip
---
 llvm/utils/TableGen/SearchableTableEmitter.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index 5646d0512563f..b4558e16d6809 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -401,15 +401,16 @@ void SearchableTableEmitter::emitLookupFunction(const GenericTable &Table,
       for (const auto &Field : Index.Fields) {
         const Init *Value = EntryRec->getValueInit(Field.Name);
         std::string Repr = primaryRepresentation(Index.Loc, Field, Value);
-        if (isa<StringRecTy>(Field.RecType))
-          Repr = StringRef(Repr).upper();
         if (isa<StringRecTy>(Field.RecType)) {
           // TODO: if most strings are lower-case already, we can save space by
-          // converting all strings to lower case instead.
+          // converting all strings to lower case instead. If strings are not
+          // already all-uppercase, we currently store them twice -- but if most
+          // strings are all-lowercase, we can use the lowercase variant for
+          // case-insenstive comparison.
           OS << LS
              << StrTab.GetOrAddStringOffset(
                     StringRef(Value->getAsUnquotedString()).upper())
-             << " /* " << Repr << " */";
+             << " /* " << StringRef(Repr).upper() << " */";
         } else {
           OS << LS << Repr;
         }



More information about the llvm-commits mailing list