[llvm] [mlir] [Support] Faster line and column lookup in SourceMgr (PR #195881)

via llvm-commits llvm-commits at lists.llvm.org
Tue May 5 14:10:22 PDT 2026


Albert =?utf-8?q?Havliček?= <havlialb at fit.cvut.cz>,
Albert =?utf-8?q?Havliček?= <havlialb at fit.cvut.cz>,
Albert =?utf-8?q?Havliček?= <havlialb at fit.cvut.cz>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/195881 at github.com>


https://github.com/Bertik23 updated https://github.com/llvm/llvm-project/pull/195881

>From fc946c71697982aff25b5ec9accbfacdfc080036 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Albert=20Havli=C4=8Dek?= <havlialb at fit.cvut.cz>
Date: Tue, 5 May 2026 17:59:49 +0200
Subject: [PATCH 1/4] [Support] Faster line and column lookup

---
 llvm/include/llvm/Support/SourceMgr.h |  9 ++++++
 llvm/lib/Support/SourceMgr.cpp        | 46 +++++++++++++++++++++++----
 2 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index 02e694cad8697..ec598336dc9b1 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -71,6 +71,15 @@ class SourceMgr {
     template <typename T>
     unsigned getLineNumberSpecialized(const char *Ptr) const;
 
+    /// Look up a given \p Ptr in the buffer, determining which line and column
+    /// it came from. This method has O(log n) complexity, where n is the number
+    /// of lines in the buffer.
+    LLVM_ABI std::pair<unsigned, unsigned>
+    getLineAndColumn(const char *Ptr) const;
+    template <typename T>
+    std::pair<unsigned, unsigned>
+    getLineAndColumnSpecialized(const char *Ptr) const;
+
     /// Return a pointer to the first character of the specified line number or
     /// null if the line number is invalid.
     LLVM_ABI const char *getPointerForLineNumber(unsigned LineNo) const;
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index 299615a6c8041..85428403626fb 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -151,6 +151,45 @@ unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
     return getLineNumberSpecialized<uint64_t>(Ptr);
 }
 
+template <typename T>
+std::pair<unsigned, unsigned>
+SourceMgr::SrcBuffer::getLineAndColumnSpecialized(const char *Ptr) const {
+  std::vector<T> &Offsets =
+      GetOrCreateOffsetCache<T>(OffsetCache, Buffer.get());
+
+  const char *BufStart = Buffer->getBufferStart();
+  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
+  ptrdiff_t PtrDiff = Ptr - BufStart;
+  assert(PtrDiff >= 0 &&
+         static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
+  T PtrOffset = static_cast<T>(PtrDiff);
+
+  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
+  // the line number.
+  auto I = llvm::lower_bound(Offsets, PtrOffset);
+  unsigned LineNo = I - Offsets.begin() + 1;
+
+  // The column number is the distance from the previous EOL (or the start of
+  // the buffer) to the pointer.
+  T LineStartOffs = (I == Offsets.begin()) ? 0 : (I[-1] + 1);
+  unsigned ColNo = PtrOffset - LineStartOffs + 1;
+  return {LineNo, ColNo};
+}
+
+/// Look up a given \p Ptr in the buffer, determining which line and column
+/// it came from.
+LLVM_ABI std::pair<unsigned, unsigned>
+SourceMgr::SrcBuffer::getLineAndColumn(const char *Ptr) const {
+  size_t Sz = Buffer->getBufferSize();
+  if (Sz <= std::numeric_limits<uint8_t>::max())
+    return getLineAndColumnSpecialized<uint8_t>(Ptr);
+  if (Sz <= std::numeric_limits<uint16_t>::max())
+    return getLineAndColumnSpecialized<uint16_t>(Ptr);
+  if (Sz <= std::numeric_limits<uint32_t>::max())
+    return getLineAndColumnSpecialized<uint32_t>(Ptr);
+  return getLineAndColumnSpecialized<uint64_t>(Ptr);
+}
+
 template <typename T>
 const char *SourceMgr::SrcBuffer::getPointerForLineNumberSpecialized(
     unsigned LineNo) const {
@@ -217,12 +256,7 @@ SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
   auto &SB = getBufferInfo(BufferID);
   const char *Ptr = Loc.getPointer();
 
-  unsigned LineNo = SB.getLineNumber(Ptr);
-  const char *BufStart = SB.Buffer->getBufferStart();
-  size_t NewlineOffs = StringRef(BufStart, Ptr - BufStart).find_last_of("\n\r");
-  if (NewlineOffs == StringRef::npos)
-    NewlineOffs = ~(size_t)0;
-  return {LineNo, Ptr - BufStart - NewlineOffs};
+  return SB.getLineAndColumn(Ptr);
 }
 
 // FIXME: Note that the formatting of source locations is spread between

>From 50b2f2aba230f77bf6574548356e06e13aaeeb58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Albert=20Havli=C4=8Dek?= <havlialb at fit.cvut.cz>
Date: Tue, 5 May 2026 18:03:51 +0200
Subject: [PATCH 2/4] [Support] Update comments about time complexity of
 getLineAndColumn

---
 llvm/include/llvm/Support/SourceMgr.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index ec598336dc9b1..842163cd96e06 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -217,13 +217,15 @@ class SourceMgr {
   LLVM_ABI unsigned FindBufferContainingLoc(SMLoc Loc) const;
 
   /// Find the line number for the specified location in the specified file.
-  /// This is not a fast method.
+  /// This method has O(log n) complexity, where n is the number of lines in the
+  /// buffer.
   unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const {
     return getLineAndColumn(Loc, BufferID).first;
   }
 
   /// Find the line and column number for the specified location in the
-  /// specified file. This is not a fast method.
+  /// specified file. This method has O(log n) complexity, where n is the number
+  /// of lines in the
   LLVM_ABI std::pair<unsigned, unsigned>
   getLineAndColumn(SMLoc Loc, unsigned BufferID = 0) const;
 

>From f15d187b62a1104d66064cad5e9c0c0774a30684 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Albert=20Havli=C4=8Dek?= <havlialb at fit.cvut.cz>
Date: Tue, 5 May 2026 18:36:16 +0200
Subject: [PATCH 3/4] [Support] Remove now unused functions

---
 llvm/include/llvm/Support/SourceMgr.h |  6 ------
 llvm/lib/Support/SourceMgr.cpp        | 31 ---------------------------
 2 files changed, 37 deletions(-)

diff --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index 842163cd96e06..ec0b4edb295d4 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -65,12 +65,6 @@ class SourceMgr {
     /// dynamically based on the size of Buffer.
     mutable void *OffsetCache = nullptr;
 
-    /// Look up a given \p Ptr in the buffer, determining which line it came
-    /// from.
-    LLVM_ABI unsigned getLineNumber(const char *Ptr) const;
-    template <typename T>
-    unsigned getLineNumberSpecialized(const char *Ptr) const;
-
     /// Look up a given \p Ptr in the buffer, determining which line and column
     /// it came from. This method has O(log n) complexity, where n is the number
     /// of lines in the buffer.
diff --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index 85428403626fb..2704025060e03 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -120,37 +120,6 @@ static std::vector<T> &GetOrCreateOffsetCache(void *&OffsetCache,
   return *Offsets;
 }
 
-template <typename T>
-unsigned SourceMgr::SrcBuffer::getLineNumberSpecialized(const char *Ptr) const {
-  std::vector<T> &Offsets =
-      GetOrCreateOffsetCache<T>(OffsetCache, Buffer.get());
-
-  const char *BufStart = Buffer->getBufferStart();
-  assert(Ptr >= BufStart && Ptr <= Buffer->getBufferEnd());
-  ptrdiff_t PtrDiff = Ptr - BufStart;
-  assert(PtrDiff >= 0 &&
-         static_cast<size_t>(PtrDiff) <= std::numeric_limits<T>::max());
-  T PtrOffset = static_cast<T>(PtrDiff);
-
-  // llvm::lower_bound gives the number of EOL before PtrOffset. Add 1 to get
-  // the line number.
-  return llvm::lower_bound(Offsets, PtrOffset) - Offsets.begin() + 1;
-}
-
-/// Look up a given \p Ptr in the buffer, determining which line it came
-/// from.
-unsigned SourceMgr::SrcBuffer::getLineNumber(const char *Ptr) const {
-  size_t Sz = Buffer->getBufferSize();
-  if (Sz <= std::numeric_limits<uint8_t>::max())
-    return getLineNumberSpecialized<uint8_t>(Ptr);
-  else if (Sz <= std::numeric_limits<uint16_t>::max())
-    return getLineNumberSpecialized<uint16_t>(Ptr);
-  else if (Sz <= std::numeric_limits<uint32_t>::max())
-    return getLineNumberSpecialized<uint32_t>(Ptr);
-  else
-    return getLineNumberSpecialized<uint64_t>(Ptr);
-}
-
 template <typename T>
 std::pair<unsigned, unsigned>
 SourceMgr::SrcBuffer::getLineAndColumnSpecialized(const char *Ptr) const {

>From c108d8d24b5470159c3194335874d76fa0cdf2a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Albert=20Havli=C4=8Dek?= <havlialb at fit.cvut.cz>
Date: Tue, 5 May 2026 22:29:00 +0200
Subject: [PATCH 4/4] [MLIR] Use public API of SourceMgr to get line and column
 location

---
 mlir/lib/AsmParser/Lexer.cpp            | 7 +------
 mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp | 7 +------
 2 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/mlir/lib/AsmParser/Lexer.cpp b/mlir/lib/AsmParser/Lexer.cpp
index 8f53529823e23..185baaa63c739 100644
--- a/mlir/lib/AsmParser/Lexer.cpp
+++ b/mlir/lib/AsmParser/Lexer.cpp
@@ -63,12 +63,7 @@ Location Lexer::getEncodedSourceLocation(SMLoc loc) {
   auto &sourceMgr = getSourceMgr();
   unsigned mainFileID = sourceMgr.getMainFileID();
 
-  // TODO: Fix performance issues in SourceMgr::getLineAndColumn so that we can
-  //       use it here.
-  auto &bufferInfo = sourceMgr.getBufferInfo(mainFileID);
-  unsigned lineNo = bufferInfo.getLineNumber(loc.getPointer());
-  unsigned column =
-      (loc.getPointer() - bufferInfo.getPointerForLineNumber(lineNo)) + 1;
+  auto [lineNo, column] = sourceMgr.getLineAndColumn(loc.getPointer());
   auto *buffer = sourceMgr.getMemoryBuffer(mainFileID);
 
   return FileLineColLoc::get(context, buffer->getBufferIdentifier(), lineNo,
diff --git a/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp b/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
index 0677828b635d4..08c085b5f279c 100644
--- a/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
+++ b/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
@@ -147,12 +147,7 @@ OwningOpRef<ModuleOp> CodeGen::generate(const ast::Module &module) {
 Location CodeGen::genLoc(llvm::SMLoc loc) {
   unsigned fileID = sourceMgr.FindBufferContainingLoc(loc);
 
-  // TODO: Fix performance issues in SourceMgr::getLineAndColumn so that we can
-  //       use it here.
-  auto &bufferInfo = sourceMgr.getBufferInfo(fileID);
-  unsigned lineNo = bufferInfo.getLineNumber(loc.getPointer());
-  unsigned column =
-      (loc.getPointer() - bufferInfo.getPointerForLineNumber(lineNo)) + 1;
+  auto [lineNo, column] = sourceMgr.getLineAndColumn(loc);
   auto *buffer = sourceMgr.getMemoryBuffer(fileID);
 
   return FileLineColLoc::get(builder.getContext(),



More information about the llvm-commits mailing list