1/* 2 * Copyright (C) 2013 Cisco Systems, Inc. All rights reserved. 3 * Copyright (C) 2009-2011 STMicroelectronics. All rights reserved. 4 * Copyright (C) 2008 Apple Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#ifndef SH4Assembler_h 29#define SH4Assembler_h 30 31#if ENABLE(ASSEMBLER) && CPU(SH4) 32 33#include "AssemblerBuffer.h" 34#include "AssemblerBufferWithConstantPool.h" 35#include "JITCompilationEffort.h" 36#include <limits.h> 37#include <stdarg.h> 38#include <stdint.h> 39#include <stdio.h> 40#include <wtf/Assertions.h> 41#include <wtf/DataLog.h> 42#include <wtf/Vector.h> 43 44#ifndef NDEBUG 45#define SH4_ASSEMBLER_TRACING 46#endif 47 48namespace JSC { 49typedef uint16_t SH4Word; 50 51enum { 52 INVALID_OPCODE = 0xffff, 53 ADD_OPCODE = 0x300c, 54 ADDIMM_OPCODE = 0x7000, 55 ADDC_OPCODE = 0x300e, 56 ADDV_OPCODE = 0x300f, 57 AND_OPCODE = 0x2009, 58 ANDIMM_OPCODE = 0xc900, 59 DIV0_OPCODE = 0x2007, 60 DIV1_OPCODE = 0x3004, 61 BF_OPCODE = 0x8b00, 62 BFS_OPCODE = 0x8f00, 63 BRA_OPCODE = 0xa000, 64 BRAF_OPCODE = 0x0023, 65 NOP_OPCODE = 0x0009, 66 BSR_OPCODE = 0xb000, 67 RTS_OPCODE = 0x000b, 68 BT_OPCODE = 0x8900, 69 BTS_OPCODE = 0x8d00, 70 BSRF_OPCODE = 0x0003, 71 BRK_OPCODE = 0x003b, 72 FTRC_OPCODE = 0xf03d, 73 CMPEQ_OPCODE = 0x3000, 74 CMPEQIMM_OPCODE = 0x8800, 75 CMPGE_OPCODE = 0x3003, 76 CMPGT_OPCODE = 0x3007, 77 CMPHI_OPCODE = 0x3006, 78 CMPHS_OPCODE = 0x3002, 79 CMPPL_OPCODE = 0x4015, 80 CMPPZ_OPCODE = 0x4011, 81 CMPSTR_OPCODE = 0x200c, 82 DT_OPCODE = 0x4010, 83 FCMPEQ_OPCODE = 0xf004, 84 FCMPGT_OPCODE = 0xf005, 85 FMOV_OPCODE = 0xf00c, 86 FADD_OPCODE = 0xf000, 87 FMUL_OPCODE = 0xf002, 88 FSUB_OPCODE = 0xf001, 89 FDIV_OPCODE = 0xf003, 90 FNEG_OPCODE = 0xf04d, 91 JMP_OPCODE = 0x402b, 92 JSR_OPCODE = 0x400b, 93 LDSPR_OPCODE = 0x402a, 94 LDSLPR_OPCODE = 0x4026, 95 MOV_OPCODE = 0x6003, 96 MOVIMM_OPCODE = 0xe000, 97 MOVB_WRITE_RN_OPCODE = 0x2000, 98 MOVB_WRITE_RNDEC_OPCODE = 0x2004, 99 MOVB_WRITE_R0RN_OPCODE = 0x0004, 100 MOVB_WRITE_OFFGBR_OPCODE = 0xc000, 101 MOVB_WRITE_OFFRN_OPCODE = 0x8000, 102 MOVB_READ_RM_OPCODE = 0x6000, 103 MOVB_READ_RMINC_OPCODE = 0x6004, 104 MOVB_READ_R0RM_OPCODE = 0x000c, 105 MOVB_READ_OFFGBR_OPCODE = 0xc400, 106 MOVB_READ_OFFRM_OPCODE = 0x8400, 107 MOVL_WRITE_RN_OPCODE = 0x2002, 108 MOVL_WRITE_RNDEC_OPCODE = 0x2006, 109 MOVL_WRITE_R0RN_OPCODE = 0x0006, 110 MOVL_WRITE_OFFGBR_OPCODE = 0xc200, 111 MOVL_WRITE_OFFRN_OPCODE = 0x1000, 112 MOVL_READ_RM_OPCODE = 0x6002, 113 MOVL_READ_RMINC_OPCODE = 0x6006, 114 MOVL_READ_R0RM_OPCODE = 0x000e, 115 MOVL_READ_OFFGBR_OPCODE = 0xc600, 116 MOVL_READ_OFFPC_OPCODE = 0xd000, 117 MOVL_READ_OFFRM_OPCODE = 0x5000, 118 MOVW_WRITE_RN_OPCODE = 0x2001, 119 MOVW_WRITE_R0RN_OPCODE = 0x0005, 120 MOVW_READ_RM_OPCODE = 0x6001, 121 MOVW_READ_RMINC_OPCODE = 0x6005, 122 MOVW_READ_R0RM_OPCODE = 0x000d, 123 MOVW_READ_OFFRM_OPCODE = 0x8500, 124 MOVW_READ_OFFPC_OPCODE = 0x9000, 125 MOVA_READ_OFFPC_OPCODE = 0xc700, 126 MOVT_OPCODE = 0x0029, 127 MULL_OPCODE = 0x0007, 128 DMULL_L_OPCODE = 0x3005, 129 STSMACL_OPCODE = 0x001a, 130 STSMACH_OPCODE = 0x000a, 131 DMULSL_OPCODE = 0x300d, 132 NEG_OPCODE = 0x600b, 133 NEGC_OPCODE = 0x600a, 134 NOT_OPCODE = 0x6007, 135 OR_OPCODE = 0x200b, 136 ORIMM_OPCODE = 0xcb00, 137 ORBIMM_OPCODE = 0xcf00, 138 SETS_OPCODE = 0x0058, 139 SETT_OPCODE = 0x0018, 140 SHAD_OPCODE = 0x400c, 141 SHAL_OPCODE = 0x4020, 142 SHAR_OPCODE = 0x4021, 143 SHLD_OPCODE = 0x400d, 144 SHLL_OPCODE = 0x4000, 145 SHLL2_OPCODE = 0x4008, 146 SHLL8_OPCODE = 0x4018, 147 SHLL16_OPCODE = 0x4028, 148 SHLR_OPCODE = 0x4001, 149 SHLR2_OPCODE = 0x4009, 150 SHLR8_OPCODE = 0x4019, 151 SHLR16_OPCODE = 0x4029, 152 STSPR_OPCODE = 0x002a, 153 STSLPR_OPCODE = 0x4022, 154 FLOAT_OPCODE = 0xf02d, 155 SUB_OPCODE = 0x3008, 156 SUBC_OPCODE = 0x300a, 157 SUBV_OPCODE = 0x300b, 158 TST_OPCODE = 0x2008, 159 TSTIMM_OPCODE = 0xc800, 160 TSTB_OPCODE = 0xcc00, 161 EXTUB_OPCODE = 0x600c, 162 EXTUW_OPCODE = 0x600d, 163 XOR_OPCODE = 0x200a, 164 XORIMM_OPCODE = 0xca00, 165 XORB_OPCODE = 0xce00, 166 FMOVS_READ_RM_INC_OPCODE = 0xf009, 167 FMOVS_READ_RM_OPCODE = 0xf008, 168 FMOVS_READ_R0RM_OPCODE = 0xf006, 169 FMOVS_WRITE_RN_OPCODE = 0xf00a, 170 FMOVS_WRITE_RN_DEC_OPCODE = 0xf00b, 171 FMOVS_WRITE_R0RN_OPCODE = 0xf007, 172 FCNVDS_DRM_FPUL_OPCODE = 0xf0bd, 173 FCNVSD_FPUL_DRN_OPCODE = 0xf0ad, 174 LDS_RM_FPUL_OPCODE = 0x405a, 175 FLDS_FRM_FPUL_OPCODE = 0xf01d, 176 STS_FPUL_RN_OPCODE = 0x005a, 177 FSTS_FPUL_FRN_OPCODE = 0xF00d, 178 LDSFPSCR_OPCODE = 0x406a, 179 STSFPSCR_OPCODE = 0x006a, 180 LDSRMFPUL_OPCODE = 0x405a, 181 FSTSFPULFRN_OPCODE = 0xf00d, 182 FABS_OPCODE = 0xf05d, 183 FSQRT_OPCODE = 0xf06d, 184 FSCHG_OPCODE = 0xf3fd, 185 CLRT_OPCODE = 8, 186 SYNCO_OPCODE = 0x00ab, 187}; 188 189namespace SH4Registers { 190typedef enum { 191 r0, 192 r1, 193 r2, 194 r3, 195 r4, 196 r5, 197 r6, 198 r7, 199 r8, 200 r9, 201 r10, 202 r11, 203 r12, 204 r13, 205 r14, fp = r14, 206 r15, sp = r15, 207 pc, 208 pr, 209} RegisterID; 210 211typedef enum { 212 fr0, dr0 = fr0, 213 fr1, 214 fr2, dr2 = fr2, 215 fr3, 216 fr4, dr4 = fr4, 217 fr5, 218 fr6, dr6 = fr6, 219 fr7, 220 fr8, dr8 = fr8, 221 fr9, 222 fr10, dr10 = fr10, 223 fr11, 224 fr12, dr12 = fr12, 225 fr13, 226 fr14, dr14 = fr14, 227 fr15, 228} FPRegisterID; 229} 230 231inline uint16_t getOpcodeGroup1(uint16_t opc, int rm, int rn) 232{ 233 return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4)); 234} 235 236inline uint16_t getOpcodeGroup2(uint16_t opc, int rm) 237{ 238 return (opc | ((rm & 0xf) << 8)); 239} 240 241inline uint16_t getOpcodeGroup3(uint16_t opc, int rm, int rn) 242{ 243 return (opc | ((rm & 0xf) << 8) | (rn & 0xff)); 244} 245 246inline uint16_t getOpcodeGroup4(uint16_t opc, int rm, int rn, int offset) 247{ 248 return (opc | ((rm & 0xf) << 8) | ((rn & 0xf) << 4) | (offset & 0xf)); 249} 250 251inline uint16_t getOpcodeGroup5(uint16_t opc, int rm) 252{ 253 return (opc | (rm & 0xff)); 254} 255 256inline uint16_t getOpcodeGroup6(uint16_t opc, int rm) 257{ 258 return (opc | (rm & 0xfff)); 259} 260 261inline uint16_t getOpcodeGroup7(uint16_t opc, int rm) 262{ 263 return (opc | ((rm & 0x7) << 9)); 264} 265 266inline uint16_t getOpcodeGroup8(uint16_t opc, int rm, int rn) 267{ 268 return (opc | ((rm & 0x7) << 9) | ((rn & 0x7) << 5)); 269} 270 271inline uint16_t getOpcodeGroup9(uint16_t opc, int rm, int rn) 272{ 273 return (opc | ((rm & 0xf) << 8) | ((rn & 0x7) << 5)); 274} 275 276inline uint16_t getOpcodeGroup10(uint16_t opc, int rm, int rn) 277{ 278 return (opc | ((rm & 0x7) << 9) | ((rn & 0xf) << 4)); 279} 280 281inline uint16_t getOpcodeGroup11(uint16_t opc, int rm, int rn) 282{ 283 return (opc | ((rm & 0xf) << 4) | (rn & 0xf)); 284} 285 286inline uint16_t getRn(uint16_t x) 287{ 288 return ((x & 0xf00) >> 8); 289} 290 291inline uint16_t getRm(uint16_t x) 292{ 293 return ((x & 0xf0) >> 4); 294} 295 296inline uint16_t getDisp(uint16_t x) 297{ 298 return (x & 0xf); 299} 300 301inline uint16_t getImm8(uint16_t x) 302{ 303 return (x & 0xff); 304} 305 306inline uint16_t getImm12(uint16_t x) 307{ 308 return (x & 0xfff); 309} 310 311inline uint16_t getDRn(uint16_t x) 312{ 313 return ((x & 0xe00) >> 9); 314} 315 316inline uint16_t getDRm(uint16_t x) 317{ 318 return ((x & 0xe0) >> 5); 319} 320 321class SH4Assembler { 322public: 323 typedef SH4Registers::RegisterID RegisterID; 324 typedef SH4Registers::FPRegisterID FPRegisterID; 325 typedef AssemblerBufferWithConstantPool<512, 4, 2, SH4Assembler> SH4Buffer; 326 static const RegisterID scratchReg1 = SH4Registers::r3; 327 static const RegisterID scratchReg2 = SH4Registers::r11; 328 static const uint32_t maxInstructionSize = 16; 329 330 static RegisterID firstRegister() { return SH4Registers::r0; } 331 static RegisterID lastRegister() { return SH4Registers::r15; } 332 333 static FPRegisterID firstFPRegister() { return SH4Registers::dr0; } 334 static FPRegisterID lastFPRegister() { return SH4Registers::dr14; } 335 336 enum { 337 padForAlign8 = 0x00, 338 padForAlign16 = 0x0009, 339 padForAlign32 = 0x00090009, 340 }; 341 342 enum JumpType { 343 JumpFar, 344 JumpNear 345 }; 346 347 SH4Assembler() 348 : m_claimscratchReg(0x0) 349 , m_indexOfLastWatchpoint(INT_MIN) 350 , m_indexOfTailOfLastWatchpoint(INT_MIN) 351 { 352 } 353 354 SH4Buffer& buffer() { return m_buffer; } 355 356 // SH4 condition codes 357 typedef enum { 358 EQ = 0x0, // Equal 359 NE = 0x1, // Not Equal 360 HS = 0x2, // Unsigned Greater Than equal 361 HI = 0x3, // Unsigned Greater Than 362 LS = 0x4, // Unsigned Lower or Same 363 LI = 0x5, // Unsigned Lower 364 GE = 0x6, // Greater or Equal 365 LT = 0x7, // Less Than 366 GT = 0x8, // Greater Than 367 LE = 0x9, // Less or Equal 368 OF = 0xa, // OverFlow 369 SI = 0xb, // Signed 370 NS = 0xc, // Not Signed 371 EQU= 0xd, // Equal or unordered(NaN) 372 NEU= 0xe, 373 GTU= 0xf, 374 GEU= 0x10, 375 LTU= 0x11, 376 LEU= 0x12, 377 } Condition; 378 379 // Opaque label types 380public: 381 bool isImmediate(int constant) 382 { 383 return ((constant <= 127) && (constant >= -128)); 384 } 385 386 RegisterID claimScratch() 387 { 388 ASSERT((m_claimscratchReg != 0x3)); 389 390 if (!(m_claimscratchReg & 0x1)) { 391 m_claimscratchReg = (m_claimscratchReg | 0x1); 392 return scratchReg1; 393 } 394 395 m_claimscratchReg = (m_claimscratchReg | 0x2); 396 return scratchReg2; 397 } 398 399 void releaseScratch(RegisterID scratchR) 400 { 401 if (scratchR == scratchReg1) 402 m_claimscratchReg = (m_claimscratchReg & 0x2); 403 else 404 m_claimscratchReg = (m_claimscratchReg & 0x1); 405 } 406 407 // Stack operations 408 409 void pushReg(RegisterID reg) 410 { 411 if (reg == SH4Registers::pr) { 412 oneShortOp(getOpcodeGroup2(STSLPR_OPCODE, SH4Registers::sp)); 413 return; 414 } 415 416 oneShortOp(getOpcodeGroup1(MOVL_WRITE_RNDEC_OPCODE, SH4Registers::sp, reg)); 417 } 418 419 void popReg(RegisterID reg) 420 { 421 if (reg == SH4Registers::pr) { 422 oneShortOp(getOpcodeGroup2(LDSLPR_OPCODE, SH4Registers::sp)); 423 return; 424 } 425 426 oneShortOp(getOpcodeGroup1(MOVL_READ_RMINC_OPCODE, reg, SH4Registers::sp)); 427 } 428 429 void movt(RegisterID dst) 430 { 431 uint16_t opc = getOpcodeGroup2(MOVT_OPCODE, dst); 432 oneShortOp(opc); 433 } 434 435 // Arithmetic operations 436 437 void addlRegReg(RegisterID src, RegisterID dst) 438 { 439 uint16_t opc = getOpcodeGroup1(ADD_OPCODE, dst, src); 440 oneShortOp(opc); 441 } 442 443 void addclRegReg(RegisterID src, RegisterID dst) 444 { 445 uint16_t opc = getOpcodeGroup1(ADDC_OPCODE, dst, src); 446 oneShortOp(opc); 447 } 448 449 void addvlRegReg(RegisterID src, RegisterID dst) 450 { 451 uint16_t opc = getOpcodeGroup1(ADDV_OPCODE, dst, src); 452 oneShortOp(opc); 453 } 454 455 void addlImm8r(int imm8, RegisterID dst) 456 { 457 ASSERT((imm8 <= 127) && (imm8 >= -128)); 458 459 uint16_t opc = getOpcodeGroup3(ADDIMM_OPCODE, dst, imm8); 460 oneShortOp(opc); 461 } 462 463 void andlRegReg(RegisterID src, RegisterID dst) 464 { 465 uint16_t opc = getOpcodeGroup1(AND_OPCODE, dst, src); 466 oneShortOp(opc); 467 } 468 469 void andlImm8r(int imm8, RegisterID dst) 470 { 471 ASSERT((imm8 <= 255) && (imm8 >= 0)); 472 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 473 474 uint16_t opc = getOpcodeGroup5(ANDIMM_OPCODE, imm8); 475 oneShortOp(opc); 476 } 477 478 void div1lRegReg(RegisterID src, RegisterID dst) 479 { 480 uint16_t opc = getOpcodeGroup1(DIV1_OPCODE, dst, src); 481 oneShortOp(opc); 482 } 483 484 void div0lRegReg(RegisterID src, RegisterID dst) 485 { 486 uint16_t opc = getOpcodeGroup1(DIV0_OPCODE, dst, src); 487 oneShortOp(opc); 488 } 489 490 void notlReg(RegisterID src, RegisterID dst) 491 { 492 uint16_t opc = getOpcodeGroup1(NOT_OPCODE, dst, src); 493 oneShortOp(opc); 494 } 495 496 void orlRegReg(RegisterID src, RegisterID dst) 497 { 498 uint16_t opc = getOpcodeGroup1(OR_OPCODE, dst, src); 499 oneShortOp(opc); 500 } 501 502 void orlImm8r(int imm8, RegisterID dst) 503 { 504 ASSERT((imm8 <= 255) && (imm8 >= 0)); 505 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 506 507 uint16_t opc = getOpcodeGroup5(ORIMM_OPCODE, imm8); 508 oneShortOp(opc); 509 } 510 511 void sublRegReg(RegisterID src, RegisterID dst) 512 { 513 uint16_t opc = getOpcodeGroup1(SUB_OPCODE, dst, src); 514 oneShortOp(opc); 515 } 516 517 void subvlRegReg(RegisterID src, RegisterID dst) 518 { 519 uint16_t opc = getOpcodeGroup1(SUBV_OPCODE, dst, src); 520 oneShortOp(opc); 521 } 522 523 void xorlRegReg(RegisterID src, RegisterID dst) 524 { 525 uint16_t opc = getOpcodeGroup1(XOR_OPCODE, dst, src); 526 oneShortOp(opc); 527 } 528 529 void xorlImm8r(int imm8, RegisterID dst) 530 { 531 ASSERT((imm8 <= 255) && (imm8 >= 0)); 532 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 533 534 uint16_t opc = getOpcodeGroup5(XORIMM_OPCODE, imm8); 535 oneShortOp(opc); 536 } 537 538 void shllImm8r(int imm, RegisterID dst) 539 { 540 switch (imm) { 541 case 1: 542 oneShortOp(getOpcodeGroup2(SHLL_OPCODE, dst)); 543 break; 544 case 2: 545 oneShortOp(getOpcodeGroup2(SHLL2_OPCODE, dst)); 546 break; 547 case 8: 548 oneShortOp(getOpcodeGroup2(SHLL8_OPCODE, dst)); 549 break; 550 case 16: 551 oneShortOp(getOpcodeGroup2(SHLL16_OPCODE, dst)); 552 break; 553 default: 554 RELEASE_ASSERT_NOT_REACHED(); 555 } 556 } 557 558 void neg(RegisterID dst, RegisterID src) 559 { 560 uint16_t opc = getOpcodeGroup1(NEG_OPCODE, dst, src); 561 oneShortOp(opc); 562 } 563 564 void shldRegReg(RegisterID dst, RegisterID rShift) 565 { 566 oneShortOp(getOpcodeGroup1(SHLD_OPCODE, dst, rShift)); 567 } 568 569 void shadRegReg(RegisterID dst, RegisterID rShift) 570 { 571 oneShortOp(getOpcodeGroup1(SHAD_OPCODE, dst, rShift)); 572 } 573 574 void shlrImm8r(int imm, RegisterID dst) 575 { 576 switch (imm) { 577 case 1: 578 oneShortOp(getOpcodeGroup2(SHLR_OPCODE, dst)); 579 break; 580 case 2: 581 oneShortOp(getOpcodeGroup2(SHLR2_OPCODE, dst)); 582 break; 583 case 8: 584 oneShortOp(getOpcodeGroup2(SHLR8_OPCODE, dst)); 585 break; 586 case 16: 587 oneShortOp(getOpcodeGroup2(SHLR16_OPCODE, dst)); 588 break; 589 default: 590 RELEASE_ASSERT_NOT_REACHED(); 591 } 592 } 593 594 void shalImm8r(int imm, RegisterID dst) 595 { 596 switch (imm) { 597 case 1: 598 oneShortOp(getOpcodeGroup2(SHAL_OPCODE, dst)); 599 break; 600 default: 601 RELEASE_ASSERT_NOT_REACHED(); 602 } 603 } 604 605 void sharImm8r(int imm, RegisterID dst) 606 { 607 switch (imm) { 608 case 1: 609 oneShortOp(getOpcodeGroup2(SHAR_OPCODE, dst)); 610 break; 611 default: 612 RELEASE_ASSERT_NOT_REACHED(); 613 } 614 } 615 616 void imullRegReg(RegisterID src, RegisterID dst) 617 { 618 uint16_t opc = getOpcodeGroup1(MULL_OPCODE, dst, src); 619 oneShortOp(opc); 620 } 621 622 void dmullRegReg(RegisterID src, RegisterID dst) 623 { 624 uint16_t opc = getOpcodeGroup1(DMULL_L_OPCODE, dst, src); 625 oneShortOp(opc); 626 } 627 628 void dmulslRegReg(RegisterID src, RegisterID dst) 629 { 630 uint16_t opc = getOpcodeGroup1(DMULSL_OPCODE, dst, src); 631 oneShortOp(opc); 632 } 633 634 void stsmacl(RegisterID reg) 635 { 636 uint16_t opc = getOpcodeGroup2(STSMACL_OPCODE, reg); 637 oneShortOp(opc); 638 } 639 640 void stsmach(RegisterID reg) 641 { 642 uint16_t opc = getOpcodeGroup2(STSMACH_OPCODE, reg); 643 oneShortOp(opc); 644 } 645 646 // Comparisons 647 648 void cmplRegReg(RegisterID left, RegisterID right, Condition cond) 649 { 650 switch (cond) { 651 case NE: 652 oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE, right, left)); 653 break; 654 case GT: 655 oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, right, left)); 656 break; 657 case EQ: 658 oneShortOp(getOpcodeGroup1(CMPEQ_OPCODE, right, left)); 659 break; 660 case GE: 661 oneShortOp(getOpcodeGroup1(CMPGE_OPCODE, right, left)); 662 break; 663 case HS: 664 oneShortOp(getOpcodeGroup1(CMPHS_OPCODE, right, left)); 665 break; 666 case HI: 667 oneShortOp(getOpcodeGroup1(CMPHI_OPCODE, right, left)); 668 break; 669 case LI: 670 oneShortOp(getOpcodeGroup1(CMPHI_OPCODE, left, right)); 671 break; 672 case LS: 673 oneShortOp(getOpcodeGroup1(CMPHS_OPCODE, left, right)); 674 break; 675 case LE: 676 oneShortOp(getOpcodeGroup1(CMPGE_OPCODE, left, right)); 677 break; 678 case LT: 679 oneShortOp(getOpcodeGroup1(CMPGT_OPCODE, left, right)); 680 break; 681 default: 682 RELEASE_ASSERT_NOT_REACHED(); 683 } 684 } 685 686 void cmppl(RegisterID reg) 687 { 688 uint16_t opc = getOpcodeGroup2(CMPPL_OPCODE, reg); 689 oneShortOp(opc); 690 } 691 692 void cmppz(RegisterID reg) 693 { 694 uint16_t opc = getOpcodeGroup2(CMPPZ_OPCODE, reg); 695 oneShortOp(opc); 696 } 697 698 void cmpEqImmR0(int imm, RegisterID dst) 699 { 700 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 701 uint16_t opc = getOpcodeGroup5(CMPEQIMM_OPCODE, imm); 702 oneShortOp(opc); 703 } 704 705 void testlRegReg(RegisterID src, RegisterID dst) 706 { 707 uint16_t opc = getOpcodeGroup1(TST_OPCODE, dst, src); 708 oneShortOp(opc); 709 } 710 711 void testlImm8r(int imm, RegisterID dst) 712 { 713 ASSERT((imm <= 255) && (imm >= 0)); 714 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 715 716 uint16_t opc = getOpcodeGroup5(TSTIMM_OPCODE, imm); 717 oneShortOp(opc); 718 } 719 720 void nop() 721 { 722 oneShortOp(NOP_OPCODE, false); 723 } 724 725 void synco() 726 { 727 oneShortOp(SYNCO_OPCODE); 728 } 729 730 void sett() 731 { 732 oneShortOp(SETT_OPCODE); 733 } 734 735 void clrt() 736 { 737 oneShortOp(CLRT_OPCODE); 738 } 739 740 void fschg() 741 { 742 oneShortOp(FSCHG_OPCODE); 743 } 744 745 void bkpt() 746 { 747 oneShortOp(BRK_OPCODE, false); 748 } 749 750 void branch(uint16_t opc, int label) 751 { 752 switch (opc) { 753 case BT_OPCODE: 754 ASSERT((label <= 127) && (label >= -128)); 755 oneShortOp(getOpcodeGroup5(BT_OPCODE, label)); 756 break; 757 case BRA_OPCODE: 758 ASSERT((label <= 2047) && (label >= -2048)); 759 oneShortOp(getOpcodeGroup6(BRA_OPCODE, label)); 760 break; 761 case BF_OPCODE: 762 ASSERT((label <= 127) && (label >= -128)); 763 oneShortOp(getOpcodeGroup5(BF_OPCODE, label)); 764 break; 765 default: 766 RELEASE_ASSERT_NOT_REACHED(); 767 } 768 } 769 770 void branch(uint16_t opc, RegisterID reg) 771 { 772 switch (opc) { 773 case BRAF_OPCODE: 774 oneShortOp(getOpcodeGroup2(BRAF_OPCODE, reg)); 775 break; 776 case JMP_OPCODE: 777 oneShortOp(getOpcodeGroup2(JMP_OPCODE, reg)); 778 break; 779 case JSR_OPCODE: 780 oneShortOp(getOpcodeGroup2(JSR_OPCODE, reg)); 781 break; 782 case BSRF_OPCODE: 783 oneShortOp(getOpcodeGroup2(BSRF_OPCODE, reg)); 784 break; 785 default: 786 RELEASE_ASSERT_NOT_REACHED(); 787 } 788 } 789 790 void ldspr(RegisterID reg) 791 { 792 uint16_t opc = getOpcodeGroup2(LDSPR_OPCODE, reg); 793 oneShortOp(opc); 794 } 795 796 void stspr(RegisterID reg) 797 { 798 uint16_t opc = getOpcodeGroup2(STSPR_OPCODE, reg); 799 oneShortOp(opc); 800 } 801 802 void extub(RegisterID src, RegisterID dst) 803 { 804 uint16_t opc = getOpcodeGroup1(EXTUB_OPCODE, dst, src); 805 oneShortOp(opc); 806 } 807 808 void extuw(RegisterID src, RegisterID dst) 809 { 810 uint16_t opc = getOpcodeGroup1(EXTUW_OPCODE, dst, src); 811 oneShortOp(opc); 812 } 813 814 // float operations 815 816 void ldsrmfpul(RegisterID src) 817 { 818 uint16_t opc = getOpcodeGroup2(LDS_RM_FPUL_OPCODE, src); 819 oneShortOp(opc); 820 } 821 822 void fneg(FPRegisterID dst) 823 { 824 uint16_t opc = getOpcodeGroup2(FNEG_OPCODE, dst); 825 oneShortOp(opc, true, false); 826 } 827 828 void fsqrt(FPRegisterID dst) 829 { 830 uint16_t opc = getOpcodeGroup2(FSQRT_OPCODE, dst); 831 oneShortOp(opc, true, false); 832 } 833 834 void stsfpulReg(RegisterID src) 835 { 836 uint16_t opc = getOpcodeGroup2(STS_FPUL_RN_OPCODE, src); 837 oneShortOp(opc); 838 } 839 840 void floatfpulfrn(FPRegisterID src) 841 { 842 uint16_t opc = getOpcodeGroup2(FLOAT_OPCODE, src); 843 oneShortOp(opc, true, false); 844 } 845 846 void fmull(FPRegisterID src, FPRegisterID dst) 847 { 848 uint16_t opc = getOpcodeGroup1(FMUL_OPCODE, dst, src); 849 oneShortOp(opc, true, false); 850 } 851 852 void fmovsRegReg(FPRegisterID src, FPRegisterID dst) 853 { 854 uint16_t opc = getOpcodeGroup1(FMOV_OPCODE, dst, src); 855 oneShortOp(opc, true, false); 856 } 857 858 void fmovsReadrm(RegisterID src, FPRegisterID dst) 859 { 860 uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_OPCODE, dst, src); 861 oneShortOp(opc, true, false); 862 } 863 864 void fmovsWriterm(FPRegisterID src, RegisterID dst) 865 { 866 uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_RN_OPCODE, dst, src); 867 oneShortOp(opc, true, false); 868 } 869 870 void fmovsWriter0r(FPRegisterID src, RegisterID dst) 871 { 872 uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_R0RN_OPCODE, dst, src); 873 oneShortOp(opc, true, false); 874 } 875 876 void fmovsReadr0r(RegisterID src, FPRegisterID dst) 877 { 878 uint16_t opc = getOpcodeGroup1(FMOVS_READ_R0RM_OPCODE, dst, src); 879 oneShortOp(opc, true, false); 880 } 881 882 void fmovsReadrminc(RegisterID src, FPRegisterID dst) 883 { 884 uint16_t opc = getOpcodeGroup1(FMOVS_READ_RM_INC_OPCODE, dst, src); 885 oneShortOp(opc, true, false); 886 } 887 888 void fmovsWriterndec(FPRegisterID src, RegisterID dst) 889 { 890 uint16_t opc = getOpcodeGroup1(FMOVS_WRITE_RN_DEC_OPCODE, dst, src); 891 oneShortOp(opc, true, false); 892 } 893 894 void ftrcRegfpul(FPRegisterID src) 895 { 896 uint16_t opc = getOpcodeGroup2(FTRC_OPCODE, src); 897 oneShortOp(opc, true, false); 898 } 899 900 void fldsfpul(FPRegisterID src) 901 { 902 uint16_t opc = getOpcodeGroup2(FLDS_FRM_FPUL_OPCODE, src); 903 oneShortOp(opc); 904 } 905 906 void fstsfpul(FPRegisterID src) 907 { 908 uint16_t opc = getOpcodeGroup2(FSTS_FPUL_FRN_OPCODE, src); 909 oneShortOp(opc); 910 } 911 912 void ldsfpscr(RegisterID reg) 913 { 914 uint16_t opc = getOpcodeGroup2(LDSFPSCR_OPCODE, reg); 915 oneShortOp(opc); 916 } 917 918 void stsfpscr(RegisterID reg) 919 { 920 uint16_t opc = getOpcodeGroup2(STSFPSCR_OPCODE, reg); 921 oneShortOp(opc); 922 } 923 924 // double operations 925 926 void dcnvds(FPRegisterID src) 927 { 928 uint16_t opc = getOpcodeGroup7(FCNVDS_DRM_FPUL_OPCODE, src >> 1); 929 oneShortOp(opc); 930 } 931 932 void dcnvsd(FPRegisterID dst) 933 { 934 uint16_t opc = getOpcodeGroup7(FCNVSD_FPUL_DRN_OPCODE, dst >> 1); 935 oneShortOp(opc); 936 } 937 938 void dcmppeq(FPRegisterID src, FPRegisterID dst) 939 { 940 uint16_t opc = getOpcodeGroup8(FCMPEQ_OPCODE, dst >> 1, src >> 1); 941 oneShortOp(opc); 942 } 943 944 void dcmppgt(FPRegisterID src, FPRegisterID dst) 945 { 946 uint16_t opc = getOpcodeGroup8(FCMPGT_OPCODE, dst >> 1, src >> 1); 947 oneShortOp(opc); 948 } 949 950 void dmulRegReg(FPRegisterID src, FPRegisterID dst) 951 { 952 uint16_t opc = getOpcodeGroup8(FMUL_OPCODE, dst >> 1, src >> 1); 953 oneShortOp(opc); 954 } 955 956 void dsubRegReg(FPRegisterID src, FPRegisterID dst) 957 { 958 uint16_t opc = getOpcodeGroup8(FSUB_OPCODE, dst >> 1, src >> 1); 959 oneShortOp(opc); 960 } 961 962 void daddRegReg(FPRegisterID src, FPRegisterID dst) 963 { 964 uint16_t opc = getOpcodeGroup8(FADD_OPCODE, dst >> 1, src >> 1); 965 oneShortOp(opc); 966 } 967 968 void dmovRegReg(FPRegisterID src, FPRegisterID dst) 969 { 970 uint16_t opc = getOpcodeGroup8(FMOV_OPCODE, dst >> 1, src >> 1); 971 oneShortOp(opc); 972 } 973 974 void ddivRegReg(FPRegisterID src, FPRegisterID dst) 975 { 976 uint16_t opc = getOpcodeGroup8(FDIV_OPCODE, dst >> 1, src >> 1); 977 oneShortOp(opc); 978 } 979 980 void dabs(FPRegisterID dst) 981 { 982 uint16_t opc = getOpcodeGroup7(FABS_OPCODE, dst >> 1); 983 oneShortOp(opc); 984 } 985 986 void dsqrt(FPRegisterID dst) 987 { 988 uint16_t opc = getOpcodeGroup7(FSQRT_OPCODE, dst >> 1); 989 oneShortOp(opc); 990 } 991 992 void dneg(FPRegisterID dst) 993 { 994 uint16_t opc = getOpcodeGroup7(FNEG_OPCODE, dst >> 1); 995 oneShortOp(opc); 996 } 997 998 void fmovReadrm(RegisterID src, FPRegisterID dst) 999 { 1000 uint16_t opc = getOpcodeGroup10(FMOVS_READ_RM_OPCODE, dst >> 1, src); 1001 oneShortOp(opc); 1002 } 1003 1004 void fmovWriterm(FPRegisterID src, RegisterID dst) 1005 { 1006 uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_RN_OPCODE, dst, src >> 1); 1007 oneShortOp(opc); 1008 } 1009 1010 void fmovWriter0r(FPRegisterID src, RegisterID dst) 1011 { 1012 uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_R0RN_OPCODE, dst, src >> 1); 1013 oneShortOp(opc); 1014 } 1015 1016 void fmovReadr0r(RegisterID src, FPRegisterID dst) 1017 { 1018 uint16_t opc = getOpcodeGroup10(FMOVS_READ_R0RM_OPCODE, dst >> 1, src); 1019 oneShortOp(opc); 1020 } 1021 1022 void fmovReadrminc(RegisterID src, FPRegisterID dst) 1023 { 1024 uint16_t opc = getOpcodeGroup10(FMOVS_READ_RM_INC_OPCODE, dst >> 1, src); 1025 oneShortOp(opc); 1026 } 1027 1028 void fmovWriterndec(FPRegisterID src, RegisterID dst) 1029 { 1030 uint16_t opc = getOpcodeGroup9(FMOVS_WRITE_RN_DEC_OPCODE, dst, src >> 1); 1031 oneShortOp(opc); 1032 } 1033 1034 void floatfpulDreg(FPRegisterID src) 1035 { 1036 uint16_t opc = getOpcodeGroup7(FLOAT_OPCODE, src >> 1); 1037 oneShortOp(opc); 1038 } 1039 1040 void ftrcdrmfpul(FPRegisterID src) 1041 { 1042 uint16_t opc = getOpcodeGroup7(FTRC_OPCODE, src >> 1); 1043 oneShortOp(opc); 1044 } 1045 1046 // Various move ops 1047 1048 void movImm8(int imm8, RegisterID dst) 1049 { 1050 ASSERT((imm8 <= 127) && (imm8 >= -128)); 1051 1052 uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, imm8); 1053 oneShortOp(opc); 1054 } 1055 1056 void movlRegReg(RegisterID src, RegisterID dst) 1057 { 1058 uint16_t opc = getOpcodeGroup1(MOV_OPCODE, dst, src); 1059 oneShortOp(opc); 1060 } 1061 1062 void movwRegMem(RegisterID src, RegisterID dst) 1063 { 1064 uint16_t opc = getOpcodeGroup1(MOVW_WRITE_RN_OPCODE, dst, src); 1065 oneShortOp(opc); 1066 } 1067 1068 void movwMemReg(RegisterID src, RegisterID dst) 1069 { 1070 uint16_t opc = getOpcodeGroup1(MOVW_READ_RM_OPCODE, dst, src); 1071 oneShortOp(opc); 1072 } 1073 1074 void movwMemRegIn(RegisterID base, RegisterID dst) 1075 { 1076 uint16_t opc = getOpcodeGroup1(MOVW_READ_RMINC_OPCODE, dst, base); 1077 oneShortOp(opc); 1078 } 1079 1080 void movwPCReg(int offset, RegisterID base, RegisterID dst) 1081 { 1082 ASSERT_UNUSED(base, base == SH4Registers::pc); 1083 ASSERT((offset <= 255) && (offset >= 0)); 1084 1085 uint16_t opc = getOpcodeGroup3(MOVW_READ_OFFPC_OPCODE, dst, offset); 1086 oneShortOp(opc); 1087 } 1088 1089 void movwMemReg(int offset, RegisterID base, RegisterID dst) 1090 { 1091 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 1092 1093 uint16_t opc = getOpcodeGroup11(MOVW_READ_OFFRM_OPCODE, base, offset); 1094 oneShortOp(opc); 1095 } 1096 1097 void movwR0mr(RegisterID src, RegisterID dst) 1098 { 1099 uint16_t opc = getOpcodeGroup1(MOVW_READ_R0RM_OPCODE, dst, src); 1100 oneShortOp(opc); 1101 } 1102 1103 void movwRegMemr0(RegisterID src, RegisterID dst) 1104 { 1105 uint16_t opc = getOpcodeGroup1(MOVW_WRITE_R0RN_OPCODE, dst, src); 1106 oneShortOp(opc); 1107 } 1108 1109 void movlRegMem(RegisterID src, int offset, RegisterID base) 1110 { 1111 ASSERT((offset <= 15) && (offset >= 0)); 1112 1113 if (!offset) { 1114 oneShortOp(getOpcodeGroup1(MOVL_WRITE_RN_OPCODE, base, src)); 1115 return; 1116 } 1117 1118 oneShortOp(getOpcodeGroup4(MOVL_WRITE_OFFRN_OPCODE, base, src, offset)); 1119 } 1120 1121 void movlRegMem(RegisterID src, RegisterID base) 1122 { 1123 uint16_t opc = getOpcodeGroup1(MOVL_WRITE_RN_OPCODE, base, src); 1124 oneShortOp(opc); 1125 } 1126 1127 void movlMemReg(int offset, RegisterID base, RegisterID dst) 1128 { 1129 if (base == SH4Registers::pc) { 1130 ASSERT((offset <= 255) && (offset >= 0)); 1131 oneShortOp(getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, dst, offset)); 1132 return; 1133 } 1134 1135 ASSERT((offset <= 15) && (offset >= 0)); 1136 if (!offset) { 1137 oneShortOp(getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base)); 1138 return; 1139 } 1140 1141 oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE, dst, base, offset)); 1142 } 1143 1144 void movlMemRegCompact(int offset, RegisterID base, RegisterID dst) 1145 { 1146 oneShortOp(getOpcodeGroup4(MOVL_READ_OFFRM_OPCODE, dst, base, offset)); 1147 } 1148 1149 void movbRegMem(RegisterID src, RegisterID base) 1150 { 1151 uint16_t opc = getOpcodeGroup1(MOVB_WRITE_RN_OPCODE, base, src); 1152 oneShortOp(opc); 1153 } 1154 1155 void movbMemReg(int offset, RegisterID base, RegisterID dst) 1156 { 1157 ASSERT_UNUSED(dst, dst == SH4Registers::r0); 1158 1159 uint16_t opc = getOpcodeGroup11(MOVB_READ_OFFRM_OPCODE, base, offset); 1160 oneShortOp(opc); 1161 } 1162 1163 void movbR0mr(RegisterID src, RegisterID dst) 1164 { 1165 uint16_t opc = getOpcodeGroup1(MOVB_READ_R0RM_OPCODE, dst, src); 1166 oneShortOp(opc); 1167 } 1168 1169 void movbMemReg(RegisterID src, RegisterID dst) 1170 { 1171 uint16_t opc = getOpcodeGroup1(MOVB_READ_RM_OPCODE, dst, src); 1172 oneShortOp(opc); 1173 } 1174 1175 void movbMemRegIn(RegisterID base, RegisterID dst) 1176 { 1177 uint16_t opc = getOpcodeGroup1(MOVB_READ_RMINC_OPCODE, dst, base); 1178 oneShortOp(opc); 1179 } 1180 1181 void movbRegMemr0(RegisterID src, RegisterID dst) 1182 { 1183 uint16_t opc = getOpcodeGroup1(MOVB_WRITE_R0RN_OPCODE, dst, src); 1184 oneShortOp(opc); 1185 } 1186 1187 void movlMemReg(RegisterID base, RegisterID dst) 1188 { 1189 uint16_t opc = getOpcodeGroup1(MOVL_READ_RM_OPCODE, dst, base); 1190 oneShortOp(opc); 1191 } 1192 1193 void movlMemRegIn(RegisterID base, RegisterID dst) 1194 { 1195 uint16_t opc = getOpcodeGroup1(MOVL_READ_RMINC_OPCODE, dst, base); 1196 oneShortOp(opc); 1197 } 1198 1199 void movlR0mr(RegisterID src, RegisterID dst) 1200 { 1201 uint16_t opc = getOpcodeGroup1(MOVL_READ_R0RM_OPCODE, dst, src); 1202 oneShortOp(opc); 1203 } 1204 1205 void movlRegMemr0(RegisterID src, RegisterID dst) 1206 { 1207 uint16_t opc = getOpcodeGroup1(MOVL_WRITE_R0RN_OPCODE, dst, src); 1208 oneShortOp(opc); 1209 } 1210 1211 void loadConstant(uint32_t constant, RegisterID dst) 1212 { 1213 if (((int)constant <= 0x7f) && ((int)constant >= -0x80)) { 1214 movImm8(constant, dst); 1215 return; 1216 } 1217 1218 uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, 0); 1219 1220 m_buffer.ensureSpace(maxInstructionSize, sizeof(uint32_t)); 1221 printInstr(getOpcodeGroup3(MOVIMM_OPCODE, dst, constant), m_buffer.codeSize()); 1222 m_buffer.putShortWithConstantInt(opc, constant, true); 1223 } 1224 1225 void loadConstantUnReusable(uint32_t constant, RegisterID dst, bool ensureSpace = false) 1226 { 1227 uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, 0); 1228 1229 if (ensureSpace) 1230 m_buffer.ensureSpace(maxInstructionSize, sizeof(uint32_t)); 1231 1232 printInstr(getOpcodeGroup3(MOVIMM_OPCODE, dst, constant), m_buffer.codeSize()); 1233 m_buffer.putShortWithConstantInt(opc, constant); 1234 } 1235 1236 // Flow control 1237 1238 AssemblerLabel call() 1239 { 1240 RegisterID scr = claimScratch(); 1241 m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t)); 1242 loadConstantUnReusable(0x0, scr); 1243 branch(JSR_OPCODE, scr); 1244 nop(); 1245 releaseScratch(scr); 1246 return m_buffer.label(); 1247 } 1248 1249 AssemblerLabel call(RegisterID dst) 1250 { 1251 m_buffer.ensureSpace(maxInstructionSize + 2); 1252 branch(JSR_OPCODE, dst); 1253 nop(); 1254 return m_buffer.label(); 1255 } 1256 1257 AssemblerLabel jmp() 1258 { 1259 RegisterID scr = claimScratch(); 1260 m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t)); 1261 loadConstantUnReusable(0x0, scr); 1262 branch(BRAF_OPCODE, scr); 1263 nop(); 1264 releaseScratch(scr); 1265 return m_buffer.label(); 1266 } 1267 1268 AssemblerLabel extraInstrForBranch(RegisterID dst) 1269 { 1270 loadConstantUnReusable(0x0, dst); 1271 branch(BRAF_OPCODE, dst); 1272 nop(); 1273 return m_buffer.label(); 1274 } 1275 1276 AssemblerLabel jmp(RegisterID dst) 1277 { 1278 jmpReg(dst); 1279 return m_buffer.label(); 1280 } 1281 1282 void jmpReg(RegisterID dst) 1283 { 1284 m_buffer.ensureSpace(maxInstructionSize + 2); 1285 branch(JMP_OPCODE, dst); 1286 nop(); 1287 } 1288 1289 AssemblerLabel jne() 1290 { 1291 branch(BF_OPCODE, 0); 1292 return m_buffer.label(); 1293 } 1294 1295 AssemblerLabel je() 1296 { 1297 branch(BT_OPCODE, 0); 1298 return m_buffer.label(); 1299 } 1300 1301 AssemblerLabel bra() 1302 { 1303 branch(BRA_OPCODE, 0); 1304 return m_buffer.label(); 1305 } 1306 1307 void ret() 1308 { 1309 m_buffer.ensureSpace(maxInstructionSize + 2); 1310 oneShortOp(RTS_OPCODE, false); 1311 } 1312 1313 AssemblerLabel labelIgnoringWatchpoints() 1314 { 1315 m_buffer.ensureSpaceForAnyInstruction(); 1316 return m_buffer.label(); 1317 } 1318 1319 AssemblerLabel labelForWatchpoint() 1320 { 1321 m_buffer.ensureSpaceForAnyInstruction(); 1322 AssemblerLabel result = m_buffer.label(); 1323 if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) 1324 result = label(); 1325 m_indexOfLastWatchpoint = result.m_offset; 1326 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); 1327 return result; 1328 } 1329 1330 AssemblerLabel label() 1331 { 1332 AssemblerLabel result = labelIgnoringWatchpoints(); 1333 while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { 1334 nop(); 1335 result = labelIgnoringWatchpoints(); 1336 } 1337 return result; 1338 } 1339 1340 int sizeOfConstantPool() 1341 { 1342 return m_buffer.sizeOfConstantPool(); 1343 } 1344 1345 AssemblerLabel align(int alignment) 1346 { 1347 m_buffer.ensureSpace(maxInstructionSize + 2); 1348 while (!m_buffer.isAligned(alignment)) { 1349 nop(); 1350 m_buffer.ensureSpace(maxInstructionSize + 2); 1351 } 1352 return label(); 1353 } 1354 1355 static void changePCrelativeAddress(int offset, uint16_t* instructionPtr, uint32_t newAddress) 1356 { 1357 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1358 uint32_t address = (offset << 2) + ((reinterpret_cast<uint32_t>(instructionPtr) + 4) &(~0x3)); 1359 *reinterpret_cast<uint32_t*>(address) = newAddress; 1360 } 1361 1362 static uint32_t readPCrelativeAddress(int offset, uint16_t* instructionPtr) 1363 { 1364 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1365 uint32_t address = (offset << 2) + ((reinterpret_cast<uint32_t>(instructionPtr) + 4) &(~0x3)); 1366 return *reinterpret_cast<uint32_t*>(address); 1367 } 1368 1369 static uint16_t* getInstructionPtr(void* code, int offset) 1370 { 1371 return reinterpret_cast<uint16_t*> (reinterpret_cast<uint32_t>(code) + offset); 1372 } 1373 1374 static void linkJump(void* code, AssemblerLabel from, void* to) 1375 { 1376 ASSERT(from.isSet()); 1377 1378 uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset) - 3; 1379 int offsetBits = (reinterpret_cast<uint32_t>(to) - reinterpret_cast<uint32_t>(code)) - from.m_offset; 1380 1381 /* MOV #imm, reg => LDR reg 1382 braf @reg braf @reg 1383 nop nop 1384 */ 1385 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1386 ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE); 1387 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); 1388 printInstr(*instructionPtr, from.m_offset + 2); 1389 } 1390 1391 static void linkCall(void* code, AssemblerLabel from, void* to) 1392 { 1393 uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset); 1394 instructionPtr -= 3; 1395 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1396 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to)); 1397 } 1398 1399 static void linkPointer(void* code, AssemblerLabel where, void* value) 1400 { 1401 uint16_t* instructionPtr = getInstructionPtr(code, where.m_offset); 1402 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1403 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(value)); 1404 } 1405 1406 static unsigned getCallReturnOffset(AssemblerLabel call) 1407 { 1408 ASSERT(call.isSet()); 1409 return call.m_offset; 1410 } 1411 1412 static uint32_t* getLdrImmAddressOnPool(SH4Word* insn, uint32_t* constPool) 1413 { 1414 return (constPool + (*insn & 0xff)); 1415 } 1416 1417 static SH4Word patchConstantPoolLoad(SH4Word load, int value) 1418 { 1419 return ((load & ~0xff) | value); 1420 } 1421 1422 static SH4Buffer::TwoShorts placeConstantPoolBarrier(int offset) 1423 { 1424 ASSERT(((offset >> 1) <= 2047) && ((offset >> 1) >= -2048)); 1425 1426 SH4Buffer::TwoShorts m_barrier; 1427 m_barrier.high = (BRA_OPCODE | (offset >> 1)); 1428 m_barrier.low = NOP_OPCODE; 1429 printInstr(((BRA_OPCODE | (offset >> 1))), 0); 1430 printInstr(NOP_OPCODE, 0); 1431 return m_barrier; 1432 } 1433 1434 static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr) 1435 { 1436 SH4Word* instructionPtr = reinterpret_cast<SH4Word*>(loadAddr); 1437 SH4Word instruction = *instructionPtr; 1438 SH4Word index = instruction & 0xff; 1439 1440 if ((instruction & 0xf000) != MOVIMM_OPCODE) 1441 return; 1442 1443 ASSERT((((reinterpret_cast<uint32_t>(constPoolAddr) - reinterpret_cast<uint32_t>(loadAddr)) + index * 4)) < 1024); 1444 1445 int offset = reinterpret_cast<uint32_t>(constPoolAddr) + (index * 4) - ((reinterpret_cast<uint32_t>(instructionPtr) & ~0x03) + 4); 1446 instruction &= 0x0f00; 1447 instruction |= 0xd000; 1448 offset &= 0x03ff; 1449 instruction |= (offset >> 2); 1450 *instructionPtr = instruction; 1451 printInstr(instruction, reinterpret_cast<uint32_t>(loadAddr)); 1452 } 1453 1454 static void repatchPointer(void* where, void* value) 1455 { 1456 patchPointer(where, value); 1457 } 1458 1459 static void* readPointer(void* code) 1460 { 1461 return reinterpret_cast<void*>(readInt32(code)); 1462 } 1463 1464 static void repatchInt32(void* where, int32_t value) 1465 { 1466 uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(where); 1467 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1468 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, value); 1469 } 1470 1471 static void repatchCompact(void* where, int32_t value) 1472 { 1473 uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(where); 1474 ASSERT(value >= 0); 1475 ASSERT(value <= 60); 1476 1477 // Handle the uncommon case where a flushConstantPool occured in movlMemRegCompact. 1478 if ((instructionPtr[0] & 0xf000) == BRA_OPCODE) 1479 instructionPtr += (instructionPtr[0] & 0x0fff) + 2; 1480 1481 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFRM_OPCODE); 1482 instructionPtr[0] = (instructionPtr[0] & 0xfff0) | (value >> 2); 1483 cacheFlush(instructionPtr, sizeof(uint16_t)); 1484 } 1485 1486 static void relinkCall(void* from, void* to) 1487 { 1488 uint16_t* instructionPtr = reinterpret_cast<uint16_t*>(from); 1489 instructionPtr -= 3; 1490 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1491 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to)); 1492 } 1493 1494 static void relinkJump(void* from, void* to) 1495 { 1496 uint16_t* instructionPtr = reinterpret_cast<uint16_t*> (from); 1497 instructionPtr -= 3; 1498 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1499 ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE); 1500 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast<uint32_t>(to) - reinterpret_cast<uint32_t>(from)); 1501 } 1502 1503 // Linking & patching 1504 1505 static ptrdiff_t maxJumpReplacementSize() 1506 { 1507 return sizeof(SH4Word) * 6; 1508 } 1509 1510 static void replaceWithJump(void *instructionStart, void *to) 1511 { 1512 SH4Word* instruction = reinterpret_cast<SH4Word*>(instructionStart); 1513 intptr_t difference = reinterpret_cast<intptr_t>(to) - (reinterpret_cast<intptr_t>(instruction) + 3 * sizeof(SH4Word)); 1514 1515 if ((instruction[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE) { 1516 // We have an entry in constant pool and we potentially replace a branchPtrWithPatch, so let's backup what would be the 1517 // condition (CMP/xx and Bx opcodes) for later use in revertJumpReplacementToBranchPtrWithPatch before putting the jump. 1518 instruction[4] = instruction[1]; 1519 instruction[5] = instruction[2]; 1520 instruction[1] = (BRAF_OPCODE | (instruction[0] & 0x0f00)); 1521 instruction[2] = NOP_OPCODE; 1522 cacheFlush(&instruction[1], 2 * sizeof(SH4Word)); 1523 } else { 1524 instruction[0] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, SH4Registers::r13, 1); 1525 instruction[1] = getOpcodeGroup2(BRAF_OPCODE, SH4Registers::r13); 1526 instruction[2] = NOP_OPCODE; 1527 cacheFlush(instruction, 3 * sizeof(SH4Word)); 1528 } 1529 1530 changePCrelativeAddress(instruction[0] & 0x00ff, instruction, difference); 1531 } 1532 1533 static void revertJumpReplacementToBranchPtrWithPatch(void* instructionStart, RegisterID rd, int imm) 1534 { 1535 SH4Word *insn = reinterpret_cast<SH4Word*>(instructionStart); 1536 ASSERT((insn[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1537 ASSERT((insn[0] & 0x00ff) != 1); 1538 1539 insn[0] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, SH4Registers::r13, insn[0] & 0x00ff); 1540 if ((insn[1] & 0xf0ff) == BRAF_OPCODE) { 1541 insn[1] = (insn[4] & 0xf00f) | (rd << 8) | (SH4Registers::r13 << 4); // Restore CMP/xx opcode. 1542 insn[2] = insn[5]; 1543 ASSERT(((insn[2] & 0xff00) == BT_OPCODE) || ((insn[2] & 0xff00) == BF_OPCODE)); 1544 ASSERT((insn[3] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1545 insn[4] = (BRAF_OPCODE | (insn[3] & 0x0f00)); 1546 insn[5] = NOP_OPCODE; 1547 cacheFlush(insn, 6 * sizeof(SH4Word)); 1548 } else { 1549 // The branchPtrWithPatch has already been restored, so we just patch the immediate value and ASSERT all is as expected. 1550 ASSERT((insn[1] & 0xf000) == 0x3000); 1551 insn[1] = (insn[1] & 0xf00f) | (rd << 8) | (SH4Registers::r13 << 4); 1552 cacheFlush(insn, 2 * sizeof(SH4Word)); 1553 ASSERT(((insn[2] & 0xff00) == BT_OPCODE) || ((insn[2] & 0xff00) == BF_OPCODE)); 1554 ASSERT((insn[3] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1555 ASSERT(insn[5] == NOP_OPCODE); 1556 } 1557 1558 changePCrelativeAddress(insn[0] & 0x00ff, insn, imm); 1559 } 1560 1561 void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type = JumpFar) 1562 { 1563 ASSERT(to.isSet()); 1564 ASSERT(from.isSet()); 1565 1566 uint16_t* instructionPtr = getInstructionPtr(data(), from.m_offset) - 1; 1567 int offsetBits = (to.m_offset - from.m_offset); 1568 1569 if (type == JumpNear) { 1570 uint16_t instruction = instructionPtr[0]; 1571 int offset = (offsetBits - 2); 1572 ASSERT((((instruction == BT_OPCODE) || (instruction == BF_OPCODE)) && (offset >= -256) && (offset <= 254)) 1573 || ((instruction == BRA_OPCODE) && (offset >= -4096) && (offset <= 4094))); 1574 *instructionPtr++ = instruction | (offset >> 1); 1575 printInstr(*instructionPtr, from.m_offset + 2); 1576 return; 1577 } 1578 1579 /* MOV # imm, reg => LDR reg 1580 braf @reg braf @reg 1581 nop nop 1582 */ 1583 instructionPtr -= 2; 1584 ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE); 1585 1586 if ((instructionPtr[0] & 0xf000) == MOVIMM_OPCODE) { 1587 uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress()); 1588 *addr = offsetBits; 1589 printInstr(*instructionPtr, from.m_offset + 2); 1590 return; 1591 } 1592 1593 ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); 1594 changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); 1595 printInstr(*instructionPtr, from.m_offset + 2); 1596 } 1597 1598 static void* getRelocatedAddress(void* code, AssemblerLabel label) 1599 { 1600 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset); 1601 } 1602 1603 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b) 1604 { 1605 return b.m_offset - a.m_offset; 1606 } 1607 1608 static void patchPointer(void* code, AssemblerLabel where, void* value) 1609 { 1610 patchPointer(reinterpret_cast<uint32_t*>(code) + where.m_offset, value); 1611 } 1612 1613 static void patchPointer(void* code, void* value) 1614 { 1615 patchInt32(code, reinterpret_cast<uint32_t>(value)); 1616 } 1617 1618 static void patchInt32(void* code, uint32_t value) 1619 { 1620 changePCrelativeAddress((*(reinterpret_cast<uint16_t*>(code)) & 0xff), reinterpret_cast<uint16_t*>(code), value); 1621 } 1622 1623 static uint32_t readInt32(void* code) 1624 { 1625 return readPCrelativeAddress((*(reinterpret_cast<uint16_t*>(code)) & 0xff), reinterpret_cast<uint16_t*>(code)); 1626 } 1627 1628 static void* readCallTarget(void* from) 1629 { 1630 uint16_t* instructionPtr = static_cast<uint16_t*>(from); 1631 instructionPtr -= 3; 1632 return reinterpret_cast<void*>(readPCrelativeAddress((*instructionPtr & 0xff), instructionPtr)); 1633 } 1634 1635 static void cacheFlush(void* code, size_t size) 1636 { 1637#if OS(LINUX) 1638 // Flush each page separately, otherwise the whole flush will fail if an uncommited page is in the area. 1639 unsigned currentPage = reinterpret_cast<unsigned>(code) & ~(pageSize() - 1); 1640 unsigned lastPage = (reinterpret_cast<unsigned>(code) + size - 1) & ~(pageSize() - 1); 1641 do { 1642#if defined CACHEFLUSH_D_L2 1643 syscall(__NR_cacheflush, currentPage, pageSize(), CACHEFLUSH_D_WB | CACHEFLUSH_I | CACHEFLUSH_D_L2); 1644#else 1645 syscall(__NR_cacheflush, currentPage, pageSize(), CACHEFLUSH_D_WB | CACHEFLUSH_I); 1646#endif 1647 currentPage += pageSize(); 1648 } while (lastPage >= currentPage); 1649#else 1650#error "The cacheFlush support is missing on this platform." 1651#endif 1652 } 1653 1654 void prefix(uint16_t pre) 1655 { 1656 m_buffer.putByte(pre); 1657 } 1658 1659 void oneShortOp(uint16_t opcode, bool checksize = true, bool isDouble = true) 1660 { 1661 printInstr(opcode, m_buffer.codeSize(), isDouble); 1662 if (checksize) 1663 m_buffer.ensureSpace(maxInstructionSize); 1664 m_buffer.putShortUnchecked(opcode); 1665 } 1666 1667 void ensureSpace(int space) 1668 { 1669 m_buffer.ensureSpace(space); 1670 } 1671 1672 void ensureSpace(int insnSpace, int constSpace) 1673 { 1674 m_buffer.ensureSpace(insnSpace, constSpace); 1675 } 1676 1677 // Administrative methods 1678 1679 void* data() const { return m_buffer.data(); } 1680 size_t codeSize() const { return m_buffer.codeSize(); } 1681 1682 unsigned debugOffset() { return m_buffer.debugOffset(); } 1683 1684#ifdef SH4_ASSEMBLER_TRACING 1685 static void printInstr(uint16_t opc, unsigned size, bool isdoubleInst = true) 1686 { 1687 if (!getenv("JavaScriptCoreDumpJIT")) 1688 return; 1689 1690 const char *format = 0; 1691 printfStdoutInstr("offset: 0x%8.8x\t", size); 1692 switch (opc) { 1693 case BRK_OPCODE: 1694 format = " BRK\n"; 1695 break; 1696 case NOP_OPCODE: 1697 format = " NOP\n"; 1698 break; 1699 case RTS_OPCODE: 1700 format =" *RTS\n"; 1701 break; 1702 case SETS_OPCODE: 1703 format = " SETS\n"; 1704 break; 1705 case SETT_OPCODE: 1706 format = " SETT\n"; 1707 break; 1708 case CLRT_OPCODE: 1709 format = " CLRT\n"; 1710 break; 1711 case FSCHG_OPCODE: 1712 format = " FSCHG\n"; 1713 break; 1714 } 1715 if (format) { 1716 printfStdoutInstr(format); 1717 return; 1718 } 1719 switch (opc & 0xf0ff) { 1720 case BRAF_OPCODE: 1721 format = " *BRAF R%d\n"; 1722 break; 1723 case DT_OPCODE: 1724 format = " DT R%d\n"; 1725 break; 1726 case CMPPL_OPCODE: 1727 format = " CMP/PL R%d\n"; 1728 break; 1729 case CMPPZ_OPCODE: 1730 format = " CMP/PZ R%d\n"; 1731 break; 1732 case JMP_OPCODE: 1733 format = " *JMP @R%d\n"; 1734 break; 1735 case JSR_OPCODE: 1736 format = " *JSR @R%d\n"; 1737 break; 1738 case LDSPR_OPCODE: 1739 format = " LDS R%d, PR\n"; 1740 break; 1741 case LDSLPR_OPCODE: 1742 format = " LDS.L @R%d+, PR\n"; 1743 break; 1744 case MOVT_OPCODE: 1745 format = " MOVT R%d\n"; 1746 break; 1747 case SHAL_OPCODE: 1748 format = " SHAL R%d\n"; 1749 break; 1750 case SHAR_OPCODE: 1751 format = " SHAR R%d\n"; 1752 break; 1753 case SHLL_OPCODE: 1754 format = " SHLL R%d\n"; 1755 break; 1756 case SHLL2_OPCODE: 1757 format = " SHLL2 R%d\n"; 1758 break; 1759 case SHLL8_OPCODE: 1760 format = " SHLL8 R%d\n"; 1761 break; 1762 case SHLL16_OPCODE: 1763 format = " SHLL16 R%d\n"; 1764 break; 1765 case SHLR_OPCODE: 1766 format = " SHLR R%d\n"; 1767 break; 1768 case SHLR2_OPCODE: 1769 format = " SHLR2 R%d\n"; 1770 break; 1771 case SHLR8_OPCODE: 1772 format = " SHLR8 R%d\n"; 1773 break; 1774 case SHLR16_OPCODE: 1775 format = " SHLR16 R%d\n"; 1776 break; 1777 case STSPR_OPCODE: 1778 format = " STS PR, R%d\n"; 1779 break; 1780 case STSLPR_OPCODE: 1781 format = " STS.L PR, @-R%d\n"; 1782 break; 1783 case LDS_RM_FPUL_OPCODE: 1784 format = " LDS R%d, FPUL\n"; 1785 break; 1786 case STS_FPUL_RN_OPCODE: 1787 format = " STS FPUL, R%d \n"; 1788 break; 1789 case FLDS_FRM_FPUL_OPCODE: 1790 format = " FLDS FR%d, FPUL\n"; 1791 break; 1792 case FSTS_FPUL_FRN_OPCODE: 1793 format = " FSTS FPUL, R%d \n"; 1794 break; 1795 case LDSFPSCR_OPCODE: 1796 format = " LDS R%d, FPSCR \n"; 1797 break; 1798 case STSFPSCR_OPCODE: 1799 format = " STS FPSCR, R%d \n"; 1800 break; 1801 case STSMACL_OPCODE: 1802 format = " STS MACL, R%d \n"; 1803 break; 1804 case STSMACH_OPCODE: 1805 format = " STS MACH, R%d \n"; 1806 break; 1807 case BSRF_OPCODE: 1808 format = " *BSRF R%d"; 1809 break; 1810 case FTRC_OPCODE: 1811 format = " FTRC FR%d, FPUL\n"; 1812 break; 1813 } 1814 if (format) { 1815 printfStdoutInstr(format, getRn(opc)); 1816 return; 1817 } 1818 switch (opc & 0xf0ff) { 1819 case FNEG_OPCODE: 1820 format = " FNEG DR%d\n"; 1821 break; 1822 case FLOAT_OPCODE: 1823 format = " FLOAT DR%d\n"; 1824 break; 1825 case FTRC_OPCODE: 1826 format = " FTRC FR%d, FPUL\n"; 1827 break; 1828 case FABS_OPCODE: 1829 format = " FABS FR%d\n"; 1830 break; 1831 case FSQRT_OPCODE: 1832 format = " FSQRT FR%d\n"; 1833 break; 1834 case FCNVDS_DRM_FPUL_OPCODE: 1835 format = " FCNVDS FR%d, FPUL\n"; 1836 break; 1837 case FCNVSD_FPUL_DRN_OPCODE: 1838 format = " FCNVSD FPUL, FR%d\n"; 1839 break; 1840 } 1841 if (format) { 1842 if (isdoubleInst) 1843 printfStdoutInstr(format, getDRn(opc) << 1); 1844 else 1845 printfStdoutInstr(format, getRn(opc)); 1846 return; 1847 } 1848 switch (opc & 0xf00f) { 1849 case ADD_OPCODE: 1850 format = " ADD R%d, R%d\n"; 1851 break; 1852 case ADDC_OPCODE: 1853 format = " ADDC R%d, R%d\n"; 1854 break; 1855 case ADDV_OPCODE: 1856 format = " ADDV R%d, R%d\n"; 1857 break; 1858 case AND_OPCODE: 1859 format = " AND R%d, R%d\n"; 1860 break; 1861 case DIV1_OPCODE: 1862 format = " DIV1 R%d, R%d\n"; 1863 break; 1864 case CMPEQ_OPCODE: 1865 format = " CMP/EQ R%d, R%d\n"; 1866 break; 1867 case CMPGE_OPCODE: 1868 format = " CMP/GE R%d, R%d\n"; 1869 break; 1870 case CMPGT_OPCODE: 1871 format = " CMP/GT R%d, R%d\n"; 1872 break; 1873 case CMPHI_OPCODE: 1874 format = " CMP/HI R%d, R%d\n"; 1875 break; 1876 case CMPHS_OPCODE: 1877 format = " CMP/HS R%d, R%d\n"; 1878 break; 1879 case MOV_OPCODE: 1880 format = " MOV R%d, R%d\n"; 1881 break; 1882 case MOVB_WRITE_RN_OPCODE: 1883 format = " MOV.B R%d, @R%d\n"; 1884 break; 1885 case MOVB_WRITE_RNDEC_OPCODE: 1886 format = " MOV.B R%d, @-R%d\n"; 1887 break; 1888 case MOVB_WRITE_R0RN_OPCODE: 1889 format = " MOV.B R%d, @(R0, R%d)\n"; 1890 break; 1891 case MOVB_READ_RM_OPCODE: 1892 format = " MOV.B @R%d, R%d\n"; 1893 break; 1894 case MOVB_READ_RMINC_OPCODE: 1895 format = " MOV.B @R%d+, R%d\n"; 1896 break; 1897 case MOVB_READ_R0RM_OPCODE: 1898 format = " MOV.B @(R0, R%d), R%d\n"; 1899 break; 1900 case MOVL_WRITE_RN_OPCODE: 1901 format = " MOV.L R%d, @R%d\n"; 1902 break; 1903 case MOVL_WRITE_RNDEC_OPCODE: 1904 format = " MOV.L R%d, @-R%d\n"; 1905 break; 1906 case MOVL_WRITE_R0RN_OPCODE: 1907 format = " MOV.L R%d, @(R0, R%d)\n"; 1908 break; 1909 case MOVL_READ_RM_OPCODE: 1910 format = " MOV.L @R%d, R%d\n"; 1911 break; 1912 case MOVL_READ_RMINC_OPCODE: 1913 format = " MOV.L @R%d+, R%d\n"; 1914 break; 1915 case MOVL_READ_R0RM_OPCODE: 1916 format = " MOV.L @(R0, R%d), R%d\n"; 1917 break; 1918 case MULL_OPCODE: 1919 format = " MUL.L R%d, R%d\n"; 1920 break; 1921 case DMULL_L_OPCODE: 1922 format = " DMULU.L R%d, R%d\n"; 1923 break; 1924 case DMULSL_OPCODE: 1925 format = " DMULS.L R%d, R%d\n"; 1926 break; 1927 case NEG_OPCODE: 1928 format = " NEG R%d, R%d\n"; 1929 break; 1930 case NEGC_OPCODE: 1931 format = " NEGC R%d, R%d\n"; 1932 break; 1933 case NOT_OPCODE: 1934 format = " NOT R%d, R%d\n"; 1935 break; 1936 case OR_OPCODE: 1937 format = " OR R%d, R%d\n"; 1938 break; 1939 case SHAD_OPCODE: 1940 format = " SHAD R%d, R%d\n"; 1941 break; 1942 case SHLD_OPCODE: 1943 format = " SHLD R%d, R%d\n"; 1944 break; 1945 case SUB_OPCODE: 1946 format = " SUB R%d, R%d\n"; 1947 break; 1948 case SUBC_OPCODE: 1949 format = " SUBC R%d, R%d\n"; 1950 break; 1951 case SUBV_OPCODE: 1952 format = " SUBV R%d, R%d\n"; 1953 break; 1954 case TST_OPCODE: 1955 format = " TST R%d, R%d\n"; 1956 break; 1957 case XOR_OPCODE: 1958 format = " XOR R%d, R%d\n";break; 1959 case MOVW_WRITE_RN_OPCODE: 1960 format = " MOV.W R%d, @R%d\n"; 1961 break; 1962 case MOVW_READ_RM_OPCODE: 1963 format = " MOV.W @R%d, R%d\n"; 1964 break; 1965 case MOVW_READ_RMINC_OPCODE: 1966 format = " MOV.W @R%d+, R%d\n"; 1967 break; 1968 case MOVW_READ_R0RM_OPCODE: 1969 format = " MOV.W @(R0, R%d), R%d\n"; 1970 break; 1971 case MOVW_WRITE_R0RN_OPCODE: 1972 format = " MOV.W R%d, @(R0, R%d)\n"; 1973 break; 1974 case EXTUB_OPCODE: 1975 format = " EXTU.B R%d, R%d\n"; 1976 break; 1977 case EXTUW_OPCODE: 1978 format = " EXTU.W R%d, R%d\n"; 1979 break; 1980 } 1981 if (format) { 1982 printfStdoutInstr(format, getRm(opc), getRn(opc)); 1983 return; 1984 } 1985 switch (opc & 0xf00f) { 1986 case FSUB_OPCODE: 1987 format = " FSUB FR%d, FR%d\n"; 1988 break; 1989 case FADD_OPCODE: 1990 format = " FADD FR%d, FR%d\n"; 1991 break; 1992 case FDIV_OPCODE: 1993 format = " FDIV FR%d, FR%d\n"; 1994 break; 1995 case FMUL_OPCODE: 1996 format = " DMULL FR%d, FR%d\n"; 1997 break; 1998 case FMOV_OPCODE: 1999 format = " FMOV FR%d, FR%d\n"; 2000 break; 2001 case FCMPEQ_OPCODE: 2002 format = " FCMP/EQ FR%d, FR%d\n"; 2003 break; 2004 case FCMPGT_OPCODE: 2005 format = " FCMP/GT FR%d, FR%d\n"; 2006 break; 2007 } 2008 if (format) { 2009 if (isdoubleInst) 2010 printfStdoutInstr(format, getDRm(opc) << 1, getDRn(opc) << 1); 2011 else 2012 printfStdoutInstr(format, getRm(opc), getRn(opc)); 2013 return; 2014 } 2015 switch (opc & 0xf00f) { 2016 case FMOVS_WRITE_RN_DEC_OPCODE: 2017 format = " %s FR%d, @-R%d\n"; 2018 break; 2019 case FMOVS_WRITE_RN_OPCODE: 2020 format = " %s FR%d, @R%d\n"; 2021 break; 2022 case FMOVS_WRITE_R0RN_OPCODE: 2023 format = " %s FR%d, @(R0, R%d)\n"; 2024 break; 2025 } 2026 if (format) { 2027 if (isdoubleInst) 2028 printfStdoutInstr(format, "FMOV", getDRm(opc) << 1, getDRn(opc)); 2029 else 2030 printfStdoutInstr(format, "FMOV.S", getRm(opc), getRn(opc)); 2031 return; 2032 } 2033 switch (opc & 0xf00f) { 2034 case FMOVS_READ_RM_OPCODE: 2035 format = " %s @R%d, FR%d\n"; 2036 break; 2037 case FMOVS_READ_RM_INC_OPCODE: 2038 format = " %s @R%d+, FR%d\n"; 2039 break; 2040 case FMOVS_READ_R0RM_OPCODE: 2041 format = " %s @(R0, R%d), FR%d\n"; 2042 break; 2043 } 2044 if (format) { 2045 if (isdoubleInst) 2046 printfStdoutInstr(format, "FMOV", getDRm(opc), getDRn(opc) << 1); 2047 else 2048 printfStdoutInstr(format, "FMOV.S", getRm(opc), getRn(opc)); 2049 return; 2050 } 2051 switch (opc & 0xff00) { 2052 case BF_OPCODE: 2053 format = " BF %d\n"; 2054 break; 2055 case BFS_OPCODE: 2056 format = " *BF/S %d\n"; 2057 break; 2058 case ANDIMM_OPCODE: 2059 format = " AND #%d, R0\n"; 2060 break; 2061 case BT_OPCODE: 2062 format = " BT %d\n"; 2063 break; 2064 case BTS_OPCODE: 2065 format = " *BT/S %d\n"; 2066 break; 2067 case CMPEQIMM_OPCODE: 2068 format = " CMP/EQ #%d, R0\n"; 2069 break; 2070 case MOVB_WRITE_OFFGBR_OPCODE: 2071 format = " MOV.B R0, @(%d, GBR)\n"; 2072 break; 2073 case MOVB_READ_OFFGBR_OPCODE: 2074 format = " MOV.B @(%d, GBR), R0\n"; 2075 break; 2076 case MOVL_WRITE_OFFGBR_OPCODE: 2077 format = " MOV.L R0, @(%d, GBR)\n"; 2078 break; 2079 case MOVL_READ_OFFGBR_OPCODE: 2080 format = " MOV.L @(%d, GBR), R0\n"; 2081 break; 2082 case MOVA_READ_OFFPC_OPCODE: 2083 format = " MOVA @(%d, PC), R0\n"; 2084 break; 2085 case ORIMM_OPCODE: 2086 format = " OR #%d, R0\n"; 2087 break; 2088 case ORBIMM_OPCODE: 2089 format = " OR.B #%d, @(R0, GBR)\n"; 2090 break; 2091 case TSTIMM_OPCODE: 2092 format = " TST #%d, R0\n"; 2093 break; 2094 case TSTB_OPCODE: 2095 format = " TST.B %d, @(R0, GBR)\n"; 2096 break; 2097 case XORIMM_OPCODE: 2098 format = " XOR #%d, R0\n"; 2099 break; 2100 case XORB_OPCODE: 2101 format = " XOR.B %d, @(R0, GBR)\n"; 2102 break; 2103 } 2104 if (format) { 2105 printfStdoutInstr(format, getImm8(opc)); 2106 return; 2107 } 2108 switch (opc & 0xff00) { 2109 case MOVB_WRITE_OFFRN_OPCODE: 2110 format = " MOV.B R0, @(%d, R%d)\n"; 2111 break; 2112 case MOVB_READ_OFFRM_OPCODE: 2113 format = " MOV.B @(%d, R%d), R0\n"; 2114 break; 2115 } 2116 if (format) { 2117 printfStdoutInstr(format, getDisp(opc), getRm(opc)); 2118 return; 2119 } 2120 switch (opc & 0xf000) { 2121 case BRA_OPCODE: 2122 format = " *BRA %d\n"; 2123 break; 2124 case BSR_OPCODE: 2125 format = " *BSR %d\n"; 2126 break; 2127 } 2128 if (format) { 2129 printfStdoutInstr(format, getImm12(opc)); 2130 return; 2131 } 2132 switch (opc & 0xf000) { 2133 case MOVL_READ_OFFPC_OPCODE: 2134 format = " MOV.L @(%d, PC), R%d\n"; 2135 break; 2136 case ADDIMM_OPCODE: 2137 format = " ADD #%d, R%d\n"; 2138 break; 2139 case MOVIMM_OPCODE: 2140 format = " MOV #%d, R%d\n"; 2141 break; 2142 case MOVW_READ_OFFPC_OPCODE: 2143 format = " MOV.W @(%d, PC), R%d\n"; 2144 break; 2145 } 2146 if (format) { 2147 printfStdoutInstr(format, getImm8(opc), getRn(opc)); 2148 return; 2149 } 2150 switch (opc & 0xf000) { 2151 case MOVL_WRITE_OFFRN_OPCODE: 2152 format = " MOV.L R%d, @(%d, R%d)\n"; 2153 printfStdoutInstr(format, getRm(opc), getDisp(opc), getRn(opc)); 2154 break; 2155 case MOVL_READ_OFFRM_OPCODE: 2156 format = " MOV.L @(%d, R%d), R%d\n"; 2157 printfStdoutInstr(format, getDisp(opc), getRm(opc), getRn(opc)); 2158 break; 2159 } 2160 } 2161 2162 static void printfStdoutInstr(const char* format, ...) 2163 { 2164 if (getenv("JavaScriptCoreDumpJIT")) { 2165 va_list args; 2166 va_start(args, format); 2167 vprintfStdoutInstr(format, args); 2168 va_end(args); 2169 } 2170 } 2171 2172 static void vprintfStdoutInstr(const char* format, va_list args) 2173 { 2174 if (getenv("JavaScriptCoreDumpJIT")) 2175 WTF::dataLogFV(format, args); 2176 } 2177 2178 static void printBlockInstr(uint16_t* first, unsigned offset, int nbInstr) 2179 { 2180 printfStdoutInstr(">> repatch instructions after link\n"); 2181 for (int i = 0; i <= nbInstr; i++) 2182 printInstr(*(first + i), offset + i); 2183 printfStdoutInstr(">> end repatch\n"); 2184 } 2185#else 2186 static void printInstr(uint16_t, unsigned, bool = true) { }; 2187 static void printBlockInstr(uint16_t*, unsigned, int) { }; 2188#endif 2189 2190 static void replaceWithLoad(void* instructionStart) 2191 { 2192 SH4Word* insPtr = reinterpret_cast<SH4Word*>(instructionStart); 2193 2194 insPtr += 2; // skip MOV and ADD opcodes 2195 2196 if (((*insPtr) & 0xf00f) != MOVL_READ_RM_OPCODE) { 2197 *insPtr = MOVL_READ_RM_OPCODE | (*insPtr & 0x0ff0); 2198 cacheFlush(insPtr, sizeof(SH4Word)); 2199 } 2200 } 2201 2202 static void replaceWithAddressComputation(void* instructionStart) 2203 { 2204 SH4Word* insPtr = reinterpret_cast<SH4Word*>(instructionStart); 2205 2206 insPtr += 2; // skip MOV and ADD opcodes 2207 2208 if (((*insPtr) & 0xf00f) != MOV_OPCODE) { 2209 *insPtr = MOV_OPCODE | (*insPtr & 0x0ff0); 2210 cacheFlush(insPtr, sizeof(SH4Word)); 2211 } 2212 } 2213 2214private: 2215 SH4Buffer m_buffer; 2216 int m_claimscratchReg; 2217 int m_indexOfLastWatchpoint; 2218 int m_indexOfTailOfLastWatchpoint; 2219}; 2220 2221} // namespace JSC 2222 2223#endif // ENABLE(ASSEMBLER) && CPU(SH4) 2224 2225#endif // SH4Assembler_h 2226