HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Integer-to-ASCII algorithm (x86 assembly)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
x86algorithmassemblyasciiinteger

Problem

This is my best effort at converting a 32 bit integer in EAX, to an 8 character ascii string (result in RDI). It will work accurately up to 99,999,999. Higher values could be done using an xmm register. The byte order in RDI is correct (e.g. if copied directly to video ram, the most significant byte is displayed first) No expensive DIV instructions or memory accesses required. Can this be improved further?

mov ebx, 0xCCCCCCCD             
    xor rdi, rdi
.loop:
    mov ecx, eax                    ; save original number

    mul ebx                         ; divide by 10 using agner fog's 'magic number'
    shr edx, 3                      ;

    mov eax, edx                    ; store it back into eax

    lea edx, [edx*4 + edx]          ; multiply by 10
    lea edx, [edx*2 - '0']          ; and ascii it
    sub ecx, edx                    ; subtract from original number to get remainder

    shl rdi, 8                      ; shift in to least significant byte
    or rdi, rcx                     ;

    test eax, eax
    jnz .loop

Solution

There are all sorts of things that LOOK like they should perform better, but I can only get a tiny bit of improvement. And that may disappear (or worsen) on other hardware:

mov ebx, 0xCCCCCCCD             
    xor rdi, rdi

.loop:
    mov ecx, eax                    ; save original number

    mul ebx                         ; divide by 10 using agner fog's 'magic number'
    shr edx, 3                      ;

    mov eax, edx                    ; store quotient for next loop

    lea edx, [edx*4 + edx]          ; multiply by 10
    shl rdi, 8                      ; make room for byte
    lea edx, [edx*2 - '0']          ; finish *10 and convert to ascii
    sub ecx, edx                    ; subtract from original number to get remainder

    lea rdi, [rdi + rcx]            ; store next byte

    test eax, eax
    jnz .loop


The 2 changes are:

  • Move shl rdi to a 'better' place



  • Use lea instead of or to set rdi

Code Snippets

mov ebx, 0xCCCCCCCD             
    xor rdi, rdi

.loop:
    mov ecx, eax                    ; save original number

    mul ebx                         ; divide by 10 using agner fog's 'magic number'
    shr edx, 3                      ;

    mov eax, edx                    ; store quotient for next loop

    lea edx, [edx*4 + edx]          ; multiply by 10
    shl rdi, 8                      ; make room for byte
    lea edx, [edx*2 - '0']          ; finish *10 and convert to ascii
    sub ecx, edx                    ; subtract from original number to get remainder

    lea rdi, [rdi + rcx]            ; store next byte

    test eax, eax
    jnz .loop

Context

StackExchange Code Review Q#142842, answer score: 2

Revisions (0)

No revisions yet.