diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index ade393c11b7a2..1ea10bf4d43ab 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -2541,53 +2541,58 @@ static void emitIsSubclass(CodeGenTarget &Target, OS << " if (A == B)\n"; OS << " return true;\n\n"; - bool EmittedSwitch = false; + // TODO: Use something like SequenceToOffsetTable to allow sequences to + // overlap in this table. + SmallVector SuperClassData; + + OS << " [[maybe_unused]] static constexpr struct {\n"; + OS << " uint32_t Offset;\n"; + OS << " uint16_t Start;\n"; + OS << " uint16_t Length;\n"; + OS << " } Table[] = {\n"; + OS << " {0, 0, 0},\n"; // InvalidMatchClass + OS << " {0, 0, 0},\n"; // OptionalMatchClass for (const auto &A : Infos) { - std::vector SuperClasses; - if (A.IsOptional) - SuperClasses.push_back("OptionalMatchClass"); - for (const auto &B : Infos) { - if (&A != &B && A.isSubsetOf(B)) - SuperClasses.push_back(B.Name); - } - - if (SuperClasses.empty()) - continue; - - // If this is the first SuperClass, emit the switch header. - if (!EmittedSwitch) { - OS << " switch (A) {\n"; - OS << " default:\n"; - OS << " return false;\n"; - EmittedSwitch = true; - } - - OS << "\n case " << A.Name << ":\n"; - - if (SuperClasses.size() == 1) { - OS << " return B == " << SuperClasses.back() << ";\n"; - continue; - } - - if (!SuperClasses.empty()) { - OS << " switch (B) {\n"; - OS << " default: return false;\n"; - for (StringRef SC : SuperClasses) - OS << " case " << SC << ": return true;\n"; - OS << " }\n"; - } else { - // No case statement to emit - OS << " return false;\n"; - } + SmallVector SuperClasses; + SuperClasses.push_back(false); // InvalidMatchClass + SuperClasses.push_back(A.IsOptional); // OptionalMatchClass + for (const auto &B : Infos) + SuperClasses.push_back(&A != &B && A.isSubsetOf(B)); + + // Trim leading and trailing zeros. + auto End = find_if(reverse(SuperClasses), [](bool B) { return B; }).base(); + auto Start = + std::find_if(SuperClasses.begin(), End, [](bool B) { return B; }); + + unsigned Offset = SuperClassData.size(); + SuperClassData.append(Start, End); + + OS << " {" << Offset << ", " << (Start - SuperClasses.begin()) << ", " + << (End - Start) << "},\n"; } + OS << " };\n\n"; - // If there were case statements emitted into the string stream write the - // default. - if (EmittedSwitch) - OS << " }\n"; - else + if (SuperClassData.empty()) { OS << " return false;\n"; - + } else { + // Dump the boolean data packed into bytes. + SuperClassData.append(-SuperClassData.size() % 8, false); + OS << " static constexpr uint8_t Data[] = {\n"; + for (unsigned I = 0, E = SuperClassData.size(); I < E; I += 8) { + unsigned Byte = 0; + for (unsigned J = 0; J < 8; ++J) + Byte |= (unsigned)SuperClassData[I + J] << J; + OS << formatv(" {:X2},\n", Byte); + } + OS << " };\n\n"; + + OS << " auto &Entry = Table[A];\n"; + OS << " unsigned Idx = B - Entry.Start;\n"; + OS << " if (Idx >= Entry.Length)\n"; + OS << " return false;\n"; + OS << " Idx += Entry.Offset;\n"; + OS << " return (Data[Idx / 8] >> (Idx % 8)) & 1;\n"; + } OS << "}\n\n"; }