D - abs
- Sean L. Palmer (10/10) Apr 18 2003 Shouldn't there be an intrinsic for abs for integral types?
- Walter (3/13) Apr 18 2003 It wouldn't generate better code than the inline of the ?: would.
- Sean L. Palmer (106/122) Apr 19 2003 Is that so?
-
Walter
(16/17)
Apr 19 2003
I'm a very old dog, Sean
. Given the following C program:
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
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
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
"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