Skip to main content
GameDev.net gamedev.net
🔒 Locked

itoa SIMD

Started by akhin Mar 28, 2011 at 12:12 PM 10 replies 3.7k views
Original Post
akhin
akhin
Hi ,

I have an itoa ASM implementation. I would like to us
SIMD for it. But trying to figure out which parts can be
written with SIMD instruction or how can it be changed
for use SIMD instructions ?

The mentioned ASM implemetation :


void myitoa(int num, char * numstr)
{
__asm {
mov ebx,numstr ; point ebx to numstr
mov esi, num ; store number in esi
cmp esi, 0 ; if number is 0
jne nextdigit
mov [ebx],48 ; just set numstr to "0"
mov [ebx+1],0 ; add terminatting null character
jmp enditoa ; and end

nextdigit: mov eax, 66666667h ; 66666667h = 2^34 / 10
imul esi ; edx:eax = number * (2^34 / 10)
; therefore edx = number * (2^2 / 10)
sar edx, 2 ; edx = edx / 2^2
; therefore edx = number / 10 (integer division)

lea ecx, [edx + edx*4] ; ecx = edx * 5
add ecx,ecx ; ecx = edx * 10
; therfore ecx = (number div 10)*10

mov eax,esi ; store original number in eax
sub eax,ecx ; subtract ecx to leave remainder in eax

add eax,48 ; add 48 to make eax the digit's ASCII code

mov [ebx],al ; store digit character in numstr
inc ebx

mov esi,edx ; move number div 10 back into esi
cmp esi,0 ; if number div 10 = 0, we've finished
jnz nextdigit

mov [ebx],0 ; so add terminating null character

;reverse string
mov edx,numstr ; the number is in reverse order of digits
nextChar: dec ebx ; so we need to reverse the string
cmp ebx,edx
jle enditoa
mov eax,[edx]
mov ecx,[ebx]
mov [ebx],al
mov [edx],cl
inc edx
jmp nextChar
enditoa:
}
}
Antheus
Antheus
Logic:value = ...;
divisors = [ ..., 1000, 100, 10, 1 ];
modulo = [ ..., 10, 10, 10, 10, 10 ];
increment = [ ..., 0x30, 0x30, 0x30, 0x30 ]

sse_divide(value, divisors)
sse_mod(value, modulo)
sse_add(value, increment);


How it works:value = 413;
413 413 413
divide 100 10 1
= 4 41 413
mod 4 1 3
add 0x34 0x31 0x33

Or, first implement unrolled itoa, then implement that with SSE instructions.
akhin
akhin

Logic:value = ...;
divisors = [ ..., 1000, 100, 10, 1 ];
modulo = [ ..., 10, 10, 10, 10, 10 ];
increment = [ ..., 0x30, 0x30, 0x30, 0x30 ]

sse_divide(value, divisors)
sse_mod(value, modulo)
sse_add(value, increment);


How it works:value = 413;
413 413 413
divide 100 10 1
= 4 41 413
mod 4 1 3
add 0x34 0x31 0x33

Or, first implement unrolled itoa, then implement that with SSE instructions.


Thanks very much for your reply, one quick question is how to implement sse modulo in that case ?


Ive just checked Intel SW Developers Manual Vol2B , could not find ,

but just found something like this : http://think-in-co.d...modulo-mit-sse/
akhin
akhin
Also I can`t understand how to do flooring with SIMD , since manual modulus operation with SIMD relies on the flooring.
Antheus
Antheus
Thanks very much for your reply, one quick question is how to implement sse modulo in that case ?[/quote]

I'm not sure it can be done in a trivial manner. You could start from mod(a,n) = a-n*floor(a/n), but division would likely require switching to floating point.

The solution I gave was about vectorization. I can't think of a way to actually implement it practically, there are too many constraints in instruction sets.

After looking around a bit, here's a method that can be implemented, see remu10 in document linked from there.

int remu10(unsigned n) {
static char table[16] = {0, 1, 2, 2, 3, 3, 4, 5,
5, 6, 7, 7, 8, 8, 9, 0};
n = (0x19999999*n + (n >> 1) + (n >> 3)) >> 28;
return table[n];
}
akhin
akhin
Actually , for an assignment , I need to use SIMD insructions somehow to implement itoa fully in assembly.

Regarding the original code I have sent , is there anything you would suggest to somehow use SIMD instructions ?



I am strugglnig to do so , but I could not find any yet , for the worst case writing a SIMD itoa from scratch is also ok , ofcourse I would need modulo/floor for this one
Antheus
Antheus

Actually , for an assignment , I need to use SIMD insructions somehow to implement itoa fully in assembly.


School assignment? That seems rather poor choice.

It's doable, barely. But most of the work will go into hacking around the limitations of SSE and MMX registers. Itoa is just a poor fit for SSE-based implementation.

Regarding the original code I have sent , is there anything you would suggest to somehow use SIMD instructions ?[/quote]Nope. SIMD algorithm is completely different in every way. It's not something you sprinkle over in the end.


am strugglnig to do so , but I could not find any yet , for the worst case writing a SIMD itoa from scratch is also ok , ofcourse I would need modulo/floor for this one[/quote]The modulo formula is given above, the div/10 can be found in linked article.

But it will still result in a lot of ugly code. There's also impedance mismatch. 32-bit integer will result in sign+9 digits, but SSE prefers multiples of 4 or 16 elements. So regardless of whether working with 32 or 8 bit values, there is no perfect fit. Then there's potential issues with rounding, signedness, whether resulting string is properly aligned.

As said, it's doable, just a lot of effort for, IMHO, no useful gain.
akhin
akhin
I see your points , actually the method you mentinoed is the only starting point in my hand including the other link for modulo

so i think for the time being the best thing for me is starting to implement , perhaps I can come up with any ideas as I go through



Thanks a lot for information
akhin
akhin
As things have turned out I learned that I am allowed to change the definition/signature of itoa

So I want to implement a different version of itoa , which will take 4 or 8 integers at a time and return string will be their combined ascii versions.


Yes , the pdf in the link above already supplies all necessary information.


I wan to re-ask my question for this special case because perhaps another approach for that particular case might be suggested.
Zahlman
Zahlman

I have an itoa ASM implementation. I would like to use SIMD for it.


Because converting numbers to strings - presumably so that they can then be written to a file or a console window, which takes far, far more time - is performance-critical? What?
Antheus
Antheus


Because converting numbers to strings - presumably so that they can then be written to a file or a console window, which takes far, far more time - is performance-critical? What?


Even though the topic here is about some sort of homework, there is actually a theoretical case - map/reduce. While raw binary dump would be ideal, it gets complicated in heterogeneous environments. A good implementation could approach that of memcpy.

But as said above, it would need to be fairly constrained and SSE opcodes really aren't ideal for this.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.