[llvm] [TableGen] Rework `EmitIntrinsicToBuiltinMap` (PR #104681)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 10:57:58 PDT 2024


================
@@ -615,70 +617,171 @@ void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(
       PrintFatalError(Int.TheDef->getLoc(),
                       "Intrinsic '" + Int.TheDef->getName() + "': duplicate " +
                           CompilerName + " builtin name!");
-    Table.GetOrAddStringOffset(BuiltinName);
-  }
 
-  OS << "// Get the LLVM intrinsic that corresponds to a builtin.\n";
-  OS << "// This is used by the C front-end.  The builtin name is passed\n";
-  OS << "// in as BuiltinName, and a target prefix (e.g. 'ppc') is passed\n";
-  OS << "// in as TargetPrefix. The result is assigned to 'IntrinsicID'.\n";
-  OS << "#ifdef GET_LLVM_INTRINSIC_FOR_" << UpperCompilerName << "_BUILTIN\n";
+    OldTable.GetOrAddStringOffset(BuiltinName);
+  }
 
-  OS << "Intrinsic::ID Intrinsic::getIntrinsicFor" << CompilerName
-     << "Builtin(const char "
-     << "*TargetPrefixStr, StringRef BuiltinNameStr) {\n";
+  // For each target, determine the common prefix for all the builtins for that
+  // target. Populate the string table with the names of all the builtins after
+  // removing this common prefix.
+  DenseMap<StringRef, StringRef> CommonPrefixMap;
+  StringToOffsetTable Table;
+  for (const auto &[TargetPrefix, Map] : BuiltinMap) {
+    // The Map is guaranteed to be non-empty here.
+    StringRef CommonPrefix = Map.begin()->first;
+    for (auto &[BuiltinName, EnumName] : Map) {
+      // Update the common prefix.
+      const char *Mismatch = mismatch(CommonPrefix, BuiltinName).first;
+      CommonPrefix = CommonPrefix.take_front(Mismatch - CommonPrefix.begin());
+      if (CommonPrefix.empty())
+        break;
+    }
+    CommonPrefixMap[TargetPrefix] = CommonPrefix;
+    for (auto &[BuiltinName, EnumName] : Map) {
+      StringRef Suffix = BuiltinName.substr(CommonPrefix.size());
+      if (!Suffix.empty())
+        Table.GetOrAddStringOffset(Suffix);
+    }
+  }
 
-  if (Table.Empty()) {
-    OS << "  return Intrinsic::not_intrinsic;\n";
-    OS << "}\n";
-    OS << "#endif\n\n";
+  std::string PreprocessorGuard =
+      "GET_LLVM_INTRINSIC_FOR_" + CompilerName.upper() + "_BUILTIN";
+
+  OS << formatv(R"(
+// Get the LLVM intrinsic that corresponds to a builtin. This is used by the
+// C front-end. The builtin name is passed in as BuiltinName, and a target
+// prefix (e.g. 'ppc') is passed in as TargetPrefix.
+#ifdef {0}
+
+Intrinsic::ID
+Intrinsic::getIntrinsicFor{1}Builtin(StringRef TargetPrefix, 
+                                      StringRef BuiltinName) {{
+  using namespace Intrinsic;
+)",
+                PreprocessorGuard, CompilerName);
+
+  if (BuiltinMap.empty()) {
+    OS << formatv(R"(
+  return not_intrinsic;
+  }
+#endif  // {0}
+)",
+                  PreprocessorGuard);
     return;
   }
 
-  OS << "  static constexpr char BuiltinNames[] = {\n";
-  Table.EmitCharArray(OS);
-  OS << "  };\n\n";
+  if (!Table.empty()) {
+    OS << "  static constexpr char BuiltinNames[] = {\n";
+    Table.EmitCharArray(OS);
+    OS << "  };\n\n";
+
+    OS << R"(
+  struct BuiltinEntry {
+    ID IntrinsicID;
+    unsigned StrTabOffset;
+    const char *getName() const { return &BuiltinNames[StrTabOffset]; }
+     bool operator<(StringRef RHS) const {
+       return strncmp(getName(), RHS.data(), RHS.size()) < 0;
----------------
jurahul wrote:

Yes, please see my comments below. I had pushed a change to make it a StringRef, but that blows up the size of each entry from 8 bytes to 24. So I've reverted back to the old code (which works) and keeps the static builtin table size unchanged. If we make it StringRef, then most of the gains from stripping out the common prefix will be eaten up by the increased size of the per-builtin entry. 

https://github.com/llvm/llvm-project/pull/104681


More information about the llvm-commits mailing list