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?
Posted on 2004-07-29 04:17:31 by optimus
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:


test eax,0800000h
jz @F
or eax,0FF000000h
@@:
Posted on 2004-07-29 06:01:34 by Ultrano
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
Posted on 2004-07-29 06:39:49 by valy
May be this variant:

mov al,byte ptr num32+2
cbw
mov byte ptr num32+3,ah
Posted on 2004-07-29 06:57:44 by MikDay
To sign extend a number in a register I'd do this (with some other instructions in between)
shl eax,8
sar eax,8
Posted on 2004-07-29 10:51:21 by Sephiroth3
Sorry, it's a silly mistake.
I've modified it. See above.
Originally posted by valy
shl ecx,31... buggy code, optimus, or else I did not understand u.
Posted on 2004-07-29 20:01:54 by optimus
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.
shl num24,8

sar num24,8
Raymond
Posted on 2004-07-29 21:31:06 by Raymond
yes, i think his method is no doubt the fastest, and that's what i want.
Posted on 2004-07-29 22:33:02 by optimus
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)
Posted on 2004-07-29 22:35:36 by optimus
Of course it can, just declare num24 as signed (which is the default)
Posted on 2004-07-29 23:08:04 by Sephiroth3
Something like this? (num24 is unsigned, no meaning for it to be signed)

num32=((long)(num24<<8))>>8
Posted on 2004-07-29 23:45:25 by optimus
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
*/
Posted on 2004-07-30 06:28:55 by f0dder
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"
Posted on 2004-07-30 07:00:37 by The Svin
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):


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)
Posted on 2004-07-30 07:54:15 by The Svin
very rewarding...
Posted on 2004-07-30 20:07:20 by optimus