Home | History | Annotate | Download | only in arm
      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  * ARM 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 ArmLIR *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 ArmLIR *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, rGLUE, offsetof(InterpState, 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, rGLUE, offsetof(InterpState, 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, rGLUE, offsetof(InterpState, 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, rGLUE, offsetof(InterpState, 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, rGLUE, offsetof(InterpState, 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, rGLUE, offsetof(InterpState, 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 ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
    266                                 int dOffset, ArmLIR *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, kArmCondEq, 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 ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
    283                               ArmConditionCode cond,
    284                               int reg1, int reg2, int dOffset,
    285                               ArmLIR *pcrLabel)
    286 {
    287     ArmLIR *res;
    288     res = opRegReg(cUnit, kOpCmp, reg1, reg2);
    289     ArmLIR *branch = opCondBranch(cUnit, cond);
    290     genCheckCommon(cUnit, dOffset, branch, pcrLabel);
    291     return res;
    292 }
    293 
    294 /*
    295  * Perform zero-check on a register. Similar to genNullCheck but the value being
    296  * checked does not have a corresponding Dalvik register.
    297  */
    298 static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
    299                                 int dOffset, ArmLIR *pcrLabel)
    300 {
    301     return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
    302 }
    303 
    304 /* Perform bound check on two registers */
    305 static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
    306                                   int rBound, int dOffset, ArmLIR *pcrLabel)
    307 {
    308     return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
    309                             pcrLabel);
    310 }
    311 
    312 /*
    313  * Jump to the out-of-line handler in ARM mode to finish executing the
    314  * remaining of more complex instructions.
    315  */
    316 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
    317 {
    318     /*
    319      * NOTE - In practice BLX only needs one operand, but since the assembler
    320      * may abort itself and retry due to other out-of-range conditions we
    321      * cannot really use operand[0] to store the absolute target address since
    322      * it may get clobbered by the final relative offset. Therefore,
    323      * we fake BLX_1 is a two operand instruction and the absolute target
    324      * address is stored in operand[1].
    325      */
    326     dvmCompilerClobberHandlerRegs(cUnit);
    327     newLIR2(cUnit, kThumbBlx1,
    328             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
    329             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
    330     newLIR2(cUnit, kThumbBlx2,
    331             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
    332             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
    333 }
    334