From ce91ddca2248fa7d5a73078ccdc822e8669f67fd Mon Sep 17 00:00:00 2001 From: Abul Hossain Khan <140191921+abulgit@users.noreply.github.com> Date: Thu, 27 Mar 2025 01:02:01 +0530 Subject: [PATCH] Optimize Loc Lookups (#21088) --- compiler/src/dmd/location.d | 109 +++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/compiler/src/dmd/location.d b/compiler/src/dmd/location.d index 7a579b278f..9a396f37e8 100644 --- a/compiler/src/dmd/location.d +++ b/compiler/src/dmd/location.d @@ -366,6 +366,11 @@ struct BaseLoc uint[] lines; /// For each line, the file offset at which it starts. At index 0 there's always a 0 entry. BaseLoc[] substitutions; /// Substitutions from #line / #file directives + /// Cache for the last line lookup + private size_t lastLineIndex = 0; + /// Cache for the last substitution lookup + private size_t lastSubstIndex = 0; + /// Register that a new line starts at `offset` bytes from the start of the source file void newLine(uint offset) { @@ -421,8 +426,61 @@ struct BaseLoc private size_t getSubstitutionIndex(uint offset) @nogc { + if (substitutions.length <= 1) + return 0; + + // Check if the offset falls within the current cached substitution or the next one + if (lastSubstIndex < substitutions.length - 1) + { + // For the current substitution's range + if (substitutions[lastSubstIndex].startIndex <= offset && + (lastSubstIndex == substitutions.length - 1 || + substitutions[lastSubstIndex + 1].startIndex > offset)) + return lastSubstIndex; + + // For the next substitution's range + if (lastSubstIndex + 1 < substitutions.length - 1 && + substitutions[lastSubstIndex + 1].startIndex <= offset && + substitutions[lastSubstIndex + 2].startIndex > offset) + { + lastSubstIndex++; + return lastSubstIndex; + } + + // For the previous substitution's range + if (lastSubstIndex > 0 && + substitutions[lastSubstIndex - 1].startIndex <= offset && + substitutions[lastSubstIndex].startIndex > offset) + { + lastSubstIndex--; + return lastSubstIndex; + } + } + else if (lastSubstIndex == substitutions.length - 1 && + substitutions[lastSubstIndex].startIndex <= offset) + { + // Last substitution case + return lastSubstIndex; + } + + // Fall back to binary search, but start near size_t lo = 0; - size_t hi = substitutions.length + -1; + size_t hi = substitutions.length - 1; + + // Adjust the range based on the offset relative to lastSubstIndex + if (offset < substitutions[lastSubstIndex].startIndex) + { + // Search backward + lo = 0; + hi = lastSubstIndex; + } + else + { + // Search forward + lo = lastSubstIndex; + hi = substitutions.length - 1; + } + size_t mid = 0; while (lo <= hi) { @@ -430,7 +488,10 @@ struct BaseLoc if (substitutions[mid].startIndex <= offset) { if (mid == substitutions.length - 1 || substitutions[mid + 1].startIndex > offset) + { + lastSubstIndex = mid; // Update cache return mid; + } lo = mid + 1; } @@ -443,10 +504,51 @@ struct BaseLoc } /// Binary search the index in `this.lines` corresponding to `offset` + /// lastLineIndex cache to avoid full binary search when possible private size_t getLineIndex(uint offset) @nogc { + if (lines.length <= 1) + return 0; + + if (lastLineIndex < lines.length - 1) + { + if (lines[lastLineIndex] <= offset && offset < lines[lastLineIndex + 1]) + return lastLineIndex; + + if (lastLineIndex + 1 < lines.length - 1 && + lines[lastLineIndex + 1] <= offset && offset < lines[lastLineIndex + 2]) + { + lastLineIndex++; + return lastLineIndex; + } + + if (lastLineIndex > 0 && + lines[lastLineIndex - 1] <= offset && offset < lines[lastLineIndex]) + { + lastLineIndex--; + return lastLineIndex; + } + } + else if (lastLineIndex == lines.length - 1 && lines[lastLineIndex] <= offset) + { + return lastLineIndex; + } + + // Fall back to binary search size_t lo = 0; - size_t hi = lines.length + -1; + size_t hi = lines.length - 1; + + if (offset < lines[lastLineIndex]) + { + lo = 0; + hi = lastLineIndex; + } + else + { + lo = lastLineIndex; + hi = lines.length - 1; + } + size_t mid = 0; while (lo <= hi) { @@ -454,7 +556,10 @@ struct BaseLoc if (lines[mid] <= offset) { if (mid == lines.length - 1 || lines[mid + 1] > offset) + { + lastLineIndex = mid; // Update cache return mid; + } lo = mid + 1; }