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