www.digitalmars.com         C & C++   DMDScript  

D - abs

reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Shouldn't there be an intrinsic for abs for integral types?

from math2.d:

int abs(int n)
{
 return n > 0 ? n : -n;
}

long abs(long n)
{
 return n > 0 ? n : -n;
}
Apr 18 2003
parent reply "Walter" <walter digitalmars.com> writes:
It wouldn't generate better code than the inline of the ?: would.

"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b7pc23$2lvt$1 digitaldaemon.com...
 Shouldn't there be an intrinsic for abs for integral types?

 from math2.d:

 int abs(int n)
 {
  return n > 0 ? n : -n;
 }

 long abs(long n)
 {
  return n > 0 ? n : -n;
 }
Apr 18 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Is that so?


Built with these settings:  (I only kept the -g so I could breakpoint near
the code to examine it.  I'm assuming it won't affect the code generation
much;  if I'm wrong, let me know and I'll test again.)
 set dmd=..\..\bin\dmd

 set options=-O -release -g

 echo on

%dmd% timer.d %options%

The code (comments inline):

const int nelem = 32768;

uint test()

00402050 sub esp,28h

00402053 push ebx

{

uint b = abs(-nelem);

00402054 push 4

00402056 push 8000h

0040205B call __d_new (402278h)  // I have no idea what this is.

00402060 mov dword ptr [esp+10h],eax

00402064 mov eax,0FFFF8000h   // at least it negates this constant at
compile time

00402069 mov dword ptr [esp+14h],edx

printf("b=%f\n",b);

uint c = abs(-(int)GetTicks());

0040206D call _Dmath2_abs_FiZi (40231Ch) // but seriously?  Its argument is
a constant... it doesn't even inline it.

00402072 push eax

00402073 push offset __xt_z+1Eh (40E08Eh)

00402078 call _printf (404F54h)

printf("c=%f\n",c);

0040207D call dword ptr [_Dtimer_GetTicks_PFZm (410A00h)]

00402083 neg eax

00402085 call _Dmath2_abs_FiZi (40231Ch)

0040208A push eax

0040208B push offset __xt_z+18h (40E088h)

00402090 call _printf (404F54h)

}



You know better than I do, but I'm sure this can be improved upon:



_Dmath2_abs_FiZi:

0040231C mov ecx,eax  // what is the purpose of this?

0040231E test eax,eax

00402320 jle _Dmath2_abs_FiZi+8 (402324h)  // why does it not just reverse
the sense of this test and jump once?

00402322 jmp _Dmath2_abs_FiZi+0Ah (402326h)

00402324 neg eax

00402326 ret

00402327 int 3



for instance:   Here is an old assembler trick that apparently MSVC does:



I quote:  (from this page:  http://www.dpgraph.com/assembly.html )

       Absolute value of an integer


One of the classic assembly language tricks is taking the absolute value of
a 2's complement integer. The naive method would be:

; Eax contains integer.
  Test  Eax,Eax ; Is Eax negative?
  Jns   GotAbsoluteValue ; If sign bit is 0, integer is already
non-negative.
  Neg   Eax ; Negate a negative integer to get a positive integer.
GotAbsoluteValue:
; Eax contains abs(integer).
This method is good for clarity and for using the minimum number of
registers, but is bad for speed because of the test and jump. The classic
trick is:

; Eax contains integer.
  Cdq   ; Edx = -1 if Eax negative, Edx = 0 otherwise.
  Xor   Eax,Edx ; Eax = -integer-1 if Eax negative, Eax = integer otherwise.
  Sub   Eax,Edx ; Eax = -integer if Eax negative, Eax = integer otherwise.
; Eax contains abs(integer), Edx = -1 if Eax was negative, Edx = 0
otherwise.
This method is bad for clarity (although most experienced assembly language
programmers would recognize it as a common idiom) and for register usage,
but is good for speed because it gets rid of the test and jump. Since the
Cdq instruction works only with the Eax and Edx registers, a variation that
will work with any pair of registers is:

; Eax contains integer.
  Mov   Edx,Eax ; Copy integer.
  Sar   Edx,31 ; Edx = -1 if Eax negative, Edx = 0 otherwise.
  Xor   Eax,Edx ; Eax = -integer-1 if Eax negative, Eax = integer otherwise.
  Sub   Eax,Edx ; Eax = -integer if Eax negative, Eax = integer otherwise.
; Eax contains abs(integer), Edx = -1 if Eax was negative, Edx = 0
otherwise.
And as a final thought, sometimes the full absolute value isn't needed. See,
for example, Divide a signed dividend by an unsigned divisor. For that
tip/trick, if the integer is positive or zero we want to leave the integer
unchanged (just as for the absolute value). However, if the integer is
negative what we want is the absolute value minus 1. So, we need only the
first three instructions above:

; Eax contains integer.
  Mov   Edx,Eax ; Copy integer.
  Sar   Edx,31 ; Edx = -1 if Eax negative, Edx = 0 otherwise.
  Xor   Eax,Edx ; Eax = -integer-1 if Eax negative, Eax = integer otherwise.
; Eax contains result, Edx = -1 if Eax was negative, Edx = 0 otherwise.
=================

You're an old dog, Walter.  I thought you'd know this one.  ;)  It's been so
long I had to look it up again.  I thought I'd never have to do that again.

Actually I bet the problem is that D's code generation is not finished.  In
particular I feel inlining and constant folding may have issues.

Abs, and all the other basic math functions, can always be performed on
constants at compile time, at least.  That's a good optimization.

As an afterthought, it seems there should be overloaded versions of abs for
unsigned types that does absolutely nothing (the values are already
guaranteed to not be negative, by definition).

Sean

P.S. Walter, I almost have the profiling timer stuff working.   Ok, the core
works, but it isn't done yet.


"Walter" <walter digitalmars.com> wrote in message
news:b7pgp6$2pba$1 digitaldaemon.com...
 It wouldn't generate better code than the inline of the ?: would.

 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b7pc23$2lvt$1 digitaldaemon.com...
 Shouldn't there be an intrinsic for abs for integral types?

 from math2.d:

 int abs(int n)
 {
  return n > 0 ? n : -n;
 }

 long abs(long n)
 {
  return n > 0 ? n : -n;
 }
Apr 19 2003
parent "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b7qv7s$1l78$1 digitaldaemon.com...
 You're an old dog, Walter.  I thought you'd know this one.  ;)
I'm a very old dog, Sean <g>. Given the following C program: int test(int a) { return (a < 0) ? -a : a; } and compiling it with DMC++ with optimization on yields: ?test YAHH Z: mov EAX,4[ESP] cdq xor EAX,EDX sub EAX,EDX ret I miss the old days when people would write whole books on assembler speed tricks!
Apr 19 2003