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 /*
     18  * This file contains codegen and support common to all supported
     19  * Mips variants.  It is included by:
     20  *
     21  *        Codegen-$(TARGET_ARCH_VARIANT).c
     22  *
     23  * which combines this common code with specific support found in the
     24  * applicable directory below this one.
     25  */
     26 
     27 
     28 /* Load a word at base + displacement.  Displacement must be word multiple */
     29 static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
     30                             int rDest)
     31 {
     32     return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
     33                         INVALID_SREG);
     34 }
     35 
     36 static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
     37                              int displacement, int rSrc)
     38 {
     39     return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
     40 }
     41 
     42 /*
     43  * Load a Dalvik register into a physical register.  Take care when
     44  * using this routine, as it doesn't perform any bookkeeping regarding
     45  * register liveness.  That is the responsibility of the caller.
     46  */
     47 static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
     48                                 int reg1)
     49 {
     50     rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
     51     if (rlSrc.location == kLocPhysReg) {
     52         genRegCopy(cUnit, reg1, rlSrc.lowReg);
     53     } else  if (rlSrc.location == kLocRetval) {
     54         loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
     55     } else {
     56         assert(rlSrc.location == kLocDalvikFrame);
     57         loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
     58                      reg1);
     59     }
     60 }
     61 
     62 /*
     63  * Similar to loadValueDirect, but clobbers and allocates the target
     64  * register.  Should be used when loading to a fixed register (for example,
     65  * loading arguments to an out of line call.
     66  */
     67 static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
     68                                  int reg1)
     69 {
     70     dvmCompilerClobber(cUnit, reg1);
     71     dvmCompilerMarkInUse(cUnit, reg1);
     72     loadValueDirect(cUnit, rlSrc, reg1);
     73 }
     74 
     75 /*
     76  * Load a Dalvik register pair into a physical register[s].  Take care when
     77  * using this routine, as it doesn't perform any bookkeeping regarding
     78  * register liveness.  That is the responsibility of the caller.
     79  */
     80 static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
     81                                 int regLo, int regHi)
     82 {
     83     rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
     84     if (rlSrc.location == kLocPhysReg) {
     85         genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
     86     } else if (rlSrc.location == kLocRetval) {
     87         loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
     88                          regLo, regHi, INVALID_SREG);
     89     } else {
     90         assert(rlSrc.location == kLocDalvikFrame);
     91             loadBaseDispWide(cUnit, NULL, rFP,
     92                              dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
     93                              regLo, regHi, INVALID_SREG);
     94     }
     95 }
     96 
     97 /*
     98  * Similar to loadValueDirect, but clobbers and allocates the target
     99  * registers.  Should be used when loading to a fixed registers (for example,
    100  * loading arguments to an out of line call.
    101  */
    102 static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
    103                                      int regLo, int regHi)
    104 {
    105     dvmCompilerClobber(cUnit, regLo);
    106     dvmCompilerClobber(cUnit, regHi);
    107     dvmCompilerMarkInUse(cUnit, regLo);
    108     dvmCompilerMarkInUse(cUnit, regHi);
    109     loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
    110 }
    111 
    112 static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
    113                              RegisterClass opKind)
    114 {
    115     rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
    116     if (rlSrc.location == kLocDalvikFrame) {
    117         loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
    118         rlSrc.location = kLocPhysReg;
    119         dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
    120     } else if (rlSrc.location == kLocRetval) {
    121         loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), rlSrc.lowReg);
    122         rlSrc.location = kLocPhysReg;
    123         dvmCompilerClobber(cUnit, rlSrc.lowReg);
    124     }
    125     return rlSrc;
    126 }
    127 
    128 static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
    129                        RegLocation rlSrc)
    130 {
    131     LIR *defStart;
    132     LIR *defEnd;
    133     assert(!rlDest.wide);
    134     assert(!rlSrc.wide);
    135     dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
    136     rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
    137     rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
    138     if (rlSrc.location == kLocPhysReg) {
    139         if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
    140             (rlDest.location == kLocPhysReg)) {
    141             // Src is live or Dest has assigned reg.
    142             rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    143             genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
    144         } else {
    145             // Just re-assign the registers.  Dest gets Src's regs
    146             rlDest.lowReg = rlSrc.lowReg;
    147             dvmCompilerClobber(cUnit, rlSrc.lowReg);
    148         }
    149     } else {
    150         // Load Src either into promoted Dest or temps allocated for Dest
    151         rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    152         loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
    153     }
    154 
    155     // Dest is now live and dirty (until/if we flush it to home location)
    156     dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
    157     dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
    158 
    159 
    160     if (rlDest.location == kLocRetval) {
    161         storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
    162                       rlDest.lowReg, kWord);
    163         dvmCompilerClobber(cUnit, rlDest.lowReg);
    164     } else {
    165         dvmCompilerResetDefLoc(cUnit, rlDest);
    166         if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
    167             defStart = (LIR *)cUnit->lastLIRInsn;
    168             int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
    169             storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
    170             dvmCompilerMarkClean(cUnit, rlDest.lowReg);
    171             defEnd = (LIR *)cUnit->lastLIRInsn;
    172             dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
    173         }
    174     }
    175 }
    176 
    177 static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
    178                                  RegisterClass opKind)
    179 {
    180     assert(rlSrc.wide);
    181     rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
    182     if (rlSrc.location == kLocDalvikFrame) {
    183         loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
    184         rlSrc.location = kLocPhysReg;
    185         dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
    186         dvmCompilerMarkLive(cUnit, rlSrc.highReg,
    187                             dvmCompilerSRegHi(rlSrc.sRegLow));
    188     } else if (rlSrc.location == kLocRetval) {
    189         loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
    190                          rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
    191         rlSrc.location = kLocPhysReg;
    192         dvmCompilerClobber(cUnit, rlSrc.lowReg);
    193         dvmCompilerClobber(cUnit, rlSrc.highReg);
    194     }
    195     return rlSrc;
    196 }
    197 
    198 static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
    199                        RegLocation rlSrc)
    200 {
    201     LIR *defStart;
    202     LIR *defEnd;
    203     assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
    204     assert(rlDest.wide);
    205     assert(rlSrc.wide);
    206     dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
    207     if (rlSrc.location == kLocPhysReg) {
    208         if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
    209             dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
    210             (rlDest.location == kLocPhysReg)) {
    211             // Src is live or Dest has assigned reg.
    212             rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    213             genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
    214                            rlSrc.lowReg, rlSrc.highReg);
    215         } else {
    216             // Just re-assign the registers.  Dest gets Src's regs
    217             rlDest.lowReg = rlSrc.lowReg;
    218             rlDest.highReg = rlSrc.highReg;
    219             dvmCompilerClobber(cUnit, rlSrc.lowReg);
    220             dvmCompilerClobber(cUnit, rlSrc.highReg);
    221         }
    222     } else {
    223         // Load Src either into promoted Dest or temps allocated for Dest
    224         rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    225         loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
    226                             rlDest.highReg);
    227     }
    228 
    229     // Dest is now live and dirty (until/if we flush it to home location)
    230     dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
    231     dvmCompilerMarkLive(cUnit, rlDest.highReg,
    232                         dvmCompilerSRegHi(rlDest.sRegLow));
    233     dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
    234     dvmCompilerMarkDirty(cUnit, rlDest.highReg);
    235     dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
    236 
    237 
    238     if (rlDest.location == kLocRetval) {
    239         storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
    240                           rlDest.lowReg, rlDest.highReg);
    241         dvmCompilerClobber(cUnit, rlDest.lowReg);
    242         dvmCompilerClobber(cUnit, rlDest.highReg);
    243     } else {
    244         dvmCompilerResetDefLocWide(cUnit, rlDest);
    245         if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
    246             dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
    247             defStart = (LIR *)cUnit->lastLIRInsn;
    248             int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
    249             assert((vReg+1) == dvmCompilerS2VReg(cUnit,
    250                                      dvmCompilerSRegHi(rlDest.sRegLow)));
    251             storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
    252                               rlDest.highReg);
    253             dvmCompilerMarkClean(cUnit, rlDest.lowReg);
    254             dvmCompilerMarkClean(cUnit, rlDest.highReg);
    255             defEnd = (LIR *)cUnit->lastLIRInsn;
    256             dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
    257         }
    258     }
    259 }
    260 /*
    261  * Perform null-check on a register. sReg is the ssa register being checked,
    262  * and mReg is the machine register holding the actual value. If internal state
    263  * indicates that sReg has been checked before the check request is ignored.
    264  */
    265 static MipsLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
    266                                 int dOffset, MipsLIR *pcrLabel)
    267 {
    268     /* This particular Dalvik register has been null-checked */
    269     if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
    270         return pcrLabel;
    271     }
    272     dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
    273     return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
    274 }
    275 
    276 
    277 
    278 /*
    279  * Perform a "reg cmp reg" operation and jump to the PCR region if condition
    280  * satisfies.
    281  */
    282 static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
    283                               MipsConditionCode cond,
    284                               int reg1, int reg2, int dOffset,
    285                               MipsLIR *pcrLabel)
    286 {
    287     MipsLIR *res = NULL;
    288     if (cond == kMipsCondGe) { /* signed >= case */
    289         int tReg = dvmCompilerAllocTemp(cUnit);
    290         res = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
    291         MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
    292         genCheckCommon(cUnit, dOffset, branch, pcrLabel);
    293     } else if (cond == kMipsCondCs) {  /* unsigned >= case */
    294         int tReg = dvmCompilerAllocTemp(cUnit);
    295         res = newLIR3(cUnit, kMipsSltu, tReg, reg1, reg2);
    296         MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
    297         genCheckCommon(cUnit, dOffset, branch, pcrLabel);
    298     } else {
    299         ALOGE("Unexpected condition in genRegRegCheck: %d\n", (int) cond);
    300         dvmAbort();
    301     }
    302     return res;
    303 }
    304 
    305 /*
    306  * Perform zero-check on a register. Similar to genNullCheck but the value being
    307  * checked does not have a corresponding Dalvik register.
    308  */
    309 static MipsLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
    310                                 int dOffset, MipsLIR *pcrLabel)
    311 {
    312     return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
    313 }
    314 
    315 /* Perform bound check on two registers */
    316 static MipsLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
    317                                   int rBound, int dOffset, MipsLIR *pcrLabel)
    318 {
    319     return genRegRegCheck(cUnit, kMipsCondCs, rIndex, rBound, dOffset,
    320                             pcrLabel);
    321 }
    322 
    323 /*
    324  * Jump to the out-of-line handler to finish executing the
    325  * remaining of more complex instructions.
    326  */
    327 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode)
    328 {
    329     /*
    330      * We're jumping from a trace to a template. Using jal is preferable to jalr,
    331      * but we need to ensure source and target addresses allow the use of jal.
    332      * This should almost always be the case, but if source and target are in
    333      * different 256mb regions then use jalr.  The test below is very conservative
    334      * since we don't have a source address yet, but this is ok for now given that
    335      * we expect this case to be very rare. The test can be made less conservative
    336      * as needed in the future in coordination with address assignment during
    337      * the assembly process.
    338      */
    339     dvmCompilerClobberHandlerRegs(cUnit);
    340     int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode];
    341     int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize;
    342 
    343     if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) {
    344         newLIR1(cUnit, kMipsJal, targetAddr);
    345     } else {
    346         loadConstant(cUnit, r_T9, targetAddr);
    347         newLIR2(cUnit, kMipsJalr, r_RA, r_T9);
    348     }
    349 }
    350