Home | History | Annotate | Download | only in mips
      1 %def binop(preinstr="", result="a0", chkzero="0", instr=""):
      2     /*
      3      * Generic 32-bit binary operation.  Provide an "instr" line that
      4      * specifies an instruction that performs "result = a0 op a1".
      5      * This could be a MIPS instruction or a function call.  (If the result
      6      * comes back in a register other than a0, you can override "result".)
      7      *
      8      * If "chkzero" is set to 1, we perform a divide-by-zero check on
      9      * vCC (a1).  Useful for integer division and modulus.  Note that we
     10      * *don't* check for (INT_MIN / -1) here, because the CPU handles it
     11      * correctly.
     12      *
     13      * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
     14      *      xor-int, shl-int, shr-int, ushr-int
     15      */
     16     /* binop vAA, vBB, vCC */
     17     FETCH(a0, 1)                           #  a0 <- CCBB
     18     GET_OPA(rOBJ)                          #  rOBJ <- AA
     19     srl       a3, a0, 8                    #  a3 <- CC
     20     and       a2, a0, 255                  #  a2 <- BB
     21     GET_VREG(a1, a3)                       #  a1 <- vCC
     22     GET_VREG(a0, a2)                       #  a0 <- vBB
     23     .if $chkzero
     24     # is second operand zero?
     25     beqz      a1, common_errDivideByZero
     26     .endif
     27 
     28     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
     29     $preinstr                              #  optional op
     30     $instr                                 #  $result <- op, a0-a3 changed
     31     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
     32     SET_VREG_GOTO($result, rOBJ, t0)       #  vAA <- $result
     33 
     34 %def binop2addr(preinstr="", result="a0", chkzero="0", instr=""):
     35     /*
     36      * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
     37      * that specifies an instruction that performs "result = a0 op a1".
     38      * This could be an MIPS instruction or a function call.
     39      *
     40      * If "chkzero" is set to 1, we perform a divide-by-zero check on
     41      * vCC (a1).  Useful for integer division and modulus.
     42      *
     43      * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
     44      *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
     45      *      shl-int/2addr, shr-int/2addr, ushr-int/2addr
     46      */
     47     /* binop/2addr vA, vB */
     48     GET_OPA4(rOBJ)                         #  rOBJ <- A+
     49     GET_OPB(a3)                            #  a3 <- B
     50     GET_VREG(a0, rOBJ)                     #  a0 <- vA
     51     GET_VREG(a1, a3)                       #  a1 <- vB
     52     .if $chkzero
     53     # is second operand zero?
     54     beqz      a1, common_errDivideByZero
     55     .endif
     56     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
     57 
     58     $preinstr                              #  optional op
     59     $instr                                 #  $result <- op, a0-a3 changed
     60     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
     61     SET_VREG_GOTO($result, rOBJ, t0)       #  vA <- $result
     62 
     63 %def binopLit16(preinstr="", result="a0", chkzero="0", instr=""):
     64     /*
     65      * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
     66      * that specifies an instruction that performs "result = a0 op a1".
     67      * This could be an MIPS instruction or a function call.  (If the result
     68      * comes back in a register other than a0, you can override "result".)
     69      *
     70      * If "chkzero" is set to 1, we perform a divide-by-zero check on
     71      * vCC (a1).  Useful for integer division and modulus.
     72      *
     73      * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
     74      *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
     75      */
     76     /* binop/lit16 vA, vB, +CCCC */
     77     FETCH_S(a1, 1)                         #  a1 <- ssssCCCC (sign-extended)
     78     GET_OPB(a2)                            #  a2 <- B
     79     GET_OPA4(rOBJ)                         #  rOBJ <- A+
     80     GET_VREG(a0, a2)                       #  a0 <- vB
     81     .if $chkzero
     82     # cmp a1, 0; is second operand zero?
     83     beqz      a1, common_errDivideByZero
     84     .endif
     85     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
     86 
     87     $preinstr                              #  optional op
     88     $instr                                 #  $result <- op, a0-a3 changed
     89     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
     90     SET_VREG_GOTO($result, rOBJ, t0)       #  vA <- $result
     91 
     92 %def binopLit8(preinstr="", result="a0", chkzero="0", instr=""):
     93     /*
     94      * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
     95      * that specifies an instruction that performs "result = a0 op a1".
     96      * This could be an MIPS instruction or a function call.  (If the result
     97      * comes back in a register other than a0, you can override "result".)
     98      *
     99      * If "chkzero" is set to 1, we perform a divide-by-zero check on
    100      * vCC (a1).  Useful for integer division and modulus.
    101      *
    102      * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
    103      *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
    104      *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
    105      */
    106     /* binop/lit8 vAA, vBB, +CC */
    107     FETCH_S(a3, 1)                         #  a3 <- ssssCCBB (sign-extended for CC)
    108     GET_OPA(rOBJ)                          #  rOBJ <- AA
    109     and       a2, a3, 255                  #  a2 <- BB
    110     GET_VREG(a0, a2)                       #  a0 <- vBB
    111     sra       a1, a3, 8                    #  a1 <- ssssssCC (sign extended)
    112     .if $chkzero
    113     # is second operand zero?
    114     beqz      a1, common_errDivideByZero
    115     .endif
    116     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    117 
    118     $preinstr                              #  optional op
    119     $instr                                 #  $result <- op, a0-a3 changed
    120     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    121     SET_VREG_GOTO($result, rOBJ, t0)       #  vAA <- $result
    122 
    123 %def binopWide(preinstr="", result0="a0", result1="a1", chkzero="0", arg0="a0", arg1="a1", arg2="a2", arg3="a3", instr=""):
    124     /*
    125      * Generic 64-bit binary operation.  Provide an "instr" line that
    126      * specifies an instruction that performs "result = a0-a1 op a2-a3".
    127      * This could be a MIPS instruction or a function call.  (If the result
    128      * comes back in a register pair other than a0-a1, you can override "result".)
    129      *
    130      * If "chkzero" is set to 1, we perform a divide-by-zero check on
    131      * vCC (a2-a3).  Useful for integer division and modulus.
    132      *
    133      * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
    134      *      xor-long
    135      *
    136      * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
    137      */
    138     /* binop vAA, vBB, vCC */
    139     FETCH(a0, 1)                           #  a0 <- CCBB
    140     GET_OPA(rOBJ)                          #  rOBJ <- AA
    141     and       a2, a0, 255                  #  a2 <- BB
    142     srl       a3, a0, 8                    #  a3 <- CC
    143     EAS2(a2, rFP, a2)                      #  a2 <- &fp[BB]
    144     EAS2(t1, rFP, a3)                      #  a3 <- &fp[CC]
    145     LOAD64($arg0, $arg1, a2)               #  a0/a1 <- vBB/vBB+1
    146     LOAD64($arg2, $arg3, t1)               #  a2/a3 <- vCC/vCC+1
    147     .if $chkzero
    148     or        t0, $arg2, $arg3             #  second arg (a2-a3) is zero?
    149     beqz      t0, common_errDivideByZero
    150     .endif
    151     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    152 
    153     $preinstr                              #  optional op
    154     $instr                                 #  result <- op, a0-a3 changed
    155     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    156     SET_VREG64_GOTO($result0, $result1, rOBJ, t0)   #  vAA/vAA+1 <- $result0/$result1
    157 
    158 %def binopWide2addr(preinstr="", result0="a0", result1="a1", chkzero="0", arg0="a0", arg1="a1", arg2="a2", arg3="a3", instr=""):
    159     /*
    160      * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
    161      * that specifies an instruction that performs "result = a0-a1 op a2-a3".
    162      * This could be a MIPS instruction or a function call.  (If the result
    163      * comes back in a register pair other than a0-a1, you can override "result".)
    164      *
    165      * If "chkzero" is set to 1, we perform a divide-by-zero check on
    166      * vB (a2-a3).  Useful for integer division and modulus.
    167      *
    168      * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
    169      *      and-long/2addr, or-long/2addr, xor-long/2addr
    170      */
    171     /* binop/2addr vA, vB */
    172     GET_OPA4(rOBJ)                         #  rOBJ <- A+
    173     GET_OPB(a1)                            #  a1 <- B
    174     EAS2(a1, rFP, a1)                      #  a1 <- &fp[B]
    175     EAS2(t0, rFP, rOBJ)                    #  t0 <- &fp[A]
    176     LOAD64($arg2, $arg3, a1)               #  a2/a3 <- vB/vB+1
    177     LOAD64($arg0, $arg1, t0)               #  a0/a1 <- vA/vA+1
    178     .if $chkzero
    179     or        t0, $arg2, $arg3             #  second arg (a2-a3) is zero?
    180     beqz      t0, common_errDivideByZero
    181     .endif
    182     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    183 
    184     $preinstr                              #  optional op
    185     $instr                                 #  result <- op, a0-a3 changed
    186     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    187     SET_VREG64_GOTO($result0, $result1, rOBJ, t0)   #  vA/vA+1 <- $result0/$result1
    188 
    189 %def unop(preinstr="", result0="a0", instr=""):
    190     /*
    191      * Generic 32-bit unary operation.  Provide an "instr" line that
    192      * specifies an instruction that performs "result0 = op a0".
    193      * This could be a MIPS instruction or a function call.
    194      *
    195      * for: int-to-byte, int-to-char, int-to-short,
    196      *      neg-int, not-int, neg-float
    197      */
    198     /* unop vA, vB */
    199     GET_OPB(a3)                            #  a3 <- B
    200     GET_OPA4(t0)                           #  t0 <- A+
    201     GET_VREG(a0, a3)                       #  a0 <- vB
    202     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    203     $preinstr                              #  optional op
    204     $instr                                 #  a0 <- op, a0-a3 changed
    205     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
    206     SET_VREG_GOTO($result0, t0, t1)        #  vA <- result0
    207 
    208 %def unopNarrower(load="LOAD64_F(fa0, fa0f, a3)", instr=""):
    209     /*
    210      * Generic 64bit-to-32bit floating-point unary operation.  Provide an "instr"
    211      * line that specifies an instruction that performs "fv0 = op fa0".
    212      *
    213      * For: double-to-float
    214      */
    215     /* unop vA, vB */
    216     GET_OPB(a3)                            #  a3 <- B
    217     GET_OPA4(rOBJ)                         #  rOBJ <- A+
    218     EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
    219     $load
    220     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    221     $instr
    222     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    223     SET_VREG_F_GOTO(fv0, rOBJ, t0)         #  vA <- fv0
    224 
    225 %def unopWide(preinstr="", result0="a0", result1="a1", instr=""):
    226     /*
    227      * Generic 64-bit unary operation.  Provide an "instr" line that
    228      * specifies an instruction that performs "result0/result1 = op a0/a1".
    229      * This could be MIPS instruction or a function call.
    230      *
    231      * For: neg-long, not-long, neg-double,
    232      */
    233     /* unop vA, vB */
    234     GET_OPA4(rOBJ)                         #  rOBJ <- A+
    235     GET_OPB(a3)                            #  a3 <- B
    236     EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
    237     LOAD64(a0, a1, a3)                     #  a0/a1 <- vA
    238     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    239     $preinstr                              #  optional op
    240     $instr                                 #  a0/a1 <- op, a2-a3 changed
    241     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    242     SET_VREG64_GOTO($result0, $result1, rOBJ, t0)   #  vA/vA+1 <- a0/a1
    243 
    244 %def unopWider(preinstr="", result0="a0", result1="a1", instr=""):
    245     /*
    246      * Generic 32bit-to-64bit unary operation.  Provide an "instr" line
    247      * that specifies an instruction that performs "result0/result1 = op a0".
    248      *
    249      * For: int-to-long
    250      */
    251     /* unop vA, vB */
    252     GET_OPA4(rOBJ)                         #  rOBJ <- A+
    253     GET_OPB(a3)                            #  a3 <- B
    254     GET_VREG(a0, a3)                       #  a0 <- vB
    255     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    256     $preinstr                              #  optional op
    257     $instr                                 #  result <- op, a0-a3 changed
    258     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    259     SET_VREG64_GOTO($result0, $result1, rOBJ, t0)   #  vA/vA+1 <- a0/a1
    260 
    261 %def op_add_int():
    262 %  binop(instr="addu a0, a0, a1")
    263 
    264 %def op_add_int_2addr():
    265 %  binop2addr(instr="addu a0, a0, a1")
    266 
    267 %def op_add_int_lit16():
    268 %  binopLit16(instr="addu a0, a0, a1")
    269 
    270 %def op_add_int_lit8():
    271 %  binopLit8(instr="addu a0, a0, a1")
    272 
    273 %def op_add_long():
    274 /*
    275  *  The compiler generates the following sequence for
    276  *  [v1 v0] =  [a1 a0] + [a3 a2];
    277  *    addu v0,a2,a0
    278  *    addu a1,a3,a1
    279  *    sltu v1,v0,a2
    280  *    addu v1,v1,a1
    281  */
    282 %  binopWide(result0="v0", result1="v1", preinstr="addu v0, a2, a0", instr="addu a1, a3, a1; sltu v1, v0, a2; addu v1, v1, a1")
    283 
    284 %def op_add_long_2addr():
    285 /*
    286  * See op_add_long.S for details
    287  */
    288 %  binopWide2addr(result0="v0", result1="v1", preinstr="addu v0, a2, a0", instr="addu a1, a3, a1; sltu v1, v0, a2; addu v1, v1, a1")
    289 
    290 %def op_and_int():
    291 %  binop(instr="and a0, a0, a1")
    292 
    293 %def op_and_int_2addr():
    294 %  binop2addr(instr="and a0, a0, a1")
    295 
    296 %def op_and_int_lit16():
    297 %  binopLit16(instr="and a0, a0, a1")
    298 
    299 %def op_and_int_lit8():
    300 %  binopLit8(instr="and a0, a0, a1")
    301 
    302 %def op_and_long():
    303 %  binopWide(preinstr="and a0, a0, a2", instr="and a1, a1, a3")
    304 
    305 %def op_and_long_2addr():
    306 %  binopWide2addr(preinstr="and a0, a0, a2", instr="and a1, a1, a3")
    307 
    308 %def op_cmp_long():
    309     /*
    310      * Compare two 64-bit values
    311      *    x = y     return  0
    312      *    x < y     return -1
    313      *    x > y     return  1
    314      *
    315      * I think I can improve on the ARM code by the following observation
    316      *    slt   t0,  x.hi, y.hi;        # (x.hi < y.hi) ? 1:0
    317      *    sgt   t1,  x.hi, y.hi;        # (y.hi > x.hi) ? 1:0
    318      *    subu  v0, t0, t1              # v0= -1:1:0 for [ < > = ]
    319      */
    320     /* cmp-long vAA, vBB, vCC */
    321     FETCH(a0, 1)                           #  a0 <- CCBB
    322     GET_OPA(rOBJ)                          #  rOBJ <- AA
    323     and       a2, a0, 255                  #  a2 <- BB
    324     srl       a3, a0, 8                    #  a3 <- CC
    325     EAS2(a2, rFP, a2)                      #  a2 <- &fp[BB]
    326     EAS2(a3, rFP, a3)                      #  a3 <- &fp[CC]
    327     LOAD64(a0, a1, a2)                     #  a0/a1 <- vBB/vBB+1
    328     LOAD64(a2, a3, a3)                     #  a2/a3 <- vCC/vCC+1
    329 
    330     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    331     slt       t0, a1, a3                   #  compare hi
    332     sgt       t1, a1, a3
    333     subu      v0, t1, t0                   #  v0 <- (-1, 1, 0)
    334     bnez      v0, .L${opcode}_finish
    335     # at this point x.hi==y.hi
    336     sltu      t0, a0, a2                   #  compare lo
    337     sgtu      t1, a0, a2
    338     subu      v0, t1, t0                   #  v0 <- (-1, 1, 0) for [< > =]
    339 
    340 .L${opcode}_finish:
    341     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    342     SET_VREG_GOTO(v0, rOBJ, t0)            #  vAA <- v0
    343 
    344 %def op_div_int():
    345 #ifdef MIPS32REVGE6
    346 %  binop(instr="div a0, a0, a1", chkzero="1")
    347 #else
    348 %  binop(preinstr="div zero, a0, a1", instr="mflo a0", chkzero="1")
    349 #endif
    350 
    351 %def op_div_int_2addr():
    352 #ifdef MIPS32REVGE6
    353 %  binop2addr(instr="div a0, a0, a1", chkzero="1")
    354 #else
    355 %  binop2addr(preinstr="div zero, a0, a1", instr="mflo a0", chkzero="1")
    356 #endif
    357 
    358 %def op_div_int_lit16():
    359 #ifdef MIPS32REVGE6
    360 %  binopLit16(instr="div a0, a0, a1", chkzero="1")
    361 #else
    362 %  binopLit16(preinstr="div zero, a0, a1", instr="mflo a0", chkzero="1")
    363 #endif
    364 
    365 %def op_div_int_lit8():
    366 #ifdef MIPS32REVGE6
    367 %  binopLit8(instr="div a0, a0, a1", chkzero="1")
    368 #else
    369 %  binopLit8(preinstr="div zero, a0, a1", instr="mflo a0", chkzero="1")
    370 #endif
    371 
    372 %def op_div_long():
    373 %  binopWide(result0="v0", result1="v1", instr="JAL(__divdi3)", chkzero="1")
    374 
    375 %def op_div_long_2addr():
    376 %  binopWide2addr(result0="v0", result1="v1", instr="JAL(__divdi3)", chkzero="1")
    377 
    378 %def op_int_to_byte():
    379 %  unop(instr="SEB(a0, a0)")
    380 
    381 %def op_int_to_char():
    382 %  unop(preinstr="", instr="and a0, 0xffff")
    383 
    384 %def op_int_to_long():
    385 %  unopWider(instr="sra a1, a0, 31")
    386 
    387 %def op_int_to_short():
    388 %  unop(instr="SEH(a0, a0)")
    389 
    390 %def op_long_to_int():
    391 /* we ignore the high word, making this equivalent to a 32-bit reg move */
    392 %  op_move()
    393 
    394 %def op_mul_int():
    395 %  binop(instr="mul a0, a0, a1")
    396 
    397 %def op_mul_int_2addr():
    398 %  binop2addr(instr="mul a0, a0, a1")
    399 
    400 %def op_mul_int_lit16():
    401 %  binopLit16(instr="mul a0, a0, a1")
    402 
    403 %def op_mul_int_lit8():
    404 %  binopLit8(instr="mul a0, a0, a1")
    405 
    406 %def op_mul_long():
    407     /*
    408      * Signed 64-bit integer multiply.
    409      *         a1   a0
    410      *   x     a3   a2
    411      *   -------------
    412      *       a2a1 a2a0
    413      *       a3a0
    414      *  a3a1 (<= unused)
    415      *  ---------------
    416      *         v1   v0
    417      */
    418     /* mul-long vAA, vBB, vCC */
    419     FETCH(a0, 1)                           #  a0 <- CCBB
    420     and       t0, a0, 255                  #  a2 <- BB
    421     srl       t1, a0, 8                    #  a3 <- CC
    422     EAS2(t0, rFP, t0)                      #  t0 <- &fp[BB]
    423     LOAD64(a0, a1, t0)                     #  a0/a1 <- vBB/vBB+1
    424 
    425     EAS2(t1, rFP, t1)                      #  t0 <- &fp[CC]
    426     LOAD64(a2, a3, t1)                     #  a2/a3 <- vCC/vCC+1
    427 
    428     mul       v1, a3, a0                   #  v1= a3a0
    429 #ifdef MIPS32REVGE6
    430     mulu      v0, a2, a0                   #  v0= a2a0
    431     muhu      t1, a2, a0
    432 #else
    433     multu     a2, a0
    434     mfhi      t1
    435     mflo      v0                           #  v0= a2a0
    436 #endif
    437     mul       t0, a2, a1                   #  t0= a2a1
    438     addu      v1, v1, t1                   #  v1+= hi(a2a0)
    439     addu      v1, v1, t0                   #  v1= a3a0 + a2a1;
    440 
    441     GET_OPA(a0)                            #  a0 <- AA
    442     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    443     b         .L${opcode}_finish
    444 %def op_mul_long_helper_code():
    445 
    446 .Lop_mul_long_finish:
    447     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    448     SET_VREG64_GOTO(v0, v1, a0, t0)        #  vAA/vAA+1 <- v0(low)/v1(high)
    449 
    450 %def op_mul_long_2addr():
    451     /*
    452      * See op_mul_long.S for more details
    453      */
    454     /* mul-long/2addr vA, vB */
    455     GET_OPA4(rOBJ)                         #  rOBJ <- A+
    456 
    457     EAS2(t0, rFP, rOBJ)                    #  t0 <- &fp[A]
    458     LOAD64(a0, a1, t0)                     #  vAA.low / high
    459 
    460     GET_OPB(t1)                            #  t1 <- B
    461     EAS2(t1, rFP, t1)                      #  t1 <- &fp[B]
    462     LOAD64(a2, a3, t1)                     #  vBB.low / high
    463 
    464     mul       v1, a3, a0                   #  v1= a3a0
    465 #ifdef MIPS32REVGE6
    466     mulu      v0, a2, a0                   #  v0= a2a0
    467     muhu      t1, a2, a0
    468 #else
    469     multu     a2, a0
    470     mfhi      t1
    471     mflo      v0                           #  v0= a2a0
    472  #endif
    473     mul       t2, a2, a1                   #  t2= a2a1
    474     addu      v1, v1, t1                   #  v1= a3a0 + hi(a2a0)
    475     addu      v1, v1, t2                   #  v1= v1 + a2a1;
    476 
    477     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    478     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
    479     SET_VREG64_GOTO(v0, v1, rOBJ, t1)      #  vA/vA+1 <- v0(low)/v1(high)
    480 
    481 %def op_neg_int():
    482 %  unop(instr="negu a0, a0")
    483 
    484 %def op_neg_long():
    485 %  unopWide(result0="v0", result1="v1", preinstr="negu v0, a0", instr="negu v1, a1; sltu a0, zero, v0; subu v1, v1, a0")
    486 
    487 %def op_not_int():
    488 %  unop(instr="not a0, a0")
    489 
    490 %def op_not_long():
    491 %  unopWide(preinstr="not a0, a0", instr="not a1, a1")
    492 
    493 %def op_or_int():
    494 %  binop(instr="or a0, a0, a1")
    495 
    496 %def op_or_int_2addr():
    497 %  binop2addr(instr="or a0, a0, a1")
    498 
    499 %def op_or_int_lit16():
    500 %  binopLit16(instr="or a0, a0, a1")
    501 
    502 %def op_or_int_lit8():
    503 %  binopLit8(instr="or a0, a0, a1")
    504 
    505 %def op_or_long():
    506 %  binopWide(preinstr="or a0, a0, a2", instr="or a1, a1, a3")
    507 
    508 %def op_or_long_2addr():
    509 %  binopWide2addr(preinstr="or a0, a0, a2", instr="or a1, a1, a3")
    510 
    511 %def op_rem_int():
    512 #ifdef MIPS32REVGE6
    513 %  binop(instr="mod a0, a0, a1", chkzero="1")
    514 #else
    515 %  binop(preinstr="div zero, a0, a1", instr="mfhi a0", chkzero="1")
    516 #endif
    517 
    518 %def op_rem_int_2addr():
    519 #ifdef MIPS32REVGE6
    520 %  binop2addr(instr="mod a0, a0, a1", chkzero="1")
    521 #else
    522 %  binop2addr(preinstr="div zero, a0, a1", instr="mfhi a0", chkzero="1")
    523 #endif
    524 
    525 %def op_rem_int_lit16():
    526 #ifdef MIPS32REVGE6
    527 %  binopLit16(instr="mod a0, a0, a1", chkzero="1")
    528 #else
    529 %  binopLit16(preinstr="div zero, a0, a1", instr="mfhi a0", chkzero="1")
    530 #endif
    531 
    532 %def op_rem_int_lit8():
    533 #ifdef MIPS32REVGE6
    534 %  binopLit8(instr="mod a0, a0, a1", chkzero="1")
    535 #else
    536 %  binopLit8(preinstr="div zero, a0, a1", instr="mfhi a0", chkzero="1")
    537 #endif
    538 
    539 %def op_rem_long():
    540 %  binopWide(result0="v0", result1="v1", instr="JAL(__moddi3)", chkzero="1")
    541 
    542 %def op_rem_long_2addr():
    543 %  binopWide2addr(result0="v0", result1="v1", instr="JAL(__moddi3)", chkzero="1")
    544 
    545 %def op_rsub_int():
    546 /* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
    547 %  binopLit16(instr="subu a0, a1, a0")
    548 
    549 %def op_rsub_int_lit8():
    550 %  binopLit8(instr="subu a0, a1, a0")
    551 
    552 %def op_shl_int():
    553 %  binop(instr="sll a0, a0, a1")
    554 
    555 %def op_shl_int_2addr():
    556 %  binop2addr(instr="sll a0, a0, a1")
    557 
    558 %def op_shl_int_lit8():
    559 %  binopLit8(instr="sll a0, a0, a1")
    560 
    561 %def op_shl_long():
    562     /*
    563      * Long integer shift.  This is different from the generic 32/64-bit
    564      * binary operations because vAA/vBB are 64-bit but vCC (the shift
    565      * distance) is 32-bit.  Also, Dalvik requires us to mask off the low
    566      * 6 bits of the shift distance.
    567      */
    568     /* shl-long vAA, vBB, vCC */
    569     FETCH(a0, 1)                           #  a0 <- CCBB
    570     GET_OPA(t2)                            #  t2 <- AA
    571     and       a3, a0, 255                  #  a3 <- BB
    572     srl       a0, a0, 8                    #  a0 <- CC
    573     EAS2(a3, rFP, a3)                      #  a3 <- &fp[BB]
    574     GET_VREG(a2, a0)                       #  a2 <- vCC
    575     LOAD64(a0, a1, a3)                     #  a0/a1 <- vBB/vBB+1
    576 
    577     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    578     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    579 
    580     andi    v1, a2, 0x20                   #  shift< shift & 0x20
    581     sll     v0, a0, a2                     #  rlo<- alo << (shift&31)
    582     bnez    v1, .L${opcode}_finish
    583     not     v1, a2                         #  rhi<- 31-shift  (shift is 5b)
    584     srl     a0, 1
    585     srl     a0, v1                         #  alo<- alo >> (32-(shift&31))
    586     sll     v1, a1, a2                     #  rhi<- ahi << (shift&31)
    587     or      v1, a0                         #  rhi<- rhi | alo
    588     SET_VREG64_GOTO(v0, v1, t2, t0)        #  vAA/vAA+1 <- v0/v1
    589 %def op_shl_long_helper_code():
    590 
    591 .Lop_shl_long_finish:
    592     SET_VREG64_GOTO(zero, v0, t2, t0)      #  vAA/vAA+1 <- rlo/rhi
    593 
    594 %def op_shl_long_2addr():
    595     /*
    596      * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
    597      * 32-bit shift distance.
    598      */
    599     /* shl-long/2addr vA, vB */
    600     GET_OPA4(rOBJ)                         #  rOBJ <- A+
    601     GET_OPB(a3)                            #  a3 <- B
    602     GET_VREG(a2, a3)                       #  a2 <- vB
    603     EAS2(t2, rFP, rOBJ)                    #  t2 <- &fp[A]
    604     LOAD64(a0, a1, t2)                     #  a0/a1 <- vA/vA+1
    605 
    606     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    607     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    608 
    609     andi    v1, a2, 0x20                   #  shift< shift & 0x20
    610     sll     v0, a0, a2                     #  rlo<- alo << (shift&31)
    611     bnez    v1, .L${opcode}_finish
    612     not     v1, a2                         #  rhi<- 31-shift  (shift is 5b)
    613     srl     a0, 1
    614     srl     a0, v1                         #  alo<- alo >> (32-(shift&31))
    615     sll     v1, a1, a2                     #  rhi<- ahi << (shift&31)
    616     or      v1, a0                         #  rhi<- rhi | alo
    617     SET_VREG64_GOTO(v0, v1, rOBJ, t0)      #  vA/vA+1 <- v0/v1
    618 %def op_shl_long_2addr_helper_code():
    619 
    620 .Lop_shl_long_2addr_finish:
    621     SET_VREG64_GOTO(zero, v0, rOBJ, t0)    #  vA/vA+1 <- rlo/rhi
    622 
    623 %def op_shr_int():
    624 %  binop(instr="sra a0, a0, a1")
    625 
    626 %def op_shr_int_2addr():
    627 %  binop2addr(instr="sra a0, a0, a1")
    628 
    629 %def op_shr_int_lit8():
    630 %  binopLit8(instr="sra a0, a0, a1")
    631 
    632 %def op_shr_long():
    633     /*
    634      * Long integer shift.  This is different from the generic 32/64-bit
    635      * binary operations because vAA/vBB are 64-bit but vCC (the shift
    636      * distance) is 32-bit.  Also, Dalvik requires us to mask off the low
    637      * 6 bits of the shift distance.
    638      */
    639     /* shr-long vAA, vBB, vCC */
    640     FETCH(a0, 1)                           #  a0 <- CCBB
    641     GET_OPA(t3)                            #  t3 <- AA
    642     and       a3, a0, 255                  #  a3 <- BB
    643     srl       a0, a0, 8                    #  a0 <- CC
    644     EAS2(a3, rFP, a3)                      #  a3 <- &fp[BB]
    645     GET_VREG(a2, a0)                       #  a2 <- vCC
    646     LOAD64(a0, a1, a3)                     #  a0/a1 <- vBB/vBB+1
    647     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    648     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    649 
    650     andi    v0, a2, 0x20                   #  shift & 0x20
    651     sra     v1, a1, a2                     #  rhi<- ahi >> (shift&31)
    652     bnez    v0, .L${opcode}_finish
    653     srl     v0, a0, a2                     #  rlo<- alo >> (shift&31)
    654     not     a0, a2                         #  alo<- 31-shift (shift is 5b)
    655     sll     a1, 1
    656     sll     a1, a0                         #  ahi<- ahi << (32-(shift&31))
    657     or      v0, a1                         #  rlo<- rlo | ahi
    658     SET_VREG64_GOTO(v0, v1, t3, t0)        #  vAA/VAA+1 <- v0/v1
    659 %def op_shr_long_helper_code():
    660 
    661 .Lop_shr_long_finish:
    662     sra     a3, a1, 31                     #  a3<- sign(ah)
    663     SET_VREG64_GOTO(v1, a3, t3, t0)        #  vAA/VAA+1 <- rlo/rhi
    664 
    665 %def op_shr_long_2addr():
    666     /*
    667      * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
    668      * 32-bit shift distance.
    669      */
    670     /* shr-long/2addr vA, vB */
    671     GET_OPA4(t2)                           #  t2 <- A+
    672     GET_OPB(a3)                            #  a3 <- B
    673     GET_VREG(a2, a3)                       #  a2 <- vB
    674     EAS2(t0, rFP, t2)                      #  t0 <- &fp[A]
    675     LOAD64(a0, a1, t0)                     #  a0/a1 <- vA/vA+1
    676     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    677     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    678 
    679     andi    v0, a2, 0x20                   #  shift & 0x20
    680     sra     v1, a1, a2                     #  rhi<- ahi >> (shift&31)
    681     bnez    v0, .L${opcode}_finish
    682     srl     v0, a0, a2                     #  rlo<- alo >> (shift&31)
    683     not     a0, a2                         #  alo<- 31-shift (shift is 5b)
    684     sll     a1, 1
    685     sll     a1, a0                         #  ahi<- ahi << (32-(shift&31))
    686     or      v0, a1                         #  rlo<- rlo | ahi
    687     SET_VREG64_GOTO(v0, v1, t2, t0)        #  vA/vA+1 <- v0/v1
    688 %def op_shr_long_2addr_helper_code():
    689 
    690 .Lop_shr_long_2addr_finish:
    691     sra     a3, a1, 31                     #  a3<- sign(ah)
    692     SET_VREG64_GOTO(v1, a3, t2, t0)        #  vA/vA+1 <- rlo/rhi
    693 
    694 %def op_sub_int():
    695 %  binop(instr="subu a0, a0, a1")
    696 
    697 %def op_sub_int_2addr():
    698 %  binop2addr(instr="subu a0, a0, a1")
    699 
    700 %def op_sub_long():
    701 /*
    702  * For little endian the code sequence looks as follows:
    703  *    subu    v0,a0,a2
    704  *    subu    v1,a1,a3
    705  *    sltu    a0,a0,v0
    706  *    subu    v1,v1,a0
    707  */
    708 %  binopWide(result0="v0", result1="v1", preinstr="subu v0, a0, a2", instr="subu v1, a1, a3; sltu a0, a0, v0; subu v1, v1, a0")
    709 
    710 %def op_sub_long_2addr():
    711 /*
    712  * See op_sub_long.S for more details
    713  */
    714 %  binopWide2addr(result0="v0", result1="v1", preinstr="subu v0, a0, a2", instr="subu v1, a1, a3; sltu a0, a0, v0; subu v1, v1, a0")
    715 
    716 %def op_ushr_int():
    717 %  binop(instr="srl a0, a0, a1")
    718 
    719 %def op_ushr_int_2addr():
    720 %  binop2addr(instr="srl a0, a0, a1 ")
    721 
    722 %def op_ushr_int_lit8():
    723 %  binopLit8(instr="srl a0, a0, a1")
    724 
    725 %def op_ushr_long():
    726     /*
    727      * Long integer shift.  This is different from the generic 32/64-bit
    728      * binary operations because vAA/vBB are 64-bit but vCC (the shift
    729      * distance) is 32-bit.  Also, Dalvik requires us to mask off the low
    730      * 6 bits of the shift distance.
    731      */
    732     /* ushr-long vAA, vBB, vCC */
    733     FETCH(a0, 1)                           #  a0 <- CCBB
    734     GET_OPA(rOBJ)                          #  rOBJ <- AA
    735     and       a3, a0, 255                  #  a3 <- BB
    736     srl       a0, a0, 8                    #  a0 <- CC
    737     EAS2(a3, rFP, a3)                      #  a3 <- &fp[BB]
    738     GET_VREG(a2, a0)                       #  a2 <- vCC
    739     LOAD64(a0, a1, a3)                     #  a0/a1 <- vBB/vBB+1
    740 
    741     FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
    742     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    743 
    744     andi      v0, a2, 0x20                 #  shift & 0x20
    745     srl       v1, a1, a2                   #  rhi<- ahi >> (shift&31)
    746     bnez      v0, .L${opcode}_finish
    747     srl       v0, a0, a2                   #  rlo<- alo >> (shift&31)
    748     not       a0, a2                       #  alo<- 31-n  (shift is 5b)
    749     sll       a1, 1
    750     sll       a1, a0                       #  ahi<- ahi << (32-(shift&31))
    751     or        v0, a1                       #  rlo<- rlo | ahi
    752     SET_VREG64_GOTO(v0, v1, rOBJ, t0)      #  vAA/vAA+1 <- v0/v1
    753 %def op_ushr_long_helper_code():
    754 
    755 .Lop_ushr_long_finish:
    756     SET_VREG64_GOTO(v1, zero, rOBJ, t0)    #  vAA/vAA+1 <- rlo/rhi
    757 
    758 %def op_ushr_long_2addr():
    759     /*
    760      * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
    761      * 32-bit shift distance.
    762      */
    763     /* ushr-long/2addr vA, vB */
    764     GET_OPA4(t3)                           #  t3 <- A+
    765     GET_OPB(a3)                            #  a3 <- B
    766     GET_VREG(a2, a3)                       #  a2 <- vB
    767     EAS2(t0, rFP, t3)                      #  t0 <- &fp[A]
    768     LOAD64(a0, a1, t0)                     #  a0/a1 <- vA/vA+1
    769 
    770     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
    771     GET_INST_OPCODE(t0)                    #  extract opcode from rINST
    772 
    773     andi      v0, a2, 0x20                 #  shift & 0x20
    774     srl       v1, a1, a2                   #  rhi<- ahi >> (shift&31)
    775     bnez      v0, .L${opcode}_finish
    776     srl       v0, a0, a2                   #  rlo<- alo >> (shift&31)
    777     not       a0, a2                       #  alo<- 31-n  (shift is 5b)
    778     sll       a1, 1
    779     sll       a1, a0                       #  ahi<- ahi << (32-(shift&31))
    780     or        v0, a1                       #  rlo<- rlo | ahi
    781     SET_VREG64_GOTO(v0, v1, t3, t0)        #  vA/vA+1 <- v0/v1
    782 %def op_ushr_long_2addr_helper_code():
    783 
    784 .Lop_ushr_long_2addr_finish:
    785     SET_VREG64_GOTO(v1, zero, t3, t0)      #  vA/vA+1 <- rlo/rhi
    786 
    787 %def op_xor_int():
    788 %  binop(instr="xor a0, a0, a1")
    789 
    790 %def op_xor_int_2addr():
    791 %  binop2addr(instr="xor a0, a0, a1")
    792 
    793 %def op_xor_int_lit16():
    794 %  binopLit16(instr="xor a0, a0, a1")
    795 
    796 %def op_xor_int_lit8():
    797 %  binopLit8(instr="xor a0, a0, a1")
    798 
    799 %def op_xor_long():
    800 %  binopWide(preinstr="xor a0, a0, a2", instr="xor a1, a1, a3")
    801 
    802 %def op_xor_long_2addr():
    803 %  binopWide2addr(preinstr="xor a0, a0, a2", instr="xor a1, a1, a3")
    804