Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions llvm/test/TableGen/RuntimeLibcallEmitter.td
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi

// CHECK: iota_range<RTLIB::LibcallImpl> RTLIB::RuntimeLibcallsInfo::lookupLibcallImplNameImpl(StringRef Name) {
// CHECK: static constexpr uint16_t HashTableNameToEnum[16] = {
// CHECK: 2, // 0x000000705301b8, ___memset
// CHECK: 2,
// CHECK: 0,
// CHECK: 6, // 0x0000001417a2af, calloc
// CHECK: 6,
// CHECK: 0,
// CHECK: };

Expand Down
76 changes: 33 additions & 43 deletions llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,13 +287,6 @@ class RuntimeLibcallEmitter {
void run(raw_ostream &OS);
};

/// Helper struct for the name hash table.
struct LookupEntry {
StringRef FuncName;
uint64_t Hash = 0;
unsigned TableValue = 0;
};

} // End anonymous namespace.

void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const {
Expand Down Expand Up @@ -339,14 +332,17 @@ static void emitHashFunction(raw_ostream &OS) {
/// Return the table size, maximum number of collisions for the set of hashes
static std::pair<int, int>
computePerfectHashParameters(ArrayRef<uint64_t> Hashes) {
const int SizeOverhead = 10;
const int NumHashes = Hashes.size();
// Chosen based on experimentation with llvm/benchmarks/RuntimeLibcalls.cpp
const int SizeOverhead = 4;

// Index derived from hash -> number of collisions.
DenseMap<uint64_t, int> Table;

unsigned NumHashes = Hashes.size();

for (int MaxCollisions = 1;; ++MaxCollisions) {
for (int N = NumHashes; N < SizeOverhead * NumHashes; ++N) {
for (unsigned N = NextPowerOf2(NumHashes - 1); N < SizeOverhead * NumHashes;
N <<= 1) {
Table.clear();

bool NeedResize = false;
Expand All @@ -365,41 +361,29 @@ computePerfectHashParameters(ArrayRef<uint64_t> Hashes) {
}
}

static std::vector<LookupEntry>
static std::vector<unsigned>
constructPerfectHashTable(ArrayRef<RuntimeLibcallImpl> Keywords,
ArrayRef<uint64_t> Hashes, int Size, int Collisions,
StringToOffsetTable &OffsetTable) {
DenseSet<StringRef> Seen;
std::vector<LookupEntry> Lookup(Size * Collisions);

for (const RuntimeLibcallImpl &LibCallImpl : Keywords) {
StringRef ImplName = LibCallImpl.getLibcallFuncName();

// We do not want to add repeated entries for cases with the same name, only
// an entry for the first, with the name collision enum values immediately
// following.
if (!Seen.insert(ImplName).second)
continue;

uint64_t HashValue = Hashes[LibCallImpl.getEnumVal() - 1];
ArrayRef<uint64_t> Hashes,
ArrayRef<unsigned> TableValues, int Size,
int Collisions, StringToOffsetTable &OffsetTable) {
std::vector<unsigned> Lookup(Size * Collisions);

for (auto [HashValue, TableValue] : zip(Hashes, TableValues)) {
uint64_t Idx = (HashValue % static_cast<uint64_t>(Size)) *
static_cast<uint64_t>(Collisions);

bool Found = false;
for (int J = 0; J < Collisions; ++J) {
LookupEntry &Entry = Lookup[Idx + J];
if (Entry.TableValue == 0) {
Entry.FuncName = ImplName;
Entry.TableValue = LibCallImpl.getEnumVal();
Entry.Hash = HashValue;
unsigned &Entry = Lookup[Idx + J];
if (Entry == 0) {
Entry = TableValue;
Found = true;
break;
}
}

if (!Found)
reportFatalInternalError("failure to hash " + ImplName);
reportFatalInternalError("failure to hash");
}

return Lookup;
Expand All @@ -409,15 +393,25 @@ constructPerfectHashTable(ArrayRef<RuntimeLibcallImpl> Keywords,
void RuntimeLibcallEmitter::emitNameMatchHashTable(
raw_ostream &OS, StringToOffsetTable &OffsetTable) const {
std::vector<uint64_t> Hashes(RuntimeLibcallImplDefList.size());
std::vector<unsigned> TableValues(RuntimeLibcallImplDefList.size());
DenseSet<StringRef> SeenFuncNames;

size_t MaxFuncNameSize = 0;
size_t Index = 0;

for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) {
StringRef ImplName = LibCallImpl.getLibcallFuncName();
MaxFuncNameSize = std::max(MaxFuncNameSize, ImplName.size());
Hashes[Index++] = hash(ImplName);
if (SeenFuncNames.insert(ImplName).second) {
MaxFuncNameSize = std::max(MaxFuncNameSize, ImplName.size());
TableValues[Index] = LibCallImpl.getEnumVal();
Hashes[Index++] = hash(ImplName);
}
}

// Trim excess elements from non-unique entries.
Hashes.resize(SeenFuncNames.size());
TableValues.resize(SeenFuncNames.size());

LLVM_DEBUG({
for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) {
StringRef ImplName = LibCallImpl.getLibcallFuncName();
Expand Down Expand Up @@ -447,8 +441,9 @@ void RuntimeLibcallEmitter::emitNameMatchHashTable(
"#endif\n";

auto [Size, Collisions] = computePerfectHashParameters(Hashes);
std::vector<LookupEntry> Lookup = constructPerfectHashTable(
RuntimeLibcallImplDefList, Hashes, Size, Collisions, OffsetTable);
std::vector<unsigned> Lookup =
constructPerfectHashTable(RuntimeLibcallImplDefList, Hashes, TableValues,
Size, Collisions, OffsetTable);

LLVM_DEBUG(dbgs() << "Runtime libcall perfect hashing parameters: Size = "
<< Size << ", maximum collisions = " << Collisions << '\n');
Expand All @@ -463,13 +458,8 @@ void RuntimeLibcallEmitter::emitNameMatchHashTable(
OS << " static constexpr uint16_t HashTableNameToEnum[" << Lookup.size()
<< "] = {\n";

for (auto [FuncName, Hash, TableVal] : Lookup) {
OS << " " << TableVal << ',';
if (TableVal != 0)
OS << " // " << format_hex(Hash, 16) << ", " << FuncName;

OS << '\n';
}
for (unsigned TableVal : Lookup)
OS << " " << TableVal << ",\n";

OS << " };\n\n";

Expand Down