blob: 3b5f0beb89312dd97dc969bac57b9bcbf77f6760 [file] [log] [blame]
%def bindiv(result="", special="", rem=""):
/*
* 32-bit binary div/rem operation. Handles special case of op0=minint and
* op1=-1.
*/
/* div/rem vAA, vBB, vCC */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
GET_VREG %eax, %eax # eax <- vBB
GET_VREG %ecx, %ecx # ecx <- vCC
mov rIBASE, LOCAL0(%esp)
testl %ecx, %ecx
je common_errDivideByZero
movl %eax, %edx
orl %ecx, %edx
testl $$0xFFFFFF00, %edx # If both arguments are less
# than 8-bit and +ve
jz .L${opcode}_8 # Do 8-bit divide
testl $$0xFFFF0000, %edx # If both arguments are less
# than 16-bit and +ve
jz .L${opcode}_16 # Do 16-bit divide
cmpl $$-1, %ecx
jne .L${opcode}_32
cmpl $$0x80000000, %eax
jne .L${opcode}_32
movl $special, $result
jmp .L${opcode}_finish
% add_helper(lambda: bindiv_helper(result, rem))
%def bindiv_helper(result, rem):
.L${opcode}_32:
cltd
idivl %ecx
jmp .L${opcode}_finish
.L${opcode}_8:
div %cl # 8-bit divide otherwise.
# Remainder in %ah, quotient in %al
.if $rem
movl %eax, %edx
shr $$8, %edx
.else
andl $$0x000000FF, %eax
.endif
jmp .L${opcode}_finish
.L${opcode}_16:
xorl %edx, %edx # Clear %edx before divide
div %cx
.L${opcode}_finish:
SET_VREG $result, rINST
mov LOCAL0(%esp), rIBASE
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def bindiv2addr(result="", special=""):
/*
* 32-bit binary div/rem operation. Handles special case of op0=minint and
* op1=-1.
*/
/* div/rem/2addr vA, vB */
movzx rINSTbl, %ecx # eax <- BA
mov rIBASE, LOCAL0(%esp)
sarl $$4, %ecx # ecx <- B
GET_VREG %ecx, %ecx # eax <- vBB
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, rINST # eax <- vBB
testl %ecx, %ecx
je common_errDivideByZero
cmpl $$-1, %ecx
jne .L${opcode}_continue_div2addr
cmpl $$0x80000000, %eax
jne .L${opcode}_continue_div2addr
movl $special, $result
SET_VREG $result, rINST
mov LOCAL0(%esp), rIBASE
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
% add_helper(lambda: bindiv2addr_helper(result))
%def bindiv2addr_helper(result):
.L${opcode}_continue_div2addr:
cltd
idivl %ecx
SET_VREG $result, rINST
mov LOCAL0(%esp), rIBASE
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def bindivLit16(result="", special=""):
/*
* 32-bit binary div/rem operation. Handles special case of op0=minint and
* op1=-1.
*/
/* div/rem/lit16 vA, vB, #+CCCC */
/* Need A in rINST, ssssCCCC in ecx, vB in eax */
movzbl rINSTbl, %eax # eax <- 000000BA
sarl $$4, %eax # eax <- B
GET_VREG %eax, %eax # eax <- vB
movswl 2(rPC), %ecx # ecx <- ssssCCCC
andb $$0xf, rINSTbl # rINST <- A
testl %ecx, %ecx
je common_errDivideByZero
cmpl $$-1, %ecx
jne .L${opcode}_continue_div
cmpl $$0x80000000, %eax
jne .L${opcode}_continue_div
movl $special, %eax
SET_VREG %eax, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
.L${opcode}_continue_div:
mov rIBASE, LOCAL0(%esp)
cltd
idivl %ecx
SET_VREG $result, rINST
mov LOCAL0(%esp), rIBASE
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def bindivLit8(result="", special=""):
/*
* 32-bit div/rem "lit8" binary operation. Handles special case of
* op0=minint & op1=-1
*/
/* div/rem/lit8 vAA, vBB, #+CC */
movzbl 2(rPC), %eax # eax <- BB
movsbl 3(rPC), %ecx # ecx <- ssssssCC
GET_VREG %eax, %eax # eax <- rBB
testl %ecx, %ecx
je common_errDivideByZero
cmpl $$0x80000000, %eax
jne .L${opcode}_continue_div
cmpl $$-1, %ecx
jne .L${opcode}_continue_div
movl $special, %eax
SET_VREG %eax, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
.L${opcode}_continue_div:
mov rIBASE, LOCAL0(%esp)
cltd
idivl %ecx
SET_VREG $result, rINST
mov LOCAL0(%esp), rIBASE
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def binop(result="%eax", instr=""):
/*
* Generic 32-bit binary operation. Provide an "instr" line that
* specifies an instruction that performs "result = eax op VREG_ADDRESS(%ecx)".
* This could be an x86 instruction or a function call. (If the result
* comes back in a register other than eax, you can override "result".)
*
* For: add-int, sub-int, and-int, or-int,
* xor-int, shl-int, shr-int, ushr-int
*/
/* binop vAA, vBB, vCC */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
GET_VREG %eax, %eax # eax <- vBB
$instr # ex: addl VREG_ADDRESS(%ecx),%eax
SET_VREG $result, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def binop1(result="%eax", tmp="%ecx", instr=""):
/*
* Generic 32-bit binary operation in which both operands loaded to
* registers (op0 in eax, op1 in ecx).
*/
/* binop vAA, vBB, vCC */
movzbl 2(rPC),%eax # eax <- BB
movzbl 3(rPC),%ecx # ecx <- CC
GET_VREG %eax, %eax # eax <- vBB
GET_VREG %ecx, %ecx # eax <- vBB
$instr # ex: addl %ecx,%eax
SET_VREG $result, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def binop2addr(result="%eax", instr=""):
/*
* Generic 32-bit "/2addr" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = r0 op r1".
* This could be an instruction or a function call.
*
* For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
* rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
* shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
* sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
*/
/* binop/2addr vA, vB */
movzx rINSTbl, %ecx # ecx <- A+
sarl $$4, rINST # rINST <- B
GET_VREG %eax, rINST # eax <- vB
andb $$0xf, %cl # ecx <- A
$instr # for ex: addl %eax,VREG_ADDRESS(%ecx)
CLEAR_REF %ecx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def binopLit16(result="%eax", instr=""):
/*
* Generic 32-bit "lit16" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = eax op ecx".
* This could be an x86 instruction or a function call. (If the result
* comes back in a register other than eax, you can override "result".)
*
* For: add-int/lit16, rsub-int,
* and-int/lit16, or-int/lit16, xor-int/lit16
*/
/* binop/lit16 vA, vB, #+CCCC */
movzbl rINSTbl, %eax # eax <- 000000BA
sarl $$4, %eax # eax <- B
GET_VREG %eax, %eax # eax <- vB
movswl 2(rPC), %ecx # ecx <- ssssCCCC
andb $$0xf, rINSTbl # rINST <- A
$instr # for example: addl %ecx, %eax
SET_VREG $result, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def binopLit8(result="%eax", instr=""):
/*
* Generic 32-bit "lit8" binary operation. Provide an "instr" line
* that specifies an instruction that performs "result = eax op ecx".
* This could be an x86 instruction or a function call. (If the result
* comes back in a register other than r0, you can override "result".)
*
* For: add-int/lit8, rsub-int/lit8
* and-int/lit8, or-int/lit8, xor-int/lit8,
* shl-int/lit8, shr-int/lit8, ushr-int/lit8
*/
/* binop/lit8 vAA, vBB, #+CC */
movzbl 2(rPC), %eax # eax <- BB
movsbl 3(rPC), %ecx # ecx <- ssssssCC
GET_VREG %eax, %eax # eax <- rBB
$instr # ex: addl %ecx,%eax
SET_VREG $result, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def binopWide(instr1="", instr2=""):
/*
* Generic 64-bit binary operation.
*/
/* binop vAA, vBB, vCC */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
movl rIBASE, LOCAL0(%esp) # save rIBASE
GET_VREG rIBASE, %eax # rIBASE <- v[BB+0]
GET_VREG_HIGH %eax, %eax # eax <- v[BB+1]
$instr1 # ex: addl VREG_ADDRESS(%ecx),rIBASE
$instr2 # ex: adcl VREG_HIGH_ADDRESS(%ecx),%eax
SET_VREG rIBASE, rINST # v[AA+0] <- rIBASE
movl LOCAL0(%esp), rIBASE # restore rIBASE
SET_VREG_HIGH %eax, rINST # v[AA+1] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def binopWide2addr(instr1="", instr2=""):
/*
* Generic 64-bit binary operation.
*/
/* binop/2addr vA, vB */
movzbl rINSTbl, %ecx # ecx<- BA
sarl $$4, %ecx # ecx<- B
GET_VREG %eax, %ecx # eax<- v[B+0]
GET_VREG_HIGH %ecx, %ecx # eax<- v[B+1]
andb $$0xF, rINSTbl # rINST<- A
$instr1 # ex: addl %eax,(rFP,rINST,4)
$instr2 # ex: adcl %ecx,4(rFP,rINST,4)
CLEAR_WIDE_REF rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def cvtfp_int(srcdouble="1", tgtlong="1"):
/* On fp to int conversions, Java requires that
* if the result > maxint, it should be clamped to maxint. If it is less
* than minint, it should be clamped to minint. If it is a nan, the result
* should be zero. Further, the rounding mode is to truncate. This model
* differs from what is delivered normally via the x86 fpu, so we have
* to play some games.
*/
/* float/double to int/long vA, vB */
movzbl rINSTbl, %ecx # ecx <- A+
sarl $$4, rINST # rINST <- B
.if $srcdouble
fldl VREG_ADDRESS(rINST) # %st0 <- vB
.else
flds VREG_ADDRESS(rINST) # %st0 <- vB
.endif
ftst
fnstcw LOCAL0(%esp) # remember original rounding mode
movzwl LOCAL0(%esp), %eax
movb $$0xc, %ah
movw %ax, LOCAL0+2(%esp)
fldcw LOCAL0+2(%esp) # set "to zero" rounding mode
andb $$0xf, %cl # ecx <- A
.if $tgtlong
fistpll VREG_ADDRESS(%ecx) # convert and store
.else
fistpl VREG_ADDRESS(%ecx) # convert and store
.endif
fldcw LOCAL0(%esp) # restore previous rounding mode
.if $tgtlong
movl $$0x80000000, %eax
xorl VREG_HIGH_ADDRESS(%ecx), %eax
orl VREG_ADDRESS(%ecx), %eax
.else
cmpl $$0x80000000, VREG_ADDRESS(%ecx)
.endif
je .L${opcode}_special_case # fix up result
.L${opcode}_finish:
xor %eax, %eax
mov %eax, VREG_REF_ADDRESS(%ecx)
.if $tgtlong
mov %eax, VREG_REF_HIGH_ADDRESS(%ecx)
.endif
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
% add_helper(lambda: cvtfp_int_helper(tgtlong))
%def cvtfp_int_helper(tgtlong):
.L${opcode}_special_case:
fnstsw %ax
sahf
jp .L${opcode}_isNaN
adcl $$-1, VREG_ADDRESS(%ecx)
.if $tgtlong
adcl $$-1, VREG_HIGH_ADDRESS(%ecx)
.endif
jmp .L${opcode}_finish
.L${opcode}_isNaN:
movl $$0, VREG_ADDRESS(%ecx)
.if $tgtlong
movl $$0, VREG_HIGH_ADDRESS(%ecx)
.endif
jmp .L${opcode}_finish
%def shop2addr(result="%eax", instr=""):
/*
* Generic 32-bit "shift/2addr" operation.
*/
/* shift/2addr vA, vB */
movzx rINSTbl, %ecx # eax <- BA
sarl $$4, %ecx # ecx <- B
GET_VREG %ecx, %ecx # eax <- vBB
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, rINST # eax <- vAA
$instr # ex: sarl %cl, %eax
SET_VREG $result, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def unop(instr=""):
/*
* Generic 32-bit unary operation. Provide an "instr" line that
* specifies an instruction that performs "result = op eax".
*/
/* unop vA, vB */
movzbl rINSTbl,%ecx # ecx <- A+
sarl $$4,rINST # rINST <- B
GET_VREG %eax, rINST # eax <- vB
andb $$0xf,%cl # ecx <- A
$instr
SET_VREG %eax, %ecx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_add_int():
% binop(instr="addl VREG_ADDRESS(%ecx), %eax")
%def op_add_int_2addr():
% binop2addr(instr="addl %eax, VREG_ADDRESS(%ecx)")
%def op_add_int_lit16():
% binopLit16(instr="addl %ecx, %eax")
%def op_add_int_lit8():
% binopLit8(instr="addl %ecx, %eax")
%def op_add_long():
% binopWide(instr1="addl VREG_ADDRESS(%ecx), rIBASE", instr2="adcl VREG_HIGH_ADDRESS(%ecx), %eax")
%def op_add_long_2addr():
% binopWide2addr(instr1="addl %eax, (rFP,rINST,4)", instr2="adcl %ecx, 4(rFP,rINST,4)")
%def op_and_int():
% binop(instr="andl VREG_ADDRESS(%ecx), %eax")
%def op_and_int_2addr():
% binop2addr(instr="andl %eax, VREG_ADDRESS(%ecx)")
%def op_and_int_lit16():
% binopLit16(instr="andl %ecx, %eax")
%def op_and_int_lit8():
% binopLit8(instr="andl %ecx, %eax")
%def op_and_long():
% binopWide(instr1="andl VREG_ADDRESS(%ecx), rIBASE", instr2="andl VREG_HIGH_ADDRESS(%ecx), %eax")
%def op_and_long_2addr():
% binopWide2addr(instr1="andl %eax, (rFP,rINST,4)", instr2="andl %ecx, 4(rFP,rINST,4)")
%def op_cmp_long():
/*
* Compare two 64-bit values. Puts 0, 1, or -1 into the destination
* register based on the results of the comparison.
*/
/* cmp-long vAA, vBB, vCC */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
GET_VREG_HIGH %eax, %eax # eax <- v[BB+1], BB is clobbered
cmpl VREG_HIGH_ADDRESS(%ecx), %eax
jl .L${opcode}_smaller
jg .L${opcode}_bigger
movzbl 2(rPC), %eax # eax <- BB, restore BB
GET_VREG %eax, %eax # eax <- v[BB]
sub VREG_ADDRESS(%ecx), %eax
ja .L${opcode}_bigger
jb .L${opcode}_smaller
.L${opcode}_finish:
SET_VREG %eax, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
.L${opcode}_bigger:
movl $$1, %eax
jmp .L${opcode}_finish
.L${opcode}_smaller:
movl $$-1, %eax
jmp .L${opcode}_finish
%def op_div_int():
% bindiv(result="%eax", special="$0x80000000", rem="0")
%def op_div_int_2addr():
% bindiv2addr(result="%eax", special="$0x80000000")
%def op_div_int_lit16():
% bindivLit16(result="%eax", special="$0x80000000")
%def op_div_int_lit8():
% bindivLit8(result="%eax", special="$0x80000000")
%def op_div_long(routine="art_quick_ldiv"):
/* art_quick_* methods has quick abi,
* so use eax, ecx, edx, ebx for args
*/
/* div vAA, vBB, vCC */
.extern $routine
mov rIBASE, LOCAL0(%esp) # save rIBASE/%edx
mov rINST, LOCAL1(%esp) # save rINST/%ebx
movzbl 3(rPC), %eax # eax <- CC
GET_VREG %ecx, %eax
GET_VREG_HIGH %ebx, %eax
movl %ecx, %edx
orl %ebx, %ecx
jz common_errDivideByZero
movzbl 2(rPC), %eax # eax <- BB
GET_VREG_HIGH %ecx, %eax
GET_VREG %eax, %eax
call SYMBOL($routine)
mov LOCAL1(%esp), rINST # restore rINST/%ebx
SET_VREG_HIGH rIBASE, rINST
SET_VREG %eax, rINST
mov LOCAL0(%esp), rIBASE # restore rIBASE/%edx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_div_long_2addr(routine="art_quick_ldiv"):
/* art_quick_* methods has quick abi,
* so use eax, ecx, edx, ebx for args
*/
/* div/2addr vA, vB */
.extern $routine
mov rIBASE, LOCAL0(%esp) # save rIBASE/%edx
movzbl rINSTbl, %eax
shrl $$4, %eax # eax <- B
andb $$0xf, rINSTbl # rINST <- A
mov rINST, LOCAL1(%esp) # save rINST/%ebx
movl %ebx, %ecx
GET_VREG %edx, %eax
GET_VREG_HIGH %ebx, %eax
movl %edx, %eax
orl %ebx, %eax
jz common_errDivideByZero
GET_VREG %eax, %ecx
GET_VREG_HIGH %ecx, %ecx
call SYMBOL($routine)
mov LOCAL1(%esp), rINST # restore rINST/%ebx
SET_VREG_HIGH rIBASE, rINST
SET_VREG %eax, rINST
mov LOCAL0(%esp), rIBASE # restore rIBASE/%edx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_int_to_byte():
% unop(instr="movsbl %al, %eax")
%def op_int_to_char():
% unop(instr="movzwl %ax,%eax")
%def op_int_to_long():
/* int to long vA, vB */
movzbl rINSTbl, %eax # eax <- +A
sarl $$4, %eax # eax <- B
GET_VREG %eax, %eax # eax <- vB
andb $$0xf, rINSTbl # rINST <- A
movl rIBASE, %ecx # cltd trashes rIBASE/edx
cltd # rINST:eax<- sssssssBBBBBBBB
SET_VREG_HIGH rIBASE, rINST # v[A+1] <- rIBASE
SET_VREG %eax, rINST # v[A+0] <- %eax
movl %ecx, rIBASE
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_int_to_short():
% unop(instr="movswl %ax, %eax")
%def op_long_to_int():
/* we ignore the high word, making this equivalent to a 32-bit reg move */
% op_move()
%def op_mul_int():
/*
* 32-bit binary multiplication.
*/
/* mul vAA, vBB, vCC */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
GET_VREG %eax, %eax # eax <- vBB
mov rIBASE, LOCAL0(%esp)
imull VREG_ADDRESS(%ecx), %eax # trashes rIBASE/edx
mov LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_mul_int_2addr():
/* mul vA, vB */
movzx rINSTbl, %ecx # ecx <- A+
sarl $$4, rINST # rINST <- B
GET_VREG %eax, rINST # eax <- vB
andb $$0xf, %cl # ecx <- A
movl rIBASE, rINST
imull VREG_ADDRESS(%ecx), %eax # trashes rIBASE/edx
movl rINST, rIBASE
SET_VREG %eax, %ecx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_mul_int_lit16():
/* mul/lit16 vA, vB, #+CCCC */
/* Need A in rINST, ssssCCCC in ecx, vB in eax */
movzbl rINSTbl, %eax # eax <- 000000BA
sarl $$4, %eax # eax <- B
GET_VREG %eax, %eax # eax <- vB
movl rIBASE, %ecx
movswl 2(rPC), rIBASE # rIBASE <- ssssCCCC
andb $$0xf, rINSTbl # rINST <- A
imull rIBASE, %eax # trashes rIBASE/edx
movl %ecx, rIBASE
SET_VREG %eax, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_mul_int_lit8():
/* mul/lit8 vAA, vBB, #+CC */
movzbl 2(rPC), %eax # eax <- BB
movl rIBASE, %ecx
GET_VREG %eax, %eax # eax <- rBB
movsbl 3(rPC), rIBASE # rIBASE <- ssssssCC
imull rIBASE, %eax # trashes rIBASE/edx
movl %ecx, rIBASE
SET_VREG %eax, rINST
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_mul_long():
/*
* Signed 64-bit integer multiply.
*
* We could definately use more free registers for
* this code. We spill rINSTw (ebx),
* giving us eax, ebc, ecx and edx as computational
* temps. On top of that, we'll spill edi (rFP)
* for use as the vB pointer and esi (rPC) for use
* as the vC pointer. Yuck.
*
*/
/* mul-long vAA, vBB, vCC */
movzbl 2(rPC), %eax # eax <- B
movzbl 3(rPC), %ecx # ecx <- C
mov rPC, LOCAL0(%esp) # save Interpreter PC
mov rFP, LOCAL1(%esp) # save FP
mov rIBASE, LOCAL2(%esp) # save rIBASE
leal (rFP,%eax,4), %esi # esi <- &v[B]
leal VREG_ADDRESS(%ecx), rFP # rFP <- &v[C]
movl 4(%esi), %ecx # ecx <- Bmsw
imull (rFP), %ecx # ecx <- (Bmsw*Clsw)
movl 4(rFP), %eax # eax <- Cmsw
imull (%esi), %eax # eax <- (Cmsw*Blsw)
addl %eax, %ecx # ecx <- (Bmsw*Clsw)+(Cmsw*Blsw)
movl (rFP), %eax # eax <- Clsw
mull (%esi) # eax <- (Clsw*Alsw)
mov LOCAL0(%esp), rPC # restore Interpreter PC
mov LOCAL1(%esp), rFP # restore FP
leal (%ecx,rIBASE), rIBASE # full result now in rIBASE:%eax
SET_VREG_HIGH rIBASE, rINST # v[B+1] <- rIBASE
mov LOCAL2(%esp), rIBASE # restore IBASE
SET_VREG %eax, rINST # v[B] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_mul_long_2addr():
/*
* Signed 64-bit integer multiply, 2-addr version
*
* We could definately use more free registers for
* this code. We must spill %edx (rIBASE) because it
* is used by imul. We'll also spill rINST (ebx),
* giving us eax, ebc, ecx and rIBASE as computational
* temps. On top of that, we'll spill %esi (edi)
* for use as the vA pointer and rFP (esi) for use
* as the vB pointer. Yuck.
*/
/* mul-long/2addr vA, vB */
movzbl rINSTbl, %eax # eax <- BA
andb $$0xf, %al # eax <- A
CLEAR_WIDE_REF %eax # clear refs in advance
sarl $$4, rINST # rINST <- B
mov rPC, LOCAL0(%esp) # save Interpreter PC
mov rFP, LOCAL1(%esp) # save FP
mov rIBASE, LOCAL2(%esp) # save rIBASE
leal (rFP,%eax,4), %esi # esi <- &v[A]
leal (rFP,rINST,4), rFP # rFP <- &v[B]
movl 4(%esi), %ecx # ecx <- Amsw
imull (rFP), %ecx # ecx <- (Amsw*Blsw)
movl 4(rFP), %eax # eax <- Bmsw
imull (%esi), %eax # eax <- (Bmsw*Alsw)
addl %eax, %ecx # ecx <- (Amsw*Blsw)+(Bmsw*Alsw)
movl (rFP), %eax # eax <- Blsw
mull (%esi) # eax <- (Blsw*Alsw)
leal (%ecx,rIBASE), rIBASE # full result now in %edx:%eax
movl rIBASE, 4(%esi) # v[A+1] <- rIBASE
movl %eax, (%esi) # v[A] <- %eax
mov LOCAL0(%esp), rPC # restore Interpreter PC
mov LOCAL2(%esp), rIBASE # restore IBASE
mov LOCAL1(%esp), rFP # restore FP
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_neg_int():
% unop(instr="negl %eax")
%def op_neg_long():
/* unop vA, vB */
movzbl rINSTbl, %ecx # ecx <- BA
sarl $$4, %ecx # ecx <- B
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, %ecx # eax <- v[B+0]
GET_VREG_HIGH %ecx, %ecx # ecx <- v[B+1]
negl %eax
adcl $$0, %ecx
negl %ecx
SET_VREG %eax, rINST # v[A+0] <- eax
SET_VREG_HIGH %ecx, rINST # v[A+1] <- ecx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_not_int():
% unop(instr="notl %eax")
%def op_not_long():
/* unop vA, vB */
movzbl rINSTbl, %ecx # ecx <- BA
sarl $$4, %ecx # ecx <- B
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, %ecx # eax <- v[B+0]
GET_VREG_HIGH %ecx, %ecx # ecx <- v[B+1]
notl %eax
notl %ecx
SET_VREG %eax, rINST # v[A+0] <- eax
SET_VREG_HIGH %ecx, rINST # v[A+1] <- ecx
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_or_int():
% binop(instr="orl VREG_ADDRESS(%ecx), %eax")
%def op_or_int_2addr():
% binop2addr(instr="orl %eax, VREG_ADDRESS(%ecx)")
%def op_or_int_lit16():
% binopLit16(instr="orl %ecx, %eax")
%def op_or_int_lit8():
% binopLit8(instr="orl %ecx, %eax")
%def op_or_long():
% binopWide(instr1="orl VREG_ADDRESS(%ecx), rIBASE", instr2="orl VREG_HIGH_ADDRESS(%ecx), %eax")
%def op_or_long_2addr():
% binopWide2addr(instr1="orl %eax, (rFP,rINST,4)", instr2="orl %ecx, 4(rFP,rINST,4)")
%def op_rem_int():
% bindiv(result="rIBASE", special="$0", rem="1")
%def op_rem_int_2addr():
% bindiv2addr(result="rIBASE", special="$0")
%def op_rem_int_lit16():
% bindivLit16(result="rIBASE", special="$0")
%def op_rem_int_lit8():
% bindivLit8(result="rIBASE", special="$0")
%def op_rem_long():
% op_div_long(routine="art_quick_lmod")
%def op_rem_long_2addr():
% op_div_long_2addr(routine="art_quick_lmod")
%def op_rsub_int():
/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
% binopLit16(instr="subl %eax, %ecx", result="%ecx")
%def op_rsub_int_lit8():
% binopLit8(instr="subl %eax, %ecx", result="%ecx")
%def op_shl_int():
% binop1(instr="sall %cl, %eax")
%def op_shl_int_2addr():
% shop2addr(instr="sall %cl, %eax")
%def op_shl_int_lit8():
% binopLit8(instr="sall %cl, %eax")
%def op_shl_long():
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
* distance) is 32-bit. Also, Dalvik requires us to mask off the low
* 6 bits of the shift distance. x86 shifts automatically mask off
* the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
* case specially.
*/
/* shl-long vAA, vBB, vCC */
/* ecx gets shift count */
/* Need to spill rINST */
/* rINSTw gets AA */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
movl rIBASE, LOCAL0(%esp)
GET_VREG_HIGH rIBASE, %eax # ecx <- v[BB+1]
GET_VREG %ecx, %ecx # ecx <- vCC
GET_VREG %eax, %eax # eax <- v[BB+0]
shldl %eax,rIBASE
sall %cl, %eax
testb $$32, %cl
je 2f
movl %eax, rIBASE
xorl %eax, %eax
2:
SET_VREG_HIGH rIBASE, rINST # v[AA+1] <- rIBASE
movl LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST # v[AA+0] <- %eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_shl_long_2addr():
/*
* Long integer shift, 2addr version. vA is 64-bit value/result, vB is
* 32-bit shift distance.
*/
/* shl-long/2addr vA, vB */
/* ecx gets shift count */
/* Need to spill rIBASE */
/* rINSTw gets AA */
movzbl rINSTbl, %ecx # ecx <- BA
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, rINST # eax <- v[AA+0]
sarl $$4, %ecx # ecx <- B
movl rIBASE, LOCAL0(%esp)
GET_VREG_HIGH rIBASE, rINST # rIBASE <- v[AA+1]
GET_VREG %ecx, %ecx # ecx <- vBB
shldl %eax, rIBASE
sall %cl, %eax
testb $$32, %cl
je 2f
movl %eax, rIBASE
xorl %eax, %eax
2:
SET_VREG_HIGH rIBASE, rINST # v[AA+1] <- rIBASE
movl LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST # v[AA+0] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_shr_int():
% binop1(instr="sarl %cl, %eax")
%def op_shr_int_2addr():
% shop2addr(instr="sarl %cl, %eax")
%def op_shr_int_lit8():
% binopLit8(instr="sarl %cl, %eax")
%def op_shr_long():
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
* distance) is 32-bit. Also, Dalvik requires us to mask off the low
* 6 bits of the shift distance. x86 shifts automatically mask off
* the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
* case specially.
*/
/* shr-long vAA, vBB, vCC */
/* ecx gets shift count */
/* Need to spill rIBASE */
/* rINSTw gets AA */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
movl rIBASE, LOCAL0(%esp)
GET_VREG_HIGH rIBASE, %eax # rIBASE<- v[BB+1]
GET_VREG %ecx, %ecx # ecx <- vCC
GET_VREG %eax, %eax # eax <- v[BB+0]
shrdl rIBASE, %eax
sarl %cl, rIBASE
testb $$32, %cl
je 2f
movl rIBASE, %eax
sarl $$31, rIBASE
2:
SET_VREG_HIGH rIBASE, rINST # v[AA+1] <- rIBASE
movl LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST # v[AA+0] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_shr_long_2addr():
/*
* Long integer shift, 2addr version. vA is 64-bit value/result, vB is
* 32-bit shift distance.
*/
/* shl-long/2addr vA, vB */
/* ecx gets shift count */
/* Need to spill rIBASE */
/* rINSTw gets AA */
movzbl rINSTbl, %ecx # ecx <- BA
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, rINST # eax <- v[AA+0]
sarl $$4, %ecx # ecx <- B
movl rIBASE, LOCAL0(%esp)
GET_VREG_HIGH rIBASE, rINST # rIBASE <- v[AA+1]
GET_VREG %ecx, %ecx # ecx <- vBB
shrdl rIBASE, %eax
sarl %cl, rIBASE
testb $$32, %cl
je 2f
movl rIBASE, %eax
sarl $$31, rIBASE
2:
SET_VREG_HIGH rIBASE, rINST # v[AA+1] <- rIBASE
movl LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST # v[AA+0] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_sub_int():
% binop(instr="subl VREG_ADDRESS(%ecx), %eax")
%def op_sub_int_2addr():
% binop2addr(instr="subl %eax, VREG_ADDRESS(%ecx)")
%def op_sub_long():
% binopWide(instr1="subl VREG_ADDRESS(%ecx), rIBASE", instr2="sbbl VREG_HIGH_ADDRESS(%ecx), %eax")
%def op_sub_long_2addr():
% binopWide2addr(instr1="subl %eax, (rFP,rINST,4)", instr2="sbbl %ecx, 4(rFP,rINST,4)")
%def op_ushr_int():
% binop1(instr="shrl %cl, %eax")
%def op_ushr_int_2addr():
% shop2addr(instr="shrl %cl, %eax")
%def op_ushr_int_lit8():
% binopLit8(instr="shrl %cl, %eax")
%def op_ushr_long():
/*
* Long integer shift. This is different from the generic 32/64-bit
* binary operations because vAA/vBB are 64-bit but vCC (the shift
* distance) is 32-bit. Also, Dalvik requires us to mask off the low
* 6 bits of the shift distance. x86 shifts automatically mask off
* the low 5 bits of %cl, so have to handle the 64 > shiftcount > 31
* case specially.
*/
/* shr-long vAA, vBB, vCC */
/* ecx gets shift count */
/* Need to spill rIBASE */
/* rINSTw gets AA */
movzbl 2(rPC), %eax # eax <- BB
movzbl 3(rPC), %ecx # ecx <- CC
movl rIBASE, LOCAL0(%esp)
GET_VREG_HIGH rIBASE, %eax # rIBASE <- v[BB+1]
GET_VREG %ecx, %ecx # ecx <- vCC
GET_VREG %eax, %eax # eax <- v[BB+0]
shrdl rIBASE, %eax
shrl %cl, rIBASE
testb $$32, %cl
je 2f
movl rIBASE, %eax
xorl rIBASE, rIBASE
2:
SET_VREG_HIGH rIBASE, rINST # v[AA+1] <- rIBASE
movl LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST # v[BB+0] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
%def op_ushr_long_2addr():
/*
* Long integer shift, 2addr version. vA is 64-bit value/result, vB is
* 32-bit shift distance.
*/
/* shl-long/2addr vA, vB */
/* ecx gets shift count */
/* Need to spill rIBASE */
/* rINSTw gets AA */
movzbl rINSTbl, %ecx # ecx <- BA
andb $$0xf, rINSTbl # rINST <- A
GET_VREG %eax, rINST # eax <- v[AA+0]
sarl $$4, %ecx # ecx <- B
movl rIBASE, LOCAL0(%esp)
GET_VREG_HIGH rIBASE, rINST # rIBASE <- v[AA+1]
GET_VREG %ecx, %ecx # ecx <- vBB
shrdl rIBASE, %eax
shrl %cl, rIBASE
testb $$32, %cl
je 2f
movl rIBASE, %eax
xorl rIBASE, rIBASE
2:
SET_VREG_HIGH rIBASE, rINST # v[AA+1] <- rIBASE
movl LOCAL0(%esp), rIBASE
SET_VREG %eax, rINST # v[AA+0] <- eax
ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
%def op_xor_int():
% binop(instr="xorl VREG_ADDRESS(%ecx), %eax")
%def op_xor_int_2addr():
% binop2addr(instr="xorl %eax, VREG_ADDRESS(%ecx)")
%def op_xor_int_lit16():
% binopLit16(instr="xorl %ecx, %eax")
%def op_xor_int_lit8():
% binopLit8(instr="xorl %ecx, %eax")
%def op_xor_long():
% binopWide(instr1="xorl VREG_ADDRESS(%ecx), rIBASE", instr2="xorl VREG_HIGH_ADDRESS(%ecx), %eax")
%def op_xor_long_2addr():
% binopWide2addr(instr1="xorl %eax, (rFP,rINST,4)", instr2="xorl %ecx, 4(rFP,rINST,4)")