987 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
			
		
		
	
	
			987 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
| %def binop(preinstr="", result="r0", chkzero="0", instr=""):
 | |
|     /*
 | |
|      * Generic 32-bit binary operation.  Provide an "instr" line that
 | |
|      * specifies an instruction that performs "result = r0 op r1".
 | |
|      * This could be an ARM instruction or a function call.  (If the result
 | |
|      * comes back in a register other than r0, you can override "result".)
 | |
|      *
 | |
|      * If "chkzero" is set to 1, we perform a divide-by-zero check on
 | |
|      * vCC (r1).  Useful for integer division and modulus.  Note that we
 | |
|      * *don't* check for (INT_MIN / -1) here, because the ARM math lib
 | |
|      * handles it correctly.
 | |
|      *
 | |
|      * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
 | |
|      *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
 | |
|      *      mul-float, div-float, rem-float
 | |
|      */
 | |
|     /* binop vAA, vBB, vCC */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     mov     r3, r0, lsr #8              @ r3<- CC
 | |
|     and     r2, r0, #255                @ r2<- BB
 | |
|     GET_VREG r1, r3                     @ r1<- vCC
 | |
|     GET_VREG r0, r2                     @ r0<- vBB
 | |
|     .if $chkzero
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     .endif
 | |
| 
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     $instr                              @ $result<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG $result, r4                @ vAA<- $result
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 11-14 instructions */
 | |
| 
 | |
| %def binop2addr(preinstr="", result="r0", chkzero="0", 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 ARM instruction or a function call.  (If the result
 | |
|      * comes back in a register other than r0, you can override "result".)
 | |
|      *
 | |
|      * If "chkzero" is set to 1, we perform a divide-by-zero check on
 | |
|      * vCC (r1).  Useful for integer division and modulus.
 | |
|      *
 | |
|      * 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 */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r1, r3                     @ r1<- vB
 | |
|     GET_VREG r0, r4                     @ r0<- vA
 | |
|     .if $chkzero
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     .endif
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
| 
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     $instr                              @ $result<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG $result, r4                @ vAA<- $result
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-13 instructions */
 | |
| 
 | |
| %def binopLit16(result="r0", chkzero="0", instr=""):
 | |
|     /*
 | |
|      * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
 | |
|      * that specifies an instruction that performs "result = r0 op r1".
 | |
|      * This could be an ARM instruction or a function call.  (If the result
 | |
|      * comes back in a register other than r0, you can override "result".)
 | |
|      *
 | |
|      * If "chkzero" is set to 1, we perform a divide-by-zero check on
 | |
|      * vCC (r1).  Useful for integer division and modulus.
 | |
|      *
 | |
|      * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
 | |
|      *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
 | |
|      */
 | |
|     /* binop/lit16 vA, vB, #+CCCC */
 | |
|     FETCH_S r1, 1                       @ r1<- ssssCCCC (sign-extended)
 | |
|     mov     r2, rINST, lsr #12          @ r2<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r0, r2                     @ r0<- vB
 | |
|     .if $chkzero
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     .endif
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| 
 | |
|     $instr                              @ $result<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG $result, r4                @ vAA<- $result
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-13 instructions */
 | |
| 
 | |
| %def binopLit8(extract="asr     r1, r3, #8", result="r0", chkzero="0", instr=""):
 | |
|     /*
 | |
|      * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
 | |
|      * that specifies an instruction that performs "result = r0 op r1".
 | |
|      * This could be an ARM instruction or a function call.  (If the result
 | |
|      * comes back in a register other than r0, you can override "result".)
 | |
|      *
 | |
|      * You can override "extract" if the extraction of the literal value
 | |
|      * from r3 to r1 is not the default "asr r1, r3, #8". The extraction
 | |
|      * can be omitted completely if the shift is embedded in "instr".
 | |
|      *
 | |
|      * If "chkzero" is set to 1, we perform a divide-by-zero check on
 | |
|      * vCC (r1).  Useful for integer division and modulus.
 | |
|      *
 | |
|      * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
 | |
|      *      rem-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 */
 | |
|     FETCH_S r3, 1                       @ r3<- ssssCCBB (sign-extended for CC)
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r2, r3, #255                @ r2<- BB
 | |
|     GET_VREG r0, r2                     @ r0<- vBB
 | |
|     $extract                            @ optional; typically r1<- ssssssCC (sign extended)
 | |
|     .if $chkzero
 | |
|     @cmp     r1, #0                     @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     .endif
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| 
 | |
|     $instr                              @ $result<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG $result, r4                @ vAA<- $result
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-12 instructions */
 | |
| 
 | |
| %def binopWide(preinstr="", result0="r0", result1="r1", chkzero="0", instr=""):
 | |
|     /*
 | |
|      * Generic 64-bit binary operation.  Provide an "instr" line that
 | |
|      * specifies an instruction that performs "result = r0-r1 op r2-r3".
 | |
|      * This could be an ARM instruction or a function call.  (If the result
 | |
|      * comes back in a register other than r0, you can override "result".)
 | |
|      *
 | |
|      * If "chkzero" is set to 1, we perform a divide-by-zero check on
 | |
|      * vCC (r1).  Useful for integer division and modulus.
 | |
|      *
 | |
|      * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
 | |
|      *      xor-long, add-double, sub-double, mul-double, div-double,
 | |
|      *      rem-double
 | |
|      *
 | |
|      * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
 | |
|      */
 | |
|     /* binop vAA, vBB, vCC */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     rINST, rINST, lsr #8        @ rINST<- AA
 | |
|     and     r2, r0, #255                @ r2<- BB
 | |
|     mov     r3, r0, lsr #8              @ r3<- CC
 | |
|     VREG_INDEX_TO_ADDR r4, rINST        @ r4<- &fp[AA]
 | |
|     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &fp[BB]
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[CC]
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r2    @ r0/r1<- vBB/vBB+1
 | |
|     GET_VREG_WIDE_BY_ADDR r2, r3, r3    @ r2/r3<- vCC/vCC+1
 | |
|     .if $chkzero
 | |
|     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
 | |
|     beq     common_errDivideByZero
 | |
|     .endif
 | |
|     CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     $instr                              @ result<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR $result0,$result1,r4  @ vAA/vAA+1<,  $result0/$result1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 14-17 instructions */
 | |
| 
 | |
| %def binopWide2addr(preinstr="", result0="r0", result1="r1", chkzero="0", instr=""):
 | |
|     /*
 | |
|      * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
 | |
|      * that specifies an instruction that performs "result = r0-r1 op r2-r3".
 | |
|      * This could be an ARM instruction or a function call.  (If the result
 | |
|      * comes back in a register other than r0, you can override "result".)
 | |
|      *
 | |
|      * If "chkzero" is set to 1, we perform a divide-by-zero check on
 | |
|      * vCC (r1).  Useful for integer division and modulus.
 | |
|      *
 | |
|      * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
 | |
|      *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
 | |
|      *      sub-double/2addr, mul-double/2addr, div-double/2addr,
 | |
|      *      rem-double/2addr
 | |
|      */
 | |
|     /* binop/2addr vA, vB */
 | |
|     mov     r1, rINST, lsr #12          @ r1<- B
 | |
|     ubfx    rINST, rINST, #8, #4        @ rINST<- A
 | |
|     VREG_INDEX_TO_ADDR r1, r1           @ r1<- &fp[B]
 | |
|     VREG_INDEX_TO_ADDR r4, rINST        @ r4<- &fp[A]
 | |
|     GET_VREG_WIDE_BY_ADDR r2, r3, r1    @ r2/r3<- vBB/vBB+1
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r4    @ r0/r1<- vAA/vAA+1
 | |
|     .if $chkzero
 | |
|     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
 | |
|     beq     common_errDivideByZero
 | |
|     .endif
 | |
|     CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     $instr                              @ result<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR $result0,$result1,r4  @ vAA/vAA+1<- $result0/$result1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 12-15 instructions */
 | |
| 
 | |
| %def unop(preinstr="", instr=""):
 | |
|     /*
 | |
|      * Generic 32-bit unary operation.  Provide an "instr" line that
 | |
|      * specifies an instruction that performs "result = op r0".
 | |
|      * This could be an ARM instruction or a function call.
 | |
|      *
 | |
|      * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
 | |
|      *      int-to-byte, int-to-char, int-to-short
 | |
|      */
 | |
|     /* unop vA, vB */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r0, r3                     @ r0<- vB
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     $instr                              @ r0<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r0, r4                     @ vAA<- r0
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 8-9 instructions */
 | |
| 
 | |
| %def unopNarrower(preinstr="", instr=""):
 | |
|     /*
 | |
|      * Generic 64bit-to-32bit unary operation.  Provide an "instr" line
 | |
|      * that specifies an instruction that performs "result = op r0/r1", where
 | |
|      * "result" is a 32-bit quantity in r0.
 | |
|      *
 | |
|      * For: long-to-float
 | |
|      *
 | |
|      * (This would work for long-to-int, but that instruction is actually
 | |
|      * an exact match for op_move.)
 | |
|      */
 | |
|     /* unop vA, vB */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[B]
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r3    @ r0/r1<- vB/vB+1
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     $instr                              @ r0<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r0, r4                     @ vA<- r0
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 9-10 instructions */
 | |
| 
 | |
| %def unopWide(preinstr="", instr=""):
 | |
|     /*
 | |
|      * Generic 64-bit unary operation.  Provide an "instr" line that
 | |
|      * specifies an instruction that performs "result = op r0/r1".
 | |
|      * This could be an ARM instruction or a function call.
 | |
|      *
 | |
|      * For: neg-long, not-long, neg-double, long-to-double, double-to-long
 | |
|      */
 | |
|     /* unop vA, vB */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    rINST, rINST, #8, #4        @ rINST<- A
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[B]
 | |
|     VREG_INDEX_TO_ADDR r4, rINST        @ r4<- &fp[A]
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r3    @ r0/r1<- vAA
 | |
|     CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     $instr                              @ r0/r1<- op, r2-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-11 instructions */
 | |
| 
 | |
| %def unopWider(preinstr="", instr=""):
 | |
|     /*
 | |
|      * Generic 32bit-to-64bit unary operation.  Provide an "instr" line
 | |
|      * that specifies an instruction that performs "result = op r0", where
 | |
|      * "result" is a 64-bit quantity in r0/r1.
 | |
|      *
 | |
|      * For: int-to-long, int-to-double, float-to-long, float-to-double
 | |
|      */
 | |
|     /* unop vA, vB */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    rINST, rINST, #8, #4        @ rINST<- A
 | |
|     GET_VREG r0, r3                     @ r0<- vB
 | |
|     VREG_INDEX_TO_ADDR r4, rINST        @ r4<- &fp[A]
 | |
|     $preinstr                           @ optional op; may set condition codes
 | |
|     CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     $instr                              @ r0<- op, r0-r3 changed
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vA/vA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 9-10 instructions */
 | |
| 
 | |
| %def op_add_int():
 | |
| %  binop(instr="add     r0, r0, r1")
 | |
| 
 | |
| %def op_add_int_2addr():
 | |
| %  binop2addr(instr="add     r0, r0, r1")
 | |
| 
 | |
| %def op_add_int_lit16():
 | |
| %  binopLit16(instr="add     r0, r0, r1")
 | |
| 
 | |
| %def op_add_int_lit8():
 | |
| %  binopLit8(extract="", instr="add     r0, r0, r3, asr #8")
 | |
| 
 | |
| %def op_add_long():
 | |
| %  binopWide(preinstr="adds    r0, r0, r2", instr="adc     r1, r1, r3")
 | |
| 
 | |
| %def op_add_long_2addr():
 | |
| %  binopWide2addr(preinstr="adds    r0, r0, r2", instr="adc     r1, r1, r3")
 | |
| 
 | |
| %def op_and_int():
 | |
| %  binop(instr="and     r0, r0, r1")
 | |
| 
 | |
| %def op_and_int_2addr():
 | |
| %  binop2addr(instr="and     r0, r0, r1")
 | |
| 
 | |
| %def op_and_int_lit16():
 | |
| %  binopLit16(instr="and     r0, r0, r1")
 | |
| 
 | |
| %def op_and_int_lit8():
 | |
| %  binopLit8(extract="", instr="and     r0, r0, r3, asr #8")
 | |
| 
 | |
| %def op_and_long():
 | |
| %  binopWide(preinstr="and     r0, r0, r2", instr="and     r1, r1, r3")
 | |
| 
 | |
| %def op_and_long_2addr():
 | |
| %  binopWide2addr(preinstr="and     r0, r0, r2", instr="and     r1, r1, r3")
 | |
| 
 | |
| %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 */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r2, r0, #255                @ r2<- BB
 | |
|     mov     r3, r0, lsr #8              @ r3<- CC
 | |
|     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &fp[BB]
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[CC]
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r2    @ r0/r1<- vBB/vBB+1
 | |
|     GET_VREG_WIDE_BY_ADDR r2, r3, r3    @ r2/r3<- vCC/vCC+1
 | |
|     cmp     r0, r2
 | |
|     sbcs    ip, r1, r3                  @ Sets correct CCs for checking LT (but not EQ/NE)
 | |
|     mov     r3, #-1
 | |
|     it      ge
 | |
|     movge   r3, #1
 | |
|     it      eq
 | |
|     cmpeq   r0, r2
 | |
|     it      eq
 | |
|     moveq   r3, #0
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     SET_VREG r3, r4                     @ vAA<- ip
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_div_int():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r0 = r0 div r1". The selection between sdiv or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * div-int
 | |
|      *
 | |
|      */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     mov     r3, r0, lsr #8              @ r3<- CC
 | |
|     and     r2, r0, #255                @ r2<- BB
 | |
|     GET_VREG r1, r3                     @ r1<- vCC
 | |
|     GET_VREG r0, r2                     @ r0<- vBB
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
| 
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r0, r0, r1                  @ r0<- op
 | |
| #else
 | |
|     bl    __aeabi_idiv                  @ r0<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r0, r4                     @ vAA<- r0
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 11-14 instructions */
 | |
| 
 | |
| %def op_div_int_2addr():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r0 = r0 div r1". The selection between sdiv or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * div-int/2addr
 | |
|      *
 | |
|      */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r1, r3                     @ r1<- vB
 | |
|     GET_VREG r0, r4                     @ r0<- vA
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
| 
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r0, r0, r1                  @ r0<- op
 | |
| #else
 | |
|     bl       __aeabi_idiv               @ r0<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r0, r4                     @ vAA<- r0
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-13 instructions */
 | |
| 
 | |
| 
 | |
| %def op_div_int_lit16():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r0 = r0 div r1". The selection between sdiv or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * div-int/lit16
 | |
|      *
 | |
|      */
 | |
|     FETCH_S r1, 1                       @ r1<- ssssCCCC (sign-extended)
 | |
|     mov     r2, rINST, lsr #12          @ r2<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r0, r2                     @ r0<- vB
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| 
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r0, r0, r1                  @ r0<- op
 | |
| #else
 | |
|     bl       __aeabi_idiv               @ r0<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r0, r4                     @ vAA<- r0
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-13 instructions */
 | |
| 
 | |
| %def op_div_int_lit8():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r0 = r0 div r1". The selection between sdiv or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * div-int/lit8
 | |
|      *
 | |
|      */
 | |
|     FETCH_S r3, 1                       @ r3<- ssssCCBB (sign-extended for CC
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r2, r3, #255                @ r2<- BB
 | |
|     GET_VREG r0, r2                     @ r0<- vBB
 | |
|     movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
 | |
|     @cmp     r1, #0                     @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| 
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r0, r0, r1                  @ r0<- op
 | |
| #else
 | |
|     bl   __aeabi_idiv                   @ r0<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r0, r4                     @ vAA<- r0
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-12 instructions */
 | |
| 
 | |
| %def op_div_long():
 | |
| %  binopWide(instr="bl      __aeabi_ldivmod", chkzero="1")
 | |
| 
 | |
| %def op_div_long_2addr():
 | |
| %  binopWide2addr(instr="bl      __aeabi_ldivmod", chkzero="1")
 | |
| 
 | |
| %def op_int_to_byte():
 | |
| %  unop(instr="sxtb    r0, r0")
 | |
| 
 | |
| %def op_int_to_char():
 | |
| %  unop(instr="uxth    r0, r0")
 | |
| 
 | |
| %def op_int_to_long():
 | |
| %  unopWider(instr="mov     r1, r0, asr #31")
 | |
| 
 | |
| %def op_int_to_short():
 | |
| %  unop(instr="sxth    r0, r0")
 | |
| 
 | |
| %def op_long_to_int():
 | |
| /* we ignore the high word, making this equivalent to a 32-bit reg move */
 | |
| %  op_move()
 | |
| 
 | |
| /*
 | |
|  * We use "mul r0, r1, r0" instead of "r0, r0, r1". The latter was illegal in old versions.
 | |
|  * Also, for T32, this operand order allows using a 16-bit instruction (encoding T1) while the
 | |
|  * other order would require 32-bit instruction (encoding T2).
 | |
|  */
 | |
| 
 | |
| %def op_mul_int():
 | |
| %  binop(instr="mul     r0, r1, r0")
 | |
| 
 | |
| %def op_mul_int_2addr():
 | |
| %  binop2addr(instr="mul     r0, r1, r0")
 | |
| 
 | |
| %def op_mul_int_lit16():
 | |
| %  binopLit16(instr="mul     r0, r1, r0")
 | |
| 
 | |
| %def op_mul_int_lit8():
 | |
| %  binopLit8(instr="mul     r0, r1, r0")
 | |
| 
 | |
| %def op_mul_long():
 | |
|     /*
 | |
|      * Signed 64-bit integer multiply.
 | |
|      *
 | |
|      * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
 | |
|      *        WX
 | |
|      *      x YZ
 | |
|      *  --------
 | |
|      *     ZW ZX
 | |
|      *  YW YX
 | |
|      *
 | |
|      * The low word of the result holds ZX, the high word holds
 | |
|      * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
 | |
|      * it doesn't fit in the low 64 bits.
 | |
|      *
 | |
|      * Unlike most ARM math operations, multiply instructions have
 | |
|      * restrictions on using the same register more than once (Rd and Rn
 | |
|      * cannot be the same).
 | |
|      */
 | |
|     /* mul-long vAA, vBB, vCC */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     and     r2, r0, #255                @ r2<- BB
 | |
|     mov     r3, r0, lsr #8              @ r3<- CC
 | |
|     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &fp[BB]
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[CC]
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r2    @ r0/r1<- vBB/vBB+1
 | |
|     GET_VREG_WIDE_BY_ADDR r2, r3, r3    @ r2/r3<- vCC/vCC+1
 | |
|     mul     ip, r0, r3                  @ ip<- YxX
 | |
|     umull   r0, lr, r2, r0              @ r0/lr <- ZxX RdLo == Rn - this is OK.
 | |
|     mla     r3, r1, r2, ip              @ r3<- YxX + (ZxW)
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     add     r1, r3, lr                  @ r1<- lr + low(ZxW + (YxX))
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r2<- &fp[AA]
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1 , r4   @ vAA/vAA+1<- r1/r2
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_mul_long_2addr():
 | |
|     /*
 | |
|      * Signed 64-bit integer multiply, "/2addr" version.
 | |
|      *
 | |
|      * See op_mul_long for an explanation.
 | |
|      *
 | |
|      * We get a little tight on registers, so to avoid looking up &fp[A]
 | |
|      * again we stuff it into rINST.
 | |
|      */
 | |
|     /* mul-long/2addr vA, vB */
 | |
|     mov     r1, rINST, lsr #12          @ r1<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     VREG_INDEX_TO_ADDR r1, r1           @ r1<- &fp[B]
 | |
|     VREG_INDEX_TO_ADDR rINST, r4        @ rINST<- &fp[A]
 | |
|     GET_VREG_WIDE_BY_ADDR r2, r3, r1    @ r2/r3<- vBB/vBB+1
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, rINST @ r0/r1<- vAA/vAA+1
 | |
|     mul     ip, r0, r3                  @ ip<- YxX
 | |
|     umull   r0, lr, r2, r0              @ r0/lr <- ZxX RdLo == Rn - this is OK.
 | |
|     mla     r3, r1, r2, ip              @ r3<- YxX + (ZxW)
 | |
|     mov     r4, rINST                   @ Save vAA before FETCH_ADVANCE_INST
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     add     r1, r3, lr                  @ r1<- lr + low(ZxW + (YxX))
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_neg_int():
 | |
| %  unop(instr="rsb     r0, r0, #0")
 | |
| 
 | |
| %def op_neg_long():
 | |
| %  unopWide(preinstr="rsbs    r0, r0, #0", instr="rsc     r1, r1, #0")
 | |
| 
 | |
| %def op_not_int():
 | |
| %  unop(instr="mvn     r0, r0")
 | |
| 
 | |
| %def op_not_long():
 | |
| %  unopWide(preinstr="mvn     r0, r0", instr="mvn     r1, r1")
 | |
| 
 | |
| %def op_or_int():
 | |
| %  binop(instr="orr     r0, r0, r1")
 | |
| 
 | |
| %def op_or_int_2addr():
 | |
| %  binop2addr(instr="orr     r0, r0, r1")
 | |
| 
 | |
| %def op_or_int_lit16():
 | |
| %  binopLit16(instr="orr     r0, r0, r1")
 | |
| 
 | |
| %def op_or_int_lit8():
 | |
| %  binopLit8(extract="", instr="orr     r0, r0, r3, asr #8")
 | |
| 
 | |
| %def op_or_long():
 | |
| %  binopWide(preinstr="orr     r0, r0, r2", instr="orr     r1, r1, r3")
 | |
| 
 | |
| %def op_or_long_2addr():
 | |
| %  binopWide2addr(preinstr="orr     r0, r0, r2", instr="orr     r1, r1, r3")
 | |
| 
 | |
| %def op_rem_int():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r1 = r0 rem r1". The selection between sdiv block or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * NOTE: idivmod returns quotient in r0 and remainder in r1
 | |
|      *
 | |
|      * rem-int
 | |
|      *
 | |
|      */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     mov     r3, r0, lsr #8              @ r3<- CC
 | |
|     and     r2, r0, #255                @ r2<- BB
 | |
|     GET_VREG r1, r3                     @ r1<- vCC
 | |
|     GET_VREG r0, r2                     @ r0<- vBB
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
| 
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r2, r0, r1
 | |
|     mls     r1, r1, r2, r0                 @ r1<- op, r0-r2 changed
 | |
| #else
 | |
|     bl      __aeabi_idivmod                @ r1<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r1, r4                     @ vAA<- r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 11-14 instructions */
 | |
| 
 | |
| %def op_rem_int_2addr():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r1 = r0 rem r1". The selection between sdiv block or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * NOTE: idivmod returns quotient in r0 and remainder in r1
 | |
|      *
 | |
|      * rem-int/2addr
 | |
|      *
 | |
|      */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r1, r3                     @ r1<- vB
 | |
|     GET_VREG r0, r4                     @ r0<- vA
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
| 
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r2, r0, r1
 | |
|     mls     r1, r1, r2, r0              @ r1<- op
 | |
| #else
 | |
|     bl      __aeabi_idivmod             @ r1<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r1, r4                     @ vAA<- r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-13 instructions */
 | |
| 
 | |
| 
 | |
| %def op_rem_int_lit16():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r1 = r0 rem r1". The selection between sdiv block or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * NOTE: idivmod returns quotient in r0 and remainder in r1
 | |
|      *
 | |
|      * rem-int/lit16
 | |
|      *
 | |
|      */
 | |
|     FETCH_S r1, 1                       @ r1<- ssssCCCC (sign-extended)
 | |
|     mov     r2, rINST, lsr #12          @ r2<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r0, r2                     @ r0<- vB
 | |
|     cmp     r1, #0                      @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| 
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r2, r0, r1
 | |
|     mls     r1, r1, r2, r0              @ r1<- op
 | |
| #else
 | |
|     bl     __aeabi_idivmod              @ r1<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r1, r4                     @ vAA<- r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-13 instructions */
 | |
| 
 | |
| %def op_rem_int_lit8():
 | |
|     /*
 | |
|      * Specialized 32-bit binary operation
 | |
|      *
 | |
|      * Performs "r1 = r0 rem r1". The selection between sdiv block or the gcc helper
 | |
|      * depends on the compile time value of __ARM_ARCH_EXT_IDIV__ (defined for
 | |
|      * ARMv7 CPUs that have hardware division support).
 | |
|      *
 | |
|      * NOTE: idivmod returns quotient in r0 and remainder in r1
 | |
|      *
 | |
|      * rem-int/lit8
 | |
|      *
 | |
|      */
 | |
|     FETCH_S r3, 1                       @ r3<- ssssCCBB (sign-extended for CC)
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r2, r3, #255                @ r2<- BB
 | |
|     GET_VREG r0, r2                     @ r0<- vBB
 | |
|     movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
 | |
|     @cmp     r1, #0                     @ is second operand zero?
 | |
|     beq     common_errDivideByZero
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
| 
 | |
| #ifdef __ARM_ARCH_EXT_IDIV__
 | |
|     sdiv    r2, r0, r1
 | |
|     mls     r1, r1, r2, r0              @ r1<- op
 | |
| #else
 | |
|     bl       __aeabi_idivmod            @ r1<- op, r0-r3 changed
 | |
| #endif
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG r1, r4                     @ vAA<- r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
|     /* 10-12 instructions */
 | |
| 
 | |
| %def op_rem_long():
 | |
| /* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
 | |
| %  binopWide(instr="bl      __aeabi_ldivmod", result0="r2", result1="r3", chkzero="1")
 | |
| 
 | |
| %def op_rem_long_2addr():
 | |
| /* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
 | |
| %  binopWide2addr(instr="bl      __aeabi_ldivmod", result0="r2", result1="r3", chkzero="1")
 | |
| 
 | |
| %def op_rsub_int():
 | |
| /* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
 | |
| %  binopLit16(instr="rsb     r0, r0, r1")
 | |
| 
 | |
| %def op_rsub_int_lit8():
 | |
| %  binopLit8(extract="", instr="rsb     r0, r0, r3, asr #8")
 | |
| 
 | |
| %def op_shl_int():
 | |
| %  binop(preinstr="and     r1, r1, #31", instr="mov     r0, r0, lsl r1")
 | |
| 
 | |
| %def op_shl_int_2addr():
 | |
| %  binop2addr(preinstr="and     r1, r1, #31", instr="mov     r0, r0, lsl r1")
 | |
| 
 | |
| %def op_shl_int_lit8():
 | |
| %  binopLit8(extract="ubfx    r1, r3, #8, #5", instr="mov     r0, r0, lsl r1")
 | |
| 
 | |
| %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.
 | |
|      */
 | |
|     /* shl-long vAA, vBB, vCC */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r3, r0, #255                @ r3<- BB
 | |
|     mov     r0, r0, lsr #8              @ r0<- CC
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[BB]
 | |
|     GET_VREG r2, r0                     @ r2<- vCC
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r3    @ r0/r1<- vBB/vBB+1
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     and     r2, r2, #63                 @ r2<- r2 & 0x3f
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r4<- &fp[AA]
 | |
|     mov     r1, r1, asl r2              @ r1<- r1 << r2
 | |
|     rsb     r3, r2, #32                 @ r3<- 32 - r2
 | |
|     orr     r1, r1, r0, lsr r3          @ r1<- r1 | (r0 << (32-r2))
 | |
|     subs    ip, r2, #32                 @ ip<- r2 - 32
 | |
|     it      pl
 | |
|     movpl   r1, r0, asl ip              @ if r2 >= 32, r1<- r0 << (r2-32)
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     mov     r0, r0, asl r2              @ r0<- r0 << r2
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %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 */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r2, r3                     @ r2<- vB
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r4<- &fp[A]
 | |
|     and     r2, r2, #63                 @ r2<- r2 & 0x3f
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r4    @ r0/r1<- vAA/vAA+1
 | |
|     mov     r1, r1, asl r2              @ r1<- r1 << r2
 | |
|     rsb     r3, r2, #32                 @ r3<- 32 - r2
 | |
|     orr     r1, r1, r0, lsr r3          @ r1<- r1 | (r0 << (32-r2))
 | |
|     subs    ip, r2, #32                 @ ip<- r2 - 32
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     it      pl
 | |
|     movpl   r1, r0, asl ip              @ if r2 >= 32, r1<- r0 << (r2-32)
 | |
|     mov     r0, r0, asl r2              @ r0<- r0 << r2
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_shr_int():
 | |
| %  binop(preinstr="and     r1, r1, #31", instr="mov     r0, r0, asr r1")
 | |
| 
 | |
| %def op_shr_int_2addr():
 | |
| %  binop2addr(preinstr="and     r1, r1, #31", instr="mov     r0, r0, asr r1")
 | |
| 
 | |
| %def op_shr_int_lit8():
 | |
| %  binopLit8(extract="ubfx    r1, r3, #8, #5", instr="mov     r0, r0, asr r1")
 | |
| 
 | |
| %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.
 | |
|      */
 | |
|     /* shr-long vAA, vBB, vCC */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r3, r0, #255                @ r3<- BB
 | |
|     mov     r0, r0, lsr #8              @ r0<- CC
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[BB]
 | |
|     GET_VREG r2, r0                     @ r2<- vCC
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r3    @ r0/r1<- vBB/vBB+1
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     and     r2, r2, #63                 @ r0<- r0 & 0x3f
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r4<- &fp[AA]
 | |
|     mov     r0, r0, lsr r2              @ r0<- r2 >> r2
 | |
|     rsb     r3, r2, #32                 @ r3<- 32 - r2
 | |
|     orr     r0, r0, r1, lsl r3          @ r0<- r0 | (r1 << (32-r2))
 | |
|     subs    ip, r2, #32                 @ ip<- r2 - 32
 | |
|     it      pl
 | |
|     movpl   r0, r1, asr ip              @ if r2 >= 32, r0<-r1 >> (r2-32)
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     mov     r1, r1, asr r2              @ r1<- r1 >> r2
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_shr_long_2addr():
 | |
|     /*
 | |
|      * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
 | |
|      * 32-bit shift distance.
 | |
|      */
 | |
|     /* shr-long/2addr vA, vB */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r2, r3                     @ r2<- vB
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r4<- &fp[A]
 | |
|     and     r2, r2, #63                 @ r2<- r2 & 0x3f
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r4    @ r0/r1<- vAA/vAA+1
 | |
|     mov     r0, r0, lsr r2              @ r0<- r2 >> r2
 | |
|     rsb     r3, r2, #32                 @ r3<- 32 - r2
 | |
|     orr     r0, r0, r1, lsl r3          @ r0<- r0 | (r1 << (32-r2))
 | |
|     subs    ip, r2, #32                 @ ip<- r2 - 32
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     it      pl
 | |
|     movpl   r0, r1, asr ip              @ if r2 >= 32, r0<-r1 >> (r2-32)
 | |
|     mov     r1, r1, asr r2              @ r1<- r1 >> r2
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_sub_int():
 | |
| %  binop(instr="sub     r0, r0, r1")
 | |
| 
 | |
| %def op_sub_int_2addr():
 | |
| %  binop2addr(instr="sub     r0, r0, r1")
 | |
| 
 | |
| %def op_sub_long():
 | |
| %  binopWide(preinstr="subs    r0, r0, r2", instr="sbc     r1, r1, r3")
 | |
| 
 | |
| %def op_sub_long_2addr():
 | |
| %  binopWide2addr(preinstr="subs    r0, r0, r2", instr="sbc     r1, r1, r3")
 | |
| 
 | |
| %def op_ushr_int():
 | |
| %  binop(preinstr="and     r1, r1, #31", instr="mov     r0, r0, lsr r1")
 | |
| 
 | |
| %def op_ushr_int_2addr():
 | |
| %  binop2addr(preinstr="and     r1, r1, #31", instr="mov     r0, r0, lsr r1")
 | |
| 
 | |
| %def op_ushr_int_lit8():
 | |
| %  binopLit8(extract="ubfx    r1, r3, #8, #5", instr="mov     r0, r0, lsr r1")
 | |
| 
 | |
| %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.
 | |
|      */
 | |
|     /* ushr-long vAA, vBB, vCC */
 | |
|     FETCH r0, 1                         @ r0<- CCBB
 | |
|     mov     r4, rINST, lsr #8           @ r4<- AA
 | |
|     and     r3, r0, #255                @ r3<- BB
 | |
|     mov     r0, r0, lsr #8              @ r0<- CC
 | |
|     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &fp[BB]
 | |
|     GET_VREG r2, r0                     @ r2<- vCC
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r3    @ r0/r1<- vBB/vBB+1
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     and     r2, r2, #63                 @ r0<- r0 & 0x3f
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r4<- &fp[AA]
 | |
|     mov     r0, r0, lsr r2              @ r0<- r2 >> r2
 | |
|     rsb     r3, r2, #32                 @ r3<- 32 - r2
 | |
|     orr     r0, r0, r1, lsl r3          @ r0<- r0 | (r1 << (32-r2))
 | |
|     subs    ip, r2, #32                 @ ip<- r2 - 32
 | |
|     it      pl
 | |
|     movpl   r0, r1, lsr ip              @ if r2 >= 32, r0<-r1 >>> (r2-32)
 | |
|     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
 | |
|     mov     r1, r1, lsr r2              @ r1<- r1 >>> r2
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_ushr_long_2addr():
 | |
|     /*
 | |
|      * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
 | |
|      * 32-bit shift distance.
 | |
|      */
 | |
|     /* ushr-long/2addr vA, vB */
 | |
|     mov     r3, rINST, lsr #12          @ r3<- B
 | |
|     ubfx    r4, rINST, #8, #4           @ r4<- A
 | |
|     GET_VREG r2, r3                     @ r2<- vB
 | |
|     CLEAR_SHADOW_PAIR r4, lr, ip        @ Zero out the shadow regs
 | |
|     VREG_INDEX_TO_ADDR r4, r4           @ r4<- &fp[A]
 | |
|     and     r2, r2, #63                 @ r2<- r2 & 0x3f
 | |
|     GET_VREG_WIDE_BY_ADDR r0, r1, r4    @ r0/r1<- vAA/vAA+1
 | |
|     mov     r0, r0, lsr r2              @ r0<- r2 >> r2
 | |
|     rsb     r3, r2, #32                 @ r3<- 32 - r2
 | |
|     orr     r0, r0, r1, lsl r3          @ r0<- r0 | (r1 << (32-r2))
 | |
|     subs    ip, r2, #32                 @ ip<- r2 - 32
 | |
|     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
 | |
|     it      pl
 | |
|     movpl   r0, r1, lsr ip              @ if r2 >= 32, r0<-r1 >>> (r2-32)
 | |
|     mov     r1, r1, lsr r2              @ r1<- r1 >>> r2
 | |
|     GET_INST_OPCODE ip                  @ extract opcode from rINST
 | |
|     SET_VREG_WIDE_BY_ADDR r0, r1, r4    @ vAA/vAA+1<- r0/r1
 | |
|     GOTO_OPCODE ip                      @ jump to next instruction
 | |
| 
 | |
| %def op_xor_int():
 | |
| %  binop(instr="eor     r0, r0, r1")
 | |
| 
 | |
| %def op_xor_int_2addr():
 | |
| %  binop2addr(instr="eor     r0, r0, r1")
 | |
| 
 | |
| %def op_xor_int_lit16():
 | |
| %  binopLit16(instr="eor     r0, r0, r1")
 | |
| 
 | |
| %def op_xor_int_lit8():
 | |
| %  binopLit8(extract="", instr="eor     r0, r0, r3, asr #8")
 | |
| 
 | |
| %def op_xor_long():
 | |
| %  binopWide(preinstr="eor     r0, r0, r2", instr="eor     r1, r1, r3")
 | |
| 
 | |
| %def op_xor_long_2addr():
 | |
| %  binopWide2addr(preinstr="eor     r0, r0, r2", instr="eor     r1, r1, r3")
 |