Precheck ascii 0-9 using an if-statement before switch for performance

96 Views Asked by At

I have two functions which both check if an input char is a number (along other characters), but they do it in different ways:

  • foo_precheck(char c) first checks if the ascii code of char is in a certain range which denotes a number.
  • foo_switch(char c) uses a jumptable with fallthrough cases from 0-9 to determine that a char is a number.

The question now is: which function is faster? I was curious if this would optimize to the same assembly under -O2, but it didn't:

LiveDemo

#include <cstdio>

void foo_precheck(char c)
{
    if (c >= 0x30 && c <= 0x39) {
        printf("Was a number!\n");
        return ;
    }
    switch(c) {
        case '{':
        case '[': {
            printf("Other stuff!\n");
            break;
        }
        default: break;
    }
}

void foo_switch(char c)
{
    switch(c) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9': {
            printf("Was a number!\n");
            break;
        }
        case '{':
        case '[': {
            printf("Other stuff!\n");
            break;
        }
        default: break;
    }
}


const volatile char r = '5';

int main()
{
    foo_precheck(r);
    foo_switch(r);
}

This is the assembly generated for each function (clang -O2):

foo_precheck(char):                      # @foo_precheck(char)
        lea     eax, [rdi - 48]
        cmp     al, 10
        jae     .LBB0_2
        lea     rdi, [rip + .Lstr.4]
        jmp     puts@PLT                        # TAILCALL
.LBB0_2:
        movsx   eax, dil
        or      eax, 32
        cmp     eax, 123
        jne     .LBB0_5
        lea     rdi, [rip + .Lstr.3]
        jmp     puts@PLT                        # TAILCALL
.LBB0_5:
        ret

foo_switch(char):                        # @foo_switch(char)
        lea     eax, [rdi - 48]
        cmp     eax, 10
        jae     .LBB1_2
        lea     rdi, [rip + .Lstr.4]
        jmp     puts@PLT                        # TAILCALL
.LBB1_2:
        cmp     edi, 123
        je      .LBB1_4
        cmp     edi, 91
        jne     .LBB1_6
.LBB1_4:
        lea     rdi, [rip + .Lstr.3]
        jmp     puts@PLT                        # TAILCALL
.LBB1_6:
        ret

Can you make a general estimate which one is faster? I know it is architecture dependent, but the fact that it doesn't generate the same assembly made me curious if you make a general statement on what I should go for.

0

There are 0 best solutions below