%def binop(preinstr="" , result="r0" , chkzero=False, 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
FETCH_ADVANCE_INST 2 @ advance rPC, load rINST
$preinstr @ optional op; may set condition codes
$instr @ $result<- op, r0-r3 changed
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG $result, r4 @ vAA<- $result
GOTO_OPCODE @ jump to next instruction
/* 11-14 instructions */
%def binop2addr(preinstr="" , result="r0" , chkzero=False, instr="" ):
/*
* Generic 32 - bit " / 2 addr " 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 / 2 addr , sub - int / 2 addr , mul - int / 2 addr , div - int / 2 addr ,
* rem - int / 2 addr , and - int / 2 addr , or - int / 2 addr , xor - int / 2 addr ,
* shl - int / 2 addr , shr - int / 2 addr , ushr - int / 2 addr , add - float / 2 addr ,
* sub - float / 2 addr , mul - float / 2 addr , div - float / 2 addr , rem - float / 2 addr
*/
/* 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
FETCH_ADVANCE_INST 1 @ advance rPC, load rINST
$preinstr @ optional op; may set condition codes
$instr @ $result<- op, r0-r3 changed
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG $result, r4 @ vAA<- $result
GOTO_OPCODE @ jump to next instruction
/* 10-13 instructions */
%def binopLit16(result="r0" , chkzero=False, 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
FETCH_ADVANCE_INST 2 @ advance rPC, load rINST
$instr @ $result<- op, r0-r3 changed
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG $result, r4 @ vAA<- $result
GOTO_OPCODE @ jump to next instruction
/* 10-13 instructions */
%def binopLit8(extract="asr r1, r3, #8" , result="r0" , chkzero=False, 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
FETCH_ADVANCE_INST 2 @ advance rPC, load rINST
$instr @ $result<- op, r0-r3 changed
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG $result, r4 @ vAA<- $result
GOTO_OPCODE @ jump to next instruction
/* 10-12 instructions */
%def binopWide(preinstr="" , result0="r0" , result1="r1" , chkzero=False, 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
*
* IMPORTANT : you may specify " chkzero " or " preinstr " but not both .
*/
/* binop vAA, vBB, vCC */
FETCH r0, 1 @ r0<- CCBB
% if chkzero:
lsrs rINST, rINST, #8 @ rINST<- AA; set flags to use 16 -bit encoding
lsrs r3, r0, #8 @ r3<- CC; set flags to use 16 -bit encoding
% else:
lsr rINST, rINST, #8 @ rINST<- AA
lsr r3, r0, #8 @ r3<- CC
and r1, r0, #255 @ r1<- BB
VREG_INDEX_TO_ADDR r4, rINST @ r4<- &fp[AA]
VREG_INDEX_TO_ADDR r3, r3 @ r3<- &fp[CC]
VREG_INDEX_TO_ADDR r1, r1 @ r1<- &fp[BB]
GET_VREG_WIDE_BY_ADDR r2, r3, r3 @ r2/r3<- vCC/vCC+1
GET_VREG_WIDE_BY_ADDR r0, r1, r1 @ r0/r1<- vBB/vBB+1
% if chkzero:
orrs ip, r2, r3 @ second arg (r2-r3) is zero?
beq common_errDivideByZero
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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
@ Use write-back for 16 -bit encoding if `chkzero`.
% wb = '!' if chkzero else ''
SET_VREG_WIDE_BY_ADDR $result0,$result1,r4, ${wb} @ vAA/vAA+1 <, $result0/$result1
GOTO_OPCODE @ jump to next instruction
/* 14-17 instructions */
%def binopWide2addr(preinstr="" , result0="r0" , result1="r1" , chkzero=False, instr="" ):
/*
* Generic 64 - bit " / 2 addr " 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 / 2 addr , sub - long / 2 addr , div - long / 2 addr , rem - long / 2 addr ,
* and - long / 2 addr , or - long / 2 addr , xor - long / 2 addr , add - double / 2 addr ,
* sub - double / 2 addr , mul - double / 2 addr , div - double / 2 addr ,
* rem - double / 2 addr
*/
/* 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
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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR $result0,$result1,r4 @ vAA/vAA+1 <- $result0/$result1
GOTO_OPCODE @ 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r0, r4 @ vAA<- r0
GOTO_OPCODE @ jump to next instruction
/* 8-9 instructions */
%def unopNarrower(preinstr="" , instr="" ):
/*
* Generic 64 bit - to - 32 bit 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r0, r4 @ vA<- r0
GOTO_OPCODE @ jump to next instruction
/* 9-10 instructions */
%def unopWide(preinstr="" , instr="" , postinstr="" ):
/*
* 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
$postinstr @ optional op
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR r0, r1, r4 @ vAA<- r0/r1
GOTO_OPCODE @ jump to next instruction
/* 10-11 instructions */
%def unopWider(preinstr="" , instr="" ):
/*
* Generic 32 bit - to - 64 bit 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR r0, r1, r4 @ vA/vA+1 <- r0/r1
GOTO_OPCODE @ 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():
// Set flags to use 16 -bit encoding for one of the instructions.
% binopWide(preinstr="ands 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
lsrs r4, rINST, #(8 -2 ) @ r4<- AA << 2 ; opcode 31 has highest two bits clear
and r2, r0, #255 @ r2<- BB
lsrs r3, r0, #8 @ r3<- CC; set flags to use 16 -bit encoding (same above)
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_PRESCALED r3, r4, s="s" @ vAA<- r3; set flags to use 16 -bit encoding.
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
GOTO_OPCODE @ 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r0, r4 @ vAA<- r0
GOTO_OPCODE @ 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 / 2 addr
*
*/
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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r0, r4 @ vAA<- r0
GOTO_OPCODE @ 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r0, r4 @ vAA<- r0
GOTO_OPCODE @ 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r0, r4 @ vAA<- r0
GOTO_OPCODE @ jump to next instruction
/* 10-12 instructions */
%def op_div_long():
% binopWide(instr="bl __aeabi_ldivmod" , chkzero=True)
%def op_div_long_2addr():
% binopWide2addr(instr="bl __aeabi_ldivmod" , chkzero=True)
%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 r1, r0, #255 @ r1<- BB
lsrs r3, r0, #8 @ r3<- CC; set flags to use 16 -bit encoding (same below)
VREG_INDEX_TO_ADDR r1, r1 @ r1<- &fp[BB]
VREG_INDEX_TO_ADDR r3, r3 @ r3<- &fp[CC]
GET_VREG_WIDE_BY_ADDR r0, r1, r1 @ r0/r1<- vBB/vBB+1
GET_VREG_WIDE_BY_ADDR r2, r3, r3 @ r2/r3<- vCC/vCC+1
muls r3, r0, r3 @ r3<- low(YxX)
umull r0, lr, r2, r0 @ r0/lr <- ZxX
mla r1, r2, r1, r3 @ r1<- low(YxX + ZxW)
lsrs r4, rINST, #8 @ r4<- AA
add r1, r1, lr @ r1<- high(ZxX) + low(ZxW + (YxX))
PRESCALE_VREG r4, r4 @ r4<- AA << 2
CLEAR_SHADOW_PAIR_PRESCALED r4, r2, r3, s="s" @ Zero out the shadow regs
VREG_INDEX_TO_ADDR_PRESCALED r4, r4 @ r4<- &fp[AA]
FETCH_ADVANCE_INST 2 @ advance rPC, load rINST
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR r0, r1, r4 @ vAA/vAA+1 <- r0/r1
GOTO_OPCODE @ jump to next instruction
%def op_mul_long_2addr():
/*
* Signed 64 - bit integer multiply , " / 2 addr " 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))
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR r0, r1, r4 @ vAA/vAA+1 <- r0/r1
GOTO_OPCODE @ 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="mov ip, #0" , postinstr="sbc r1, ip, r1" )
%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():
// Set flags to use 16 -bit encoding for one of the instructions.
% binopWide(preinstr="orrs 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r1, r4 @ vAA<- r1
GOTO_OPCODE @ 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 / 2 addr
*
*/
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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r1, r4 @ vAA<- r1
GOTO_OPCODE @ 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r1, r4 @ vAA<- r1
GOTO_OPCODE @ 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
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG r1, r4 @ vAA<- r1
GOTO_OPCODE @ 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=True)
%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=True)
%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_shift_long(large_shift):
/*
* 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,shr,ushr}-long vAA, vBB, vCC */
FETCH r0, 1 @ r0<- CCBB
lsrs r4, rINST, #8 @ r4<- AA; set flags to use 16 -bit encoding (same below)
and r3, r0, #255 @ r3<- BB
lsrs r0, r0, #8 @ r0<- CC
VREG_INDEX_TO_ADDR r1, r3 @ r1<- &fp[BB]
PRESCALE_VREG r4, r4, s="s" @ r4<- A << 2
GET_VREG r2, r0 @ r2<- vCC
CLEAR_SHADOW_PAIR_PRESCALED r4, r0, r3, s="s" @ Zero out the shadow regs
GET_VREG_WIDE_BY_ADDR r0, r1, r1 @ r0/r1<- vBB/vBB+1
VREG_INDEX_TO_ADDR_PRESCALED r4, r4 @ r4<- &fp[AA]
FETCH_ADVANCE_INST 2
lsls r3, r2, #27 @ set C from bit 6 with a 16 -bit instruction
and r2, r2, #0 x1f @ r2<- (r2 & 0 x1f)
bcc .L${opcode}_2 addr_small_shift
.L${opcode}_large_shift:
% large_shift()
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR r0, r1, r4 @ vAA/vAA+1 <- r0/r1
GOTO_OPCODE @ jump to next instruction
%def op_shift_long_2addr(small_shift):
/*
* Long integer shift , 2 addr version . vA is 64 - bit value / result , vB is
* 32 - bit shift distance .
*/
/* shl-long/2addr vA, vB */
lsrs r3, rINST, #12 @ r3<- B; set flags to use 16 -bit encoding (same below)
ubfx r4, rINST, #8 , #4 @ r4<- A
GET_VREG r2, r3 @ r2<- vB
PRESCALE_VREG r4, r4, s="s" @ r4<- A << 2
CLEAR_SHADOW_PAIR_PRESCALED r4, r0, r1, s="s" @ Zero out the shadow regs
VREG_INDEX_TO_ADDR_PRESCALED r4, r4 @ r4<- &fp[A]
GET_VREG_WIDE_BY_ADDR r0, r1, r4 @ r0/r1<- vAA/vAA+1
lsls r3, r2, #27 @ set C from bit 6 with a 16 -bit instruction
FETCH_ADVANCE_INST 1
and r2, r2, #0 x1f @ r2<- (r2 & 0 x1f)
% other_opcode = re.sub (r"_2addr" , r"" , opcode)
bcs .L${other_opcode}_large_shift
.L${opcode}_small_shift:
% small_shift()
PREPARE_OPCODE_DISPATCH @ insert opcode to rIBASE
SET_VREG_WIDE_BY_ADDR r0, r1, r4 @ vAA/vAA+1 <- r0/r1
GOTO_OPCODE @ jump to next instruction
%def shl_long_large_shift():
@ Calculate {r0-r1} << (r2 + 32 ) with r2 < 32 .
lsl r1, r0, r2 @ r1<- r0 << r2
movs r0, #0 @ r0<- 0 ; set flags to use 16 -bit encoding
%def shl_long_small_shift():
@ Calculate {r0-r1} << r2 with r2 < 32 .
rsb r3, r2, #32 @ r3<- 32 - r2
lsls r1, r1, r2 @ r1<- r1 << r2; set flags to use 16 -bit encoding
lsr r3, r0, r3 @ r3<- r0 >>> (32 -r2)
lsls r0, r0, r2 @ r0<- r0 << r2; set flags to use 16 -bit encoding
add r1, r1, r3 @ r1<- r1 | (r0 >>> (32 -r2)); use `add` for 16 -bit encoding
%def op_shl_long():
% op_shift_long(shl_long_large_shift)
%def op_shl_long_2addr():
% op_shift_long_2addr(shl_long_small_shift)
%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 shr_long_large_shift():
@ Calculate {r0-r1} >> (r2 + 32 ) with r2 < 32 .
asrs r0, r1, r2 @ r0<- r1 >> r2
asrs r1, r1, #31 @ r1<- r1 >> 31 ; set flags to use 16 -bit encoding
%def shr_long_small_shift():
@ Calculate {r0-r1} >> r2 with r2 < 32 .
rsb r3, r2, #32 @ r3<- 32 - r2
lsrs r0, r0, r2 @ r0<- r0 >>> r2; set flags to use 16 -bit encoding
lsl r3, r1, r3 @ r3<- r1 << (32 -r2)
asrs r1, r1, r2 @ r1<- r1 >> r2; set flags to use 16 -bit encoding
add r0, r0, r3 @ r0<- r0 | (r1 << (32 -r2)); use `add` for 16 -bit encoding
%def op_shr_long():
% op_shift_long(shr_long_large_shift)
%def op_shr_long_2addr():
% op_shift_long_2addr(shr_long_small_shift)
%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 ushr_long_large_shift():
@ Calculate {r0-r1} >>> (r2 + 32 ) with r2 < 32 .
lsr r0, r1, r2 @ r1<- r0 >>> r2;
movs r1, #0 @ r1<- 0 ; set flags to use 16 -bit encoding
%def ushr_long_small_shift():
@ Calculate {r0-r1} >>> r2 with r2 < 32 .
rsb r3, r2, #32 @ r3<- 32 - r2
lsrs r0, r0, r2 @ r0<- r0 >>> r2; set flags to use 16 -bit encoding
lsl r3, r1, r3 @ r3<- r1 << (32 -r2)
lsrs r1, r1, r2 @ r1<- r1 >>> r2; set flags to use 16 -bit encoding
add r0, r0, r3 @ r0<- r0 | (r1 << (32 -r2)); use `add` for 16 -bit encoding
%def op_ushr_long():
% op_shift_long(ushr_long_large_shift)
%def op_ushr_long_2addr():
% op_shift_long_2addr(ushr_long_small_shift)
%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():
// Set flags to use 16 -bit encoding for one of the instructions.
% binopWide(preinstr="eors r0, r0, r2" , instr="eor r1, r1, r3" )
%def op_xor_long_2addr():
% binopWide2addr(preinstr="eor r0, r0, r2" , instr="eor r1, r1, r3" )
Messung V0.5 in Prozent C=91 H=93 G=91
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland