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 LOAD_SCALED_VREG_MASK w5, 0xff // w5<- ff * sizeof(vreg) 146 EXTRACT_SCALED_VREG w4, w5, wINST, 8 // w4<- AA * sizeof(vreg) 147 EXTRACT_SCALED_VREG w2, w5, w0, 8 // w2<- CC * sizeof(vreg) 148 EXTRACT_SCALED_VREG w1, w5, w0, 0 // w1<- BB * sizeof(vreg) 149 GET_VREG_WIDE_PRESCALED $r2, w2 // w2<- vCC 150 GET_VREG_WIDE_PRESCALED $r1, w1 // w1<- vBB 151 .if $chkzero 152 cbz $r2, common_errDivideByZero // is second operand zero? 153 .endif 154 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 155 $preinstr 156 $instr // $result<- op, w0-w4 changed 157 GET_INST_OPCODE ip // extract opcode from rINST 158 SET_VREG_WIDE_PRESCALED $result, w4 // vAA<- $result 159 GOTO_OPCODE ip // jump to next instruction 160 /* 11-14 instructions */ 161 162%def binopWide2addr(preinstr="", instr="add x0, x0, x1", r0="x0", r1="x1", chkzero="0"): 163 /* 164 * Generic 64-bit "/2addr" binary operation. Provide an "instr" line 165 * that specifies an instruction that performs "x0 = x0 op x1". 166 * This must not be a function call, as we keep w2 live across it. 167 * 168 * If "chkzero" is set to 1, we perform a divide-by-zero check on 169 * vCC (w1). Useful for integer division and modulus. 170 * 171 * For: add-long/2addr, sub-long/2addr, mul-long/2addr, div-long/2addr, 172 * and-long/2addr, or-long/2addr, xor-long/2addr, 173 * shl-long/2addr, shr-long/2addr, ushr-long/2addr, add-double/2addr, 174 * sub-double/2addr, mul-double/2addr, div-double/2addr, rem-double/2addr 175 */ 176 /* binop/2addr vA, vB */ 177 lsr w1, wINST, #12 // w1<- B 178 ubfx w2, wINST, #8, #4 // w2<- A 179 GET_VREG_WIDE $r1, w1 // x1<- vB 180 GET_VREG_WIDE $r0, w2 // x0<- vA 181 .if $chkzero 182 cbz $r1, common_errDivideByZero 183 .endif 184 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 185 $preinstr 186 $instr // result<- op 187 GET_INST_OPCODE ip // extract opcode from rINST 188 SET_VREG_WIDE $r0, w2 // vAA<- result 189 GOTO_OPCODE ip // jump to next instruction 190 /* 10-13 instructions */ 191 192%def shiftWide(opcode="shl"): 193 /* 194 * 64-bit shift operation. 195 * 196 * For: shl-long, shr-long, ushr-long 197 */ 198 /* binop vAA, vBB, vCC */ 199 FETCH w0, 1 // w0<- CCBB 200 lsr w3, wINST, #8 // w3<- AA 201 lsr w2, w0, #8 // w2<- CC 202 GET_VREG w2, w2 // w2<- vCC (shift count) 203 and w1, w0, #255 // w1<- BB 204 GET_VREG_WIDE x1, w1 // x1<- vBB 205 FETCH_ADVANCE_INST 2 // advance rPC, load rINST 206 $opcode x0, x1, x2 // Do the shift. Only low 6 bits of x2 are used. 207 GET_INST_OPCODE ip // extract opcode from rINST 208 SET_VREG_WIDE x0, w3 // vAA<- x0 209 GOTO_OPCODE ip // jump to next instruction 210 /* 11-14 instructions */ 211 212%def shiftWide2addr(opcode="lsl"): 213 /* 214 * Generic 64-bit shift operation. 215 */ 216 /* binop/2addr vA, vB */ 217 lsr w1, wINST, #12 // w1<- B 218 ubfx w2, wINST, #8, #4 // w2<- A 219 GET_VREG w1, w1 // x1<- vB 220 GET_VREG_WIDE x0, w2 // x0<- vA 221 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 222 $opcode x0, x0, x1 // Do the shift. Only low 6 bits of x1 are used. 223 GET_INST_OPCODE ip // extract opcode from rINST 224 SET_VREG_WIDE x0, w2 // vAA<- result 225 GOTO_OPCODE ip // jump to next instruction 226 /* 10-13 instructions */ 227 228%def unop(instr=""): 229 /* 230 * Generic 32-bit unary operation. Provide an "instr" line that 231 * specifies an instruction that performs "result = op w0". 232 * This could be an ARM instruction or a function call. 233 * 234 * for: neg-int, not-int, neg-float, int-to-float, float-to-int, 235 * int-to-byte, int-to-char, int-to-short 236 */ 237 /* unop vA, vB */ 238 lsr w3, wINST, #12 // w3<- B 239 GET_VREG w0, w3 // w0<- vB 240 ubfx w9, wINST, #8, #4 // w9<- A 241 FETCH_ADVANCE_INST 1 // advance rPC, load rINST 242 $instr // w0<- op, w0-w3 changed 243 GET_INST_OPCODE ip // extract opcode from rINST 244 SET_VREG w0, w9 // vAA<- w0 245 GOTO_OPCODE ip // jump to next instruction 246 /* 8-9 instructions */ 247 248%def unopWide(instr="sub x0, xzr, x0"): 249 /* 250 * Generic 64-bit unary operation. Provide an "instr" line that 251 * specifies an instruction that performs "result = op x0". 252 * 253 * For: neg-long, not-long 254 */ 255 /* unop vA, vB */ 256 lsr w3, wINST, #12 // w3<- B 257 ubfx w4, wINST, #8, #4 // w4<- A 258 GET_VREG_WIDE x0, w3 259 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 260 $instr 261 GET_INST_OPCODE ip // extract opcode from wINST 262 SET_VREG_WIDE x0, w4 263 GOTO_OPCODE ip // jump to next instruction 264 /* 10-11 instructions */ 265 266%def op_add_int(): 267% binop(instr="add w0, w0, w1") 268 269%def op_add_int_2addr(): 270% binop2addr(instr="add w0, w0, w1") 271 272%def op_add_int_lit16(): 273% binopLit16(instr="add w0, w0, w1") 274 275%def op_add_int_lit8(): 276% binopLit8(extract="", instr="add w0, w0, w3, asr #8") 277 278%def op_add_long(): 279% binopWide(instr="add x0, x1, x2") 280 281%def op_add_long_2addr(): 282% binopWide2addr(instr="add x0, x0, x1") 283 284%def op_and_int(): 285% binop(instr="and w0, w0, w1") 286 287%def op_and_int_2addr(): 288% binop2addr(instr="and w0, w0, w1") 289 290%def op_and_int_lit16(): 291% binopLit16(instr="and w0, w0, w1") 292 293%def op_and_int_lit8(): 294% binopLit8(extract="", instr="and w0, w0, w3, asr #8") 295 296%def op_and_long(): 297% binopWide(instr="and x0, x1, x2") 298 299%def op_and_long_2addr(): 300% binopWide2addr(instr="and x0, x0, x1") 301 302%def op_cmp_long(): 303 FETCH w0, 1 // w0<- CCBB 304 LOAD_SCALED_VREG_MASK w5, 0xff // w4<- ff * sizeof(vreg) 305 lsr w4, wINST, #8 // w4<- AA 306 EXTRACT_SCALED_VREG w2, w5, w0, 0 // w2<- BB * sizeof(vreg) 307 EXTRACT_SCALED_VREG w3, w5, w0, 8 // w3<- CC * sizeof(vreg) 308 GET_VREG_WIDE_PRESCALED x1, w2 309 GET_VREG_WIDE_PRESCALED x2, w3 310 cmp x1, x2 311 cset w0, ne 312 cneg w0, w0, lt 313 FETCH_ADVANCE_INST 2 // advance rPC, load wINST 314 SET_VREG w0, w4 315 GET_INST_OPCODE ip // extract opcode from wINST 316 GOTO_OPCODE ip // jump to next instruction 317 318%def op_div_int(): 319% binop(instr="sdiv w0, w0, w1", chkzero="1") 320 321%def op_div_int_2addr(): 322% binop2addr(instr="sdiv w0, w0, w1", chkzero="1") 323 324%def op_div_int_lit16(): 325% binopLit16(instr="sdiv w0, w0, w1", chkzero="1") 326 327%def op_div_int_lit8(): 328% binopLit8(instr="sdiv w0, w0, w1", chkzero="1") 329 330%def op_div_long(): 331% binopWide(instr="sdiv x0, x1, x2", chkzero="1") 332 333%def op_div_long_2addr(): 334% binopWide2addr(instr="sdiv x0, x0, x1", chkzero="1") 335 336%def op_int_to_byte(): 337% unop(instr="sxtb w0, w0") 338 339%def op_int_to_char(): 340% unop(instr="uxth w0, w0") 341 342%def op_int_to_long(): 343 /* int-to-long vA, vB */ 344 lsr w3, wINST, #12 // w3<- B 345 ubfx w4, wINST, #8, #4 // w4<- A 346 GET_VREG_S x0, w3 // x0<- sign_extend(fp[B]) 347 FETCH_ADVANCE_INST 1 // advance rPC, load wINST 348 GET_INST_OPCODE ip // extract opcode from wINST 349 SET_VREG_WIDE x0, w4 // fp[A]<- x0 350 GOTO_OPCODE ip // jump to next instruction 351 352%def op_int_to_short(): 353% unop(instr="sxth w0, w0") 354 355%def op_long_to_int(): 356/* we ignore the high word, making this equivalent to a 32-bit reg move */ 357% op_move() 358 359%def op_mul_int(): 360/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 361% binop(instr="mul w0, w1, w0") 362 363%def op_mul_int_2addr(): 364/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 365% binop2addr(instr="mul w0, w1, w0") 366 367%def op_mul_int_lit16(): 368/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 369% binopLit16(instr="mul w0, w1, w0") 370 371%def op_mul_int_lit8(): 372/* must be "mul w0, w1, w0" -- "w0, w0, w1" is illegal */ 373% binopLit8(instr="mul w0, w1, w0") 374 375%def op_mul_long(): 376% binopWide(instr="mul x0, x1, x2") 377 378%def op_mul_long_2addr(): 379% binopWide2addr(instr="mul x0, x0, x1") 380 381%def op_neg_int(): 382% unop(instr="sub w0, wzr, w0") 383 384%def op_neg_long(): 385% unopWide(instr="sub x0, xzr, x0") 386 387%def op_not_int(): 388% unop(instr="mvn w0, w0") 389 390%def op_not_long(): 391% unopWide(instr="mvn x0, x0") 392 393%def op_or_int(): 394% binop(instr="orr w0, w0, w1") 395 396%def op_or_int_2addr(): 397% binop2addr(instr="orr w0, w0, w1") 398 399%def op_or_int_lit16(): 400% binopLit16(instr="orr w0, w0, w1") 401 402%def op_or_int_lit8(): 403% binopLit8(extract="", instr="orr w0, w0, w3, asr #8") 404 405%def op_or_long(): 406% binopWide(instr="orr x0, x1, x2") 407 408%def op_or_long_2addr(): 409% binopWide2addr(instr="orr x0, x0, x1") 410 411%def op_rem_int(): 412% binop(preinstr="sdiv w2, w0, w1", instr="msub w0, w2, w1, w0", chkzero="1") 413 414%def op_rem_int_2addr(): 415% binop2addr(preinstr="sdiv w2, w0, w1", instr="msub w0, w2, w1, w0", chkzero="1") 416 417%def op_rem_int_lit16(): 418% binopLit16(preinstr="sdiv w3, w0, w1", instr="msub w0, w3, w1, w0", chkzero="1") 419 420%def op_rem_int_lit8(): 421% binopLit8(preinstr="sdiv w3, w0, w1", instr="msub w0, w3, w1, w0", chkzero="1") 422 423%def op_rem_long(): 424% binopWide(preinstr="sdiv x3, x1, x2", instr="msub x0, x3, x2, x1", chkzero="1") 425 426%def op_rem_long_2addr(): 427% binopWide2addr(preinstr="sdiv x3, x0, x1", instr="msub x0, x3, x1, x0", chkzero="1") 428 429%def op_rsub_int(): 430/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */ 431% binopLit16(instr="sub w0, w1, w0") 432 433%def op_rsub_int_lit8(): 434% binopLit8(instr="sub w0, w1, w0") 435 436%def op_shl_int(): 437% binop(instr="lsl w0, w0, w1") 438 439%def op_shl_int_2addr(): 440% binop2addr(instr="lsl w0, w0, w1") 441 442%def op_shl_int_lit8(): 443% binopLit8(extract="ubfx w1, w3, #8, #5", instr="lsl w0, w0, w1") 444 445%def op_shl_long(): 446% shiftWide(opcode="lsl") 447 448%def op_shl_long_2addr(): 449% shiftWide2addr(opcode="lsl") 450 451%def op_shr_int(): 452% binop(instr="asr w0, w0, w1") 453 454%def op_shr_int_2addr(): 455% binop2addr(instr="asr w0, w0, w1") 456 457%def op_shr_int_lit8(): 458% binopLit8(extract="ubfx w1, w3, #8, #5", instr="asr w0, w0, w1") 459 460%def op_shr_long(): 461% shiftWide(opcode="asr") 462 463%def op_shr_long_2addr(): 464% shiftWide2addr(opcode="asr") 465 466%def op_sub_int(): 467% binop(instr="sub w0, w0, w1") 468 469%def op_sub_int_2addr(): 470% binop2addr(instr="sub w0, w0, w1") 471 472%def op_sub_long(): 473% binopWide(instr="sub x0, x1, x2") 474 475%def op_sub_long_2addr(): 476% binopWide2addr(instr="sub x0, x0, x1") 477 478%def op_ushr_int(): 479% binop(instr="lsr w0, w0, w1") 480 481%def op_ushr_int_2addr(): 482% binop2addr(instr="lsr w0, w0, w1") 483 484%def op_ushr_int_lit8(): 485% binopLit8(extract="ubfx w1, w3, #8, #5", instr="lsr w0, w0, w1") 486 487%def op_ushr_long(): 488% shiftWide(opcode="lsr") 489 490%def op_ushr_long_2addr(): 491% shiftWide2addr(opcode="lsr") 492 493%def op_xor_int(): 494% binop(instr="eor w0, w0, w1") 495 496%def op_xor_int_2addr(): 497% binop2addr(instr="eor w0, w0, w1") 498 499%def op_xor_int_lit16(): 500% binopLit16(instr="eor w0, w0, w1") 501 502%def op_xor_int_lit8(): 503% binopLit8(extract="", instr="eor w0, w0, w3, asr #8") 504 505%def op_xor_long(): 506% binopWide(instr="eor x0, x1, x2") 507 508%def op_xor_long_2addr(): 509% binopWide2addr(instr="eor x0, x0, x1") 510