1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 University of Szeged 4 * All rights reserved. 5 * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#ifndef MIPSAssembler_h 30#define MIPSAssembler_h 31 32#if ENABLE(ASSEMBLER) && CPU(MIPS) 33 34#include "AssemblerBuffer.h" 35#include "JITCompilationEffort.h" 36#include <wtf/Assertions.h> 37#include <wtf/SegmentedVector.h> 38 39namespace JSC { 40 41typedef uint32_t MIPSWord; 42 43namespace MIPSRegisters { 44typedef enum { 45 r0 = 0, 46 r1, 47 r2, 48 r3, 49 r4, 50 r5, 51 r6, 52 r7, 53 r8, 54 r9, 55 r10, 56 r11, 57 r12, 58 r13, 59 r14, 60 r15, 61 r16, 62 r17, 63 r18, 64 r19, 65 r20, 66 r21, 67 r22, 68 r23, 69 r24, 70 r25, 71 r26, 72 r27, 73 r28, 74 r29, 75 r30, 76 r31, 77 zero = r0, 78 at = r1, 79 v0 = r2, 80 v1 = r3, 81 a0 = r4, 82 a1 = r5, 83 a2 = r6, 84 a3 = r7, 85 t0 = r8, 86 t1 = r9, 87 t2 = r10, 88 t3 = r11, 89 t4 = r12, 90 t5 = r13, 91 t6 = r14, 92 t7 = r15, 93 s0 = r16, 94 s1 = r17, 95 s2 = r18, 96 s3 = r19, 97 s4 = r20, 98 s5 = r21, 99 s6 = r22, 100 s7 = r23, 101 t8 = r24, 102 t9 = r25, 103 k0 = r26, 104 k1 = r27, 105 gp = r28, 106 sp = r29, 107 fp = r30, 108 ra = r31 109} RegisterID; 110 111typedef enum { 112 f0, 113 f1, 114 f2, 115 f3, 116 f4, 117 f5, 118 f6, 119 f7, 120 f8, 121 f9, 122 f10, 123 f11, 124 f12, 125 f13, 126 f14, 127 f15, 128 f16, 129 f17, 130 f18, 131 f19, 132 f20, 133 f21, 134 f22, 135 f23, 136 f24, 137 f25, 138 f26, 139 f27, 140 f28, 141 f29, 142 f30, 143 f31 144} FPRegisterID; 145 146} // namespace MIPSRegisters 147 148class MIPSAssembler { 149public: 150 typedef MIPSRegisters::RegisterID RegisterID; 151 typedef MIPSRegisters::FPRegisterID FPRegisterID; 152 typedef SegmentedVector<AssemblerLabel, 64> Jumps; 153 154 static RegisterID firstRegister() { return MIPSRegisters::r0; } 155 static RegisterID lastRegister() { return MIPSRegisters::r31; } 156 157 static FPRegisterID firstFPRegister() { return MIPSRegisters::f0; } 158 static FPRegisterID lastFPRegister() { return MIPSRegisters::f31; } 159 160 MIPSAssembler() 161 : m_indexOfLastWatchpoint(INT_MIN) 162 , m_indexOfTailOfLastWatchpoint(INT_MIN) 163 { 164 } 165 166 AssemblerBuffer& buffer() { return m_buffer; } 167 168 // MIPS instruction opcode field position 169 enum { 170 OP_SH_RD = 11, 171 OP_SH_RT = 16, 172 OP_SH_RS = 21, 173 OP_SH_SHAMT = 6, 174 OP_SH_CODE = 16, 175 OP_SH_FD = 6, 176 OP_SH_FS = 11, 177 OP_SH_FT = 16 178 }; 179 180 void emitInst(MIPSWord op) 181 { 182 void* oldBase = m_buffer.data(); 183 184 m_buffer.putInt(op); 185 186 void* newBase = m_buffer.data(); 187 if (oldBase != newBase) 188 relocateJumps(oldBase, newBase); 189 } 190 191 void nop() 192 { 193 emitInst(0x00000000); 194 } 195 196 void sync() 197 { 198 emitInst(0x0000000f); 199 } 200 201 /* Need to insert one load data delay nop for mips1. */ 202 void loadDelayNop() 203 { 204#if WTF_MIPS_ISA(1) 205 nop(); 206#endif 207 } 208 209 /* Need to insert one coprocessor access delay nop for mips1. */ 210 void copDelayNop() 211 { 212#if WTF_MIPS_ISA(1) 213 nop(); 214#endif 215 } 216 217 void move(RegisterID rd, RegisterID rs) 218 { 219 /* addu */ 220 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)); 221 } 222 223 /* Set an immediate value to a register. This may generate 1 or 2 224 instructions. */ 225 void li(RegisterID dest, int imm) 226 { 227 if (imm >= -32768 && imm <= 32767) 228 addiu(dest, MIPSRegisters::zero, imm); 229 else if (imm >= 0 && imm < 65536) 230 ori(dest, MIPSRegisters::zero, imm); 231 else { 232 lui(dest, imm >> 16); 233 if (imm & 0xffff) 234 ori(dest, dest, imm); 235 } 236 } 237 238 void lui(RegisterID rt, int imm) 239 { 240 emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff)); 241 } 242 243 void addiu(RegisterID rt, RegisterID rs, int imm) 244 { 245 emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff)); 246 } 247 248 void addu(RegisterID rd, RegisterID rs, RegisterID rt) 249 { 250 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 251 } 252 253 void subu(RegisterID rd, RegisterID rs, RegisterID rt) 254 { 255 emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 256 } 257 258 void mult(RegisterID rs, RegisterID rt) 259 { 260 emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 261 } 262 263 void div(RegisterID rs, RegisterID rt) 264 { 265 emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 266 } 267 268 void mfhi(RegisterID rd) 269 { 270 emitInst(0x00000010 | (rd << OP_SH_RD)); 271 } 272 273 void mflo(RegisterID rd) 274 { 275 emitInst(0x00000012 | (rd << OP_SH_RD)); 276 } 277 278 void mul(RegisterID rd, RegisterID rs, RegisterID rt) 279 { 280#if WTF_MIPS_ISA_AT_LEAST(32) 281 emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 282#else 283 mult(rs, rt); 284 mflo(rd); 285#endif 286 } 287 288 void andInsn(RegisterID rd, RegisterID rs, RegisterID rt) 289 { 290 emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 291 } 292 293 void andi(RegisterID rt, RegisterID rs, int imm) 294 { 295 emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff)); 296 } 297 298 void nor(RegisterID rd, RegisterID rs, RegisterID rt) 299 { 300 emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 301 } 302 303 void orInsn(RegisterID rd, RegisterID rs, RegisterID rt) 304 { 305 emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 306 } 307 308 void ori(RegisterID rt, RegisterID rs, int imm) 309 { 310 emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff)); 311 } 312 313 void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt) 314 { 315 emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 316 } 317 318 void xori(RegisterID rt, RegisterID rs, int imm) 319 { 320 emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff)); 321 } 322 323 void slt(RegisterID rd, RegisterID rs, RegisterID rt) 324 { 325 emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 326 } 327 328 void sltu(RegisterID rd, RegisterID rs, RegisterID rt) 329 { 330 emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT)); 331 } 332 333 void sltiu(RegisterID rt, RegisterID rs, int imm) 334 { 335 emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff)); 336 } 337 338 void sll(RegisterID rd, RegisterID rt, int shamt) 339 { 340 emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT)); 341 } 342 343 void sllv(RegisterID rd, RegisterID rt, RegisterID rs) 344 { 345 emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS)); 346 } 347 348 void sra(RegisterID rd, RegisterID rt, int shamt) 349 { 350 emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT)); 351 } 352 353 void srav(RegisterID rd, RegisterID rt, RegisterID rs) 354 { 355 emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS)); 356 } 357 358 void srl(RegisterID rd, RegisterID rt, int shamt) 359 { 360 emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT)); 361 } 362 363 void srlv(RegisterID rd, RegisterID rt, RegisterID rs) 364 { 365 emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS)); 366 } 367 368 void lb(RegisterID rt, RegisterID rs, int offset) 369 { 370 emitInst(0x80000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 371 loadDelayNop(); 372 } 373 374 void lbu(RegisterID rt, RegisterID rs, int offset) 375 { 376 emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 377 loadDelayNop(); 378 } 379 380 void lw(RegisterID rt, RegisterID rs, int offset) 381 { 382 emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 383 loadDelayNop(); 384 } 385 386 void lwl(RegisterID rt, RegisterID rs, int offset) 387 { 388 emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 389 loadDelayNop(); 390 } 391 392 void lwr(RegisterID rt, RegisterID rs, int offset) 393 { 394 emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 395 loadDelayNop(); 396 } 397 398 void lh(RegisterID rt, RegisterID rs, int offset) 399 { 400 emitInst(0x84000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 401 loadDelayNop(); 402 } 403 404 void lhu(RegisterID rt, RegisterID rs, int offset) 405 { 406 emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 407 loadDelayNop(); 408 } 409 410 void sb(RegisterID rt, RegisterID rs, int offset) 411 { 412 emitInst(0xa0000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 413 } 414 415 void sh(RegisterID rt, RegisterID rs, int offset) 416 { 417 emitInst(0xa4000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 418 } 419 420 void sw(RegisterID rt, RegisterID rs, int offset) 421 { 422 emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff)); 423 } 424 425 void jr(RegisterID rs) 426 { 427 emitInst(0x00000008 | (rs << OP_SH_RS)); 428 } 429 430 void jalr(RegisterID rs) 431 { 432 emitInst(0x0000f809 | (rs << OP_SH_RS)); 433 } 434 435 void jal() 436 { 437 emitInst(0x0c000000); 438 } 439 440 void bkpt() 441 { 442 int value = 512; /* BRK_BUG */ 443 emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE)); 444 } 445 446 void bgez(RegisterID rs, int imm) 447 { 448 emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff)); 449 } 450 451 void bltz(RegisterID rs, int imm) 452 { 453 emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff)); 454 } 455 456 void beq(RegisterID rs, RegisterID rt, int imm) 457 { 458 emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff)); 459 } 460 461 void bne(RegisterID rs, RegisterID rt, int imm) 462 { 463 emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff)); 464 } 465 466 void bc1t() 467 { 468 emitInst(0x45010000); 469 } 470 471 void bc1f() 472 { 473 emitInst(0x45000000); 474 } 475 476 void appendJump() 477 { 478 m_jumps.append(m_buffer.label()); 479 } 480 481 void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) 482 { 483 emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 484 } 485 486 void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) 487 { 488 emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 489 } 490 491 void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) 492 { 493 emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 494 } 495 496 void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) 497 { 498 emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 499 } 500 501 void lwc1(FPRegisterID ft, RegisterID rs, int offset) 502 { 503 emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff)); 504 copDelayNop(); 505 } 506 507 void ldc1(FPRegisterID ft, RegisterID rs, int offset) 508 { 509 emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff)); 510 } 511 512 void swc1(FPRegisterID ft, RegisterID rs, int offset) 513 { 514 emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff)); 515 } 516 517 void sdc1(FPRegisterID ft, RegisterID rs, int offset) 518 { 519 emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff)); 520 } 521 522 void mtc1(RegisterID rt, FPRegisterID fs) 523 { 524 emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); 525 copDelayNop(); 526 } 527 528 void mthc1(RegisterID rt, FPRegisterID fs) 529 { 530 emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); 531 copDelayNop(); 532 } 533 534 void mfc1(RegisterID rt, FPRegisterID fs) 535 { 536 emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); 537 copDelayNop(); 538 } 539 540 void sqrtd(FPRegisterID fd, FPRegisterID fs) 541 { 542 emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 543 } 544 545 void movd(FPRegisterID fd, FPRegisterID fs) 546 { 547 emitInst(0x46200006 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 548 } 549 550 void negd(FPRegisterID fd, FPRegisterID fs) 551 { 552 emitInst(0x46200007 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 553 } 554 555 void truncwd(FPRegisterID fd, FPRegisterID fs) 556 { 557 emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 558 } 559 560 void cvtdw(FPRegisterID fd, FPRegisterID fs) 561 { 562 emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 563 } 564 565 void cvtds(FPRegisterID fd, FPRegisterID fs) 566 { 567 emitInst(0x46000021 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 568 } 569 570 void cvtwd(FPRegisterID fd, FPRegisterID fs) 571 { 572 emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 573 } 574 575 void cvtsd(FPRegisterID fd, FPRegisterID fs) 576 { 577 emitInst(0x46200020 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); 578 } 579 580 void ceqd(FPRegisterID fs, FPRegisterID ft) 581 { 582 emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 583 copDelayNop(); 584 } 585 586 void cngtd(FPRegisterID fs, FPRegisterID ft) 587 { 588 emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 589 copDelayNop(); 590 } 591 592 void cnged(FPRegisterID fs, FPRegisterID ft) 593 { 594 emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 595 copDelayNop(); 596 } 597 598 void cltd(FPRegisterID fs, FPRegisterID ft) 599 { 600 emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 601 copDelayNop(); 602 } 603 604 void cled(FPRegisterID fs, FPRegisterID ft) 605 { 606 emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 607 copDelayNop(); 608 } 609 610 void cueqd(FPRegisterID fs, FPRegisterID ft) 611 { 612 emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 613 copDelayNop(); 614 } 615 616 void coled(FPRegisterID fs, FPRegisterID ft) 617 { 618 emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 619 copDelayNop(); 620 } 621 622 void coltd(FPRegisterID fs, FPRegisterID ft) 623 { 624 emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 625 copDelayNop(); 626 } 627 628 void culed(FPRegisterID fs, FPRegisterID ft) 629 { 630 emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 631 copDelayNop(); 632 } 633 634 void cultd(FPRegisterID fs, FPRegisterID ft) 635 { 636 emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); 637 copDelayNop(); 638 } 639 640 // General helpers 641 642 AssemblerLabel labelIgnoringWatchpoints() 643 { 644 return m_buffer.label(); 645 } 646 647 AssemblerLabel labelForWatchpoint() 648 { 649 AssemblerLabel result = m_buffer.label(); 650 if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint) 651 result = label(); 652 m_indexOfLastWatchpoint = result.m_offset; 653 m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); 654 return result; 655 } 656 657 AssemblerLabel label() 658 { 659 AssemblerLabel result = m_buffer.label(); 660 while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { 661 nop(); 662 result = m_buffer.label(); 663 } 664 return result; 665 } 666 667 AssemblerLabel align(int alignment) 668 { 669 while (!m_buffer.isAligned(alignment)) 670 bkpt(); 671 672 return label(); 673 } 674 675 static void* getRelocatedAddress(void* code, AssemblerLabel label) 676 { 677 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset); 678 } 679 680 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b) 681 { 682 return b.m_offset - a.m_offset; 683 } 684 685 // Assembler admin methods: 686 687 size_t codeSize() const 688 { 689 return m_buffer.codeSize(); 690 } 691 692 unsigned debugOffset() { return m_buffer.debugOffset(); } 693 694 // Assembly helpers for moving data between fp and registers. 695 void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn) 696 { 697#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 698 mfc1(rd1, rn); 699 mfhc1(rd2, rn); 700#else 701 mfc1(rd1, rn); 702 mfc1(rd2, FPRegisterID(rn + 1)); 703#endif 704 } 705 706 void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2) 707 { 708#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 709 mtc1(rn1, rd); 710 mthc1(rn2, rd); 711#else 712 mtc1(rn1, rd); 713 mtc1(rn2, FPRegisterID(rd + 1)); 714#endif 715 } 716 717 static unsigned getCallReturnOffset(AssemblerLabel call) 718 { 719 // The return address is after a call and a delay slot instruction 720 return call.m_offset; 721 } 722 723 // Linking & patching: 724 // 725 // 'link' and 'patch' methods are for use on unprotected code - such as the code 726 // within the AssemblerBuffer, and code being patched by the patch buffer. Once 727 // code has been finalized it is (platform support permitting) within a non- 728 // writable region of memory; to modify the code in an execute-only execuable 729 // pool the 'repatch' and 'relink' methods should be used. 730 731 static size_t linkDirectJump(void* code, void* to) 732 { 733 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code)); 734 size_t ops = 0; 735 int32_t slotAddr = reinterpret_cast<int>(insn) + 4; 736 int32_t toAddr = reinterpret_cast<int>(to); 737 738 if ((slotAddr & 0xf0000000) != (toAddr & 0xf0000000)) { 739 // lui 740 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((toAddr >> 16) & 0xffff); 741 ++insn; 742 // ori 743 *insn = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (toAddr & 0xffff); 744 ++insn; 745 // jr 746 *insn = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); 747 ++insn; 748 ops = 4 * sizeof(MIPSWord); 749 } else { 750 // j 751 *insn = 0x08000000 | ((toAddr & 0x0fffffff) >> 2); 752 ++insn; 753 ops = 2 * sizeof(MIPSWord); 754 } 755 // nop 756 *insn = 0x00000000; 757 return ops; 758 } 759 760 void linkJump(AssemblerLabel from, AssemblerLabel to) 761 { 762 ASSERT(to.isSet()); 763 ASSERT(from.isSet()); 764 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset); 765 MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset); 766 767 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5))); 768 insn = insn - 6; 769 linkWithOffset(insn, toPos); 770 } 771 772 static void linkJump(void* code, AssemblerLabel from, void* to) 773 { 774 ASSERT(from.isSet()); 775 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset); 776 777 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5))); 778 insn = insn - 6; 779 linkWithOffset(insn, to); 780 } 781 782 static void linkCall(void* code, AssemblerLabel from, void* to) 783 { 784 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset); 785 linkCallInternal(insn, to); 786 } 787 788 static void linkPointer(void* code, AssemblerLabel from, void* to) 789 { 790 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset); 791 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 792 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff); 793 insn++; 794 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori 795 *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff); 796 } 797 798 static void relinkJump(void* from, void* to) 799 { 800 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); 801 802 ASSERT(!(*(insn - 1)) && !(*(insn - 5))); 803 insn = insn - 6; 804 int flushSize = linkWithOffset(insn, to); 805 806 cacheFlush(insn, flushSize); 807 } 808 809 static void relinkCall(void* from, void* to) 810 { 811 void* start; 812 int size = linkCallInternal(from, to); 813 if (size == sizeof(MIPSWord)) 814 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord)); 815 else 816 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord)); 817 818 cacheFlush(start, size); 819 } 820 821 static void repatchInt32(void* from, int32_t to) 822 { 823 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); 824 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 825 *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff); 826 insn++; 827 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori 828 *insn = (*insn & 0xffff0000) | (to & 0xffff); 829 insn--; 830 cacheFlush(insn, 2 * sizeof(MIPSWord)); 831 } 832 833 static int32_t readInt32(void* from) 834 { 835 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); 836 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 837 int32_t result = (*insn & 0x0000ffff) << 16; 838 insn++; 839 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori 840 result |= *insn & 0x0000ffff; 841 return result; 842 } 843 844 static void repatchCompact(void* where, int32_t value) 845 { 846 repatchInt32(where, value); 847 } 848 849 static void repatchPointer(void* from, void* to) 850 { 851 repatchInt32(from, reinterpret_cast<int32_t>(to)); 852 } 853 854 static void* readPointer(void* from) 855 { 856 return reinterpret_cast<void*>(readInt32(from)); 857 } 858 859 static void* readCallTarget(void* from) 860 { 861 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); 862 insn -= 4; 863 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 864 int32_t result = (*insn & 0x0000ffff) << 16; 865 insn++; 866 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori 867 result |= *insn & 0x0000ffff; 868 return reinterpret_cast<void*>(result); 869 } 870 871 static void cacheFlush(void* code, size_t size) 872 { 873 intptr_t end = reinterpret_cast<intptr_t>(code) + size; 874 __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end)); 875 } 876 877 static ptrdiff_t maxJumpReplacementSize() 878 { 879 return sizeof(MIPSWord) * 4; 880 } 881 882 static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm) 883 { 884 MIPSWord* insn = static_cast<MIPSWord*>(instructionStart); 885 size_t codeSize = 2 * sizeof(MIPSWord); 886 887 // lui 888 *insn = 0x3c000000 | (rt << OP_SH_RT) | ((imm >> 16) & 0xffff); 889 ++insn; 890 // ori 891 *insn = 0x34000000 | (rt << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff); 892 ++insn; 893 // if jr $t9 894 if (*insn == 0x03200008) { 895 *insn = 0x00000000; 896 codeSize += sizeof(MIPSWord); 897 } 898 cacheFlush(insn, codeSize); 899 } 900 901 static void replaceWithJump(void* instructionStart, void* to) 902 { 903 ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 3)); 904 ASSERT(!(bitwise_cast<uintptr_t>(to) & 3)); 905 size_t ops = linkDirectJump(instructionStart, to); 906 cacheFlush(instructionStart, ops); 907 } 908 909 static void replaceWithLoad(void* instructionStart) 910 { 911 MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart); 912 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 913 insn++; 914 ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu 915 insn++; 916 *insn = 0x8c000000 | ((*insn) & 0x3ffffff); // lw 917 cacheFlush(insn, 4); 918 } 919 920 static void replaceWithAddressComputation(void* instructionStart) 921 { 922 MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart); 923 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 924 insn++; 925 ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu 926 insn++; 927 *insn = 0x24000000 | ((*insn) & 0x3ffffff); // addiu 928 cacheFlush(insn, 4); 929 } 930 931 /* Update each jump in the buffer of newBase. */ 932 void relocateJumps(void* oldBase, void* newBase) 933 { 934 // Check each jump 935 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { 936 int pos = iter->m_offset; 937 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos); 938 insn = insn + 2; 939 // Need to make sure we have 5 valid instructions after pos 940 if ((unsigned)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord)) 941 continue; 942 943 if ((*insn & 0xfc000000) == 0x08000000) { // j 944 int offset = *insn & 0x03ffffff; 945 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase; 946 int topFourBits = (oldInsnAddress + 4) >> 28; 947 int oldTargetAddress = (topFourBits << 28) | (offset << 2); 948 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase; 949 int newInsnAddress = (int)insn; 950 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28)) 951 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff); 952 else { 953 /* lui */ 954 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); 955 /* ori */ 956 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); 957 /* jr */ 958 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); 959 } 960 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui 961 int high = (*insn & 0xffff) << 16; 962 int low = *(insn + 1) & 0xffff; 963 int oldTargetAddress = high | low; 964 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase; 965 /* lui */ 966 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); 967 /* ori */ 968 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); 969 } 970 } 971 } 972 973private: 974 static int linkWithOffset(MIPSWord* insn, void* to) 975 { 976 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq 977 || (*insn & 0xfc000000) == 0x14000000 // bne 978 || (*insn & 0xffff0000) == 0x45010000 // bc1t 979 || (*insn & 0xffff0000) == 0x45000000); // bc1f 980 intptr_t diff = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(insn) - 4) >> 2; 981 982 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) { 983 /* 984 Convert the sequence: 985 beq $2, $3, target 986 nop 987 b 1f 988 nop 989 nop 990 nop 991 1: 992 993 to the new sequence if possible: 994 bne $2, $3, 1f 995 nop 996 j target 997 nop 998 nop 999 nop 1000 1: 1001 1002 OR to the new sequence: 1003 bne $2, $3, 1f 1004 nop 1005 lui $25, target >> 16 1006 ori $25, $25, target & 0xffff 1007 jr $25 1008 nop 1009 1: 1010 1011 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t. 1012 */ 1013 1014 if (*(insn + 2) == 0x10000003) { 1015 if ((*insn & 0xfc000000) == 0x10000000) // beq 1016 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne 1017 else if ((*insn & 0xfc000000) == 0x14000000) // bne 1018 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq 1019 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t 1020 *insn = 0x45000005; // bc1f 1021 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f 1022 *insn = 0x45010005; // bc1t 1023 else 1024 ASSERT(0); 1025 } 1026 1027 insn = insn + 2; 1028 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28 1029 == reinterpret_cast<intptr_t>(to) >> 28) { 1030 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff); 1031 *(insn + 1) = 0; 1032 return 4 * sizeof(MIPSWord); 1033 } 1034 1035 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to); 1036 /* lui */ 1037 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); 1038 /* ori */ 1039 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); 1040 /* jr */ 1041 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); 1042 return 5 * sizeof(MIPSWord); 1043 } 1044 1045 *insn = (*insn & 0xffff0000) | (diff & 0xffff); 1046 return sizeof(MIPSWord); 1047 } 1048 1049 static int linkCallInternal(void* from, void* to) 1050 { 1051 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); 1052 insn = insn - 4; 1053 1054 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal 1055 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28 1056 == reinterpret_cast<intptr_t>(to) >> 28) { 1057 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff); 1058 return sizeof(MIPSWord); 1059 } 1060 1061 /* lui $25, (to >> 16) & 0xffff */ 1062 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff); 1063 /* ori $25, $25, to & 0xffff */ 1064 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff); 1065 /* jalr $25 */ 1066 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS); 1067 return 3 * sizeof(MIPSWord); 1068 } 1069 1070 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui 1071 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori 1072 1073 /* lui */ 1074 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff); 1075 /* ori */ 1076 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff); 1077 return 2 * sizeof(MIPSWord); 1078 } 1079 1080 AssemblerBuffer m_buffer; 1081 Jumps m_jumps; 1082 int m_indexOfLastWatchpoint; 1083 int m_indexOfTailOfLastWatchpoint; 1084}; 1085 1086} // namespace JSC 1087 1088#endif // ENABLE(ASSEMBLER) && CPU(MIPS) 1089 1090#endif // MIPSAssembler_h 1091