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