what's the fastest way to sign extend from 24-bit to 32-bit?
what I can think of is like following:
mov eax,num24
mov ecx,eax
shl ecx,8 ;keep and move the sign bit
and eax,7FFFFFh ;keep the remaining bits
or eax,ecx
mov num32,eax
any better method?
what I can think of is like following:
mov eax,num24
mov ecx,eax
shl ecx,8 ;keep and move the sign bit
and eax,7FFFFFh ;keep the remaining bits
or eax,ecx
mov num32,eax
any better method?
24-bit "-1" is FFFFFF , while 32-bit "-1" is FFFFFFFF, so you can't just toggle the highest bit. And btw you'll lose that bit with a shl.
I guess this will work OK and as fast as possible:
I guess this will work OK and as fast as possible:
test eax,0800000h
jz @F
or eax,0FF000000h
@@:
jz is rarely optimal for speed : only well-predicted branches (Cf agner's doc)
shl ecx,31... buggy code, optimus, or else I did not understand u.
Take an example, please.
Here it is :
Say eax=03h
Output will be 03h
Say eax=0812345h
Output will be 0FF812345h
Correct ?
So I suggest :
mov ebx,0ff0000h
test eax,800000h
cmovz ebx,eax
or eax,ebx
Regards
shl ecx,31... buggy code, optimus, or else I did not understand u.
Take an example, please.
Here it is :
Say eax=03h
Output will be 03h
Say eax=0812345h
Output will be 0FF812345h
Correct ?
So I suggest :
mov ebx,0ff0000h
test eax,800000h
cmovz ebx,eax
or eax,ebx
Regards
May be this variant:
mov al,byte ptr num32+2
cbw
mov byte ptr num32+3,ah
mov al,byte ptr num32+2
cbw
mov byte ptr num32+3,ah
To sign extend a number in a register I'd do this (with some other instructions in between)
shl eax,8
sar eax,8
shl eax,8
sar eax,8
Sorry, it's a silly mistake.
I've modified it. See above.
I've modified it. See above.
Originally posted by valy
shl ecx,31... buggy code, optimus, or else I did not understand u.
shl ecx,31... buggy code, optimus, or else I did not understand u.
Your "corrected" code will still not yield proper results. Sephiroth3 provided the simplest solution to always get proper results (with or without some other instructions in between).
And, if you don't need to retain the 24-bit value in its memory variable, you can sign-extend it directly to its 32-bit value without using any register.
And, if you don't need to retain the 24-bit value in its memory variable, you can sign-extend it directly to its 32-bit value without using any register.
shl num24,8
sar num24,8
Raymondyes, i think his method is no doubt the fastest, and that's what i want.
actually, what i want is to do this job with C code. So I didn't use sar which cannot be done with C (with no in-line assembly)
Of course it can, just declare num24 as signed (which is the default)
Something like this? (num24 is unsigned, no meaning for it to be signed)
num32=((long)(num24<<8))>>8
num32=((long)(num24<<8))>>8
VC2003 + generated assembly. This function should of course be placed in a header so it can be inlined.
inline unsigned sign24to32(signed input)
{
return ((input << 8) >> 8);
}
/*
mov eax, DWORD PTR _input$[esp-4]
shl eax, 8
sar eax, 8
*/
In machines With sign shift most effective (in hence of instruction numbers) the way of Sephiroth3.
let x is bits in one size number (smaller in bits) y in another (bigger)
then (y-x) constant
code:
number_x shl (y-x) ;logical shift left
number_x sar (y-x) ;sign arithm. shifr right
like in Sephiroth3 code
shl eax,(32-24)
sar eax,(32-24)
If you don't like to use shl or sar then for 24-32 bits
yet want branchless code
extention you may use one of formulaes (in any machine)
((x+0080000h) and (00FFFFFFh)) - 800000h
((x and 00FFFFFFh) xor (0800000h)) - 800000h
instead of "+" you may you "xor" or "-"
The methods also can me more "math formal"
For example in 24 bits number sign bit is bit 23rd.
And the bit itself represent 2^23.
The for n-bits number it would be (n-1)th bit and would represent 2^(n-1)
Then for n-bits number 0800000h in above formulea we can replace by 2^(n-1) and 0FFFFFFh replaced by (2^n)-1
So for any n-bits number to be sign extended to current "machine word" we have
((x+2^(n-1)) and ((2^n)-1) - 2^(n-1)
((x xor 2^(n-1)) and ((2^n)-1) - 2^(n-1)
((x-2^(n-1)) and ((2^n)-1) - 2^(n-1)
((x and (2^n)-1)) xor (2^(n-1)) - 2^(n-1)
Both 2^(n-1) and (2^n)-1) - are some immeadiates:constants that calculated depending on "n"
let x is bits in one size number (smaller in bits) y in another (bigger)
then (y-x) constant
code:
number_x shl (y-x) ;logical shift left
number_x sar (y-x) ;sign arithm. shifr right
like in Sephiroth3 code
shl eax,(32-24)
sar eax,(32-24)
If you don't like to use shl or sar then for 24-32 bits
yet want branchless code
extention you may use one of formulaes (in any machine)
((x+0080000h) and (00FFFFFFh)) - 800000h
((x and 00FFFFFFh) xor (0800000h)) - 800000h
instead of "+" you may you "xor" or "-"
The methods also can me more "math formal"
For example in 24 bits number sign bit is bit 23rd.
And the bit itself represent 2^23.
The for n-bits number it would be (n-1)th bit and would represent 2^(n-1)
Then for n-bits number 0800000h in above formulea we can replace by 2^(n-1) and 0FFFFFFh replaced by (2^n)-1
So for any n-bits number to be sign extended to current "machine word" we have
((x+2^(n-1)) and ((2^n)-1) - 2^(n-1)
((x xor 2^(n-1)) and ((2^n)-1) - 2^(n-1)
((x-2^(n-1)) and ((2^n)-1) - 2^(n-1)
((x and (2^n)-1)) xor (2^(n-1)) - 2^(n-1)
Both 2^(n-1) and (2^n)-1) - are some immeadiates:constants that calculated depending on "n"
well, depending on how 24bits signed number is loaded in 32 bits register there might be even shorter way, if
upper 8 bits are unchanged (zeroes) in 24bits number image in 32 bits register and "and" instruction in formulea can be left out. Then it can be done by derivation of one of the above formula with 2 commands and without shifts (eax= image of 24bits number with zeroes in upper 8 bits):
The same if it in case on any n-bits number image in wider register
xor eax,2^(n-1)
sub eax,2^(n-1)
upper 8 bits are unchanged (zeroes) in 24bits number image in 32 bits register and "and" instruction in formulea can be left out. Then it can be done by derivation of one of the above formula with 2 commands and without shifts (eax= image of 24bits number with zeroes in upper 8 bits):
xor eax,800000h
sub eax,800000h
The same if it in case on any n-bits number image in wider register
xor eax,2^(n-1)
sub eax,2^(n-1)
very rewarding...