[llvm] r258871 - Handle more edge cases in intrinsic name binary search

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 26 14:33:20 PST 2016


Author: rnk
Date: Tue Jan 26 16:33:19 2016
New Revision: 258871

URL: http://llvm.org/viewvc/llvm-project?rev=258871&view=rev
Log:
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.

Added:
    llvm/trunk/unittests/IR/IntrinsicsTest.cpp
Modified:
    llvm/trunk/include/llvm/IR/Intrinsics.h
    llvm/trunk/lib/IR/Function.cpp
    llvm/trunk/lib/IR/IntrinsicInst.cpp
    llvm/trunk/unittests/IR/CMakeLists.txt

Modified: llvm/trunk/include/llvm/IR/Intrinsics.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.h?rev=258871&r1=258870&r2=258871&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Intrinsics.h (original)
+++ llvm/trunk/include/llvm/IR/Intrinsics.h Tue Jan 26 16:33:19 2016
@@ -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);
 

Modified: llvm/trunk/lib/IR/Function.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=258871&r1=258870&r2=258871&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Function.cpp (original)
+++ llvm/trunk/lib/IR/Function.cpp Tue Jan 26 16:33:19 2016
@@ -414,53 +414,14 @@ static const char * const IntrinsicNameT
 #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;

Modified: llvm/trunk/lib/IR/IntrinsicInst.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/IntrinsicInst.cpp?rev=258871&r1=258870&r2=258871&view=diff
==============================================================================
--- llvm/trunk/lib/IR/IntrinsicInst.cpp (original)
+++ llvm/trunk/lib/IR/IntrinsicInst.cpp Tue Jan 26 16:33:19 2016
@@ -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() co
 }
 
 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;
+}

Modified: llvm/trunk/unittests/IR/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/CMakeLists.txt?rev=258871&r1=258870&r2=258871&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/CMakeLists.txt (original)
+++ llvm/trunk/unittests/IR/CMakeLists.txt Tue Jan 26 16:33:19 2016
@@ -14,6 +14,7 @@ set(IRSources
   DominatorTreeTest.cpp
   IRBuilderTest.cpp
   InstructionsTest.cpp
+  IntrinsicsTest.cpp
   LegacyPassManagerTest.cpp
   MDBuilderTest.cpp
   MetadataTest.cpp

Added: llvm/trunk/unittests/IR/IntrinsicsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/IntrinsicsTest.cpp?rev=258871&view=auto
==============================================================================
--- llvm/trunk/unittests/IR/IntrinsicsTest.cpp (added)
+++ llvm/trunk/unittests/IR/IntrinsicsTest.cpp Tue Jan 26 16:33:19 2016
@@ -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




More information about the llvm-commits mailing list