x86 Assembly - 2 largest values out of 4 given numbers

后端 未结 3 757
隐瞒了意图╮
隐瞒了意图╮ 2021-01-29 02:28

I\'m writing a C subroutine in assembler that needs to find the 2 largest values out of 4 values passed in and multiplies them together. I\'m working on finding the largest val

3条回答
  •  面向向阳花
    2021-01-29 02:46

    This is my first solution to process the maximum number between four 16 Bit unsigned integer input numbers (80x86+ processors compatibile):

    Procedure Max4; Assembler;
    
    { Input: AX, BX, CX, DX
     Output: AX= MAX(AX,BX,CX,DX).
       Temp: DI}
    
    Asm
    
    { Input: AX, BX
     Output: AX= MAX(AX,BX).
       Temp: DI}
    
         Sub   AX,BX
         CmC
         SbB   DI,DI
         And   AX,DI
         Add   AX,BX
    
    { Input: CX, DX
     Output: CX= MAX(CX,DX).
       Temp: DI}
    
         Sub   CX,DX
         CmC
         SbB   DI,DI
         And   CX,DI
         Add   CX,DX
    
    { Input: AX, CX
     Output: AX= MAX(AX,CX).
       Temp: DI}
    
         Sub   AX,CX
         CmC
         SbB   DI,DI
         And   AX,DI
         Add   AX,CX
    
    End;
    

    My procedure Max4(), that is equivalent to AX=Max4(AX,BX,CX,DX), works great to a AX=Max(AX,BX) sub-routine that return a maximum value between two numbers and it is used three time:

    AX=Max(Max(AX,BX),Max(CX,DX))

    The AX=Max(AX,BX) sub-routine works as follow:

    1) Diff=AX-BX.
    2) If Diff>=0 then AX is the greatest number,
       Output= Diff+BX= AX-BX+BX= AX.
    3) If Diff<0 then BX is the greatest number,
       must set Diff to 0,
       Output= Diff+BX= 0+BX= BX.
    

    In ASSEMBY:

    { Input: AX, BX
     Output: AX= MAX(AX,BX).
       Temp: DI}
    
         Sub   AX,BX
        {Diff= AX-BX}
         CmC
        {If Diff>=0 -> FCarry=1 else FCarry=0}
         SbB   DI,DI
        {If Diff>=0 -> DI=DI-DI-1==-1 else DI=DI-DI-0==0}
         And   AX,DI
        {If Diff>=0 -> Diff=(Diff & -1)==Diff else Diff=(Diff & 0)==0}
         Add   AX,BX
        {AX= Diff+BX}
    

    But this solution works with unsigned 16 Bit numbers only and process only one largest number (don't do the multiplication). The next solution works correctly on 80x86+ processors (works with signed integer numbers; process two largest numbers):

    Function Max42R(A,B,C,D:Integer):LongInt; Assembler;
    
    Asm
    
         Mov   AX,A
         Mov   BX,B
         Mov   CX,C
         Mov   DX,D
    
       {1ø swap (when needed), 1ø scan}
    
         Cmp   AX,BX
         JLE   @01
    
         XChg  AX,BX
    
       {2ø swap (when needed), 1ø scan}
    
     @01:Cmp   BX,CX
         JLE   @02
    
         XChg  BX,CX
    
       {3ø swap (when needed), 1ø scan}
    
     @02:Cmp   CX,DX
         JLE   @03
    
         XChg  CX,DX
    
       {1ø swap (when needed), 2ø scan}
    
     @03:Cmp   AX,BX
         JLE   @04
    
         XChg  AX,BX
    
       {2ø swap (when needed), 2ø scan}
    
     @04:Cmp   BX,CX
         JLE   @05
    
         XChg  BX,CX
    
     {DX is the first greatest number;
      CX is the second greatest number}
    
     @05:Mov   AX,DX
         Mul   CX
    
    End;
    

    It is a variation of bubble-sort algorithm. In the bubble-sort yo must compare each pair of adjacent numbers in the array and swap them if the first is greater than the second; repeat the array scan if a swap is occurred until the array is sorted. But after the first scan the last value of the array is always the greatest number. Supposing that the four input values are as in a virtual array, I swap the first three pairs of registers, only when needed, to get the first greatest value,

    that is in the last register. After, I swap the first two pairs of registers, only when needed, to get the second greatest value, that is in the penultimate register.

    Max4() procedure can be written on 80386+ processor as follow (support 32 Bit signed integer numbers; process one largest number):

    Function Max4I(A,B,C,D:Integer):Integer; Assembler;
    
    { Input: EAX, EBX, ESI, EDI
     Output: EAX= MAX(EAX,EBX,ESI,EDI).
       Temp: CX.
    
      EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
      Can freely modify the EAX, ECX, AND EDX REGISTERs. }
    
    Asm
    
         Push  EBX
         Push  EDI
         Push  ESI
    
    {------------------------}
    
         Mov   EAX,A
         Mov   EBX,B
         Mov   ESI,C
         Mov   EDI,D
    
    { Input: EAX, EBX
     Output: EAX= MAX(EAX,EBX).
       Temp: ECX}
    
         Sub   EAX,EBX
         Mov   ECX,0
         SetL  CL
         Dec   ECX
         And   EAX,ECX
         Add   EAX,EBX
    
    { Input: EAX, ESI
     Output: EAX= MAX(EAX,ESI).
       Temp: ECX}
    
         Sub   EAX,ESI
         Mov   ECX,0
         SetL  CL
         Dec   ECX
         And   EAX,ECX
         Add   EAX,ESI
    
    { Input: EAX, EDI
     Output: EAX= MAX(EAX,EDI).
       Temp: ECX}
    
         Sub   EAX,EDI
         Mov   ECX,0
         SetL  CL
         Dec   ECX
         And   EAX,ECX
         Add   EAX,EDI
    
    {------------------------}
    
         Pop   ESI
         Pop   EDI
         Pop   EBX
    
    End;
    

    Finally the definitive solution that get the two greatest numbers between four 32 Bit signed integer numbers (80386+ processors). It works as Max42R() function:

    Function Max42(A,B,C,D:Integer):Integer; Assembler;
    
    { Input: EAX, EBX, ESI, EDI
     Output: EDI= 1° MAX(EAX,EBX,ESI,EDI).
             ESI= 2° MAX(EAX,EBX,ESI,EDI).
       Temp: ECX, EDX.
    
      EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
      Can freely modify the EAX, ECX, AND EDX REGISTERs. }
    
    Asm
    
         Push  EBX
         Push  EDI
         Push  ESI
    
         Mov   EAX,A
         Mov   EBX,B
         Mov   ESI,C
         Mov   EDI,D
    
    { Input: EAX, EBX
     Output: EAX= MIN(EAX,EBX).
             EBX= MAX(EAX,EBX).
       Temp: ECX, EDX}
    
         Sub   EAX,EBX
         Mov   EDX,EAX
         Mov   ECX,0
         SetGE CL
         Dec   ECX
         And   EAX,ECX
         Add   EAX,EBX
         Not   ECX
         And   EDX,ECX
         Add   EBX,EDX
    
    { Input: EBX, ESI
     Output: EBX= MIN(EBX,ESI).
             ESI= MAX(EBX,ESI).
       Temp: ECX, EDX}
    
         Sub   EBX,ESI
         Mov   EDX,EBX
         Mov   ECX,0
         SetGE CL
         Dec   ECX
         And   EBX,ECX
         Add   EBX,ESI
         Not   ECX
         And   EDX,ECX
         Add   ESI,EDX
    
    { Input: ESI, EDI
     Output: ESI= MIN(ESI,EDI).
             EDI= MAX(ESI,EDI).
       Temp: ECX, EDX}
    
         Sub   ESI,EDI
         Mov   EDX,ESI
         Mov   ECX,0
         SetGE CL
         Dec   ECX
         And   ESI,ECX
         Add   ESI,EDI
         Not   ECX
         And   EDX,ECX
         Add   EDI,EDX
    
    { Input: EAX, EBX
     Output: EAX= MIN(EAX,EBX).
             EBX= MAX(EAX,EBX).
       Temp: ECX, EDX}
    
         Sub   EAX,EBX
         Mov   EDX,EAX
         Mov   ECX,0
         SetGE CL
         Dec   ECX
         And   EAX,ECX
         Add   EAX,EBX
         Not   ECX
         And   EDX,ECX
         Add   EBX,EDX
    
    { Input: EBX, ESI
     Output: EBX= MIN(EBX,ESI).
             ESI= MAX(EBX,ESI).
       Temp: ECX, EDX}
    
         Sub   EBX,ESI
         Mov   EDX,EBX
         Mov   ECX,0
         SetGE CL
         Dec   ECX
         And   EBX,ECX
         Add   EBX,ESI
         Not   ECX
         And   EDX,ECX
         Add   ESI,EDX
    
    {EDI contain the first maximum number;
     ESI contain the second maximum number}
    
         Mov   EAX,EDI
    
    {------------------------}
    
         Pop   ESI
         Pop   EDI
         Pop   EBX
    
    End;
    

    How to swap two register only if the first is greater then the second ?

    This is the code (on the 80386+):

    { Input: EAX, EBX
     Output: EAX= MIN(EAX,EBX).
             EBX= MAX(EAX,EBX).
       Temp: ECX, EDX}
    
         Sub   EAX,EBX (* Diff= EAX-EBX; set Overflow flag and Sign flag *)
         Mov   EDX,EAX (* EDX= Diff; flags not altered *)
         Mov   ECX,0   (* ECX= 0; flags not altered *)
         SetGE CL      (* If Sign flag == Overflow flag ECX= 1 else ECX=0 *)
         Dec   ECX     (* If Diff>=0, ECX=0 else ECX=-1 *)
         And   EAX,ECX (* If Diff>=0, EAX=(EAX & 0)=0 else EAX=(EAX & -1)=EAX *)
         Add   EAX,EBX (* EAX= Minimum value between input n. *)
         Not   ECX     (* If Diff<0, ECX=0 else ECX=-1 *)
         And   EDX,ECX (* If Diff<0, EDX=(EDX & 0)=0 else EDX=(EDX & -1)=EDX *)
         Add   EBX,EDX (* EBX= Maximum value between input n. *)
    

    Function Max42 can be written also as the next code for 80686+ processors, that require only 20 fast ASM registers' instructions:

    Function Max42B(A,B,C,D:Integer):Integer; Assembler;
    
    { Input: EAX, EBX, ESI, EDI
     Output: EDI= 1° MAX(EAX,EBX,ESI,EDI).
             ESI= 2° MAX(EAX,EBX,ESI,EDI).
       Temp: ECX.
    
      EAX EDX ECX are 1°, 2° AND 3° PARAMETERs.
      Can freely modify the EAX, ECX, AND EDX REGISTERs. }
    
    Asm
    
         Push   EBX
         Push   EDI
         Push   ESI
    
         Mov    EAX,A
         Mov    EBX,B
         Mov    ESI,C
         Mov    EDI,D
    
    { Input: EAX, EBX
     Output: EAX= MIN(EAX,EBX).
             EBX= MAX(EAX,EBX).
       Temp: ECX}
    
         Mov    ECX,EAX
         Cmp    EAX,EBX
         CMovGE EAX,EBX
         CMovGE EBX,ECX
    
    { Input: EBX, ESI
     Output: EBX= MIN(EBX,ESI).
             ESI= MAX(EBX,ESI).
       Temp: ECX}
    
         Mov    ECX,EBX
         Cmp    EBX,ESI
         CMovGE EBX,ESI
         CMovGE ESI,ECX
    
    { Input: ESI, EDI
     Output: ESI= MIN(ESI,EDI).
             EDI= MAX(ESI,EDI).
       Temp: ECX}
    
         Mov    ECX,ESI
         Cmp    ESI,EDI
         CMovGE ESI,EDI
         CMovGE EDI,ECX
    
    { Input: EAX, EBX
     Output: EAX= MIN(EAX,EBX).
             EBX= MAX(EAX,EBX).
       Temp: ECX}
    
         Mov    ECX,EAX
         Cmp    EAX,EBX
         CMovGE EAX,EBX
         CMovGE EBX,ECX
    
    { Input: EBX, ESI
     Output: EBX= MIN(EBX,ESI).
             ESI= MAX(EBX,ESI).
       Temp: ECX}
    
         Mov    ECX,EBX
         Cmp    EBX,ESI
         CMovGE EBX,ESI
         CMovGE ESI,ECX
    
    {EDI contain the first maximum number;
     ESI contain the second maximum number}
    
         Mov   EAX,EDI
    
    {------------------------}
    
         Pop   ESI
         Pop   EDI
         Pop   EBX
    
    End;
    

    Hi!

提交回复
热议问题