[fpc-devel] Patch to speed up Uppercase/Lowercase functions

David Butler david at e.co.za
Sat Jun 11 18:07:53 CEST 2005

On Sat, 11 Jun 2005 13:33:57 +0200 (CEST), you wrote:

>To compare, I made 6 versions of Lowercase:

>Result on an AMD 64 3000:
>Lowercase time to execute: 00:00:01.563
>Lowercase2 Time to execute: 00:00:01.363
>Lowercase3 Time to execute: 00:00:01.394
>Lowercase4 Time to execute: 00:00:00.999
>Lowercase5 Time to execute: 00:00:01.021
>Lowercase6 Time to execute: 00:00:00.948
>So, judge for yourself. I think this is worth the 256 byte lookup table.

One of the major optimisations for the LowerCase function is actually
for the case when the function does nothing!

The most expensive operation in the whole LowerCase function is the
UniqueString allocation for when the string changes. For the case
where the string is already in lower case it is important not call
UniqueString. It makes a 600% difference is speed on Delphi for my
test case (haven't tested on fpc yet).

This is why it is important to have this line in Lowercase2 for

    if (result[i] in ['A'..'Z']) then 

It prevents the UniqueString call if nothing changes.

Just for comparison, here is the implementation in Fundamentals. The
pure pascal version is like your lowercase2.

procedure ConvertLower(var S: AnsiString);
      OR      EAX, EAX
      JZ      @Exit
      PUSH    EAX
      MOV     EAX, [EAX]
      OR      EAX, EAX
      JZ      @ExitP
      MOV     ECX, [EAX - 4]
      OR      ECX, ECX
      JZ      @ExitP
      XOR     DH, DH
      DEC     ECX
      MOV     DL, [EAX + ECX]
      CMP     DL, 'A'
      JB      @L1
      CMP     DL, 'Z'
      JA      @L1
      OR      DH, DH
      JZ      @Uniq
      ADD     DL, 'a' - 'A'
      MOV     [EAX + ECX], DL
      OR      ECX, ECX
      JNZ     @L2
      OR      DH, DH
      JNZ     @Exit
      POP     EAX
      POP     EAX
      PUSH    ECX
      PUSH    EDX
      CALL    UniqueString
      POP     EDX
      POP     ECX
      MOV     DH, 1
      JMP     @L3
procedure ConvertLower(var S: AnsiString);
var F : Integer;
  For F := 1 to Length(S) do
    if S[F] in ['A'..'Z'] then
      S[F] := AnsiChar(Ord(S[F]) + 32);


More information about the fpc-devel mailing list