github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-rules-arm.ins (about) 1 /* 2 * jit-rules-arm.ins - Instruction selector for ARM. 3 * 4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd. 5 * Copyright (C) 2008 Michele Tartara <mikyt@users.sourceforge.net> 6 * 7 * This file is part of the libjit library. 8 * 9 * The libjit library is free software: you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public License 11 * as published by the Free Software Foundation, either version 2.1 of 12 * the License, or (at your option) any later version. 13 * 14 * The libjit library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with the libjit library. If not, see 21 * <http://www.gnu.org/licenses/>. 22 */ 23 24 %inst_type arm_inst_buf 25 26 /* 27 * Register classes 28 */ 29 %regclass reg arm_reg 30 %regclass freg arm_freg 31 %regclass freg32 arm_freg32 32 %regclass freg64 arm_freg64 33 %lregclass lreg arm_lreg 34 35 /* 36 * Conversion opcodes. 37 */ 38 39 JIT_OP_TRUNC_SBYTE: 40 [reg] -> { 41 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 24); 42 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 24); 43 } 44 45 JIT_OP_TRUNC_UBYTE: 46 [reg] -> { 47 arm_alu_reg_imm8(inst, ARM_AND, $1, $1, 0xFF); 48 } 49 50 JIT_OP_TRUNC_SHORT: 51 [reg] -> { 52 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16); 53 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 16); 54 } 55 56 JIT_OP_TRUNC_USHORT: 57 [reg] -> { 58 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16); 59 arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, 16); 60 } 61 62 JIT_OP_INT_TO_NFLOAT: 63 [=freg64, local, scratch freg32] -> { 64 //Load int from a local variable stored in memory 65 arm_load_membase_float(inst, $3, ARM_FP, $2, 0); 66 arm_convert_float_signed_integer_double(inst, $1, $3); 67 } 68 [=freg64, reg, scratch freg32] -> { 69 //The int value is in a register 70 arm_mov_float_reg(inst, $3, $2); 71 arm_convert_float_signed_integer_double(inst, $1, $3) 72 } 73 74 JIT_OP_NFLOAT_TO_FLOAT32: 75 [=freg32, freg64] -> { 76 arm_convert_float_single_double(inst, $1, $2); 77 } 78 79 JIT_OP_NFLOAT_TO_FLOAT64, JIT_OP_FLOAT64_TO_NFLOAT: copy 80 [freg64] -> { 81 /* Nothing to do: float64 and nfloat are the same thing on ARM linux. Just copy the value */ 82 } 83 84 JIT_OP_FLOAT32_TO_NFLOAT: 85 [=freg64, freg32] -> { 86 arm_convert_float_double_single(inst, $1, $2); 87 } 88 89 /* 90 * Arithmetic opcodes. 91 */ 92 93 JIT_OP_IADD: 94 [reg, immu8] -> { 95 arm_alu_reg_imm8(inst, ARM_ADD, $1, $1, $2); 96 } 97 [reg, reg] -> { 98 arm_alu_reg_reg(inst, ARM_ADD, $1, $1, $2); 99 } 100 101 JIT_OP_ISUB: 102 [reg, immu8] -> { 103 arm_alu_reg_imm8(inst, ARM_SUB, $1, $1, $2); 104 } 105 [reg, reg] -> { 106 arm_alu_reg_reg(inst, ARM_SUB, $1, $1, $2); 107 } 108 109 JIT_OP_IMUL: 110 [reg, immu8] -> { 111 /* Handle special cases of immediate multiplies */ 112 switch($2) 113 { 114 case 0: 115 { 116 arm_mov_reg_imm8(inst, $1, 0); 117 } 118 break; 119 120 case 1: break; 121 122 case 2: 123 { 124 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 1); 125 } 126 break; 127 128 case 4: 129 { 130 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 2); 131 } 132 break; 133 134 case 8: 135 { 136 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 3); 137 } 138 break; 139 140 case 16: 141 { 142 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 4); 143 } 144 break; 145 146 case 32: 147 { 148 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 5); 149 } 150 break; 151 152 case 64: 153 { 154 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 6); 155 } 156 break; 157 158 case 128: 159 { 160 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 7); 161 } 162 break; 163 164 default: 165 { 166 arm_mov_reg_imm8(inst, ARM_WORK, $2); 167 arm_mul_reg_reg(inst, $1, $1, ARM_WORK); 168 } 169 break; 170 } 171 } 172 [reg, reg] -> { 173 if($1 != $2) 174 { 175 arm_mul_reg_reg(inst, $1, $1, $2); 176 } 177 else 178 { 179 /* Cannot use the same register for both arguments */ 180 arm_mov_reg_reg(inst, ARM_WORK, $2); 181 arm_mul_reg_reg(inst, $1, $1, ARM_WORK); 182 } 183 } 184 185 JIT_OP_IDIV: 186 [any, immzero] -> { 187 throw_builtin(&inst, func, ARM_CC_AL, JIT_RESULT_DIVISION_BY_ZERO); 188 } 189 [reg, immu8, if("$2 == 1")] -> { 190 /* Division by 1. Return the value itself */ 191 } 192 [reg, immu8, if("($2 > 0) && (((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> { 193 /* Handle special cases of small immediate divides: divisions by positive powers of two */ 194 /* NB: (n & (n-1)) == 0 if and only if n is a power of 2 */ 195 196 /* Move the dividend in the work register, setting the codes (in order to know if it's positive or negative) */ 197 arm_alu_cc_reg(inst, ARM_MOV, ARM_WORK, $1); 198 199 /* If the dividend is negative, make it positive (0-x = -x)*/ 200 arm_alu_reg_imm8_cond(inst, ARM_RSB, $1, ARM_WORK, 0, ARM_CC_MI); 201 202 switch($2) 203 { 204 //Integer divide by shifting 205 case 2: 206 { 207 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 1); 208 } 209 break; 210 211 case 4: 212 { 213 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 2); 214 } 215 break; 216 217 case 8: 218 { 219 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 3); 220 } 221 break; 222 223 case 16: 224 { 225 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 4); 226 } 227 break; 228 229 case 32: 230 { 231 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 5); 232 } 233 break; 234 235 case 64: 236 { 237 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 6); 238 } 239 break; 240 241 case 128: 242 { 243 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 7); 244 } 245 break; 246 } 247 248 /* If the dividend was negative, make it negative again (0-x = -x)*/ 249 arm_alu_reg_imm8_cond(inst, ARM_RSB, $1, $1, 0, ARM_CC_MI); 250 251 } 252 [reg, imm, if("$2 == -1")] -> { 253 /* Dividing by -1 simply negates */ 254 /*TODO: if the value to be divided by -1 is jit_min_int, 255 an exception (JIT_RESULT_ARITHMETIC) should probably be thrown */ 256 arm_alu_reg(inst, ARM_MVN, $1, $1); 257 } 258 [reg, imm, clobber("r0", "r1")] -> { 259 /* Every other immediate division: 260 ARM does not have an integer division operation. It's emulated via software. */ 261 262 //Put the dividend in the right position 263 if ($1 != ARM_R0) 264 arm_mov_reg_reg(inst, ARM_R0, $1); 265 266 //Put the divisor in the right position 267 mov_reg_imm(gen, &inst, ARM_R1, $2); 268 269 //Perform the division by calling a function from the runtime ABI 270 extern int __aeabi_idiv(int numerator, int denominator); 271 arm_call(inst, __aeabi_idiv); 272 273 if($1 != ARM_R0) 274 { 275 //Move the result back where it is expected to be 276 arm_mov_reg_reg(inst, $1, ARM_R0); 277 } 278 279 } 280 [reg, reg, scratch reg, clobber("r0", "r1")] -> { 281 /* Every division taking data from two registers: 282 ARM does not have an integer division operation. It's emulated via software. */ 283 284 int dividend = $1; 285 int divisor = $2; 286 int scratch = $3; 287 288 //Put the dividend in the right position 289 if (dividend != ARM_R0) 290 { 291 if (divisor==ARM_R0) 292 { 293 //Prevent the divisor from being overwritten 294 if(dividend != ARM_R1) 295 { 296 //The place where the divisor should be is free. Move it there 297 arm_mov_reg_reg(inst, ARM_R1, divisor); 298 divisor=1; 299 } 300 else 301 { 302 /* The dividend is where the divisor should be. 303 We must use a scratch register to swap them */ 304 arm_mov_reg_reg(inst, scratch, divisor); 305 divisor=scratch; 306 } 307 308 } 309 310 arm_mov_reg_reg(inst, ARM_R0, dividend); 311 } 312 313 if (divisor != ARM_R1) 314 { 315 //Put the divisor in the right position 316 arm_mov_reg_reg(inst, ARM_R1, divisor); 317 } 318 319 //Perform the division by calling a function from the runtime ABI 320 extern int __aeabi_idiv(int numerator, int denominator); 321 arm_call(inst, __aeabi_idiv); 322 323 //Move the result back where it is expected to be 324 if($1 != ARM_R0) 325 { 326 arm_mov_reg_reg(inst, $1, ARM_R0); 327 } 328 } 329 330 JIT_OP_INEG: 331 [reg] -> { 332 /* -x is the same as (0 - x) */ 333 arm_alu_reg_imm8(inst, ARM_RSB, $1, $1, 0); 334 } 335 336 JIT_OP_LADD: 337 [lreg, lreg] -> { 338 arm_alu_cc_reg_reg(inst, ARM_ADD, $1, $1, $2); 339 arm_alu_reg_reg(inst, ARM_ADC, %1, %1, %2); 340 } 341 342 JIT_OP_LSUB: 343 [lreg, lreg] -> { 344 arm_alu_cc_reg_reg(inst, ARM_SUB, $1, $1, $2); 345 arm_alu_reg_reg(inst, ARM_SBC, %1, %1, %2); 346 } 347 348 JIT_OP_LNEG: 349 [lreg] -> { 350 arm_alu_reg(inst, ARM_MVN, $1, $1); 351 arm_alu_reg(inst, ARM_MVN, %1, %1); 352 arm_alu_cc_reg_imm8(inst, ARM_ADD, $1, $1, 1); 353 arm_alu_reg_imm8(inst, ARM_ADC, %1, %1, 0); 354 } 355 356 JIT_OP_FADD (JIT_ARM_HAS_VFP): 357 [freg32, freg32] -> { 358 arm_alu_freg_freg_32(inst, ARM_FADD, $1, $1, $2); 359 } 360 361 JIT_OP_FADD (JIT_ARM_HAS_FPA): /*binary*/ 362 [freg, freg] -> { 363 arm_alu_freg_freg_32(inst, ARM_ADF, $1, $1, $2); 364 } 365 366 JIT_OP_FSUB (JIT_ARM_HAS_VFP): 367 [freg32, freg32] -> { 368 arm_alu_freg_freg_32(inst, ARM_FSUB, $1, $1, $2); 369 } 370 371 JIT_OP_FSUB (JIT_ARM_HAS_FPA): /*binary*/ 372 [freg, freg] -> { 373 arm_alu_freg_freg_32(inst, ARM_SUF, $1, $1, $2); 374 } 375 376 JIT_OP_FMUL (JIT_ARM_HAS_VFP): 377 [freg32, freg32] -> { 378 arm_alu_freg_freg_32(inst, ARM_FMUL, $1, $1, $2); 379 } 380 381 JIT_OP_FMUL (JIT_ARM_HAS_FPA): /*binary*/ 382 [freg, freg] -> { 383 arm_alu_freg_freg_32(inst, ARM_MUF, $1, $1, $2); 384 } 385 386 JIT_OP_FDIV (JIT_ARM_HAS_VFP): 387 [freg32, freg32] -> { 388 arm_alu_freg_freg_32(inst, ARM_FDIV, $1, $1, $2); 389 } 390 391 JIT_OP_FDIV (JIT_ARM_HAS_FPA): /*binary*/ 392 [freg, freg] -> { 393 arm_alu_freg_freg_32(inst, ARM_DVF, $1, $1, $2); 394 } 395 396 JIT_OP_FNEG (JIT_ARM_HAS_VFP): 397 [freg32] -> { 398 arm_alu_freg_32(inst, ARM_MNF, $1, $1); 399 } 400 401 JIT_OP_FNEG (JIT_ARM_HAS_FPA): /*unary*/ 402 [freg] -> { 403 arm_alu_freg_32(inst, ARM_MNF, $1, $1); 404 } 405 406 JIT_OP_DADD, JIT_OP_NFADD (JIT_ARM_HAS_VFP): 407 [freg64, freg64] -> { 408 arm_alu_freg_freg(inst, ARM_FADD, $1, $1, $2); 409 } 410 411 JIT_OP_DADD, JIT_OP_NFADD (JIT_ARM_HAS_FPA): /*binary*/ 412 [freg, freg] -> { 413 arm_alu_freg_freg(inst, ARM_ADF, $1, $1, $2); 414 } 415 416 JIT_OP_DSUB, JIT_OP_NFSUB (JIT_ARM_HAS_VFP): 417 [freg64, freg64] -> { 418 arm_alu_freg_freg(inst, ARM_FSUB, $1, $1, $2); 419 } 420 421 JIT_OP_DSUB, JIT_OP_NFSUB (JIT_ARM_HAS_FPA): /*binary*/ 422 [freg, freg] -> { 423 arm_alu_freg_freg(inst, ARM_SUF, $1, $1, $2); 424 } 425 426 JIT_OP_DMUL, JIT_OP_NFMUL (JIT_ARM_HAS_VFP): 427 [freg64, freg64] -> { 428 arm_alu_freg_freg(inst, ARM_FMUL, $1, $1, $2); 429 } 430 431 JIT_OP_DMUL, JIT_OP_NFMUL (JIT_ARM_HAS_FPA): /*binary*/ 432 [freg, freg] -> { 433 arm_alu_freg_freg(inst, ARM_MUF, $1, $1, $2); 434 } 435 436 JIT_OP_DDIV, JIT_OP_NFDIV (JIT_ARM_HAS_VFP): 437 [freg64, freg64] -> { 438 arm_alu_freg_freg(inst, ARM_FDIV, $1, $1, $2); 439 } 440 441 JIT_OP_DDIV, JIT_OP_NFDIV (JIT_ARM_HAS_FPA): /*binary*/ 442 [freg, freg] -> { 443 arm_alu_freg_freg(inst, ARM_DVF, $1, $1, $2); 444 } 445 446 JIT_OP_DNEG, JIT_OP_NFNEG (JIT_ARM_HAS_VFP): 447 [freg64] -> { 448 arm_alu_freg(inst, ARM_MNF, $1, $1); 449 } 450 451 JIT_OP_DNEG, JIT_OP_NFNEG (JIT_ARM_HAS_FPA): /*unary*/ 452 [freg] -> { 453 arm_alu_freg(inst, ARM_MNF, $1, $1); 454 } 455 456 /* 457 * Bitwise opcodes. 458 */ 459 460 JIT_OP_IAND: 461 [reg, immu8] -> { 462 arm_alu_reg_imm8(inst, ARM_AND, $1, $1, $2); 463 } 464 [reg, reg] -> { 465 arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2); 466 } 467 468 JIT_OP_IOR: 469 [reg, immu8] -> { 470 arm_alu_reg_imm8(inst, ARM_ORR, $1, $1, $2); 471 } 472 [reg, reg] -> { 473 arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2); 474 } 475 476 JIT_OP_IXOR: 477 [reg, immu8] -> { 478 arm_alu_reg_imm8(inst, ARM_EOR, $1, $1, $2); 479 } 480 [reg, reg] -> { 481 arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2); 482 } 483 484 JIT_OP_INOT: 485 [reg] -> { 486 /* MVN == "move not" */ 487 arm_alu_reg(inst, ARM_MVN, $1, $1); 488 } 489 490 JIT_OP_ISHL: 491 [reg, imm] -> { 492 arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, ($2 & 0x1F)); 493 } 494 [reg, reg] -> { 495 arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F); 496 arm_shift_reg_reg(inst, ARM_SHL, $1, $1, ARM_WORK); 497 } 498 499 JIT_OP_ISHR: 500 [reg, imm] -> { 501 arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, ($2 & 0x1F)); 502 } 503 [reg, reg] -> { 504 arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F); 505 arm_shift_reg_reg(inst, ARM_SAR, $1, $1, ARM_WORK); 506 } 507 508 JIT_OP_ISHR_UN: 509 [reg, imm] -> { 510 arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, ($2 & 0x1F)); 511 } 512 [reg, reg] -> { 513 arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F); 514 arm_shift_reg_reg(inst, ARM_SHR, $1, $1, ARM_WORK); 515 } 516 517 JIT_OP_LAND: 518 [lreg, lreg] -> { 519 arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2); 520 arm_alu_reg_reg(inst, ARM_AND, %1, %1, %2); 521 } 522 523 JIT_OP_LOR: 524 [lreg, lreg] -> { 525 arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2); 526 arm_alu_reg_reg(inst, ARM_ORR, %1, %1, %2); 527 } 528 529 JIT_OP_LXOR: 530 [lreg, lreg] -> { 531 arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2); 532 arm_alu_reg_reg(inst, ARM_EOR, %1, %1, %2); 533 } 534 535 JIT_OP_LNOT: 536 [lreg] -> { 537 arm_alu_reg(inst, ARM_MVN, $1, $1); 538 arm_alu_reg(inst, ARM_MVN, %1, %1); 539 } 540 541 /* 542 * Branch opcodes. 543 */ 544 545 JIT_OP_BR: branch /*spill_before*/ 546 [] -> { 547 /* ARM_CC_AL == "always branch" */ 548 output_branch(func, &inst, ARM_CC_AL, insn); 549 550 /* Flush the constant pool now, to minimize the probability that 551 it is accidentally flushed in the middle of a loop body */ 552 jit_gen_save_inst_ptr(gen, inst); 553 flush_constants(gen, 1); 554 jit_gen_load_inst_ptr(gen, inst); 555 } 556 557 JIT_OP_BR_IFALSE: branch 558 [reg] -> { 559 arm_test_reg_imm8(inst, ARM_CMP, $1, 0); 560 output_branch(func, &inst, ARM_CC_EQ, insn); 561 } 562 563 JIT_OP_BR_ITRUE: branch 564 [reg] -> { 565 arm_test_reg_imm8(inst, ARM_CMP, $1, 0); 566 output_branch(func, &inst, ARM_CC_NE, insn); 567 } 568 569 JIT_OP_BR_IEQ: branch 570 [reg, immu8] -> { 571 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 572 output_branch(func, &inst, ARM_CC_EQ, insn); 573 } 574 [reg, reg] -> { 575 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 576 output_branch(func, &inst, ARM_CC_EQ, insn); 577 } 578 579 JIT_OP_BR_INE: branch 580 [reg, immu8] -> { 581 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 582 output_branch(func, &inst, ARM_CC_NE, insn); 583 } 584 [reg, reg] -> { 585 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 586 output_branch(func, &inst, ARM_CC_NE, insn); 587 } 588 589 JIT_OP_BR_ILT: branch 590 [reg, immu8] -> { 591 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 592 output_branch(func, &inst, ARM_CC_LT, insn); 593 } 594 [reg, reg] -> { 595 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 596 output_branch(func, &inst, ARM_CC_LT, insn); 597 } 598 599 JIT_OP_BR_ILT_UN: branch 600 [reg, immu8] -> { 601 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 602 output_branch(func, &inst, ARM_CC_LT_UN, insn); 603 } 604 [reg, reg] -> { 605 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 606 output_branch(func, &inst, ARM_CC_LT_UN, insn); 607 } 608 609 JIT_OP_BR_ILE: branch 610 [reg, immu8] -> { 611 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 612 output_branch(func, &inst, ARM_CC_LE, insn); 613 } 614 [reg, reg] -> { 615 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 616 output_branch(func, &inst, ARM_CC_LE, insn); 617 } 618 619 JIT_OP_BR_ILE_UN: branch 620 [reg, immu8] -> { 621 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 622 output_branch(func, &inst, ARM_CC_LE_UN, insn); 623 } 624 [reg, reg] -> { 625 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 626 output_branch(func, &inst, ARM_CC_LE_UN, insn); 627 } 628 629 JIT_OP_BR_IGT: branch 630 [reg, immu8] -> { 631 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 632 output_branch(func, &inst, ARM_CC_GT, insn); 633 } 634 [reg, reg] -> { 635 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 636 output_branch(func, &inst, ARM_CC_GT, insn); 637 } 638 639 JIT_OP_BR_IGT_UN: branch 640 [reg, immu8] -> { 641 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 642 output_branch(func, &inst, ARM_CC_GT_UN, insn); 643 } 644 [reg, reg] -> { 645 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 646 output_branch(func, &inst, ARM_CC_GT_UN, insn); 647 } 648 649 JIT_OP_BR_IGE: branch 650 [reg, immu8] -> { 651 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 652 output_branch(func, &inst, ARM_CC_GE, insn); 653 } 654 [reg, reg] -> { 655 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 656 output_branch(func, &inst, ARM_CC_GE, insn); 657 } 658 659 JIT_OP_BR_IGE_UN: branch 660 [reg, immu8] -> { 661 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 662 output_branch(func, &inst, ARM_CC_GE_UN, insn); 663 } 664 [reg, reg] -> { 665 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 666 output_branch(func, &inst, ARM_CC_GE_UN, insn); 667 } 668 669 /* 670 * Comparison opcodes. 671 */ 672 673 JIT_OP_ICMP: 674 [reg, immu8] -> { 675 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 676 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); 677 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); 678 arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT); 679 } 680 [reg, reg] -> { 681 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 682 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); 683 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); 684 arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT); 685 } 686 687 JIT_OP_ICMP_UN: 688 [reg, immu8] -> { 689 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 690 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); 691 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); 692 arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN); 693 } 694 [reg, reg] -> { 695 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 696 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); 697 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); 698 arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN); 699 } 700 701 JIT_OP_IEQ: 702 [reg, immu8] -> { 703 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 704 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ); 705 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE); 706 } 707 [reg, reg] -> { 708 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 709 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ); 710 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE); 711 } 712 713 JIT_OP_INE: 714 [reg, immu8] -> { 715 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 716 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE); 717 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ); 718 } 719 [reg, reg] -> { 720 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 721 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE); 722 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ); 723 } 724 725 JIT_OP_ILT: 726 [reg, immu8] -> { 727 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 728 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT); 729 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE); 730 } 731 [reg, reg] -> { 732 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 733 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT); 734 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE); 735 } 736 737 JIT_OP_ILT_UN: 738 [reg, immu8] -> { 739 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 740 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN); 741 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN); 742 } 743 [reg, reg] -> { 744 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 745 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN); 746 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN); 747 } 748 749 JIT_OP_ILE: 750 [reg, immu8] -> { 751 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 752 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE); 753 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT); 754 } 755 [reg, reg] -> { 756 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 757 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE); 758 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT); 759 } 760 761 JIT_OP_ILE_UN: 762 [reg, immu8] -> { 763 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 764 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN); 765 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN); 766 } 767 [reg, reg] -> { 768 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 769 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN); 770 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN); 771 } 772 773 JIT_OP_IGT: 774 [reg, immu8] -> { 775 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 776 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); 777 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); 778 } 779 [reg, reg] -> { 780 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 781 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); 782 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); 783 } 784 785 JIT_OP_IGT_UN: 786 [reg, immu8] -> { 787 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 788 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); 789 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); 790 } 791 [reg, reg] -> { 792 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 793 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); 794 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); 795 } 796 797 JIT_OP_IGE: 798 [reg, immu8] -> { 799 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 800 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE); 801 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT); 802 } 803 [reg, reg] -> { 804 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 805 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE); 806 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT); 807 } 808 809 JIT_OP_IGE_UN: 810 [reg, immu8] -> { 811 arm_test_reg_imm8(inst, ARM_CMP, $1, $2); 812 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN); 813 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN); 814 } 815 [reg, reg] -> { 816 arm_test_reg_reg(inst, ARM_CMP, $1, $2); 817 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN); 818 arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN); 819 } 820 821 /* 822 * Pointer check opcodes. 823 */ 824 825 JIT_OP_CHECK_NULL: note 826 [reg] -> { 827 arm_test_reg_imm8(inst, ARM_CMP, $1, 0); 828 throw_builtin(&inst, func, ARM_CC_EQ, JIT_RESULT_NULL_REFERENCE); 829 } 830 831 /* 832 * Function calls. 833 */ 834 835 JIT_OP_CALL: 836 [] -> { 837 jit_function_t func = (jit_function_t)(insn->dest); 838 arm_call(inst, jit_function_to_closure(func)); 839 } 840 841 JIT_OP_CALL_TAIL: 842 [] -> { 843 jit_function_t func = (jit_function_t)(insn->dest); 844 arm_pop_frame_tail(inst, 0); 845 arm_jump(inst, jit_function_to_closure(func)); 846 } 847 848 JIT_OP_CALL_INDIRECT: 849 [] -> { 850 arm_mov_reg_reg((inst), ARM_LINK, ARM_PC); 851 arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); 852 } 853 854 JIT_OP_CALL_VTABLE_PTR: 855 [] -> { 856 arm_mov_reg_reg((inst), ARM_LINK, ARM_PC); 857 arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); 858 } 859 860 JIT_OP_CALL_EXTERNAL: 861 [] -> { 862 arm_call(inst, (void *)(insn->dest)); 863 } 864 865 JIT_OP_RETURN: 866 [] -> { 867 jump_to_epilog(gen, &inst, block); 868 } 869 870 JIT_OP_RETURN_INT: /*unary_branch*/ 871 [reg] -> { 872 int cpu_reg = $1; 873 if(cpu_reg != ARM_R0) 874 { 875 arm_mov_reg_reg(inst, ARM_R0, cpu_reg); 876 } 877 jump_to_epilog(gen, &inst, block); 878 } 879 880 JIT_OP_RETURN_LONG: /*unary_branch*/ 881 [imm] -> { 882 mov_reg_imm(gen, &inst, ARM_R0, ((jit_int *)($1))[0]); 883 mov_reg_imm(gen, &inst, ARM_R1, ((jit_int *)($1))[1]); 884 jump_to_epilog(gen, &inst, block); 885 } 886 [local] -> { 887 arm_load_membase(inst, ARM_R0, ARM_FP, $1); 888 arm_load_membase(inst, ARM_R1, ARM_FP, $1 + 4); 889 jump_to_epilog(gen, &inst, block); 890 } 891 [lreg] -> { 892 if($1 != 0) 893 { 894 arm_mov_reg_reg(inst, ARM_R0, $1); 895 arm_mov_reg_reg(inst, ARM_R1, %1); 896 } 897 jump_to_epilog(gen, &inst, block); 898 } 899 900 JIT_OP_RETURN_FLOAT32 (JIT_ARM_HAS_VFP): branch 901 [freg32, clobber("r0")] -> { 902 arm_mov_reg_float(inst, ARM_R0, $1); 903 jump_to_epilog(gen, &inst, block); 904 } 905 906 JIT_OP_RETURN_FLOAT32 (JIT_ARM_HAS_FPA): branch 907 [freg] -> { 908 if($1 != 0) 909 { 910 arm_alu_freg_32(inst, ARM_MVF, ARM_F0, $1); 911 } 912 jump_to_epilog(gen, &inst, block); 913 } 914 915 916 JIT_OP_RETURN_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual 917 [] -> { 918 arm_inst_buf inst; 919 _jit_regs_spill_all(gen); 920 _jit_gen_fix_value(insn->value1); 921 jit_gen_load_inst_ptr(gen, inst); 922 if(insn->value1->is_constant) 923 { 924 mov_reg_imm 925 (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]); 926 } 927 else 928 { 929 arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset); 930 } 931 jump_to_epilog(gen, &inst, block); 932 jit_gen_save_inst_ptr(gen, inst); 933 } 934 935 JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT 936 (JIT_ARM_HAS_VFP): branch 937 [freg64, clobber("r0", "r1")] -> { 938 arm_mov_reg_reg_double(inst,ARM_R0,ARM_R1, $1); 939 jump_to_epilog(gen, &inst, block); 940 } 941 942 JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (JIT_ARM_HAS_FPA): branch 943 [freg] -> { 944 if($1 != 0) 945 { 946 arm_alu_freg(inst, ARM_MVF, ARM_F0, $1); 947 } 948 jump_to_epilog(gen, &inst, block); 949 } 950 951 JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual 952 [] -> { 953 arm_inst_buf inst; 954 _jit_regs_spill_all(gen); 955 _jit_gen_fix_value(insn->value1); 956 jit_gen_load_inst_ptr(gen, inst); 957 if(insn->value1->is_constant) 958 { 959 mov_reg_imm 960 (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]); 961 mov_reg_imm 962 (gen, &inst, ARM_R1, ((int *)(insn->value1->address))[1]); 963 } 964 else 965 { 966 arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset); 967 arm_load_membase(inst, ARM_R1, ARM_FP, 968 insn->value1->frame_offset + 4); 969 } 970 jump_to_epilog(gen, &inst, block); 971 jit_gen_save_inst_ptr(gen, inst); 972 } 973 974 JIT_OP_RETURN_SMALL_STRUCT: note 975 [reg, imm, clobber("r0", "r1")] -> { 976 //$1: address of the struct to be returned 977 //$2: size of the struct to be returned 978 979 //Prevent the accidental overwriting of the address 980 int temp_reg = $1; 981 if(temp_reg < 3) 982 { 983 arm_mov_reg_reg(inst, ARM_WORK, temp_reg); 984 temp_reg = ARM_WORK; 985 } 986 987 //Copy the struct to the return register in a way that's appropriate to its size 988 switch($2) 989 { 990 case 1: 991 arm_load_membase_byte(inst, ARM_R0, temp_reg, 0); 992 break; 993 994 case 2: 995 arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0); 996 break; 997 998 case 3: 999 arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0); 1000 arm_load_membase_byte(inst, ARM_R1, temp_reg, 2); 1001 arm_shift_reg_imm8(inst, ARM_SHL, ARM_R1, ARM_R1, 16); 1002 arm_alu_reg_reg(inst, ARM_ORR, ARM_R0, ARM_R0, ARM_R1); 1003 break; 1004 1005 case 4: 1006 arm_load_membase(inst, ARM_R0, temp_reg, 0); 1007 break; 1008 1009 /*TODO: is this the right way to return a struct > 4 bytes? 1010 * Or should it be returned by address? Look at the Procedure Call Standard! 1011 */ 1012 1013 case 5: 1014 arm_load_membase(inst, ARM_R0, temp_reg, 0); 1015 arm_load_membase_byte(inst, ARM_R1, temp_reg, 4); 1016 break; 1017 1018 case 6: 1019 arm_load_membase(inst, ARM_R0, temp_reg, 0); 1020 arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4); 1021 break; 1022 1023 case 7: 1024 arm_load_membase(inst, ARM_R0, temp_reg, 0); 1025 arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4); 1026 arm_load_membase_byte(inst, ARM_R2, temp_reg, 6); 1027 arm_shift_reg_imm8(inst, ARM_SHL, ARM_R2, ARM_R2, 16); 1028 arm_alu_reg_reg(inst, ARM_ORR, ARM_R1, ARM_R1, ARM_R2); 1029 break; 1030 1031 case 8: 1032 arm_load_membase(inst, ARM_R0, temp_reg, 0); 1033 arm_load_membase(inst, ARM_R1, temp_reg, 4); 1034 break; 1035 } 1036 1037 jump_to_epilog(gen, &inst, block); 1038 } 1039 1040 /* 1041 * Exception handling 1042 */ 1043 JIT_OP_THROW: branch 1044 [reg] -> { 1045 1046 arm_push_reg(inst, $1); 1047 if(func->builder->setjmp_value != 0) 1048 { 1049 /* We have a "setjmp" block in the current function, 1050 so we must record the location of the throw first */ 1051 jit_nint pc_offset; 1052 1053 _jit_gen_fix_value(func->builder->setjmp_value); 1054 1055 pc_offset = func->builder->setjmp_value->frame_offset + 1056 jit_jmp_catch_pc_offset; 1057 1058 if(func->builder->position_independent) 1059 { 1060 arm_call_imm(inst, 0); 1061 arm_pop_membase(inst, ARM_FP, pc_offset); 1062 } 1063 else 1064 { 1065 int pc = (int) (unsigned char *) arm_inst_get_posn(inst); 1066 arm_mov_membase_imm(inst, ARM_FP, pc_offset, pc, 4, ARM_WORK); 1067 } 1068 } 1069 arm_call(inst, (void *)jit_exception_throw); 1070 } 1071 1072 JIT_OP_LOAD_PC: 1073 [=reg] -> { 1074 if(func->builder->position_independent) 1075 { 1076 arm_call_imm(inst, 0); 1077 arm_pop_reg(inst, $1); 1078 } 1079 else 1080 { 1081 int pc = inst.current; 1082 mov_reg_imm(gen, &inst, $1, pc); 1083 } 1084 } 1085 1086 JIT_OP_ENTER_FINALLY: 1087 [] -> { /* 1088 * The return address is in the link register 1089 * We must save it on the stack in case it will be overwritten by the content 1090 * of the "finally" block. 1091 * In order to respect the ABI of the ARM architecture, that prescribes an 8-byte 1092 * alignment for the stack at a public interface, we save the value twice, 1093 * in order to move the current SP by 8 bytes 1094 * (we could have just saved the value once and then moved the SP by 4 bytes) 1095 */ 1096 arm_push_reg(inst, ARM_LINK); 1097 arm_push_reg(inst, ARM_LINK); 1098 } 1099 1100 JIT_OP_LEAVE_FINALLY: branch 1101 [] -> { 1102 /* The "finally" return address is on the stack (twice, just for padding)*/ 1103 arm_pop_reg(inst, ARM_LINK); 1104 arm_pop_reg(inst, ARM_LINK); 1105 arm_return(inst); 1106 } 1107 1108 JIT_OP_CALL_FINALLY: branch 1109 [] -> { 1110 jit_block_t block; 1111 int offset; 1112 block = jit_block_from_label(func, (jit_label_t)(insn->dest)); 1113 if(!block) 1114 { 1115 return; 1116 } 1117 if(arm_inst_get_posn(inst) >= arm_inst_get_limit(inst)) 1118 { 1119 /* The buffer has overflowed, so don't worry about fixups */ 1120 return; 1121 } 1122 if(block->address) 1123 { 1124 /* We already know the address of the block */ 1125 arm_call(inst, block->address); 1126 } 1127 else 1128 { 1129 /* Output a placeholder and record on the block's fixup list */ 1130 if(block->fixup_list) 1131 { 1132 offset = (int)(((unsigned char *)arm_inst_get_posn(inst)) - 1133 ((unsigned char *)(block->fixup_list))); 1134 } 1135 else 1136 { 1137 offset = 0; 1138 } 1139 arm_call_imm(inst, offset); 1140 block->fixup_list = (void *)(arm_inst_get_posn(inst) - 1); 1141 } 1142 } 1143 1144 JIT_OP_ADDRESS_OF_LABEL: 1145 [=reg] -> { 1146 block = jit_block_from_label(func, (jit_label_t)(insn->value1)); 1147 if(func->builder->position_independent) 1148 { 1149 /* TODO */ 1150 TODO(); 1151 } 1152 else 1153 { 1154 if(block->address) 1155 { 1156 mov_reg_imm(gen, &inst, $1, block->address); 1157 } 1158 else 1159 { 1160 /* Output a placeholder and record on the block's fixup list */ 1161 mov_reg_imm(gen, &inst, $1, (int)(block->fixup_absolute_list)); 1162 block->fixup_absolute_list = (void *)(inst.current - 1); 1163 } 1164 } 1165 } 1166 1167 /* 1168 * Data manipulation. 1169 */ 1170 1171 JIT_OP_COPY_LOAD_SBYTE: 1172 [reg] -> {} 1173 1174 JIT_OP_COPY_LOAD_UBYTE: 1175 [reg] -> {} 1176 1177 JIT_OP_COPY_LOAD_SHORT: 1178 [reg] -> {} 1179 1180 JIT_OP_COPY_LOAD_USHORT: 1181 [reg] -> {} 1182 1183 JIT_OP_COPY_INT: copy 1184 [=local, imm, scratch reg] -> { 1185 arm_mov_membase_imm(inst, ARM_FP, $1, $2, 4, $3); 1186 } 1187 [reg] -> {} 1188 1189 1190 JIT_OP_COPY_LONG: copy 1191 [lreg] -> {} 1192 1193 JIT_OP_COPY_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): copy 1194 [freg32] -> {} 1195 1196 JIT_OP_COPY_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual 1197 [] -> { 1198 arm_inst_buf inst; 1199 _jit_regs_force_out(gen, insn->value1, 0); 1200 _jit_regs_force_out(gen, insn->dest, 1); 1201 _jit_gen_fix_value(insn->value1); 1202 _jit_gen_fix_value(insn->dest); 1203 jit_gen_load_inst_ptr(gen, inst); 1204 if(insn->value1->is_constant) 1205 { 1206 mov_reg_imm 1207 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); 1208 } 1209 else 1210 { 1211 arm_load_membase(inst, ARM_WORK, ARM_FP, 1212 insn->value1->frame_offset); 1213 } 1214 arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset); 1215 jit_gen_save_inst_ptr(gen, inst); 1216 } 1217 1218 JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): copy 1219 [freg64] -> {} 1220 1221 JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual 1222 [] -> { 1223 arm_inst_buf inst; 1224 _jit_regs_force_out(gen, insn->value1, 0); 1225 _jit_regs_force_out(gen, insn->dest, 1); 1226 _jit_gen_fix_value(insn->value1); 1227 _jit_gen_fix_value(insn->dest); 1228 jit_gen_load_inst_ptr(gen, inst); 1229 if(insn->value1->is_constant) 1230 { 1231 mov_reg_imm 1232 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); 1233 arm_store_membase(inst, ARM_WORK, ARM_FP, 1234 insn->dest->frame_offset); 1235 mov_reg_imm 1236 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]); 1237 arm_store_membase(inst, ARM_WORK, ARM_FP, 1238 insn->dest->frame_offset + 4); 1239 } 1240 else 1241 { 1242 arm_load_membase(inst, ARM_WORK, ARM_FP, 1243 insn->value1->frame_offset); 1244 arm_store_membase(inst, ARM_WORK, ARM_FP, 1245 insn->dest->frame_offset); 1246 arm_load_membase(inst, ARM_WORK, ARM_FP, 1247 insn->value1->frame_offset + 4); 1248 arm_store_membase(inst, ARM_WORK, ARM_FP, 1249 insn->dest->frame_offset + 4); 1250 } 1251 jit_gen_save_inst_ptr(gen, inst); 1252 } 1253 1254 JIT_OP_COPY_STRUCT: 1255 [=frame, frame, scratch reg] -> { 1256 inst = memory_copy(gen, inst, ARM_FP, $1, ARM_FP, $2, 1257 jit_type_get_size(jit_value_get_type(insn->dest)), $3); 1258 } 1259 1260 JIT_OP_COPY_STORE_BYTE: manual 1261 [] -> { 1262 arm_inst_buf inst; 1263 int reg; 1264 _jit_regs_force_out(gen, insn->dest, 1); 1265 _jit_gen_fix_value(insn->dest); 1266 reg = _jit_regs_load_value 1267 (gen, insn->value1, 0, 1268 (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | 1269 JIT_INSN_VALUE1_LIVE))); 1270 jit_gen_load_inst_ptr(gen, inst); 1271 arm_store_membase_byte(inst, _jit_reg_info[reg].cpu_reg, 1272 ARM_FP, insn->dest->frame_offset); 1273 jit_gen_save_inst_ptr(gen, inst); 1274 } 1275 1276 JIT_OP_COPY_STORE_SHORT: manual 1277 [] -> { 1278 arm_inst_buf inst; 1279 int reg; 1280 _jit_regs_force_out(gen, insn->dest, 1); 1281 _jit_gen_fix_value(insn->dest); 1282 reg = _jit_regs_load_value 1283 (gen, insn->value1, 1, 1284 (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | 1285 JIT_INSN_VALUE1_LIVE))); 1286 jit_gen_load_inst_ptr(gen, inst); 1287 arm_store_membase_short(inst, _jit_reg_info[reg].cpu_reg, 1288 ARM_FP, insn->dest->frame_offset); 1289 jit_gen_save_inst_ptr(gen, inst); 1290 //_jit_regs_free_reg(gen, reg, 1); //TODO: check if it's needed 1291 } 1292 1293 JIT_OP_ADDRESS_OF: 1294 [=reg, frame] -> { 1295 if($2 > 0) 1296 { 1297 arm_alu_reg_imm(inst, ARM_ADD, $1, ARM_FP, $2); 1298 } 1299 else if($2 < 0) 1300 { 1301 arm_alu_reg_imm(inst, ARM_SUB, $1, ARM_FP, -$2); 1302 } 1303 else 1304 { 1305 arm_mov_reg_reg(inst, $1, ARM_FP); 1306 } 1307 1308 } 1309 1310 /* 1311 * Stack pushes and pops. 1312 */ 1313 1314 JIT_OP_INCOMING_REG, JIT_OP_RETURN_REG: note 1315 [reg] -> { 1316 /* 1317 * This rule does nothing itself. Also at this point 1318 * the value is supposed to be already in the register 1319 * so the "reg" pattern does not load it either. But 1320 * it allows the allocator to check the liveness flags 1321 * and free the register if the value is dead. 1322 */ 1323 } 1324 1325 JIT_OP_RETRIEVE_FRAME_POINTER: note 1326 [=reg] -> { 1327 arm_mov_reg_reg(inst, $1, ARM_FP); 1328 } 1329 1330 JIT_OP_PUSH_INT: note 1331 [reg] -> { 1332 arm_push_reg(inst, $1); 1333 } 1334 1335 JIT_OP_PUSH_LONG: note 1336 [lreg] -> { 1337 arm_push_reg(inst, %1); 1338 arm_push_reg(inst, $1); 1339 gen->stack_changed=1; 1340 } 1341 1342 JIT_OP_PUSH_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): note 1343 [freg32] -> { 1344 arm_push_reg_float32(inst, $1); 1345 } 1346 1347 JIT_OP_PUSH_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual 1348 [] -> { 1349 arm_inst_buf inst; 1350 _jit_regs_force_out(gen, insn->value1, 0); 1351 _jit_gen_fix_value(insn->value1); 1352 jit_gen_load_inst_ptr(gen, inst); 1353 if(insn->value1->is_constant) 1354 { 1355 mov_reg_imm 1356 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); 1357 } 1358 else 1359 { 1360 arm_load_membase(inst, ARM_WORK, ARM_FP, 1361 insn->value1->frame_offset); 1362 } 1363 arm_push_reg(inst, ARM_WORK); 1364 jit_gen_save_inst_ptr(gen, inst); 1365 } 1366 1367 JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): note 1368 [freg64] -> { 1369 arm_push_reg_float64(inst, $1); 1370 } 1371 1372 JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual 1373 [] -> { 1374 arm_inst_buf inst; 1375 _jit_regs_force_out(gen, insn->value1, 0); 1376 _jit_gen_fix_value(insn->value1); 1377 jit_gen_load_inst_ptr(gen, inst); 1378 if(insn->value1->is_constant) 1379 { 1380 mov_reg_imm 1381 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]); 1382 arm_push_reg(inst, ARM_WORK); 1383 mov_reg_imm 1384 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); 1385 arm_push_reg(inst, ARM_WORK); 1386 } 1387 else 1388 { 1389 arm_load_membase(inst, ARM_WORK, ARM_FP, 1390 insn->value1->frame_offset + 4); 1391 arm_push_reg(inst, ARM_WORK); 1392 arm_load_membase(inst, ARM_WORK, ARM_FP, 1393 insn->value1->frame_offset); 1394 arm_push_reg(inst, ARM_WORK); 1395 } 1396 jit_gen_save_inst_ptr(gen, inst); 1397 } 1398 1399 JIT_OP_PUSH_STRUCT: /*unary_note*/ 1400 [reg] -> { 1401 /* TODO */ 1402 TODO(); 1403 } 1404 1405 JIT_OP_POP_STACK: 1406 [] -> { 1407 arm_alu_reg_imm(inst, ARM_ADD, ARM_SP, ARM_SP, insn->value1->address); 1408 } 1409 1410 JIT_OP_FLUSH_SMALL_STRUCT: 1411 [] -> { 1412 jit_nuint size; 1413 jit_nint offset; 1414 _jit_gen_fix_value(insn->value1); 1415 size = jit_type_get_size(jit_value_get_type(insn->value1)); 1416 offset = insn->value1->frame_offset; 1417 switch(size) 1418 { 1419 case 1: 1420 { 1421 arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset); 1422 } 1423 break; 1424 1425 case 2: 1426 { 1427 arm_store_membase_short(inst, ARM_R0, ARM_FP, offset); 1428 } 1429 break; 1430 1431 case 3: 1432 { 1433 arm_mov_reg_reg(inst, ARM_R1, ARM_R0); 1434 arm_store_membase_short(inst, ARM_R0, ARM_FP, offset); 1435 arm_shift_reg_imm8(inst, ARM_SHR, ARM_R0, ARM_R1, 16); 1436 arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset + 2); 1437 } 1438 break; 1439 1440 case 4: 1441 { 1442 arm_store_membase(inst, ARM_R0, ARM_FP, offset); 1443 } 1444 break; 1445 1446 case 5: 1447 { 1448 arm_store_membase(inst, ARM_R0, ARM_FP, offset); 1449 arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 4); 1450 } 1451 break; 1452 1453 case 6: 1454 { 1455 arm_store_membase(inst, ARM_R0, ARM_FP, offset); 1456 arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4); 1457 } 1458 break; 1459 1460 case 7: 1461 { 1462 arm_store_membase(inst, ARM_R0, ARM_FP, offset); 1463 arm_mov_reg_reg(inst, ARM_R2, ARM_R1); 1464 arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4); 1465 arm_shift_reg_imm8(inst, ARM_SHR, ARM_R1, ARM_R2, 16); 1466 arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 6); 1467 } 1468 break; 1469 1470 case 8: 1471 { 1472 arm_store_membase(inst, ARM_R0, ARM_FP, offset); 1473 arm_store_membase(inst, ARM_R1, ARM_FP, offset + 4); 1474 } 1475 break; 1476 } 1477 } 1478 1479 JIT_OP_SET_PARAM_INT: note 1480 [imm, imm] -> { 1481 arm_mov_membase_imm(inst, ARM_SP, $2, $1, 4, ARM_WORK); 1482 } 1483 [reg, imm] -> { 1484 arm_mov_membase_reg(inst, ARM_SP, $2, $1, 4); 1485 } 1486 1487 JIT_OP_SET_PARAM_LONG: /*unary_note*/ 1488 [lreg] -> { 1489 arm_store_membase(inst, $1, ARM_SP, insn->value2->address); 1490 arm_store_membase(inst, %1, ARM_SP, insn->value2->address + 4); 1491 } 1492 1493 JIT_OP_SET_PARAM_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): /*unary_note*/ 1494 [freg32] -> { 1495 arm_store_membase_float32(inst, $1, ARM_SP, insn->value2->address); 1496 } 1497 1498 JIT_OP_SET_PARAM_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual 1499 [] -> { 1500 arm_inst_buf inst; 1501 _jit_regs_force_out(gen, insn->value1, 0); 1502 _jit_gen_fix_value(insn->value1); 1503 jit_gen_load_inst_ptr(gen, inst); 1504 if(insn->value1->is_constant) 1505 { 1506 mov_reg_imm 1507 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); 1508 arm_store_membase 1509 (inst, ARM_WORK, ARM_SP, insn->value2->address); 1510 } 1511 else 1512 { 1513 arm_load_membase(inst, ARM_WORK, ARM_FP, 1514 insn->value1->frame_offset); 1515 arm_store_membase 1516 (inst, ARM_WORK, ARM_SP, insn->value2->address); 1517 } 1518 jit_gen_save_inst_ptr(gen, inst); 1519 } 1520 1521 JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT 1522 (JIT_ARM_HAS_FLOAT_REGS): /*unary_note*/ 1523 [freg64] -> { 1524 arm_store_membase_float64(inst, $1, ARM_SP, insn->value2->address); 1525 } 1526 1527 JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT 1528 (!JIT_ARM_HAS_FLOAT_REGS): manual 1529 [] -> { 1530 arm_inst_buf inst; 1531 _jit_regs_force_out(gen, insn->value1, 0); 1532 _jit_gen_fix_value(insn->value1); 1533 jit_gen_load_inst_ptr(gen, inst); 1534 if(insn->value1->is_constant) 1535 { 1536 mov_reg_imm 1537 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); 1538 arm_store_membase 1539 (inst, ARM_WORK, ARM_SP, insn->value2->address); 1540 mov_reg_imm 1541 (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]); 1542 arm_store_membase 1543 (inst, ARM_WORK, ARM_SP, insn->value2->address + 4); 1544 } 1545 else 1546 { 1547 arm_load_membase(inst, ARM_WORK, ARM_FP, 1548 insn->value1->frame_offset); 1549 arm_store_membase 1550 (inst, ARM_WORK, ARM_SP, insn->value2->address); 1551 arm_load_membase(inst, ARM_WORK, ARM_FP, 1552 insn->value1->frame_offset + 4); 1553 arm_store_membase 1554 (inst, ARM_WORK, ARM_SP, insn->value2->address + 4); 1555 } 1556 jit_gen_save_inst_ptr(gen, inst); 1557 } 1558 1559 JIT_OP_SET_PARAM_STRUCT: note 1560 [reg, imm, scratch reg] -> { 1561 /* Handle arbitrary-sized structures */ 1562 jit_nint offset = jit_value_get_nint_constant(insn->dest); 1563 inst = memory_copy(gen, inst, ARM_SP, offset, $1, 0, $2, $3); 1564 } 1565 1566 /* 1567 * Pointer-relative loads and stores. 1568 */ 1569 JIT_OP_LOAD_RELATIVE_SBYTE: 1570 [reg] -> { 1571 arm_load_membase_sbyte(inst, $1, $1, insn->value2->address); 1572 } 1573 1574 JIT_OP_LOAD_RELATIVE_UBYTE: 1575 [reg] -> { 1576 arm_load_membase_byte(inst, $1, $1, insn->value2->address); 1577 } 1578 1579 JIT_OP_LOAD_RELATIVE_SHORT: 1580 [reg] -> { 1581 arm_load_membase_short(inst, $1, $1, insn->value2->address); 1582 } 1583 1584 JIT_OP_LOAD_RELATIVE_USHORT: 1585 [reg] -> { 1586 arm_load_membase_ushort(inst, $1, $1, insn->value2->address); 1587 } 1588 1589 JIT_OP_LOAD_RELATIVE_INT: 1590 [reg] -> { 1591 arm_load_membase(inst, $1, $1, insn->value2->address); 1592 } 1593 1594 JIT_OP_LOAD_RELATIVE_LONG: 1595 [=lreg, reg, imm] -> { 1596 if($1 == $2) 1597 { 1598 arm_mov_reg_membase(inst, %1, $2, $3 + 4, 4); 1599 arm_mov_reg_membase(inst, $1, $2, $3, 4); 1600 } 1601 else 1602 { 1603 arm_mov_reg_membase(inst, $1, $2, $3, 4); 1604 arm_mov_reg_membase(inst, %1, $2, $3 + 4, 4); 1605 } 1606 } 1607 1608 JIT_OP_LOAD_RELATIVE_FLOAT32 (JIT_ARM_HAS_VFP): 1609 [=freg32, reg, imm] -> { 1610 arm_fld_membase(inst, $1, $2, $3, 0); 1611 } 1612 1613 JIT_OP_LOAD_RELATIVE_FLOAT64 (JIT_ARM_HAS_VFP): 1614 [=freg64, reg, imm] -> { 1615 arm_fld_membase(inst, $1, $2, $3, 1); 1616 } 1617 1618 JIT_OP_LOAD_RELATIVE_NFLOAT: manual 1619 [] -> { 1620 /* TODO */ 1621 TODO(); 1622 abort(); 1623 } 1624 1625 JIT_OP_LOAD_RELATIVE_STRUCT: more_space 1626 [=frame, reg, imm, scratch reg] -> { 1627 inst = memory_copy(gen, inst, ARM_FP, $1, $2, $3, jit_type_get_size(jit_value_get_type(insn->dest)), $4); 1628 } 1629 1630 JIT_OP_STORE_RELATIVE_BYTE: ternary 1631 [imm, imm, imm, scratch reg] -> { 1632 arm_mov_mem_imm(inst, $1 + $3, $2, 1, $4); 1633 } 1634 [imm, reg, imm] -> { 1635 arm_mov_mem_reg(inst, $1 + $3, $2, 1); 1636 } 1637 [reg, imm, imm] -> { 1638 arm_mov_membase_imm(inst, $1, $3, $2, 1, ARM_WORK); 1639 } 1640 [reg, reg, imm] -> { 1641 arm_mov_membase_reg(inst, $1, $3, $2, 1); 1642 } 1643 1644 JIT_OP_STORE_RELATIVE_SHORT: ternary 1645 [imm, imm, imm, scratch reg] -> { 1646 arm_mov_mem_imm(inst, $1 + $3, $2, 2, $4); 1647 } 1648 [imm, reg, imm] -> { 1649 arm_mov_mem_reg(inst, $1 + $3, $2, 2); 1650 } 1651 [reg, imm, imm] -> { 1652 arm_mov_membase_imm(inst, $1, $3, $2, 2, ARM_WORK); 1653 } 1654 [reg, reg, imm] -> { 1655 arm_mov_membase_reg(inst, $1, $3, $2, 2); 1656 } 1657 1658 JIT_OP_STORE_RELATIVE_INT: ternary 1659 [imm, imm, imm, scratch reg] -> { 1660 arm_mov_mem_imm(inst, $1 + $3, $2, 4, $4); 1661 } 1662 [imm, reg, imm] -> { 1663 arm_mov_mem_reg(inst, $1 + $3, $2, 4); 1664 } 1665 [reg, imm, imm] -> { 1666 arm_mov_membase_imm(inst, $1, $3, $2, 4, ARM_WORK); 1667 } 1668 [reg, reg, imm] -> { 1669 arm_mov_membase_reg(inst, $1, $3, $2, 4); 1670 } 1671 1672 JIT_OP_STORE_RELATIVE_LONG: ternary 1673 [reg, imm, imm] -> { 1674 arm_mov_membase_imm(inst, $1, $3, *(int *)($2), 4, ARM_WORK); 1675 arm_mov_membase_imm(inst, $1, $3 + 4, *(int *)($2 + 4), 4, ARM_WORK); 1676 } 1677 [reg, local, imm, scratch reg] -> { 1678 arm_mov_reg_membase(inst, $4, ARM_FP, $2, 4); 1679 arm_mov_membase_reg(inst, $1, $3, $4, 4); 1680 arm_mov_reg_membase(inst, $4, ARM_FP, $2 + 4, 4); 1681 arm_mov_membase_reg(inst, $1, $3 + 4, $4, 4); 1682 } 1683 [reg, lreg, imm] -> { 1684 arm_mov_membase_reg(inst, $1, $3, $2, 4); 1685 arm_mov_membase_reg(inst, $1, $3 + 4, %2, 4); 1686 } 1687 1688 JIT_OP_STORE_RELATIVE_FLOAT32 (JIT_ARM_HAS_VFP): ternary 1689 [reg, imm, imm] -> { 1690 arm_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4, ARM_WORK); 1691 } 1692 [reg, freg32, imm] -> { 1693 arm_store_membase_float32(inst, $2, $1, $3); 1694 } 1695 1696 JIT_OP_STORE_RELATIVE_FLOAT64 (JIT_ARM_HAS_VFP): ternary 1697 [reg, imm, imm, scratch reg] -> { 1698 arm_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4, $4); 1699 arm_mov_membase_imm(inst, $1, $3 + 4, ((int *)($2))[1], 4, $4); 1700 } 1701 [reg, freg64, imm] -> { 1702 arm_store_membase_float64(inst, $2, $1, $3); 1703 } 1704 1705 JIT_OP_STORE_RELATIVE_NFLOAT: manual 1706 [] -> { 1707 /* TODO */ 1708 TODO(); 1709 abort(); 1710 } 1711 1712 JIT_OP_STORE_RELATIVE_STRUCT: manual 1713 [] -> { 1714 arm_inst_buf inst; 1715 int reg = _jit_regs_load_value(gen, insn->dest, 0, 1716 (insn->flags & (JIT_INSN_DEST_NEXT_USE | 1717 JIT_INSN_DEST_LIVE))); 1718 _jit_regs_spill_all(gen); 1719 _jit_gen_fix_value(insn->value1); 1720 jit_gen_load_inst_ptr(gen, inst); 1721 _jit_gen_check_space(gen, 128); 1722 reg = _jit_reg_info[reg].cpu_reg; 1723 inst = memory_copy(gen, inst, reg, (int)(insn->value2->address), 1724 ARM_FP, insn->value1->frame_offset, 1725 jit_type_get_size(jit_value_get_type(insn->value1)), -1); 1726 jit_gen_save_inst_ptr(gen, inst); 1727 } 1728 1729 JIT_OP_ADD_RELATIVE: 1730 [reg] -> { 1731 if(insn->value2->address != 0) 1732 { 1733 arm_alu_reg_imm(inst, ARM_ADD, $1, $1, insn->value2->address); 1734 } 1735 } 1736 1737 /* 1738 * Array element loads and stores. 1739 */ 1740 JIT_OP_LOAD_ELEMENT_UBYTE: 1741 [=reg, reg, reg] -> { 1742 arm_widen_memindex(inst, $1, $2, 0, $3, 0, 0, 0); 1743 } 1744 1745 JIT_OP_LOAD_ELEMENT_USHORT: 1746 [=reg, reg, reg] -> { 1747 arm_widen_memindex(inst, $1, $2, 0, $3, 1, 0, 1); 1748 } 1749 1750 JIT_OP_LOAD_ELEMENT_INT: 1751 [=reg, reg, reg] -> { 1752 /* The last parameter is unimportant: it's not used, 1753 since the displacement (4th param) is 0 */ 1754 arm_mov_reg_memindex(inst, $1, $2, 0, $3, 2, 4, 0); 1755 } 1756 1757 JIT_OP_LOAD_ELEMENT_LONG: 1758 [=lreg, reg, reg, scratch reg, scratch reg] -> { 1759 //$1=destination long register (1-st word, LSB) 1760 //%1=destination long register (2-nd word, MSB) 1761 //$2=base register 1762 //$3=index register 1763 //$4=scratch register for arm_mov_reg_memindex 1764 //$5=scratch register for overwriting prevention 1765 1766 assert($2 != $3); 1767 1768 int basereg=$2; 1769 int indexreg=$3; 1770 1771 //Write the 1-st word 1772 if($1 == basereg) 1773 { 1774 //Prevent base reg from being overwritten 1775 arm_mov_reg_reg(inst, $5, basereg); 1776 basereg=$5; 1777 } 1778 else if ($1 == indexreg) 1779 { 1780 //Prevent index reg from being overwritten 1781 arm_mov_reg_reg(inst, $5, indexreg); 1782 indexreg=$5; 1783 } 1784 arm_mov_reg_memindex(inst, $1, basereg, 0, indexreg, 3, 4, $4); 1785 1786 //Write the 2-nd word 1787 arm_mov_reg_memindex(inst, %1, basereg, 4, indexreg, 3, 4, $4); 1788 } 1789 1790 JIT_OP_LOAD_ELEMENT_FLOAT64: 1791 [=freg64, reg, reg, scratch reg] -> { 1792 arm_fld_memindex(inst, $1, $2, 0, $3, 3, 1, $4); 1793 } 1794 1795 JIT_OP_STORE_ELEMENT_BYTE: ternary 1796 [reg, reg, reg, scratch reg] -> { 1797 arm_mov_memindex_reg(inst, $1, 0, $2, 0, $3, 1, $4); 1798 } 1799 1800 JIT_OP_STORE_ELEMENT_SHORT: ternary 1801 [reg, reg, reg, scratch reg] -> { 1802 arm_mov_memindex_reg(inst, $1, 0, $2, 1, $3, 2, $4); 1803 } 1804 1805 JIT_OP_STORE_ELEMENT_INT: ternary 1806 [reg, reg, reg, scratch reg] -> { 1807 arm_mov_memindex_reg(inst, $1, 0, $2, 2, $3, 4, $4); 1808 } 1809 1810 JIT_OP_STORE_ELEMENT_LONG: ternary 1811 [reg, reg, imm] -> { 1812 TODO(); 1813 abort(); 1814 //x86_mov_memindex_imm(inst, $1, 0, $2, 3, *(int *)($3), 4); 1815 //x86_mov_memindex_imm(inst, $1, 4, $2, 3, *(int *)($3 + 4), 4); 1816 } 1817 [reg, reg, local, scratch reg, scratch reg] -> { 1818 arm_mov_reg_membase(inst, $4, ARM_FP, $3, 4); 1819 arm_mov_memindex_reg(inst, $1, 0, $2, 3, $4, 4, $5); 1820 arm_mov_reg_membase(inst, $4, ARM_FP, $3 + 4, 4); 1821 arm_mov_memindex_reg(inst, $1, 4, $2, 3, $4, 4, $5); 1822 } 1823 [reg, reg, lreg, scratch reg] -> { 1824 arm_mov_memindex_reg(inst, $1, 0, $2, 3, $3, 4, $4); 1825 arm_mov_memindex_reg(inst, $1, 4, $2, 3, %3, 4, $4); 1826 } 1827 1828 JIT_OP_STORE_ELEMENT_FLOAT64: ternary 1829 [reg, reg, freg64, scratch reg] -> { 1830 arm_fst_memindex(inst, $3, $1, 0, $2, 3, 1, $4); 1831 } 1832 1833 /* 1834 * Allocate memory from the stack. 1835 */ 1836 JIT_OP_ALLOCA: 1837 [reg] -> { 1838 arm_alu_reg_reg(inst, ARM_SUB, ARM_SP, ARM_SP, $1); 1839 arm_mov_reg_reg(inst, $1, ARM_SP); 1840 gen->stack_changed = 1; 1841 } 1842 1843 /* 1844 * Block operations 1845 */ 1846 JIT_OP_MEMCPY: ternary 1847 [any, any, imm, if("$3 <= 0")] -> { } 1848 [reg, reg, imm, scratch reg, clobber("r0", "r1", "r2")] -> 1849 { 1850 /* 1851 * Call jit_memcpy(dest,src,size). 1852 * $1=dest, $2=src, $3=size 1853 */ 1854 int dest=$1; 1855 int src=$2; 1856 1857 if (dest != ARM_R0) { 1858 if(src==ARM_R0) 1859 { 1860 //Prevent overwriting useful data 1861 arm_mov_reg_reg(inst, $4, src); 1862 src=$4; 1863 } 1864 arm_mov_reg_reg((inst), ARM_R0, dest); 1865 } 1866 if (src != ARM_R1) { 1867 //Move the "src" from wherever it is to where it should be 1868 arm_mov_reg_reg(inst, ARM_R1, src); 1869 } 1870 mov_reg_imm(gen, &(inst), ARM_R2, $3); 1871 1872 //Call the function 1873 arm_call(inst, jit_memcpy); 1874 } 1875 [reg, reg, reg, scratch reg, clobber("r0", "r1", "r2")] -> { 1876 /* 1877 * Call jit_memcpy(dest,src,size). 1878 * $1=dest, $2=src, $3=size 1879 */ 1880 if ($1 != ARM_R0) { 1881 if($2==ARM_R0) 1882 { 1883 //Prevent overwriting useful data 1884 arm_mov_reg_reg(inst, $4, $2); 1885 } 1886 arm_mov_reg_reg((inst), ARM_R0, $1); 1887 } 1888 if ($2 != ARM_R1) { 1889 if ($2==ARM_R0) 1890 { 1891 //Recover previously saved data 1892 arm_mov_reg_reg(inst, ARM_R1, $4); 1893 } 1894 else 1895 { 1896 arm_mov_reg_reg((inst), ARM_R1, $2); 1897 } 1898 } 1899 if ($3 != ARM_R2) { 1900 arm_mov_reg_reg((inst), ARM_R2, $3); 1901 } 1902 1903 //Call the function 1904 arm_call(inst, jit_memcpy); 1905 1906 } 1907 1908 JIT_OP_MEMSET: ternary 1909 [any, any, imm, if("$3 <= 0")] -> { } 1910 [reg, imm, imm, if("$3 <= 32"), space("32 + $3 * 4")] -> { 1911 // $1 = pointer to the initial memory location 1912 // $2 = value to be written in memory 1913 // $3 = length in bytes 1914 int disp; 1915 disp = 0; 1916 while($3 >= (disp + 4)) 1917 { 1918 //NB: if 0<A<255, then A*0x01010101 = a 32-bit value where each of its four bytes is A. 1919 arm_mov_membase_imm(inst, $1, disp, $2 * 0x01010101, 4, ARM_WORK); 1920 disp += 4; 1921 } 1922 if($3 >= (disp + 2)) 1923 { 1924 arm_mov_membase_imm(inst, $1, disp, $2 * 0x0101, 2, ARM_WORK); 1925 disp += 2; 1926 } 1927 if(insn->value2->address > disp) 1928 { 1929 arm_mov_membase_imm(inst, $1, disp, $2, 1, ARM_WORK); 1930 } 1931 } 1932 [reg, reg, imm, if("$3 < 4")] -> { 1933 TODO(); 1934 abort(); 1935 } 1936 [reg, +reg, imm, scratch reg, if("$3 <= 32 && ($3 % 2) == 0"), space("32 + $3 * 4")] -> { 1937 // $1 = pointer to the initial memory location 1938 // $2 = value to be written in memory 1939 // $3 = length in bytes 1940 // $4 = scratch register 1941 int disp; 1942 arm_mov_reg_reg(inst, $4, $2); 1943 arm_shift_reg_imm8(inst, ARM_SHL, $2, $2, 8); 1944 arm_alu_reg_reg(inst, ARM_ORR, $2, $2, $4); 1945 arm_mov_reg_reg(inst, $4, $2); 1946 arm_shift_reg_imm8(inst, ARM_SHL, $2, $2, 16); 1947 arm_alu_reg_reg(inst, ARM_ORR, $2, $2, $4); 1948 disp = 0; 1949 while($3 >= (disp + 4)) 1950 { 1951 arm_mov_membase_reg(inst, $1, disp, $2, 4); 1952 disp += 4; 1953 } 1954 if($3 > disp) 1955 { 1956 arm_mov_membase_reg(inst, $1, disp, $2, 2); 1957 } 1958 } 1959 [reg, +reg, imm, scratch reg, 1960 if("$3 <= 32 && ($3 % 2) != 0"), space("32 + $3 * 4")] -> { 1961 TODO(); 1962 abort(); 1963 } 1964 [reg, reg, reg, clobber("r0", "r1", "r2"), scratch reg] -> { 1965 // $1 = pointer to the initial memory location 1966 // $2 = value to be written in memory 1967 // $3 = length in bytes 1968 // $4 = scratch register 1969 1970 int pointer=$1; 1971 int value=$2; 1972 int length=$3; 1973 int scratch=$4; 1974 1975 1976 /* Move the outgoing parameters in the right registers (if they are not already where they should be */ 1977 if (pointer != ARM_R0) { 1978 if(value == ARM_R0) 1979 { 1980 //Prevent the value from being overwritten 1981 arm_mov_reg_reg((inst), scratch, ARM_R0); 1982 value=scratch; 1983 } 1984 else if(length==ARM_R0) 1985 { 1986 //Prevent the length from being overwritten 1987 arm_mov_reg_reg((inst), scratch, ARM_R0); 1988 length=scratch; 1989 } 1990 1991 arm_mov_reg_reg((inst), ARM_R0, pointer); 1992 1993 //The register that contained the pointer is now free 1994 scratch=pointer; 1995 } 1996 1997 if (value != ARM_R1) 1998 { 1999 if (length == ARM_R1) 2000 { 2001 //The length is stored in R1. Prevent it from being overwritten 2002 arm_mov_reg_reg(inst, scratch, length); 2003 length=scratch; 2004 } 2005 2006 //Set param 2 2007 arm_mov_reg_reg((inst), ARM_R1, value); 2008 2009 //The register that contained the value is now free 2010 scratch=value; 2011 } 2012 2013 if(length != ARM_R1) 2014 { 2015 //Param 3 still isn't in place: move it! 2016 arm_mov_reg_reg(inst, ARM_R2, length); 2017 } 2018 2019 arm_call(inst, jit_memset); 2020 }