Handle more edge cases in intrinsic name binary search

I tried to make the AMDGPU intrinsic info table use this instead of
another StringMatcher, and some issues arose.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@258871 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Kleckner 2016-01-26 22:33:19 +00:00
parent 6c77f5367f
commit dc8eb983e7
5 changed files with 88 additions and 40 deletions

View File

@ -69,6 +69,13 @@ namespace Intrinsic {
/// the intrinsic.
Function *getDeclaration(Module *M, ID id, ArrayRef<Type*> Tys = None);
/// Looks up Name in NameTable via binary search. NameTable must be sorted
/// and all entries must start with "llvm.". If NameTable contains an exact
/// match for Name or a prefix of Name followed by a dot, its index in
/// NameTable is returned. Otherwise, -1 is returned.
int lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
StringRef Name);
/// Map a GCC builtin name to an intrinsic ID.
ID getIntrinsicForGCCBuiltin(const char *Prefix, const char *BuiltinName);

View File

@ -414,53 +414,14 @@ static const char * const IntrinsicNameTable[] = {
#undef GET_INTRINSIC_NAME_TABLE
};
static int lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
StringRef Name) {
// Do a binary search over the table of intrinsic names.
const char *const *NameEntry =
std::lower_bound(NameTable.begin(), NameTable.end(), Name.data(),
[](const char *LHS, const char *RHS) {
// Don't compare the first 5 characters, they are
// always "llvm.".
return strcmp(LHS + 5, RHS + 5) < 0;
});
unsigned Idx = NameEntry - NameTable.begin();
// Check if this is a direct match.
if (Idx < NameTable.size() && strcmp(Name.data(), NameTable[Idx]) == 0)
return Idx;
// Otherwise, back up one entry to look for a prefix of Name where the next
// character in Name is a dot.
if (Idx == 0)
return -1;
--Idx;
bool CheckPrefixes = true;
while (CheckPrefixes) {
StringRef FoundName = NameTable[Idx];
if (Name.startswith(FoundName) && Name[FoundName.size()] == '.')
return Idx;
if (Idx == 0)
return -1;
--Idx;
// We have to keep scanning backwards until the previous entry is not a
// prefix of the current entry. Consider a key of llvm.foo.f64 and a table
// of llvm.foo and llvm.foo.bar.
CheckPrefixes = FoundName.startswith(NameTable[Idx]);
}
return -1;
}
/// \brief This does the actual lookup of an intrinsic ID which
/// matches the given function name.
static Intrinsic::ID lookupIntrinsicID(const ValueName *ValName) {
StringRef Name = ValName->getKey();
assert(Name.data()[Name.size()] == '\0' && "non-null terminated ValueName");
ArrayRef<const char *> NameTable(&IntrinsicNameTable[1],
std::end(IntrinsicNameTable));
int Idx = lookupLLVMIntrinsicByName(NameTable, Name);
int Idx = Intrinsic::lookupLLVMIntrinsicByName(NameTable, Name);
Intrinsic::ID ID = static_cast<Intrinsic::ID>(Idx + 1);
if (ID == Intrinsic::not_intrinsic)
return ID;

View File

@ -25,6 +25,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
@ -79,3 +80,41 @@ const Value *DbgValueInst::getValue() const {
}
Value *DbgValueInst::getValue() { return getValueImpl(getArgOperand(0)); }
int llvm::Intrinsic::lookupLLVMIntrinsicByName(ArrayRef<const char *> NameTable,
StringRef Name) {
assert(Name.startswith("llvm."));
// Do successive binary searches of the dotted name components. For
// "llvm.gc.experimental.statepoint.p1i8.p1i32", we will find the range of
// intrinsics starting with "llvm.gc", then "llvm.gc.experimental", then
// "llvm.gc.experimental.statepoint", and then we will stop as the range is
// size 1. During the search, we can skip the prefix that we already know is
// identical. By using strncmp we consider names with differing suffixes to
// be part of the equal range.
size_t CmpStart = 0;
size_t CmpEnd = 4; // Skip the "llvm" component.
const char *const *Low = NameTable.begin();
const char *const *High = NameTable.end();
const char *const *LastLow = Low;
while (CmpEnd < Name.size() && High - Low > 0) {
CmpStart = CmpEnd;
CmpEnd = Name.find('.', CmpStart + 1);
CmpEnd = CmpEnd == StringRef::npos ? Name.size() : CmpEnd;
auto Cmp = [CmpStart, CmpEnd](const char *LHS, const char *RHS) {
return strncmp(LHS + CmpStart, RHS + CmpStart, CmpEnd - CmpStart) < 0;
};
LastLow = Low;
std::tie(Low, High) = std::equal_range(Low, High, Name.data(), Cmp);
}
if (High - Low > 0)
LastLow = Low;
if (LastLow == NameTable.end())
return -1;
StringRef NameFound = *LastLow;
if (Name == NameFound ||
(Name.startswith(NameFound) && Name[NameFound.size()] == '.'))
return LastLow - NameTable.begin();
return -1;
}

View File

@ -14,6 +14,7 @@ set(IRSources
DominatorTreeTest.cpp
IRBuilderTest.cpp
InstructionsTest.cpp
IntrinsicsTest.cpp
LegacyPassManagerTest.cpp
MDBuilderTest.cpp
MetadataTest.cpp

View File

@ -0,0 +1,40 @@
//===- llvm/unittest/IR/IntrinsicsTest.cpp - ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/IntrinsicInst.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
static const char *const NameTable1[] = {
"llvm.foo",
"llvm.foo.a",
"llvm.foo.b",
"llvm.foo.b.a",
"llvm.foo.c",
};
TEST(IntrinNameLookup, Basic) {
int I = Intrinsic::lookupLLVMIntrinsicByName(NameTable1, "llvm.foo");
EXPECT_EQ(0, I);
I = Intrinsic::lookupLLVMIntrinsicByName(NameTable1, "llvm.foo.f64");
EXPECT_EQ(0, I);
I = Intrinsic::lookupLLVMIntrinsicByName(NameTable1, "llvm.foo.b");
EXPECT_EQ(2, I);
I = Intrinsic::lookupLLVMIntrinsicByName(NameTable1, "llvm.foo.b.a");
EXPECT_EQ(3, I);
I = Intrinsic::lookupLLVMIntrinsicByName(NameTable1, "llvm.foo.c");
EXPECT_EQ(4, I);
I = Intrinsic::lookupLLVMIntrinsicByName(NameTable1, "llvm.foo.c.f64");
EXPECT_EQ(4, I);
}
} // end namespace