Single Quoted Character Literals (Why yes, again)

i assume that @xwu probably meant:

Character.init(Unicode.Scalar.init(digit)).hexDigitValue.flatMap(UInt8.init(exactly:))

i plugged this into godbolt (with -O):

func test1(_ digit:UInt8) -> UInt8?
{
    Character.init(Unicode.Scalar.init(digit)).hexDigitValue.flatMap(UInt8.init(exactly:))
}

func test2(_ digit:UInt8) -> UInt8?
{
    switch digit 
    {
    case 0x30 ... 0x39: return digit      - 0x30
    case 0x61 ... 0x66: return digit + 10 - 0x61
    case 0x41 ... 0x46: return digit + 10 - 0x41
    default:            return nil
    }
}

version 1:

output.test1(Swift.UInt8) -> Swift.UInt8?:
        test    dil, dil
        js      .LBB1_6
        inc     dil
        movzx   eax, dil
        test    eax, eax
        je      .LBB1_3
.LBB1_4:
        bsr     ecx, eax
        xor     ecx, 31
        jmp     .LBB1_5
.LBB1_6:
        movzx   eax, dil
        mov     ecx, eax
        and     ecx, 63
        shl     ecx, 8
        shr     eax, 6
        add     eax, ecx
        add     eax, 33217
        test    eax, eax
        jne     .LBB1_4
.LBB1_3:
        mov     ecx, 32
.LBB1_5:
        push    rbp
        push    r14
        push    rbx
        sub     rsp, 16
        shr     ecx, 3
        mov     esi, 4
        sub     rsi, rcx
        lea     ecx, [8*rsi]
        mov     rdx, -1
        shl     rdx, cl
        not     rdx
        mov     eax, eax
        movabs  rcx, 71775015237779199
        add     rcx, rax
        and     rcx, rdx
        mov     qword ptr [rsp], rcx
        mov     rdi, rsp
        call    ($sSS18_uncheckedFromUTF8ySSSRys5UInt8VGFZ)@PLT
        mov     r14, rdx
        mov     rdi, rax
        mov     rsi, rdx
        call    ($sSJ13hexDigitValueSiSgvg)@PLT
        mov     rbx, rax
        mov     ebp, edx
        mov     rdi, r14
        call    swift_bridgeObjectRelease@PLT
        test    rbx, rbx
        sets    cl
        or      cl, bpl
        cmp     rbx, 256
        setae   al
        mov     edx, 256
        cmovb   rdx, rbx
        or      al, cl
        and     al, 1
        movzx   esi, al
        shl     esi, 8
        movzx   edx, dl
        xor     eax, eax
        test    cl, 1
        cmove   eax, edx
        or      eax, esi
        add     rsp, 16
        pop     rbx
        pop     r14
        pop     rbp
        ret

version 2:


output.test2(Swift.UInt8) -> Swift.UInt8?:
        lea     eax, [rdi - 58]
        cmp     al, -10
        jae     .LBB2_3
        lea     eax, [rdi - 103]
        cmp     al, -6
        jae     .LBB2_4
        lea     eax, [rdi - 71]
        add     dil, -55
        xor     ecx, ecx
        cmp     al, -6
        setb    al
        movzx   edi, dil
        cmovb   edi, ecx
        jmp     .LBB2_6
.LBB2_3:
        add     dil, -48
        jmp     .LBB2_5
.LBB2_4:
        add     dil, -87
.LBB2_5:
        xor     eax, eax
.LBB2_6:
        movzx   ecx, al
        shl     ecx, 8
        movzx   eax, dil
        or      eax, ecx
        ret

so i think version 2 is a clear winner here, and the “performance issues notwithstanding” are actually quite significant.

1 Like