JavaScriptCore/assembler/MIPSAssembler.h
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 
       
   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:
       
   172         JmpSrc()
       
   173             : m_offset(-1)
       
   174         {
       
   175         }
       
   176 
       
   177     private:
       
   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:
       
   189         JmpDst()
       
   190             : m_offset(-1)
       
   191             , m_used(false)
       
   192         {
       
   193         }
       
   194 
       
   195         bool isUsed() const { return m_used; }
       
   196         void used() { m_used = true; }
       
   197     private:
       
   198         JmpDst(int offset)
       
   199             : m_offset(offset)
       
   200             , m_used(false)
       
   201         {
       
   202             ASSERT(m_offset == offset);
       
   203         }
       
   204 
       
   205         int m_offset : 31;
       
   206         int m_used : 1;
       
   207     };
       
   208 
       
   209     void emitInst(MIPSWord op)
       
   210     {
       
   211         void* oldBase = m_buffer.data();
       
   212 
       
   213         m_buffer.putInt(op);
       
   214 
       
   215         void* newBase = m_buffer.data();
       
   216         if (oldBase != newBase)
       
   217             relocateJumps(oldBase, newBase);
       
   218     }
       
   219 
       
   220     void nop()
       
   221     {
       
   222         emitInst(0x00000000);
       
   223     }
       
   224 
       
   225     /* Need to insert one load data delay nop for mips1.  */
       
   226     void loadDelayNop()
       
   227     {
       
   228 #if WTF_MIPS_ISA(1)
       
   229         nop();
       
   230 #endif
       
   231     }
       
   232 
       
   233     /* Need to insert one coprocessor access delay nop for mips1.  */
       
   234     void copDelayNop()
       
   235     {
       
   236 #if WTF_MIPS_ISA(1)
       
   237         nop();
       
   238 #endif
       
   239     }
       
   240 
       
   241     void move(RegisterID rd, RegisterID rs)
       
   242     {
       
   243         /* addu */
       
   244         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
       
   245     }
       
   246 
       
   247     /* Set an immediate value to a register.  This may generate 1 or 2
       
   248        instructions.  */
       
   249     void li(RegisterID dest, int imm)
       
   250     {
       
   251         if (imm >= -32768 && imm <= 32767)
       
   252             addiu(dest, MIPSRegisters::zero, imm);
       
   253         else if (imm >= 0 && imm < 65536)
       
   254             ori(dest, MIPSRegisters::zero, imm);
       
   255         else {
       
   256             lui(dest, imm >> 16);
       
   257             if (imm & 0xffff)
       
   258                 ori(dest, dest, imm);
       
   259         }
       
   260     }
       
   261 
       
   262     void lui(RegisterID rt, int imm)
       
   263     {
       
   264         emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
       
   265     }
       
   266 
       
   267     void addiu(RegisterID rt, RegisterID rs, int imm)
       
   268     {
       
   269         emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   270                  | (imm & 0xffff));
       
   271     }
       
   272 
       
   273     void addu(RegisterID rd, RegisterID rs, RegisterID rt)
       
   274     {
       
   275         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   276                  | (rt << OP_SH_RT));
       
   277     }
       
   278 
       
   279     void subu(RegisterID rd, RegisterID rs, RegisterID rt)
       
   280     {
       
   281         emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   282                  | (rt << OP_SH_RT));
       
   283     }
       
   284 
       
   285     void mult(RegisterID rs, RegisterID rt)
       
   286     {
       
   287         emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
       
   288     }
       
   289 
       
   290     void mfhi(RegisterID rd)
       
   291     {
       
   292         emitInst(0x00000010 | (rd << OP_SH_RD));
       
   293     }
       
   294 
       
   295     void mflo(RegisterID rd)
       
   296     {
       
   297         emitInst(0x00000012 | (rd << OP_SH_RD));
       
   298     }
       
   299 
       
   300     void mul(RegisterID rd, RegisterID rs, RegisterID rt)
       
   301     {
       
   302 #if WTF_MIPS_ISA_AT_LEAST(32) 
       
   303         emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   304                  | (rt << OP_SH_RT));
       
   305 #else
       
   306         mult(rs, rt);
       
   307         mflo(rd);
       
   308 #endif
       
   309     }
       
   310 
       
   311     void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
       
   312     {
       
   313         emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   314                  | (rt << OP_SH_RT));
       
   315     }
       
   316 
       
   317     void andi(RegisterID rt, RegisterID rs, int imm)
       
   318     {
       
   319         emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   320                  | (imm & 0xffff));
       
   321     }
       
   322 
       
   323     void nor(RegisterID rd, RegisterID rs, RegisterID rt)
       
   324     {
       
   325         emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   326                  | (rt << OP_SH_RT));
       
   327     }
       
   328 
       
   329     void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
       
   330     {
       
   331         emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   332                  | (rt << OP_SH_RT));
       
   333     }
       
   334 
       
   335     void ori(RegisterID rt, RegisterID rs, int imm)
       
   336     {
       
   337         emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   338                  | (imm & 0xffff));
       
   339     }
       
   340 
       
   341     void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
       
   342     {
       
   343         emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   344                  | (rt << OP_SH_RT));
       
   345     }
       
   346 
       
   347     void xori(RegisterID rt, RegisterID rs, int imm)
       
   348     {
       
   349         emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   350                  | (imm & 0xffff));
       
   351     }
       
   352 
       
   353     void slt(RegisterID rd, RegisterID rs, RegisterID rt)
       
   354     {
       
   355         emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   356                  | (rt << OP_SH_RT));
       
   357     }
       
   358 
       
   359     void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
       
   360     {
       
   361         emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
       
   362                  | (rt << OP_SH_RT));
       
   363     }
       
   364 
       
   365     void sltiu(RegisterID rt, RegisterID rs, int imm)
       
   366     {
       
   367         emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   368                  | (imm & 0xffff));
       
   369     }
       
   370 
       
   371     void sll(RegisterID rd, RegisterID rt, int shamt)
       
   372     {
       
   373         emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
       
   374                  | ((shamt & 0x1f) << OP_SH_SHAMT));
       
   375     }
       
   376 
       
   377     void sllv(RegisterID rd, RegisterID rt, int rs)
       
   378     {
       
   379         emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
       
   380                  | (rs << OP_SH_RS));
       
   381     }
       
   382 
       
   383     void sra(RegisterID rd, RegisterID rt, int shamt)
       
   384     {
       
   385         emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
       
   386                  | ((shamt & 0x1f) << OP_SH_SHAMT));
       
   387     }
       
   388 
       
   389     void srav(RegisterID rd, RegisterID rt, RegisterID rs)
       
   390     {
       
   391         emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
       
   392                  | (rs << OP_SH_RS));
       
   393     }
       
   394 
       
   395     void srl(RegisterID rd, RegisterID rt, int shamt)
       
   396     {
       
   397         emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
       
   398                  | ((shamt & 0x1f) << OP_SH_SHAMT));
       
   399     }
       
   400 
       
   401     void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
       
   402     {
       
   403         emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
       
   404                  | (rs << OP_SH_RS));
       
   405     }
       
   406 
       
   407     void lbu(RegisterID rt, RegisterID rs, int offset)
       
   408     {
       
   409         emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   410                  | (offset & 0xffff));
       
   411         loadDelayNop();
       
   412     }
       
   413 
       
   414     void lw(RegisterID rt, RegisterID rs, int offset)
       
   415     {
       
   416         emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   417                  | (offset & 0xffff));
       
   418         loadDelayNop();
       
   419     }
       
   420 
       
   421     void lwl(RegisterID rt, RegisterID rs, int offset)
       
   422     {
       
   423         emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   424                  | (offset & 0xffff));
       
   425         loadDelayNop();
       
   426     }
       
   427 
       
   428     void lwr(RegisterID rt, RegisterID rs, int offset)
       
   429     {
       
   430         emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   431                  | (offset & 0xffff));
       
   432         loadDelayNop();
       
   433     }
       
   434 
       
   435     void lhu(RegisterID rt, RegisterID rs, int offset)
       
   436     {
       
   437         emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   438                  | (offset & 0xffff));
       
   439         loadDelayNop();
       
   440     }
       
   441 
       
   442     void sw(RegisterID rt, RegisterID rs, int offset)
       
   443     {
       
   444         emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
       
   445                  | (offset & 0xffff));
       
   446     }
       
   447 
       
   448     void jr(RegisterID rs)
       
   449     {
       
   450         emitInst(0x00000008 | (rs << OP_SH_RS));
       
   451     }
       
   452 
       
   453     void jalr(RegisterID rs)
       
   454     {
       
   455         emitInst(0x0000f809 | (rs << OP_SH_RS));
       
   456     }
       
   457 
       
   458     void jal()
       
   459     {
       
   460         emitInst(0x0c000000);
       
   461     }
       
   462 
       
   463     void bkpt()
       
   464     {
       
   465         int value = 512; /* BRK_BUG */
       
   466         emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
       
   467     }
       
   468 
       
   469     void bgez(RegisterID rs, int imm)
       
   470     {
       
   471         emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
       
   472     }
       
   473 
       
   474     void bltz(RegisterID rs, int imm)
       
   475     {
       
   476         emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
       
   477     }
       
   478 
       
   479     void beq(RegisterID rs, RegisterID rt, int imm)
       
   480     {
       
   481         emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
       
   482     }
       
   483 
       
   484     void bne(RegisterID rs, RegisterID rt, int imm)
       
   485     {
       
   486         emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
       
   487     }
       
   488 
       
   489     void bc1t()
       
   490     {
       
   491         emitInst(0x45010000);
       
   492     }
       
   493 
       
   494     void bc1f()
       
   495     {
       
   496         emitInst(0x45000000);
       
   497     }
       
   498 
       
   499     JmpSrc newJmpSrc()
       
   500     {
       
   501         return JmpSrc(m_buffer.size());
       
   502     }
       
   503 
       
   504     void appendJump()
       
   505     {
       
   506         m_jumps.append(m_buffer.size());
       
   507     }
       
   508 
       
   509     void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
       
   510     {
       
   511         emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
       
   512                  | (ft << OP_SH_FT));
       
   513     }
       
   514 
       
   515     void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
       
   516     {
       
   517         emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
       
   518                  | (ft << OP_SH_FT));
       
   519     }
       
   520 
       
   521     void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
       
   522     {
       
   523         emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
       
   524                  | (ft << OP_SH_FT));
       
   525     }
       
   526 
       
   527     void lwc1(FPRegisterID ft, RegisterID rs, int offset)
       
   528     {
       
   529         emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
       
   530                  | (offset & 0xffff));
       
   531         copDelayNop();
       
   532     }
       
   533 
       
   534     void ldc1(FPRegisterID ft, RegisterID rs, int offset)
       
   535     {
       
   536         emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
       
   537                  | (offset & 0xffff));
       
   538     }
       
   539 
       
   540     void swc1(FPRegisterID ft, RegisterID rs, int offset)
       
   541     {
       
   542         emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
       
   543                  | (offset & 0xffff));
       
   544     }
       
   545 
       
   546     void sdc1(FPRegisterID ft, RegisterID rs, int offset)
       
   547     {
       
   548         emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
       
   549                  | (offset & 0xffff));
       
   550     }
       
   551 
       
   552     void mtc1(RegisterID rt, FPRegisterID fs)
       
   553     {
       
   554         emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
       
   555         copDelayNop();
       
   556     }
       
   557 
       
   558     void mfc1(RegisterID rt, FPRegisterID fs)
       
   559     {
       
   560         emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
       
   561         copDelayNop();
       
   562     }
       
   563 
       
   564     void sqrtd(FPRegisterID fd, FPRegisterID fs)
       
   565     {
       
   566         emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
       
   567     }
       
   568 
       
   569     void truncwd(FPRegisterID fd, FPRegisterID fs)
       
   570     {
       
   571         emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
       
   572     }
       
   573 
       
   574     void cvtdw(FPRegisterID fd, FPRegisterID fs)
       
   575     {
       
   576         emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
       
   577     }
       
   578 
       
   579     void ceqd(FPRegisterID fs, FPRegisterID ft)
       
   580     {
       
   581         emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   582         copDelayNop();
       
   583     }
       
   584 
       
   585     void cngtd(FPRegisterID fs, FPRegisterID ft)
       
   586     {
       
   587         emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   588         copDelayNop();
       
   589     }
       
   590 
       
   591     void cnged(FPRegisterID fs, FPRegisterID ft)
       
   592     {
       
   593         emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   594         copDelayNop();
       
   595     }
       
   596 
       
   597     void cltd(FPRegisterID fs, FPRegisterID ft)
       
   598     {
       
   599         emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   600         copDelayNop();
       
   601     }
       
   602 
       
   603     void cled(FPRegisterID fs, FPRegisterID ft)
       
   604     {
       
   605         emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   606         copDelayNop();
       
   607     }
       
   608 
       
   609     void cueqd(FPRegisterID fs, FPRegisterID ft)
       
   610     {
       
   611         emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   612         copDelayNop();
       
   613     }
       
   614 
       
   615     void coled(FPRegisterID fs, FPRegisterID ft)
       
   616     {
       
   617         emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   618         copDelayNop();
       
   619     }
       
   620 
       
   621     void coltd(FPRegisterID fs, FPRegisterID ft)
       
   622     {
       
   623         emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   624         copDelayNop();
       
   625     }
       
   626 
       
   627     void culed(FPRegisterID fs, FPRegisterID ft)
       
   628     {
       
   629         emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   630         copDelayNop();
       
   631     }
       
   632 
       
   633     void cultd(FPRegisterID fs, FPRegisterID ft)
       
   634     {
       
   635         emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
       
   636         copDelayNop();
       
   637     }
       
   638 
       
   639     // General helpers
       
   640 
       
   641     JmpDst label()
       
   642     {
       
   643         return JmpDst(m_buffer.size());
       
   644     }
       
   645 
       
   646     JmpDst align(int alignment)
       
   647     {
       
   648         while (!m_buffer.isAligned(alignment))
       
   649             bkpt();
       
   650 
       
   651         return label();
       
   652     }
       
   653 
       
   654     static void* getRelocatedAddress(void* code, JmpSrc jump)
       
   655     {
       
   656         ASSERT(jump.m_offset != -1);
       
   657         void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
       
   658         return b;
       
   659     }
       
   660 
       
   661     static void* getRelocatedAddress(void* code, JmpDst label)
       
   662     {
       
   663         void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
       
   664         return b;
       
   665     }
       
   666 
       
   667     static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
       
   668     {
       
   669         return to.m_offset - from.m_offset;
       
   670     }
       
   671 
       
   672     static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
       
   673     {
       
   674         return to.m_offset - from.m_offset;
       
   675     }
       
   676 
       
   677     static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
       
   678     {
       
   679         return to.m_offset - from.m_offset;
       
   680     }
       
   681 
       
   682     // Assembler admin methods:
       
   683 
       
   684     size_t size() const
       
   685     {
       
   686         return m_buffer.size();
       
   687     }
       
   688 
       
   689     void* executableCopy(ExecutablePool* allocator)
       
   690     {
       
   691         void *result = m_buffer.executableCopy(allocator);
       
   692         if (!result)
       
   693             return 0;
       
   694 
       
   695         relocateJumps(m_buffer.data(), result);
       
   696         return result;
       
   697     }
       
   698 
       
   699     static unsigned getCallReturnOffset(JmpSrc call)
       
   700     {
       
   701         // The return address is after a call and a delay slot instruction
       
   702         return call.m_offset;
       
   703     }
       
   704 
       
   705     // Linking & patching:
       
   706     //
       
   707     // 'link' and 'patch' methods are for use on unprotected code - such as the code
       
   708     // within the AssemblerBuffer, and code being patched by the patch buffer.  Once
       
   709     // code has been finalized it is (platform support permitting) within a non-
       
   710     // writable region of memory; to modify the code in an execute-only execuable
       
   711     // pool the 'repatch' and 'relink' methods should be used.
       
   712 
       
   713     void linkJump(JmpSrc from, JmpDst to)
       
   714     {
       
   715         ASSERT(to.m_offset != -1);
       
   716         ASSERT(from.m_offset != -1);
       
   717         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
       
   718         MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
       
   719 
       
   720         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
       
   721         insn = insn - 6;
       
   722         linkWithOffset(insn, toPos);
       
   723     }
       
   724 
       
   725     static void linkJump(void* code, JmpSrc from, void* to)
       
   726     {
       
   727         ASSERT(from.m_offset != -1);
       
   728         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
       
   729 
       
   730         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
       
   731         insn = insn - 6;
       
   732         linkWithOffset(insn, to);
       
   733     }
       
   734 
       
   735     static void linkCall(void* code, JmpSrc from, void* to)
       
   736     {
       
   737         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
       
   738         linkCallInternal(insn, to);
       
   739     }
       
   740 
       
   741     static void linkPointer(void* code, JmpDst from, void* to)
       
   742     {
       
   743         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
       
   744         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
       
   745         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
       
   746         insn++;
       
   747         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
       
   748         *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
       
   749     }
       
   750 
       
   751     static void relinkJump(void* from, void* to)
       
   752     {
       
   753         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
       
   754 
       
   755         ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
       
   756         insn = insn - 6;
       
   757         int flushSize = linkWithOffset(insn, to);
       
   758 
       
   759         ExecutableAllocator::cacheFlush(insn, flushSize);
       
   760     }
       
   761 
       
   762     static void relinkCall(void* from, void* to)
       
   763     {
       
   764         void* start;
       
   765         int size = linkCallInternal(from, to);
       
   766         if (size == sizeof(MIPSWord))
       
   767             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
       
   768         else
       
   769             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
       
   770 
       
   771         ExecutableAllocator::cacheFlush(start, size);
       
   772     }
       
   773 
       
   774     static void repatchInt32(void* from, int32_t to)
       
   775     {
       
   776         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
       
   777         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
       
   778         *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
       
   779         insn++;
       
   780         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
       
   781         *insn = (*insn & 0xffff0000) | (to & 0xffff);
       
   782         insn--;
       
   783         ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
       
   784     }
       
   785 
       
   786     static void repatchPointer(void* from, void* to)
       
   787     {
       
   788         repatchInt32(from, reinterpret_cast<int32_t>(to));
       
   789     }
       
   790 
       
   791     static void repatchLoadPtrToLEA(void* from)
       
   792     {
       
   793         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
       
   794         insn = insn + 3;
       
   795         ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
       
   796         /* lw -> addiu */
       
   797         *insn = 0x24000000 | (*insn & 0x03ffffff);
       
   798 
       
   799         ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
       
   800     }
       
   801 
       
   802 private:
       
   803 
       
   804     /* Update each jump in the buffer of newBase.  */
       
   805     void relocateJumps(void* oldBase, void* newBase)
       
   806     {
       
   807         // Check each jump
       
   808         for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
       
   809             int pos = *iter;
       
   810             MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
       
   811             insn = insn + 2;
       
   812             // Need to make sure we have 5 valid instructions after pos
       
   813             if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
       
   814                 continue;
       
   815 
       
   816             if ((*insn & 0xfc000000) == 0x08000000) { // j
       
   817                 int offset = *insn & 0x03ffffff;
       
   818                 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
       
   819                 int topFourBits = (oldInsnAddress + 4) >> 28;
       
   820                 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
       
   821                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
       
   822                 int newInsnAddress = (int)insn;
       
   823                 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
       
   824                     *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
       
   825                 else {
       
   826                     /* lui */
       
   827                     *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
       
   828                     /* ori */
       
   829                     *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
       
   830                     /* jr */
       
   831                     *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
       
   832                 }
       
   833             } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
       
   834                 int high = (*insn & 0xffff) << 16;
       
   835                 int low = *(insn + 1) & 0xffff;
       
   836                 int oldTargetAddress = high | low;
       
   837                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
       
   838                 /* lui */
       
   839                 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
       
   840                 /* ori */
       
   841                 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
       
   842             }
       
   843         }
       
   844     }
       
   845 
       
   846     static int linkWithOffset(MIPSWord* insn, void* to)
       
   847     {
       
   848         ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
       
   849                || (*insn & 0xfc000000) == 0x14000000 // bne
       
   850                || (*insn & 0xffff0000) == 0x45010000 // bc1t
       
   851                || (*insn & 0xffff0000) == 0x45000000); // bc1f
       
   852         intptr_t diff = (reinterpret_cast<intptr_t>(to)
       
   853                          - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
       
   854 
       
   855         if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
       
   856             /*
       
   857                 Convert the sequence:
       
   858                   beq $2, $3, target
       
   859                   nop
       
   860                   b 1f
       
   861                   nop
       
   862                   nop
       
   863                   nop
       
   864                 1:
       
   865 
       
   866                 to the new sequence if possible:
       
   867                   bne $2, $3, 1f
       
   868                   nop
       
   869                   j    target
       
   870                   nop
       
   871                   nop
       
   872                   nop
       
   873                 1:
       
   874 
       
   875                 OR to the new sequence:
       
   876                   bne $2, $3, 1f
       
   877                   nop
       
   878                   lui $25, target >> 16
       
   879                   ori $25, $25, target & 0xffff
       
   880                   jr $25
       
   881                   nop
       
   882                 1:
       
   883 
       
   884                 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
       
   885             */
       
   886 
       
   887             if (*(insn + 2) == 0x10000003) {
       
   888                 if ((*insn & 0xfc000000) == 0x10000000) // beq
       
   889                     *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
       
   890                 else if ((*insn & 0xfc000000) == 0x14000000) // bne
       
   891                     *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
       
   892                 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
       
   893                     *insn = 0x45000005; // bc1f
       
   894                 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
       
   895                     *insn = 0x45010005; // bc1t
       
   896                 else
       
   897                     ASSERT(0);
       
   898             }
       
   899 
       
   900             insn = insn + 2;
       
   901             if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
       
   902                 == reinterpret_cast<intptr_t>(to) >> 28) {
       
   903                 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
       
   904                 *(insn + 1) = 0;
       
   905                 return 4 * sizeof(MIPSWord);
       
   906             }
       
   907 
       
   908             intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
       
   909             /* lui */
       
   910             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
       
   911             /* ori */
       
   912             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
       
   913             /* jr */
       
   914             *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
       
   915             return 5 * sizeof(MIPSWord);
       
   916         }
       
   917 
       
   918         *insn = (*insn & 0xffff0000) | (diff & 0xffff);
       
   919         return sizeof(MIPSWord);
       
   920     }
       
   921 
       
   922     static int linkCallInternal(void* from, void* to)
       
   923     {
       
   924         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
       
   925         insn = insn - 4;
       
   926 
       
   927         if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
       
   928             if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
       
   929                 == reinterpret_cast<intptr_t>(to) >> 28) {
       
   930                 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
       
   931                 return sizeof(MIPSWord);
       
   932             }
       
   933 
       
   934             /* lui $25, (to >> 16) & 0xffff */
       
   935             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
       
   936             /* ori $25, $25, to & 0xffff */
       
   937             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
       
   938             /* jalr $25 */
       
   939             *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
       
   940             return 3 * sizeof(MIPSWord);
       
   941         }
       
   942 
       
   943         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
       
   944         ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
       
   945 
       
   946         /* lui */
       
   947         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
       
   948         /* ori */
       
   949         *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
       
   950         return 2 * sizeof(MIPSWord);
       
   951     }
       
   952 
       
   953     AssemblerBuffer m_buffer;
       
   954     Jumps m_jumps;
       
   955 };
       
   956 
       
   957 } // namespace JSC
       
   958 
       
   959 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
       
   960 
       
   961 #endif // MIPSAssembler_h