1%def binop(preinstr="", result="w0", chkzero="0", instr=""): 2 /* 3 * Generic 32-bit binary operation. Provide an "instr" line that 4 * specifies an instruction that performs "result = w0 op w1". 5 * This could be an ARM instruction or a function call. (If the result 6 * comes back in a register other than w0, you can override "result".) 7 * 8 * If "chkzero" is set to 1, we perform a divide-by-zero check on 9 * vCC (w1). Useful for integer division and modulus. Note that we 10 * *don't* check for (INT_MIN / -1) here, because the ARM math lib 11 * handles it 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, add-float, sub-float, 15 * mul-float, div-float, rem-float 16 */ 17 /* binop vAA, vBB, vCC */ 18 FETCH w0, 1 // w0<- CCBB 19 lsr w9, wINST, #8 // w9<- AA 20 lsr w3, w0, #8 // w3<- CC 21 and w2, w0, #255 // w2<- BB 22 GET_VREG w1, w3 // w1<- vCC 23 GET_VREG w0, w2 // w0<- vBB 24 .if $chkzero 25 cbz w1, common_errDivideByZero // is second operand zero? 26 .endif 27 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 28 $preinstr // optional op; may set condition codes 29 $instr // $result<- op, w0-w3 changed 30 GET_INST_OPCODE ip // extract opcode from rINST 31 SET_VREG $result, w9 // vAA<- $result 32 GOTO_OPCODE ip // jump to next instruction 33 /* 11-14 instructions */ 34 35%def binop2addr(preinstr="", result="w0", chkzero="0", instr=""): 36 /* 37 * Generic 32-bit "/2addr" binary operation. Provide an "instr" line 38 * that specifies an instruction that performs "result = w0 op w1". 39 * This could be an ARM instruction or a function call. (If the result 40 * comes back in a register other than w0, you can override "result".) 41 * 42 * If "chkzero" is set to 1, we perform a divide-by-zero check on 43 * vCC (w1). Useful for integer division and modulus. 44 * 45 * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr, 46 * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr, 47 * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr, 48 * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr 49 */ 50 /* binop/2addr vA, vB */ 51 lsr w3, wINST, #12 // w3<- B 52 ubfx w9, wINST, #8, #4 // w9<- A 53 GET_VREG w1, w3 // w1<- vB 54 GET_VREG w0, w9 // w0<- vA 55 .if $chkzero 56 cbz w1, common_errDivideByZero 57 .endif 58 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 59 $preinstr // optional op; may set condition codes 60 $instr // $result<- op, w0-w3 changed 61 GET_INST_OPCODE ip // extract opcode from rINST 62 SET_VREG $result, w9 // vAA<- $result 63 GOTO_OPCODE ip // jump to next instruction 64 /* 10-13 instructions */ 65 66%def binopLit16(preinstr="", result="w0", chkzero="0", instr=""): 67 /* 68 * Generic 32-bit "lit16" binary operation. Provide an "instr" line 69 * that specifies an instruction that performs "result = w0 op w1". 70 * This could be an ARM instruction or a function call. (If the result 71 * comes back in a register other than w0, you can override "result".) 72 * 73 * If "chkzero" is set to 1, we perform a divide-by-zero check on 74 * vCC (w1). Useful for integer division and modulus. 75 * 76 * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16, 77 * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16 78 */ 79 /* binop/lit16 vA, vB, #+CCCC */ 80 FETCH_S w1, 1 // w1<- ssssCCCC (sign-extended) 81 lsr w2, wINST, #12 // w2<- B 82 ubfx w9, wINST, #8, #4 // w9<- A 83 GET_VREG w0, w2 // w0<- vB 84 .if $chkzero 85 cbz w1, common_errDivideByZero 86 .endif 87 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 88 $preinstr 89 $instr // $result<- op, w0-w3 changed 90 GET_INST_OPCODE ip // extract opcode from rINST 91 SET_VREG $result, w9 // vAA<- $result 92 GOTO_OPCODE ip // jump to next instruction 93 /* 10-13 instructions */ 94 95%def binopLit8(extract="asr w1, w3, #8", preinstr="", result="w0", chkzero="0", instr=""): 96 /* 97 * Generic 32-bit "lit8" binary operation. Provide an "instr" line 98 * that specifies an instruction that performs "result = w0 op w1". 99 * This could be an ARM instruction or a function call. (If the result 100 * comes back in a register other than w0, you can override "result".) 101 * 102 * You can override "extract" if the extraction of the literal value 103 * from w3 to w1 is not the default "asr w1, w3, #8". The extraction 104 * can be omitted completely if the shift is embedded in "instr". 105 * 106 * If "chkzero" is set to 1, we perform a divide-by-zero check on 107 * vCC (w1). Useful for integer division and modulus. 108 * 109 * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8, 110 * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8, 111 * shl-int/lit8, shr-int/lit8, ushr-int/lit8 112 */ 113 /* binop/lit8 vAA, vBB, #+CC */ 114 FETCH_S w3, 1 // w3<- ssssCCBB (sign-extended for CC) 115 lsr w9, wINST, #8 // w9<- AA 116 and w2, w3, #255 // w2<- BB 117 GET_VREG w0, w2 // w0<- vBB 118 $extract // optional; typically w1<- ssssssCC (sign extended) 119 .if $chkzero 120 cbz w1, common_errDivideByZero 121 .endif 122 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 123 $preinstr // optional op; may set condition codes 124 $instr // $result<- op, w0-w3 changed 125 GET_INST_OPCODE ip // extract opcode from rINST 126 SET_VREG $result, w9 // vAA<- $result 127 GOTO_OPCODE ip // jump to next instruction 128 /* 10-12 instructions */ 129 130%def binopWide(preinstr="", instr="add x0, x1, x2", result="x0", r1="x1", r2="x2", chkzero="0"): 131 /* 132 * Generic 64-bit binary operation. Provide an "instr" line that 133 * specifies an instruction that performs "result = x1 op x2". 134 * This could be an ARM instruction or a function call. (If the result 135 * comes back in a register other than x0, you can override "result".) 136 * 137 * If "chkzero" is set to 1, we perform a divide-by-zero check on 138 * vCC (w1). Useful for integer division and modulus. 139 * 140 * For: add-long, sub-long, mul-long, div-long, rem-long, and-long, or-long, 141 * xor-long, add-double, sub-double, mul-double, div-double, rem-double 142 */ 143 /* binop vAA, vBB, vCC */ 144 FETCH w0, 1 // w0<- CCBB 145 lsr w4, wINST, #8 // w4<- AA 146 lsr w2, w0, #8 // w2<- CC 147 and w1, w0, #255 // w1<- BB 148 GET_VREG_WIDE $r2, w2 // w2<- vCC 149 GET_VREG_WIDE $r1, w1 // w1<- vBB 150 .if $chkzero 151 cbz $r2, common_errDivideByZero // is second operand zero? 152 .endif 153 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 154 $preinstr 155 $instr // $result<- op, w0-w4 changed 156 GET_INST_OPCODE ip // extract opcode from rINST 157 SET_VREG_WIDE $result, w4 // vAA<- $result 158 GOTO_OPCODE ip // jump to next instruction 159 /* 11-14 instructions */ 160 161%def binopWide2addr(preinstr="", instr="add x0, x0, x1", r0="x0", r1="x1", chkzero="0"): 162 /* 163 * Generic 64-bit "/2addr" binary operation. Provide an "instr" line 164 * that specifies an instruction that performs "x0 = x0 op x1". 165 * This must not be a function call, as we keep w2 live across it. 166 * 167 * If "chkzero" is set to 1, we perform a divide-by-zero check on 168 * vCC (w1). Useful for integer division and modulus. 169 * 170 * For: add-long/2addr, sub-long/2addr, mul-long/2addr, div-long/2addr, 171 * and-long/2addr, or-long/2addr, xor-long/2addr, 172 * shl-long/2addr, shr-long/2addr, ushr-long/2addr, add-double/2addr, 173 * sub-double/2addr, mul-double/2addr, div-double/2addr, rem-double/2addr 174 */ 175 /* binop/2addr vA, vB */ 176 lsr w1, wINST, #12 // w1<- B 177 ubfx w2, wINST, #8, #4 // w2<- A 178 GET_VREG_WIDE $r1, w1 // x1<- vB 179 GET_VREG_WIDE $r0, w2 // x0<- vA 180 .if $chkzero 181 cbz $r1, common_errDivideByZero 182 .endif 183 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 184 $preinstr 185 $instr // result<- op 186 GET_INST_OPCODE ip // extract opcode from rINST 187 SET_VREG_WIDE $r0, w2 // vAA<- result 188 GOTO_OPCODE ip // jump to next instruction 189 /* 10-13 instructions */ 190 191%def shiftWide(opcode="shl"): 192 /* 193 * 64-bit shift operation. 194 * 195 * For: shl-long, shr-long, ushr-long 196 */ 197 /* binop vAA, vBB, vCC */ 198 FETCH w0, 1 // w0<- CCBB 199 lsr w3, wINST, #8 // w3<- AA 200 lsr w2, w0, #8 // w2<- CC 201 GET_VREG w2, w2 // w2<- vCC (shift count) 202 and w1, w0, #255 // w1<- BB 203 GET_VREG_WIDE x1, w1 // x1<- vBB 204 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 205 $opcode x0, x1, x2 // Do the shift. Only low 6 bits of x2 are used. 206 GET_INST_OPCODE ip // extract opcode from rINST 207 SET_VREG_WIDE x0, w3 // vAA<- x0 208 GOTO_OPCODE ip // jump to next instruction 209 /* 11-14 instructions */ 210 211%def shiftWide2addr(opcode="lsl"): 212 /* 213 * Generic 64-bit shift operation. 214 */ 215 /* binop/2addr vA, vB */ 216 lsr w1, wINST, #12 // w1<- B 217 ubfx w2, wINST, #8, #4 // w2<- A 218 GET_VREG w1, w1 // x1<- vB 219 GET_VREG_WIDE x0, w2 // x0<- vA 220 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 221 $opcode x0, x0, x1 // Do the shift. Only low 6 bits of x1 are used. 222 GET_INST_OPCODE ip // extract opcode from rINST 223 SET_VREG_WIDE x0, w2 // vAA<- result 224 GOTO_OPCODE ip // jump to next instruction 225 /* 10-13 instructions */ 226 227%def unop(instr=""): 228 /* 229 * Generic 32-bit unary operation. Provide an "instr" line that 230 * specifies an instruction that performs "result = op w0". 231 * This could be an ARM instruction or a function call. 232 * 233 * for: neg-int, not-int, neg-float, int-to-float, float-to-int, 234 * int-to-byte, int-to-char, int-to-short 235 */ 236 /* unop vA, vB */ 237 lsr w3, wINST, #12 // w3<- B 238 GET_VREG w0, w3 // w0<- vB 239 ubfx w9, wINST, #8, #4 // w9<- A 240 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 241 $instr // w0<- op, w0-w3 changed 242 GET_INST_OPCODE ip // extract opcode from rINST 243 SET_VREG w0, w9 // vAA<- w0 244 GOTO_OPCODE ip // jump to next instruction 245 /* 8-9 instructions */ 246 247%def unopWide(instr="sub x0, xzr, x0"): 248 /* 249 * Generic 64-bit unary operation. Provide an "instr" line that 250 * specifies an instruction that performs "result = op x0". 251 * 252 * For: neg-long, not-long 253 */ 254 /* unop vA, vB */ 255 lsr w3, wINST, #12 // w3<- B 256 ubfx w4, wINST, #8, #4 // w4<- A 257 GET_VREG_WIDE x0, w3 258 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 259 $instr 260 GET_INST_OPCODE ip // extract opcode from wINST 261 SET_VREG_WIDE x0, w4 262 GOTO_OPCODE ip // jump to next instruction 263 /* 10-11 instructions */ 264 265%def op_add_int(): 266% binop(instr="add w0, w0, w1") 267 268%def op_add_int_2addr(): 269% binop2addr(instr="add w0, w0, w1") 270 271%def op_add_int_lit16(): 272% binopLit16(instr="add w0, w0, w1") 273 274%def op_add_int_lit8(): 275% binopLit8(extract="", instr="add w0, w0, w3, asr #8") 276 277%def op_add_long(): 278% binopWide(instr="add x0, x1, x2") 279 280%def op_add_long_2addr(): 281% binopWide2addr(instr="add x0, x0, x1") 282 283%def op_and_int(): 284% binop(instr="and w0, w0, w1") 285 286%def op_and_int_2addr(): 287% binop2addr(instr="and w0, w0, w1") 288 289%def op_and_int_lit16(): 290% binopLit16(instr="and w0, w0, w1") 291 292%def op_and_int_lit8(): 293% binopLit8(extract="", instr="and w0, w0, w3, asr #8") 294 295%def op_and_long(): 296% binopWide(instr="and x0, x1, x2") 297 298%def op_and_long_2addr(): 299% binopWide2addr(instr="and x0, x0, x1") 300 301%def op_cmp_long(): 302 FETCH w0, 1 // w0<- CCBB 303 lsr w4, wINST, #8 // w4<- AA 304 and w2, w0, #255 // w2<- BB 305 lsr w3, w0, #8 // w3<- CC 306 GET_VREG_WIDE x1, w2 307 GET_VREG_WIDE x2, w3 308 cmp x1, x2 309 cset w0, ne 310 cneg w0, w0, lt 311 FETCH_ADVANCE_INST 2 // advance rPC, load wINST 312 SET_VREG w0, w4 313 GET_INST_OPCODE ip // extract opcode from wINST 314 GOTO_OPCODE ip // jump to next instruction 315 316%def op_div_int(): 317% binop(instr="sdiv w0, w0, w1", chkzero="1") 318 319%def op_div_int_2addr(): 320% binop2addr(instr="sdiv w0, w0, w1", chkzero="1") 321 322%def op_div_int_lit16(): 323% binopLit16(instr="sdiv w0, w0, w1", chkzero="1") 324 325%def op_div_int_lit8(): 326% binopLit8(instr="sdiv w0, w0, w1", chkzero="1") 327 328%def op_div_long(): 329% binopWide(instr="sdiv x0, x1, x2", chkzero="1") 330 331%def op_div_long_2addr(): 332% binopWide2addr(instr="sdiv x0, x0, x1", chkzero="1") 333 334%def op_int_to_byte(): 335% unop(instr="sxtb w0, w0") 336 337%def op_int_to_char(): 338% unop(instr="uxth w0, w0") 339 340%def op_int_to_long(): 341 /* int-to-long vA, vB */ 342 lsr w3, wINST, #12 // w3<- B 343 ubfx w4, wINST, #8, #4 // w4<- A 344 GET_VREG_S x0, w3 // x0<- sign_extend(fp[B]) 345 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 346 GET_INST_OPCODE ip // extract opcode from wINST 347 SET_VREG_WIDE x0, w4 // fp[A]<- x0 348 GOTO_OPCODE ip // jump to next instruction 349 350%def op_int_to_short(): 351% unop(instr="sxth w0, w0") 352 353%def op_long_to_int(): 354/* we ignore the high word, making this equivalent to a 32-bit reg move */ 355% op_move() 356 357%def op_mul_int(): 358/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 359% binop(instr="mul w0, w1, w0") 360 361%def op_mul_int_2addr(): 362/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 363% binop2addr(instr="mul w0, w1, w0") 364 365%def op_mul_int_lit16(): 366/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 367% binopLit16(instr="mul w0, w1, w0") 368 369%def op_mul_int_lit8(): 370/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 371% binopLit8(instr="mul w0, w1, w0") 372 373%def op_mul_long(): 374% binopWide(instr="mul x0, x1, x2") 375 376%def op_mul_long_2addr(): 377% binopWide2addr(instr="mul x0, x0, x1") 378 379%def op_neg_int(): 380% unop(instr="sub w0, wzr, w0") 381 382%def op_neg_long(): 383% unopWide(instr="sub x0, xzr, x0") 384 385%def op_not_int(): 386% unop(instr="mvn w0, w0") 387 388%def op_not_long(): 389% unopWide(instr="mvn x0, x0") 390 391%def op_or_int(): 392% binop(instr="orr w0, w0, w1") 393 394%def op_or_int_2addr(): 395% binop2addr(instr="orr w0, w0, w1") 396 397%def op_or_int_lit16(): 398% binopLit16(instr="orr w0, w0, w1") 399 400%def op_or_int_lit8(): 401% binopLit8(extract="", instr="orr w0, w0, w3, asr #8") 402 403%def op_or_long(): 404% binopWide(instr="orr x0, x1, x2") 405 406%def op_or_long_2addr(): 407% binopWide2addr(instr="orr x0, x0, x1") 408 409%def op_rem_int(): 410% binop(preinstr="sdiv w2, w0, w1", instr="msub w0, w2, w1, w0", chkzero="1") 411 412%def op_rem_int_2addr(): 413% binop2addr(preinstr="sdiv w2, w0, w1", instr="msub w0, w2, w1, w0", chkzero="1") 414 415%def op_rem_int_lit16(): 416% binopLit16(preinstr="sdiv w3, w0, w1", instr="msub w0, w3, w1, w0", chkzero="1") 417 418%def op_rem_int_lit8(): 419% binopLit8(preinstr="sdiv w3, w0, w1", instr="msub w0, w3, w1, w0", chkzero="1") 420 421%def op_rem_long(): 422% binopWide(preinstr="sdiv x3, x1, x2", instr="msub x0, x3, x2, x1", chkzero="1") 423 424%def op_rem_long_2addr(): 425% binopWide2addr(preinstr="sdiv x3, x0, x1", instr="msub x0, x3, x1, x0", chkzero="1") 426 427%def op_rsub_int(): 428/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */ 429% binopLit16(instr="sub w0, w1, w0") 430 431%def op_rsub_int_lit8(): 432% binopLit8(instr="sub w0, w1, w0") 433 434%def op_shl_int(): 435% binop(instr="lsl w0, w0, w1") 436 437%def op_shl_int_2addr(): 438% binop2addr(instr="lsl w0, w0, w1") 439 440%def op_shl_int_lit8(): 441% binopLit8(extract="ubfx w1, w3, #8, #5", instr="lsl w0, w0, w1") 442 443%def op_shl_long(): 444% shiftWide(opcode="lsl") 445 446%def op_shl_long_2addr(): 447% shiftWide2addr(opcode="lsl") 448 449%def op_shr_int(): 450% binop(instr="asr w0, w0, w1") 451 452%def op_shr_int_2addr(): 453% binop2addr(instr="asr w0, w0, w1") 454 455%def op_shr_int_lit8(): 456% binopLit8(extract="ubfx w1, w3, #8, #5", instr="asr w0, w0, w1") 457 458%def op_shr_long(): 459% shiftWide(opcode="asr") 460 461%def op_shr_long_2addr(): 462% shiftWide2addr(opcode="asr") 463 464%def op_sub_int(): 465% binop(instr="sub w0, w0, w1") 466 467%def op_sub_int_2addr(): 468% binop2addr(instr="sub w0, w0, w1") 469 470%def op_sub_long(): 471% binopWide(instr="sub x0, x1, x2") 472 473%def op_sub_long_2addr(): 474% binopWide2addr(instr="sub x0, x0, x1") 475 476%def op_ushr_int(): 477% binop(instr="lsr w0, w0, w1") 478 479%def op_ushr_int_2addr(): 480% binop2addr(instr="lsr w0, w0, w1") 481 482%def op_ushr_int_lit8(): 483% binopLit8(extract="ubfx w1, w3, #8, #5", instr="lsr w0, w0, w1") 484 485%def op_ushr_long(): 486% shiftWide(opcode="lsr") 487 488%def op_ushr_long_2addr(): 489% shiftWide2addr(opcode="lsr") 490 491%def op_xor_int(): 492% binop(instr="eor w0, w0, w1") 493 494%def op_xor_int_2addr(): 495% binop2addr(instr="eor w0, w0, w1") 496 497%def op_xor_int_lit16(): 498% binopLit16(instr="eor w0, w0, w1") 499 500%def op_xor_int_lit8(): 501% binopLit8(extract="", instr="eor w0, w0, w3, asr #8") 502 503%def op_xor_long(): 504% binopWide(instr="eor x0, x1, x2") 505 506%def op_xor_long_2addr(): 507% binopWide2addr(instr="eor x0, x0, x1") 508