From 14f2edc56ebb3b19fc0e831185004aadf53b1ad8 Mon Sep 17 00:00:00 2001 From: daniel Date: Fri, 15 Jun 2007 13:59:20 +0000 Subject: [PATCH] + Assembler implementation of min/max by Alex Rayne. git-svn-id: trunk@7668 - --- rtl/i386/mathu.inc | 193 +++++++++++++++++++++++++++++++++++++- rtl/objpas/math.pp | 214 ++++++++++++++++++++++++++++++++++++++----- rtl/x86_64/mathu.inc | 25 +++++ 3 files changed, 408 insertions(+), 24 deletions(-) diff --git a/rtl/i386/mathu.inc b/rtl/i386/mathu.inc index a85db115d5..eb6825669f 100644 --- a/rtl/i386/mathu.inc +++ b/rtl/i386/mathu.inc @@ -11,8 +11,199 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} - {$ASMMODE ATT} + + {this optimisations ported from Cris Kaspersky articles + kpnc@itech.ru, kpnc@programme.ru + } + {$define FPC_MATH_HAS_MIN_BYTE} + function Min(a, b: byte): byte;inline;assembler;nostackframe; + asm + movb b, %al + subb a ,%al + sbbb %cl, %cl + andb %cl, %al + addb a, %al + end['AL','CL']; + + {$define FPC_MATH_HAS_MAX_BYTE} + function Max(a, b: byte): byte;inline;assembler;nostackframe; + asm + movb b, %al + subb a ,%al + sbbb %cl, %cl + andb %al, %cl + movb b ,%al + subb %cl,%al + end['AL','CL']; + + {$define FPC_MATH_HAS_MIN_DWORD} + function Min(a, b: LongWord): LongWord;inline;assembler;nostackframe; + asm + movl b, %eax + subl a ,%eax + sbbl %ecx, %ecx + andl %ecx, %eax + addl a, %eax + end['EAX','ECX']; + + {$define FPC_MATH_HAS_MAX_DWORD} + function Max(a, b: LongWord): LongWord;inline;assembler;nostackframe; + asm + movl b, %eax + subl a ,%eax + sbbl %ecx, %ecx + andl %eax, %ecx + movl b ,%eax + subl %ecx,%eax + end['EAX','ECX']; + + {$define FPC_MATH_HAS_MIN_QWORD} + function Min(a, b: QWord): QWord;inline;assembler;nostackframe; + asm + movl b, %eax + movl b+4, %edx + + subl a ,%eax + sbbl a+4 ,%edx + + sbbl %ecx, %ecx + + andl %ecx, %eax + andl %ecx, %edx + + addl a, %eax + adcl a+4, %edx + end['EAX','EBX','ECX','EDX']; + + {$define FPC_MATH_HAS_MAX_QWORD} + function Max(a, b: QWord): QWord;inline;assembler;nostackframe; + asm + movl b, %eax + movl b+4, %edx + + subl a ,%eax + sbbl a+4 ,%edx + + sbbl %ebx, %ebx + sbbl %ecx, %ecx + + andl %eax, %ebx + andl %edx, %ecx + + subl a ,%eax + sbbl a+4 ,%edx + + addl %ebx, %eax + adcl %ecx, %edx + end['EAX','EBX','ECX','EDX']; + +{$define FPC_MATH_HAS_Min_DWORDS} +function MinValue(const Data : PLongWord; const N : cardinal): LongWord;assembler; + var + saveesi : LongWord; + asm + movl %esi,saveesi + movl Data,%esi + movl N,%ecx + lodsl + movl %eax,%edx + decl %ecx + jg .LFinalLineLoop + jmp .Lfinish +.LFinalLineLoop: + lodsl + subl %eax ,%edx {eax - a, edx - result=b} + sbbl %ebx, %ebx + andl %ebx, %eax + addl %eax, %edx + decl %ecx + jne .LFinalLineLoop +.Lfinish: + movl %edx,%eax + movl saveesi, %esi + end['EAX','EBX','ECX','EDX']; + +{$define FPC_MATH_HAS_Max_DWORDS} +function MaxValue(const Data : PLongWord; const N : cardinal): LongWord;assembler; + var + saveesi : LongWord; + asm + movl %esi,saveesi + movl Data,%esi + movl N,%ecx + lodsl + movl %eax,%edx + decl %ecx + jg .LFinalLineLoop + jmp .Lfinish +.LFinalLineLoop: + + lodsl + pushl %edx + subl %eax ,%edx {eax - a, edx - result=b} + sbbl %ebx, %ebx + andl %edx, %ebx + popl %edx + subl %ebx, %edx + + decl %ecx + jne .LFinalLineLoop +.Lfinish: + movl %edx,%eax + movl saveesi, %esi + end['EAX','EBX','ECX','EDX']; + +{$define FPC_MATH_HAS_Min_INTS} +function MinValue(const Data : PInteger; const N : cardinal): Integer;assembler; +var + saveesi : LongWord; + asm + movl %esi,saveesi + movl Data,%esi + movl N,%ecx + lodsl + decl %ecx + jg .LFinalLineLoop + jmp .Lfinish +.LFinalLineLoop: + lodsl + cmpl %eax ,%edx {eax - a, edx - result=b} + jle .LIAskip + movl %eax ,%edx +.LIAskip: + decl %ecx + jne .LFinalLineLoop +.Lfinish: + movl %edx,%eax + movl saveesi, %esi + end['EAX','ECX','EDX']; + +{$define FPC_MATH_HAS_Max_INTS} +function MaxValue(const Data : PInteger; const N : cardinal): Integer;assembler; +var + saveesi : LongWord; + asm + movl %esi,saveesi + movl Data,%esi + movl N,%ecx + lodsl + decl %ecx + jg .LFinalLineLoop + jmp .Lfinish +.LFinalLineLoop: + lodsl + cmpl %eax ,%edx {eax - a, edx - result=b} + jge .LIAskip + movl %eax ,%edx +.LIAskip: + decl %ecx + jne .LFinalLineLoop +.Lfinish: + movl %edx,%eax + movl saveesi, %esi + end['EAX','ECX','EDX']; + {$define FPC_MATH_HAS_ARCTAN2} function arctan2(y,x : float) : float;assembler; asm diff --git a/rtl/objpas/math.pp b/rtl/objpas/math.pp index 53639cc01a..5136586c75 100644 --- a/rtl/objpas/math.pp +++ b/rtl/objpas/math.pp @@ -136,6 +136,10 @@ interface function MinIntValue(const Data: array of Integer): Integer; function MaxIntValue(const Data: array of Integer): Integer; +function Min(a, b: byte): byte;inline; +function Max(a, b: byte): byte;inline; +function Min(a, b: ShortInt): ShortInt;inline; +function Max(a, b: ShortInt): ShortInt;inline; { Extra, not present in Delphi, but used frequently } function Min(a, b: Integer): Integer;inline; function Max(a, b: Integer): Integer;inline; @@ -143,8 +147,13 @@ function Max(a, b: Integer): Integer;inline; function Min(a, b: Cardinal): Cardinal; function Max(a, b: Cardinal): Cardinal; } +function Min(a, b: LongWord): LongWord;inline; +function Max(a, b: LongWord): LongWord;inline; function Min(a, b: Int64): Int64;inline; function Max(a, b: Int64): Int64;inline; +function Min(a, b: QWord): QWord;inline; +function Max(a, b: QWord): QWord;inline; + {$ifdef FPC_HAS_TYPE_SINGLE} function Min(a, b: Single): Single;inline; function Max(a, b: Single): Single;inline; @@ -166,6 +175,8 @@ function InRange(const AValue, AMin, AMax: Double): Boolean;inline; function EnsureRange(const AValue, AMin, AMax: Integer): Integer;inline; function EnsureRange(const AValue, AMin, AMax: Int64): Int64;inline; +function EnsureRange(const AValue, AMin, AMax: LongWord): LongWord;inline; +function EnsureRange(const AValue, AMin, AMax: QWord): QWord;inline; {$ifdef FPC_HAS_TYPE_DOUBLE} function EnsureRange(const AValue, AMin, AMax: Double): Double;inline; {$endif FPC_HAS_TYPE_DOUBLE} @@ -410,11 +421,23 @@ function maxvalue(const data : array of Extended) : Extended; function maxvalue(const data : PExtended; Const N : Integer) : Extended; {$endif FPC_HAS_TYPE_EXTENDED} +function MinValue(const Data: array of LongWord): LongWord; +function MinValue(const Data : PLongWord; Const N : cardinal): LongWord; + +function MinValue(const Data: array of byte): byte; +function MinValue(const Data : PByte; Const N : cardinal): byte; + function minvalue(const data : array of integer) : Integer; -function MinValue(const Data : PInteger; Const N : Integer): Integer; +function MinValue(const Data : PInteger; Const N : cardinal): Integer; + +function MaxValue(const Data: array of LongWord): LongWord; +function MaxValue(const Data : PLongWord; Const N : cardinal): LongWord; + +function MaxValue(const Data: array of byte): byte; +function MaxValue(const Data : PByte; Const N : cardinal): byte; function maxvalue(const data : array of integer) : Integer; -function maxvalue(const data : PInteger; Const N : Integer) : Integer; +function maxvalue(const data : PInteger; Const N : cardinal) : Integer; { returns random values with gaussian distribution } function randg(mean,stddev : float) : float; @@ -1705,12 +1728,44 @@ begin If Data[I] > Result Then Result := Data[I]; end; -function MinValue(const Data: array of Integer): Integer; +function MinValue(const Data: array of LongWord): LongWord; +begin + Result:=MinValue(PLongWord(@Data[0]),Length(Data)) +end; +{$ifndef FPC_MATH_HAS_MIN_DWORDS} +function MinValue(const Data : PLongWord; Const N : cardinal): LongWord; +var + I : Integer; +begin + Result := Data[0]; + For I := 1 To N-1 do + Result := Min(Data[I], Result); +end; +{$endif FPC_MATH_HAS_MIN_DWORDS} + +function MinValue(const Data: array of byte): byte; +begin + Result:=MinValue(PByte(@Data[0]),Length(Data)) +end; + +{$ifndef FPC_MATH_HAS_MIN_BYTES} +function MinValue(const Data : PByte; Const N : cardinal): byte; +var + I: Integer; +begin + Result := Data[0]; + For I := 1 To N-1 do + Result := Min(Data[I], Result); +end; +{$endif FPC_MATH_HAS_MIN_BYTES} + +function MinValue(const Data: array of Integer): Integer; begin Result:=MinValue(Pinteger(@Data[0]),High(Data)+1) end; +{$ifndef FPC_MATH_HAS_MIN_INTS} function MinValue(const Data: PInteger; Const N : Integer): Integer; var I: Integer; @@ -1719,18 +1774,17 @@ begin For I := 1 To N-1 do If Data[I] < Result Then Result := Data[I]; end; +{$endif FPC_MATH_HAS_MIN_INTS} function MaxValue(const Data: array of Integer): Integer; - begin Result:=MaxValue(PInteger(@Data[0]),High(Data)+1) end; +{$ifndef FPC_MATH_HAS_MAX_INTS} function maxvalue(const data : PInteger; Const N : Integer) : Integer; - var - i : longint; - + i : longint; begin { get an initial value } maxvalue:=data[0]; @@ -1738,6 +1792,39 @@ begin if data[i]>maxvalue then maxvalue:=data[i]; end; +{$endif FPC_MATH_HAS_MAX_INTS} + +function MaxValue(const Data: array of LongWord): LongWord; +begin + Result:=MaxValue(PLongWord(@Data[0]),High(Data)+1) +end; + +{$ifndef FPC_MATH_HAS_MAX_DWORDS} +function MaxValue(const Data : PLongWord; Const N : cardinal): LongWord; +var + I: Integer; +begin + Result := Data[0]; + For I := 1 To N-1 do + Result := Max(Data[I], Result); +end; +{$endif FPC_MATH_HAS_MAX_DWORDS} + +function MaxValue(const Data: array of byte): byte; +begin + Result:=MaxValue(PByte(@Data[0]),High(Data)+1) +end; + +{$ifndef FPC_MATH_HAS_MAX_BYTES} +function MaxValue(const Data : PByte; Const N : cardinal): byte; +var + I: Integer; +begin + Result := Data[0]; + For I := 1 To N-1 do + Result := Max(Data[I], Result); +end; +{$endif FPC_MATH_HAS_MAX_BYTES} {$ifdef FPC_HAS_TYPE_SINGLE} function minvalue(const data : array of Single) : Single; @@ -1747,10 +1834,8 @@ begin end; function minvalue(const data : PSingle; Const N : Integer) : Single; - var - i : longint; - + i : longint; begin { get an initial value } minvalue:=data[0]; @@ -1767,10 +1852,8 @@ begin end; function maxvalue(const data : PSingle; Const N : Integer) : Single; - var i : longint; - begin { get an initial value } maxvalue:=data[0]; @@ -1788,10 +1871,8 @@ begin end; function minvalue(const data : PDouble; Const N : Integer) : Double; - var i : longint; - begin { get an initial value } minvalue:=data[0]; @@ -1800,7 +1881,6 @@ begin minvalue:=data[i]; end; - function maxvalue(const data : array of Double) : Double; begin @@ -1808,10 +1888,8 @@ begin end; function maxvalue(const data : PDouble; Const N : Integer) : Double; - var i : longint; - begin { get an initial value } maxvalue:=data[0]; @@ -1832,7 +1910,6 @@ function minvalue(const data : PExtended; Const N : Integer) : Extended; var i : longint; - begin { get an initial value } minvalue:=data[0]; @@ -1849,10 +1926,8 @@ begin end; function maxvalue(const data : PExtended; Const N : Integer) : Extended; - var i : longint; - begin { get an initial value } maxvalue:=data[0]; @@ -1862,7 +1937,47 @@ begin end; {$endif FPC_HAS_TYPE_EXTENDED} +{$ifndef FPC_MATH_HAS_MIN_BYTE} +function Min(a, b: byte): byte;inline; +begin + if a < b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MIN_BYTE} +{$ifndef FPC_MATH_HAS_MAX_BYTE} +function Max(a, b: byte): byte;inline; +begin + if a > b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MAX_BYTE} + +{$ifndef FPC_MATH_HAS_MIN_SINT} +function Min(a, b: ShortInt): ShortInt;inline; +begin + if a < b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MIN_SINT} + +{$ifndef FPC_MATH_HAS_MAX_SINT} +function Max(a, b: ShortInt): ShortInt;inline; +begin + if a > b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MAX_SINT} + +{$ifndef FPC_MATH_HAS_MIN_INT} function Min(a, b: Integer): Integer;inline; begin if a < b then @@ -1870,7 +1985,9 @@ begin else Result := b; end; +{$endif FPC_MATH_HAS_MIN_INT} +{$ifndef FPC_MATH_HAS_MAX_INT} function Max(a, b: Integer): Integer;inline; begin if a > b then @@ -1878,6 +1995,7 @@ begin else Result := b; end; +{$endif FPC_MATH_HAS_MAX_INT} { function Min(a, b: Cardinal): Cardinal;inline; @@ -1896,7 +2014,27 @@ begin Result := b; end; } +{$ifndef FPC_MATH_HAS_MIN_DWORD} +function Min(a, b: LongWord): LongWord;inline; +begin + if a < b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MIN_DWORD} +{$ifndef FPC_MATH_HAS_MAX_DWORD} +function Max(a, b: LongWord): LongWord;inline; +begin + if a > b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MAX_DWORD} + +{$ifndef FPC_MATH_HAS_MIN_INT64} function Min(a, b: Int64): Int64;inline; begin if a < b then @@ -1904,7 +2042,9 @@ begin else Result := b; end; +{$endif FPC_MATH_HAS_MIN_INT64} +{$ifndef FPC_MATH_HAS_MAX_INT64} function Max(a, b: Int64): Int64;inline; begin if a > b then @@ -1912,6 +2052,27 @@ begin else Result := b; end; +{$endif FPC_MATH_HAS_MIN_INT64} + +{$ifndef FPC_MATH_HAS_MIN_QWORD} +function Min(a, b: QWord): QWord;inline; +begin + if a < b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MIN_QWORD} + +{$ifndef FPC_MATH_HAS_MAX_QWORD} +function Max(a, b: QWord): QWord;inline; +begin + if a > b then + Result := a + else + Result := b; +end; +{$endif FPC_MATH_HAS_MAX_QWORD} {$ifdef FPC_HAS_TYPE_SINGLE} function Min(a, b: Single): Single;inline; @@ -1987,7 +2148,6 @@ end; {$endif FPC_HAS_TYPE_DOUBLE} function EnsureRange(const AValue, AMin, AMax: Integer): Integer;inline; - begin Result:=AValue; If Result