Home | History | Annotate | Download | only in mips
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "../../CompilerInternals.h"
     18 #include "libdex/DexOpcodes.h"
     19 #include "MipsLIR.h"
     20 
     21 /* For dumping instructions */
     22 #define MIPS_REG_COUNT 32
     23 static const char *mipsRegName[MIPS_REG_COUNT] = {
     24     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
     25     "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
     26     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
     27     "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
     28 };
     29 
     30 /*
     31  * Interpret a format string and build a string no longer than size
     32  * See format key in Assemble.c.
     33  */
     34 static void buildInsnString(const char *fmt, MipsLIR *lir, char* buf,
     35                             unsigned char *baseAddr, int size)
     36 {
     37     int i;
     38     char *bufEnd = &buf[size-1];
     39     const char *fmtEnd = &fmt[strlen(fmt)];
     40     char tbuf[256];
     41     char nc;
     42     while (fmt < fmtEnd) {
     43         int operand;
     44         if (*fmt == '!') {
     45             fmt++;
     46             assert(fmt < fmtEnd);
     47             nc = *fmt++;
     48             if (nc=='!') {
     49                 strcpy(tbuf, "!");
     50             } else {
     51                assert(fmt < fmtEnd);
     52                assert((unsigned)(nc-'0') < 4);
     53                operand = lir->operands[nc-'0'];
     54                switch(*fmt++) {
     55                    case 'b':
     56                        strcpy(tbuf,"0000");
     57                        for (i=3; i>= 0; i--) {
     58                            tbuf[i] += operand & 1;
     59                            operand >>= 1;
     60                        }
     61                        break;
     62                    case 's':
     63                        sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
     64                        break;
     65                    case 'S':
     66 		       assert(((operand & FP_REG_MASK) & 1) == 0);
     67                        sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
     68                        break;
     69                    case 'h':
     70                        sprintf(tbuf,"%04x", operand);
     71                        break;
     72                    case 'M':
     73                    case 'd':
     74                        sprintf(tbuf,"%d", operand);
     75                        break;
     76                    case 'D':
     77                        sprintf(tbuf,"%d", operand+1);
     78                        break;
     79                    case 'E':
     80                        sprintf(tbuf,"%d", operand*4);
     81                        break;
     82                    case 'F':
     83                        sprintf(tbuf,"%d", operand*2);
     84                        break;
     85                    case 'c':
     86                        switch (operand) {
     87                            case kMipsCondEq:
     88                                strcpy(tbuf, "eq");
     89                                break;
     90                            case kMipsCondNe:
     91                                strcpy(tbuf, "ne");
     92                                break;
     93                            case kMipsCondLt:
     94                                strcpy(tbuf, "lt");
     95                                break;
     96                            case kMipsCondGe:
     97                                strcpy(tbuf, "ge");
     98                                break;
     99                            case kMipsCondGt:
    100                                strcpy(tbuf, "gt");
    101                                break;
    102                            case kMipsCondLe:
    103                                strcpy(tbuf, "le");
    104                                break;
    105                            case kMipsCondCs:
    106                                strcpy(tbuf, "cs");
    107                                break;
    108                            case kMipsCondMi:
    109                                strcpy(tbuf, "mi");
    110                                break;
    111                            default:
    112                                strcpy(tbuf, "");
    113                                break;
    114                        }
    115                        break;
    116                    case 't':
    117                        sprintf(tbuf,"0x%08x (L%p)",
    118                                (int) baseAddr + lir->generic.offset + 4 +
    119                                (operand << 2),
    120                                lir->generic.target);
    121                        break;
    122                    case 'T':
    123                        sprintf(tbuf,"0x%08x",
    124                                (int) (operand << 2));
    125                        break;
    126                    case 'u': {
    127                        int offset_1 = lir->operands[0];
    128                        int offset_2 = NEXT_LIR(lir)->operands[0];
    129                        intptr_t target =
    130                            ((((intptr_t) baseAddr + lir->generic.offset + 4) &
    131                             ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
    132                            0xfffffffc;
    133                        sprintf(tbuf, "%p", (void *) target);
    134                        break;
    135                     }
    136 
    137                    /* Nothing to print for BLX_2 */
    138                    case 'v':
    139                        strcpy(tbuf, "see above");
    140                        break;
    141                    case 'r':
    142                        assert(operand >= 0 && operand < MIPS_REG_COUNT);
    143                        strcpy(tbuf, mipsRegName[operand]);
    144                        break;
    145                    default:
    146                        strcpy(tbuf,"DecodeError");
    147                        break;
    148                }
    149                if (buf+strlen(tbuf) <= bufEnd) {
    150                    strcpy(buf, tbuf);
    151                    buf += strlen(tbuf);
    152                } else {
    153                    break;
    154                }
    155             }
    156         } else {
    157            *buf++ = *fmt++;
    158         }
    159         if (buf == bufEnd)
    160             break;
    161     }
    162     *buf = 0;
    163 }
    164 
    165 void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
    166 {
    167     char buf[256];
    168     buf[0] = 0;
    169     MipsLIR *mipsLIR = (MipsLIR *) lir;
    170 
    171     if (mask == ENCODE_ALL) {
    172         strcpy(buf, "all");
    173     } else {
    174         char num[8];
    175         int i;
    176 
    177         for (i = 0; i < kRegEnd; i++) {
    178             if (mask & (1ULL << i)) {
    179                 sprintf(num, "%d ", i);
    180                 strcat(buf, num);
    181             }
    182         }
    183 
    184         if (mask & ENCODE_CCODE) {
    185             strcat(buf, "cc ");
    186         }
    187         if (mask & ENCODE_FP_STATUS) {
    188             strcat(buf, "fpcc ");
    189         }
    190         /* Memory bits */
    191         if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
    192             sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
    193                     (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
    194         }
    195         if (mask & ENCODE_LITERAL) {
    196             strcat(buf, "lit ");
    197         }
    198 
    199         if (mask & ENCODE_HEAP_REF) {
    200             strcat(buf, "heap ");
    201         }
    202         if (mask & ENCODE_MUST_NOT_ALIAS) {
    203             strcat(buf, "noalias ");
    204         }
    205     }
    206     if (buf[0]) {
    207         ALOGD("%s: %s", prefix, buf);
    208     }
    209 }
    210 
    211 /*
    212  * Debugging macros
    213  */
    214 #define DUMP_RESOURCE_MASK(X)
    215 #define DUMP_SSA_REP(X)
    216 
    217 /* Pretty-print a LIR instruction */
    218 void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
    219 {
    220     MipsLIR *lir = (MipsLIR *) arg;
    221     char buf[256];
    222     char opName[256];
    223     int offset = lir->generic.offset;
    224     int dest = lir->operands[0];
    225     const bool dumpNop = false;
    226 
    227     /* Handle pseudo-ops individually, and all regular insns as a group */
    228     switch(lir->opcode) {
    229         case kMipsChainingCellBottom:
    230             ALOGD("-------- end of chaining cells (0x%04x)", offset);
    231             break;
    232         case kMipsPseudoBarrier:
    233             ALOGD("-------- BARRIER");
    234             break;
    235         case kMipsPseudoExtended:
    236             /* intentional fallthrough */
    237         case kMipsPseudoSSARep:
    238             DUMP_SSA_REP(ALOGD("-------- %s", (char *) dest));
    239             break;
    240         case kMipsPseudoChainingCellBackwardBranch:
    241             ALOGD("L%p:", lir);
    242             ALOGD("-------- chaining cell (backward branch): 0x%04x", dest);
    243             break;
    244         case kMipsPseudoChainingCellNormal:
    245             ALOGD("L%p:", lir);
    246             ALOGD("-------- chaining cell (normal): 0x%04x", dest);
    247             break;
    248         case kMipsPseudoChainingCellHot:
    249             ALOGD("L%p:", lir);
    250             ALOGD("-------- chaining cell (hot): 0x%04x", dest);
    251             break;
    252         case kMipsPseudoChainingCellInvokePredicted:
    253             ALOGD("L%p:", lir);
    254             ALOGD("-------- chaining cell (predicted): %s%s",
    255                  dest ? ((Method *) dest)->clazz->descriptor : "",
    256                  dest ? ((Method *) dest)->name : "N/A");
    257             break;
    258         case kMipsPseudoChainingCellInvokeSingleton:
    259             ALOGD("L%p:", lir);
    260             ALOGD("-------- chaining cell (invoke singleton): %s%s/%p",
    261                  ((Method *)dest)->clazz->descriptor,
    262                  ((Method *)dest)->name,
    263                  ((Method *)dest)->insns);
    264             break;
    265         case kMipsPseudoEntryBlock:
    266             ALOGD("-------- entry offset: 0x%04x", dest);
    267             break;
    268         case kMipsPseudoDalvikByteCodeBoundary:
    269             ALOGD("-------- dalvik offset: 0x%04x @ %s", dest,
    270                  (char *) lir->operands[1]);
    271             break;
    272         case kMipsPseudoExitBlock:
    273             ALOGD("-------- exit offset: 0x%04x", dest);
    274             break;
    275         case kMipsPseudoPseudoAlign4:
    276             ALOGD("%p (%04x): .align4", baseAddr + offset, offset);
    277             break;
    278         case kMipsPseudoPCReconstructionCell:
    279             ALOGD("L%p:", lir);
    280             ALOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x", dest,
    281                  lir->operands[1]);
    282             break;
    283         case kMipsPseudoPCReconstructionBlockLabel:
    284             /* Do nothing */
    285             break;
    286         case kMipsPseudoEHBlockLabel:
    287             ALOGD("Exception_Handling:");
    288             break;
    289         case kMipsPseudoTargetLabel:
    290         case kMipsPseudoNormalBlockLabel:
    291             ALOGD("L%p:", lir);
    292             break;
    293         default:
    294             if (lir->flags.isNop && !dumpNop) {
    295                 break;
    296             }
    297             buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
    298                             baseAddr, 256);
    299             buildInsnString(EncodingMap[lir->opcode].fmt, lir, buf, baseAddr,
    300                             256);
    301             ALOGD("%p (%04x): %08x %-9s%s%s",
    302                  baseAddr + offset, offset, *(u4 *)(baseAddr + offset), opName, buf,
    303                  lir->flags.isNop ? "(nop)" : "");
    304             break;
    305     }
    306 
    307     if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
    308         DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
    309                                                lir->useMask, "use"));
    310     }
    311     if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
    312         DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
    313                                                lir->defMask, "def"));
    314     }
    315 }
    316 
    317 /* Dump instructions and constant pool contents */
    318 void dvmCompilerCodegenDump(CompilationUnit *cUnit)
    319 {
    320     ALOGD("Dumping LIR insns");
    321     LIR *lirInsn;
    322     MipsLIR *mipsLIR;
    323 
    324     ALOGD("installed code is at %p", cUnit->baseAddr);
    325     ALOGD("total size is %d bytes", cUnit->totalSize);
    326     for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
    327         dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr);
    328     }
    329     for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
    330         mipsLIR = (MipsLIR *) lirInsn;
    331         ALOGD("%p (%04x): .class (%s)",
    332              (char*)cUnit->baseAddr + mipsLIR->generic.offset,
    333              mipsLIR->generic.offset,
    334              ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor);
    335     }
    336     for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
    337         mipsLIR = (MipsLIR *) lirInsn;
    338         ALOGD("%p (%04x): .word (%#x)",
    339              (char*)cUnit->baseAddr + mipsLIR->generic.offset,
    340              mipsLIR->generic.offset,
    341              mipsLIR->operands[0]);
    342     }
    343 }
    344 
    345 /* Target-specific cache flushing */
    346 void dvmCompilerCacheFlush(long start, long end, long flags)
    347 {
    348     cacheflush(start, end, flags);
    349 }
    350 
    351 /* Target-specific cache clearing */
    352 void dvmCompilerCacheClear(char *start, size_t size)
    353 {
    354     /* 0x66 is an invalid opcode for mips. */
    355     memset(start, 0x66, size);
    356 }
    357