586 lines
16 KiB
ArmAsm
586 lines
16 KiB
ArmAsm
/* -*- Mode: asm; tab-width:4; truncate-lines:t -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
#include <md/Asm.h>
|
|
|
|
.file "x86Stub_gas.S"
|
|
|
|
|
|
GLOBAL_ENTRY(staticCompileStub)
|
|
|
|
push %ebp /* Make stack frame */
|
|
mov %esp,%ebp
|
|
|
|
/* Even though ESI and EDI are non-volatile (callee-saved) registers, we need to
|
|
preserve them here in case an exception is thrown. The exception-handling
|
|
code expects to encounter this specially-prepared stack "guard" frame when
|
|
unwinding the stack. See x86ExceptionHandler.cpp. */
|
|
push %edi
|
|
push %esi
|
|
push %ebx /* XXX - Why push EBX ? It's caller-saved */
|
|
|
|
/* Call compileAndBackPatchMethod() with 2 args */
|
|
push 16(%esp) /* Push the second argument to compileAndBackPatchMethod (return address) */
|
|
push %eax /* Push the first argument to compileAndBackPatchMethod (cacheEntry) */
|
|
call SYMBOL_NAME(compileAndBackPatchMethod)
|
|
|
|
mov %ebp,%esp /* Pop stack frame */
|
|
pop %ebp
|
|
|
|
jmp *%eax /* Jump to function leaving the return address at the top of the stack */
|
|
|
|
END_ENTRY(staticCompileStub)
|
|
|
|
/*
|
|
* 64bit Arithmetic Support Functions
|
|
*
|
|
* x86Extract64Bit
|
|
*
|
|
* Origin: Simon
|
|
* Purpose: signed right-aligned field extraction
|
|
* In: 64 bit source (on stack)
|
|
* 32 bit extraction size (on stack)
|
|
* Out: 64 bit result
|
|
* Note: Only works in range 1 <= b <= 63, b is extraction amount
|
|
*/
|
|
GLOBAL_ENTRY(x86Extract64Bit)
|
|
|
|
mov 4(%esp),%eax /* load low byte of a */
|
|
|
|
mov 12(%esp),%ecx /*load shift amount */
|
|
cmp $0x20,%ecx
|
|
jg greater32
|
|
|
|
/* extract <= than 32 bits
|
|
* shift amount = 32 - extract
|
|
*/
|
|
neg %ecx
|
|
add $0x20,%ecx /* ecx = 32 - extract */
|
|
shl %cl,%eax
|
|
sar %cl,%eax
|
|
cdq /* sign extend into EDX:EAX */
|
|
ret $12
|
|
|
|
greater32:
|
|
/* ext > 32 bits
|
|
* shift amount = 64 - extract
|
|
*/
|
|
mov 8(%esp),%edx /* load high byte of a */
|
|
neg %ecx
|
|
add $0x40,%ecx /* ecx = 64 - extract */
|
|
shl %cl,%edx
|
|
sar %cl,%edx
|
|
ret $12
|
|
|
|
END_ENTRY(x86Extract64Bit)
|
|
|
|
/*
|
|
* 3WayCompare
|
|
*
|
|
* Origin: Symantec JIT
|
|
* Purpose: compare two longs
|
|
* In: two longs on the stack
|
|
* Out: depends on condition flags:
|
|
* less = -1
|
|
* equal = 0
|
|
* greater = 1
|
|
*/
|
|
GLOBAL_ENTRY(x86ThreeWayCMP_L)
|
|
|
|
/* edx:eax is tos, ecx:ebx is nos */
|
|
mov 8(%esp),%ecx
|
|
mov 16(%esp),%edx
|
|
|
|
cmp %edx,%ecx
|
|
jl lcmp_m1
|
|
|
|
jg lcmp_1
|
|
|
|
mov 4(%esp),%ecx
|
|
mov 12(%esp),%edx
|
|
|
|
cmp %edx,%ecx
|
|
ja lcmp_1
|
|
|
|
mov $0,%eax
|
|
jb lcmp_m1
|
|
|
|
ret $16
|
|
|
|
.align 4
|
|
lcmp_m1:
|
|
mov $-1,%eax
|
|
ret $16
|
|
|
|
.align 4
|
|
lcmp_1:
|
|
mov $1,%eax
|
|
ret $16
|
|
|
|
END_ENTRY(x86ThreeWayCMP_L)
|
|
|
|
/*
|
|
* llmul
|
|
*
|
|
* Origin: Intel Code (via MSDev)
|
|
* Purpose: long multiply (same for signed/unsigned)
|
|
* In: args are passed on the stack:
|
|
* 1st pushed: multiplier (QWORD)
|
|
* 2nd pushed: multiplicand (QWORD)
|
|
* Out: EDX:EAX - product of multiplier and multiplicand
|
|
* Note: parameters are removed from the stack
|
|
* Uses: ECX
|
|
*/
|
|
GLOBAL_ENTRY(x86Mul64Bit)
|
|
|
|
/* A*B = (A.lo * B.lo) + (A.lo * B.hi) + (B.lo * A.hi) ??? */
|
|
mov 8(%esp),%eax /* A.hi */
|
|
mov 16(%esp),%ecx /* B.hi */
|
|
or %eax,%ecx /* test for both hiwords zero */
|
|
mov 12(%esp),%ecx /* B.lo */
|
|
jnz hard
|
|
|
|
/* easy case
|
|
* both are zero, just mult ALO and BLO
|
|
*/
|
|
mov 4(%esp),%eax /* A.lo */
|
|
mul %ecx /* A.lo * B.lo */
|
|
ret $16 /* callee restores the stack */
|
|
|
|
/* hard case */
|
|
hard:
|
|
push %ebx
|
|
|
|
mul %ecx /* A.hi * B.lo */
|
|
mov %eax,%ebx /* save result */
|
|
|
|
mov 8(%esp),%eax /* A.lo */
|
|
mull 14(%esp) /* A.lo * B.hi */
|
|
add %eax,%ebx /* ebx = ((A.lo * B.hi) + (A.hi * B.lo)) */
|
|
|
|
mov 8(%esp),%eax /* A.lo */
|
|
mul %ecx /* edx:eax = A.lo * B.lo */
|
|
add %ebx,%edx /* now edx has all the LO*HI stuff */
|
|
|
|
pop %ebx
|
|
|
|
ret $16 /* callee restores the stack */
|
|
|
|
END_ENTRY(x86Mul64Bit)
|
|
|
|
/*
|
|
* lldiv
|
|
*
|
|
* Origin: Intel Code (via MSDev)
|
|
* Purpose: signed long divide
|
|
* In: args are passed on the stack:
|
|
* 1st pushed: divisor (QWORD)
|
|
* 2nd pushed: dividend (QWORD)
|
|
* Out: EDX:EAX contains the quotient (dividend/divisor)
|
|
* Note: parameters are removed from the stack
|
|
* Uses: ECX
|
|
*/
|
|
GLOBAL_ENTRY(x86Div64Bit)
|
|
|
|
push %edi
|
|
push %esi
|
|
push %ebx
|
|
|
|
/* Determine sign of the result (%edi = 0 if result is positive, non-zero
|
|
* otherwise) and make operands positive.
|
|
*/
|
|
xor %edi,%edi /* result sign assumed positive */
|
|
|
|
mov 20(%esp),%eax /* hi word of a */
|
|
or %eax,%eax /* test to see if signed */
|
|
jge L1 /* skip rest if a is already positive */
|
|
inc %edi /* complement result sign flag */
|
|
mov 16(%esp),%edx /* lo word of a */
|
|
neg %eax /* make a positive */
|
|
neg %edx
|
|
sbb $0,%eax
|
|
mov %eax,20(%esp) /* save positive value */
|
|
mov %edx,16(%esp)
|
|
L1:
|
|
mov 28(%esp),%eax /* hi word of b */
|
|
or %eax,%eax /* test to see if signed */
|
|
jge L2 /* skip rest if b is already positive */
|
|
inc %edi /* complement the result sign flag */
|
|
mov 24(%esp),%edx /* lo word of a */
|
|
neg %eax /* make b positive */
|
|
neg %edx
|
|
sbb $0,%eax
|
|
mov %eax,28(%esp) /* save positive value */
|
|
mov %edx,24(%esp)
|
|
L2:
|
|
|
|
/* Now do the divide. First look to see if the divisor is less than 4194304K.
|
|
* If so, then we can use a simple algorithm with word divides, otherwise
|
|
* things get a little more complex.
|
|
* NOTE - %eax currently contains the high order word of DVSR
|
|
*/
|
|
or %eax,%eax /* check to see if divisor < 4194304K */
|
|
jnz L3 /* nope, gotta do this the hard way */
|
|
mov 24(%esp),%ecx /* load divisor */
|
|
mov 20(%esp),%eax /* load high word of dividend */
|
|
xor %edx,%edx
|
|
div %ecx /* %eax <- high order bits of quotient */
|
|
mov %eax,%ebx /* save high bits of quotient */
|
|
mov 16(%esp),%eax /* %edx:%eax <- remainder:lo word of dividend */
|
|
div %ecx /* %eax <- low order bits of quotient */
|
|
mov %ebx,%edx /* %edx:%eax <- quotient */
|
|
jmp L4 /* set sign, restore stack and return */
|
|
|
|
/* Here we do it the hard way. Remember, %eax contains the high word of DVSR */
|
|
L3:
|
|
mov %eax,%ebx /* %ebx:ecx <- divisor */
|
|
mov 24(%esp),%ecx
|
|
mov 20(%esp),%edx /* %edx:%eax <- dividend */
|
|
mov 16(%esp),%eax
|
|
L5:
|
|
shr $1,%ebx /* shift divisor right one bit */
|
|
rcr $1,%ecx
|
|
shr $1,%edx /* shift dividend right one bit */
|
|
rcr $1,%eax
|
|
or %ebx,%ebx
|
|
jnz L5 /* loop until divisor < 4194304K */
|
|
div %ecx /* now divide, ignore remainder */
|
|
mov %eax,%esi /* save quotient */
|
|
|
|
/* We may be off by one, so to check, we will multiply the quotient
|
|
* by the divisor and check the result against the orignal dividend
|
|
* Note that we must also check for overflow, which can occur if the
|
|
* dividend is close to 2**64 and the quotient is off by 1.
|
|
*/
|
|
mull 28(%esp) /* QUOT * HIWORD(DVSR) */
|
|
mov %eax,%ecx
|
|
mov 24(%esp),%eax
|
|
mul %esi /* QUOT * LOWORD(DVSR) */
|
|
add %ecx,%edx /* %EDX:%EAX = QUOT * DVSR */
|
|
jc L6 /* carry means Quotient is off by 1 */
|
|
|
|
/* do long compare here between original dividend and the result of the
|
|
* multiply in %edx:%eax. If original is larger or equal, we are ok, otherwise
|
|
* subtract one (1) from the quotient.
|
|
*/
|
|
cmp 20(%esp),%edx /* compare hi words of result and original */
|
|
ja L6 /* if result > original, do subtract */
|
|
jb L7 /* if result < original, we are ok */
|
|
cmp 16(%esp),%eax /* hi words are equal, compare lo words */
|
|
jbe L7 /* if less or equal we are ok, else subtract */
|
|
L6:
|
|
dec %esi /* subtract 1 from quotient */
|
|
L7:
|
|
xor %edx,%edx /* %edx:%eax <- quotient */
|
|
mov %esi,%eax
|
|
|
|
/* Just the cleanup left to do. %edx:%eax contains the quotient. Set the sign
|
|
* according to the save value, cleanup the stack, and return.
|
|
*/
|
|
L4:
|
|
dec %edi /* check to see if result is negative */
|
|
jnz L8 /* if %EDI == 0, result should be negative */
|
|
neg %edx /* otherwise, negate the result */
|
|
neg %eax
|
|
sbb $0,%edx
|
|
|
|
/* Restore the saved registers and return. */
|
|
L8:
|
|
pop %ebx
|
|
pop %esi
|
|
pop %edi
|
|
|
|
ret $16
|
|
|
|
END_ENTRY(x86Div64Bit)
|
|
|
|
/*
|
|
* llrem
|
|
*
|
|
* Origin: MSDev
|
|
* Purpose: signed long remainder
|
|
* In: args are passed on the stack:
|
|
* 1st pushed: divisor (QWORD)
|
|
* 2nd pushed: dividend (QWORD)
|
|
* Out: %EDX:%EAX contains the quotient (dividend/divisor)
|
|
* Note: parameters are removed from the stack
|
|
* Uses: %ECX
|
|
*/
|
|
GLOBAL_ENTRY(x86Mod64Bit)
|
|
|
|
push %ebx
|
|
push %edi
|
|
|
|
/* Determine sign of the result (%edi = 0 if result is positive, non-zero
|
|
* otherwise) and make operands positive.
|
|
*/
|
|
xor %edi,%edi /* result sign assumed positive */
|
|
|
|
mov 16(%esp),%eax /* hi word of a */
|
|
or %eax,%eax /* test to see if signed */
|
|
jge LL1 /* skip rest if a is already positive */
|
|
inc %edi /* complement result sign flag bit */
|
|
mov 12(%esp),%edx /* lo word of a */
|
|
neg %eax /* make a positive */
|
|
neg %edx
|
|
sbb $0,%eax
|
|
mov %eax,16(%esp) /* save positive value */
|
|
mov %edx,12(%esp)
|
|
LL1:
|
|
mov 24(%esp),%eax /* hi word of b */
|
|
or %eax,%eax /* test to see if signed */
|
|
jge LL2 /* skip rest if b is already positive */
|
|
mov 20(%esp),%edx /* lo word of b */
|
|
neg %eax /* make b positive */
|
|
neg %edx
|
|
sbb $0,%eax
|
|
mov %eax,24(%esp) /* save positive value */
|
|
mov %edx,20(%esp)
|
|
LL2:
|
|
/* Now do the divide. First look to see if the divisor is less than 4194304K.
|
|
* If so, then we can use a simple algorithm with word divides, otherwise
|
|
* things get a little more complex.
|
|
* NOTE - %eax currently contains the high order word of DVSR
|
|
*/
|
|
or %eax,%eax /* check to see if divisor < 4194304K */
|
|
jnz LL3 /* nope, gotta do this the hard way */
|
|
mov 20(%esp),%ecx /* load divisor */
|
|
mov 16(%esp),%eax /* load high word of dividend */
|
|
xor %edx,%edx
|
|
div %ecx /* %edx <- remainder */
|
|
mov 12(%esp),%eax /* %edx:%eax <- remainder:lo word of dividend */
|
|
div %ecx /* %edx <- final remainder */
|
|
mov %edx,%eax /* %edx:%eax <- remainder */
|
|
xor %edx,%edx
|
|
dec %edi /* check result sign flag */
|
|
jns LL4 /* negate result, restore stack and return */
|
|
jmp LL8 /* result sign ok, restore stack and return */
|
|
|
|
/* Here we do it the hard way. Remember, %eax contains the high word of DVSR */
|
|
LL3:
|
|
mov %eax,%ebx /* %ebx:%ecx <- divisor */
|
|
mov 20(%esp),%ecx
|
|
mov 16(%esp),%edx /* %edx:%eax <- dividend */
|
|
mov 12(%esp),%eax
|
|
LL5:
|
|
shr $1,%ebx /* shift divisor right one bit */
|
|
rcr $1,%ecx
|
|
shr $1,%edx /* shift dividend right one bit */
|
|
rcr $1,%eax
|
|
or %ebx,%ebx
|
|
jnz LL5 /* loop until divisor < 4194304K */
|
|
div %ecx /* now divide, ignore remainder */
|
|
|
|
/* We may be off by one, so to check, we will multiply the quotient
|
|
* by the divisor and check the result against the orignal dividend
|
|
* Note that we must also check for overflow, which can occur if the
|
|
* dividend is close to 2**64 and the quotient is off by 1.
|
|
*/
|
|
mov %eax,%ecx /* save a copy of quotient in %ECX */
|
|
mull 24(%esp)
|
|
xchg %eax,%ecx /* save product, get quotient in %EAX */
|
|
mull 20(%esp)
|
|
add %ecx,%edx /* %EDX:%EAX = QUOT * DVSR */
|
|
jc LL6 /* carry means Quotient is off by 1 */
|
|
|
|
/* do long compare here between original dividend and the result of the
|
|
* multiply in %edx:%eax. If original is larger or equal, we are ok, otherwise
|
|
* subtract the original divisor from the result.
|
|
*/
|
|
cmp 16(%esp),%edx /* compare hi words of result and original */
|
|
ja LL6 /* if result > original, do subtract */
|
|
jb LL7 /* if result < original, we are ok */
|
|
cmp 12(%esp),%eax /* hi words are equal, compare lo words */
|
|
jbe LL7 /* if less or equal we are ok, else subtract */
|
|
LL6:
|
|
sub 20(%esp),%eax /* subtract divisor from result */
|
|
sbb 24(%esp),%edx
|
|
LL7:
|
|
|
|
/* Calculate remainder by subtracting the result from the original dividend.
|
|
* Since the result is already in a register, we will do the subtract in the
|
|
* opposite direction and negate the result if necessary.
|
|
*/
|
|
sub 12(%esp),%eax /* subtract dividend from result */
|
|
sbb 16(%esp),%edx
|
|
|
|
/* Now check the result sign flag to see if the result is supposed to be positive
|
|
* or negative. It is currently negated (because we subtracted in the 'wrong'
|
|
* direction), so if the sign flag is set we are done, otherwise we must negate
|
|
* the result to make it positive again.
|
|
*/
|
|
dec %edi /* check result sign flag */
|
|
jns LL8 /* result is ok, restore stack and return */
|
|
LL4:
|
|
neg %edx /* otherwise, negate the result */
|
|
neg %eax
|
|
sbb $0,%edx
|
|
|
|
/* Just the cleanup left to do. %edx:%eax contains the quotient.
|
|
* Restore the saved registers and return.
|
|
*/
|
|
LL8:
|
|
pop %edi
|
|
pop %ebx
|
|
|
|
ret $16
|
|
|
|
END_ENTRY(x86Mod64Bit)
|
|
|
|
/*
|
|
* llshl
|
|
*
|
|
* Origin: MSDev. modified
|
|
* Purpose: long shift left
|
|
* In: args are passed on the stack: (FIX make fastcall)
|
|
* 1st pushed: amount (int)
|
|
* 2nd pushed: source (long)
|
|
* Out: %EDX:%EAX contains the result
|
|
* Note: parameters are removed from the stack
|
|
* Uses: %ECX, destroyed
|
|
*/
|
|
GLOBAL_ENTRY(x86Shl64Bit)
|
|
|
|
/* prepare from stack */
|
|
mov 4(%esp),%eax
|
|
mov 8(%esp),%edx
|
|
mov 12(%esp),%ecx
|
|
|
|
cmp $64,%cl
|
|
jae RETZERO
|
|
|
|
/* Handle shifts of between 0 and 31 bits */
|
|
cmp $32,%cl
|
|
jae MORE32
|
|
shld %eax,%edx
|
|
shl %cl,%eax
|
|
ret $12
|
|
|
|
/* Handle shifts of between 32 and 63 bits */
|
|
MORE32:
|
|
mov %eax,%edx
|
|
xor %eax,%eax
|
|
and $31,%cl
|
|
shl %cl,%edx
|
|
ret $12
|
|
|
|
/* return 0 in %edx:%eax */
|
|
RETZERO:
|
|
xor %eax,%eax
|
|
xor %edx,%edx
|
|
ret $12
|
|
|
|
END_ENTRY(x86Shl64Bit)
|
|
|
|
|
|
/*
|
|
* llshr
|
|
*
|
|
* Origin: MSDev. modified
|
|
* Purpose: long shift right
|
|
* In: args are passed on the stack: (FIX make fastcall)
|
|
* 1st pushed: amount (int)
|
|
* 2nd pushed: source (long)
|
|
* Out: %EDX:%EAX contains the result
|
|
* Note: parameters are removed from the stack
|
|
* Uses: %ECX, destroyed
|
|
*/
|
|
GLOBAL_ENTRY(x86Shr64Bit)
|
|
|
|
/* prepare from stack */
|
|
mov 4(%esp),%eax
|
|
mov 8(%esp),%edx
|
|
mov 12(%esp),%ecx
|
|
|
|
cmp $64,%cl
|
|
jae RRETZERO
|
|
|
|
/* Handle shifts of between 0 and 31 bits */
|
|
cmp $32,%cl
|
|
jae MMORE32
|
|
shrd %edx,%eax
|
|
shr %cl,%edx
|
|
ret $12
|
|
|
|
/* Handle shifts of between 32 and 63 bits */
|
|
MMORE32:
|
|
mov %edx,%eax
|
|
xor %edx,%edx
|
|
and $31,%cl
|
|
shr %cl,%eax
|
|
ret $12
|
|
|
|
/* return 0 in %edx:%eax */
|
|
RRETZERO:
|
|
xor %eax,%eax
|
|
xor %edx,%edx
|
|
ret $12
|
|
|
|
END_ENTRY(x86Shr64Bit)
|
|
|
|
/*
|
|
* llsar
|
|
*
|
|
* Origin: MSDev. modified
|
|
* Purpose: long shift right signed
|
|
* In: args are passed on the stack: (FIX make fastcall)
|
|
* 1st pushed: amount (int)
|
|
* 2nd pushed: source (long)
|
|
* Out: %EDX:%EAX contains the result
|
|
* Note: parameters are removed from the stack
|
|
* Uses: %ECX, destroyed
|
|
*/
|
|
GLOBAL_ENTRY(x86Sar64Bit)
|
|
|
|
/* prepare from stack */
|
|
mov 4(%esp),%eax
|
|
mov 8(%esp),%edx
|
|
mov 12(%esp),%ecx
|
|
|
|
/* Handle shifts of 64 bits or more (if shifting 64 bits or more, the result */
|
|
/* depends only on the high order bit of %edx). */
|
|
cmp $64,%cl
|
|
jae RETSIGN
|
|
|
|
/* Handle shifts of between 0 and 31 bits */
|
|
cmp $32,%cl
|
|
jae MMMORE32
|
|
shrd %edx,%eax
|
|
sar %cl,%edx
|
|
ret $12
|
|
|
|
/* Handle shifts of between 32 and 63 bits */
|
|
MMMORE32:
|
|
mov %edx,%eax
|
|
sar $31,%edx
|
|
and $31,%cl
|
|
sar %cl,%eax
|
|
ret $12
|
|
|
|
/* Return double precision 0 or -1, depending on the sign of %edx */
|
|
RETSIGN:
|
|
sar $31,%edx
|
|
mov %edx,%eax
|
|
ret $12
|
|
|
|
END_ENTRY(x86Sar64Bit)
|