Home | History | Annotate | Download | only in codegen
      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 target-independent codegen and support, and is
     19  * included by:
     20  *
     21  *        $(TARGET_ARCH)/Codegen-$(TARGET_ARCH_VARIANT).c
     22  *
     23  * which combines this common code with specific support found in the
     24  * applicable directories below this one.
     25  *
     26  * Prior to including this file, TGT_LIR should be #defined.
     27  * For example, for arm:
     28  *    #define TGT_LIR ArmLIR
     29  * and for x86:
     30  *    #define TGT_LIR X86LIR
     31  */
     32 
     33 
     34 /* Load a word at base + displacement.  Displacement must be word multiple */
     35 static TGT_LIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
     36                              int displacement, int rDest)
     37 {
     38     return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
     39                         INVALID_SREG);
     40 }
     41 
     42 static TGT_LIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
     43                              int displacement, int rSrc)
     44 {
     45     return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
     46 }
     47 
     48 /*
     49  * Load a Dalvik register into a physical register.  Take care when
     50  * using this routine, as it doesn't perform any bookkeeping regarding
     51  * register liveness.  That is the responsibility of the caller.
     52  */
     53 static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
     54                             int reg1)
     55 {
     56     rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
     57     if (rlSrc.location == kLocPhysReg) {
     58         genRegCopy(cUnit, reg1, rlSrc.lowReg);
     59     } else  if (rlSrc.location == kLocRetval) {
     60         loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
     61     } else {
     62         assert(rlSrc.location == kLocDalvikFrame);
     63         loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
     64                      reg1);
     65     }
     66 }
     67 
     68 /*
     69  * Similar to loadValueDirect, but clobbers and allocates the target
     70  * register.  Should be used when loading to a fixed register (for example,
     71  * loading arguments to an out of line call.
     72  */
     73 static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
     74                                  int reg1)
     75 {
     76     dvmCompilerClobber(cUnit, reg1);
     77     dvmCompilerMarkInUse(cUnit, reg1);
     78     loadValueDirect(cUnit, rlSrc, reg1);
     79 }
     80 
     81 /*
     82  * Load a Dalvik register pair into a physical register[s].  Take care when
     83  * using this routine, as it doesn't perform any bookkeeping regarding
     84  * register liveness.  That is the responsibility of the caller.
     85  */
     86 static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
     87                                 int regLo, int regHi)
     88 {
     89     rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
     90     if (rlSrc.location == kLocPhysReg) {
     91         genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
     92     } else if (rlSrc.location == kLocRetval) {
     93         loadBaseDispWide(cUnit, NULL, rSELF,
     94                          offsetof(Thread, interpSave.retval),
     95                          regLo, regHi, INVALID_SREG);
     96     } else {
     97         assert(rlSrc.location == kLocDalvikFrame);
     98             loadBaseDispWide(cUnit, NULL, rFP,
     99                              dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
    100                              regLo, regHi, INVALID_SREG);
    101     }
    102 }
    103 
    104 /*
    105  * Similar to loadValueDirect, but clobbers and allocates the target
    106  * registers.  Should be used when loading to a fixed registers (for example,
    107  * loading arguments to an out of line call.
    108  */
    109 static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
    110                                      int regLo, int regHi)
    111 {
    112     dvmCompilerClobber(cUnit, regLo);
    113     dvmCompilerClobber(cUnit, regHi);
    114     dvmCompilerMarkInUse(cUnit, regLo);
    115     dvmCompilerMarkInUse(cUnit, regHi);
    116     loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
    117 }
    118 
    119 static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
    120                              RegisterClass opKind)
    121 {
    122     rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
    123     if (rlSrc.location == kLocDalvikFrame) {
    124         loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
    125         rlSrc.location = kLocPhysReg;
    126         dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
    127     } else if (rlSrc.location == kLocRetval) {
    128         loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
    129                      rlSrc.lowReg);
    130         rlSrc.location = kLocPhysReg;
    131         dvmCompilerClobber(cUnit, rlSrc.lowReg);
    132     }
    133     return rlSrc;
    134 }
    135 
    136 static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
    137                        RegLocation rlSrc)
    138 {
    139     LIR *defStart;
    140     LIR *defEnd;
    141     assert(!rlDest.wide);
    142     assert(!rlSrc.wide);
    143     dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
    144     rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
    145     rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
    146     if (rlSrc.location == kLocPhysReg) {
    147         if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
    148             (rlDest.location == kLocPhysReg)) {
    149             // Src is live or Dest has assigned reg.
    150             rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    151             genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
    152         } else {
    153             // Just re-assign the registers.  Dest gets Src's regs
    154             rlDest.lowReg = rlSrc.lowReg;
    155             dvmCompilerClobber(cUnit, rlSrc.lowReg);
    156         }
    157     } else {
    158         // Load Src either into promoted Dest or temps allocated for Dest
    159         rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    160         loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
    161     }
    162 
    163     // Dest is now live and dirty (until/if we flush it to home location)
    164     dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
    165     dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
    166 
    167 
    168     if (rlDest.location == kLocRetval) {
    169         storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
    170                       rlDest.lowReg, kWord);
    171         dvmCompilerClobber(cUnit, rlDest.lowReg);
    172     } else {
    173         dvmCompilerResetDefLoc(cUnit, rlDest);
    174         if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
    175             defStart = (LIR *)cUnit->lastLIRInsn;
    176             int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
    177             storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
    178             dvmCompilerMarkClean(cUnit, rlDest.lowReg);
    179             defEnd = (LIR *)cUnit->lastLIRInsn;
    180             dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
    181         }
    182     }
    183 }
    184 
    185 static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
    186                                  RegisterClass opKind)
    187 {
    188     assert(rlSrc.wide);
    189     rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
    190     if (rlSrc.location == kLocDalvikFrame) {
    191         loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
    192         rlSrc.location = kLocPhysReg;
    193         dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
    194         dvmCompilerMarkLive(cUnit, rlSrc.highReg,
    195                             dvmCompilerSRegHi(rlSrc.sRegLow));
    196     } else if (rlSrc.location == kLocRetval) {
    197         loadBaseDispWide(cUnit, NULL, rSELF,
    198                          offsetof(Thread, interpSave.retval),
    199                          rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
    200         rlSrc.location = kLocPhysReg;
    201         dvmCompilerClobber(cUnit, rlSrc.lowReg);
    202         dvmCompilerClobber(cUnit, rlSrc.highReg);
    203     }
    204     return rlSrc;
    205 }
    206 
    207 static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
    208                            RegLocation rlSrc)
    209 {
    210     LIR *defStart;
    211     LIR *defEnd;
    212     assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
    213     assert(rlDest.wide);
    214     assert(rlSrc.wide);
    215     dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
    216     if (rlSrc.location == kLocPhysReg) {
    217         if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
    218             dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
    219             (rlDest.location == kLocPhysReg)) {
    220             // Src is live or Dest has assigned reg.
    221             rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    222             genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
    223                            rlSrc.lowReg, rlSrc.highReg);
    224         } else {
    225             // Just re-assign the registers.  Dest gets Src's regs
    226             rlDest.lowReg = rlSrc.lowReg;
    227             rlDest.highReg = rlSrc.highReg;
    228             dvmCompilerClobber(cUnit, rlSrc.lowReg);
    229             dvmCompilerClobber(cUnit, rlSrc.highReg);
    230         }
    231     } else {
    232         // Load Src either into promoted Dest or temps allocated for Dest
    233         rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
    234         loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
    235                             rlDest.highReg);
    236     }
    237 
    238     // Dest is now live and dirty (until/if we flush it to home location)
    239     dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
    240     dvmCompilerMarkLive(cUnit, rlDest.highReg,
    241                         dvmCompilerSRegHi(rlDest.sRegLow));
    242     dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
    243     dvmCompilerMarkDirty(cUnit, rlDest.highReg);
    244     dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
    245 
    246 
    247     if (rlDest.location == kLocRetval) {
    248         storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
    249                           rlDest.lowReg, rlDest.highReg);
    250         dvmCompilerClobber(cUnit, rlDest.lowReg);
    251         dvmCompilerClobber(cUnit, rlDest.highReg);
    252     } else {
    253         dvmCompilerResetDefLocWide(cUnit, rlDest);
    254         if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
    255             dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
    256             defStart = (LIR *)cUnit->lastLIRInsn;
    257             int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
    258             assert((vReg+1) == dvmCompilerS2VReg(cUnit,
    259                                      dvmCompilerSRegHi(rlDest.sRegLow)));
    260             storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
    261                               rlDest.highReg);
    262             dvmCompilerMarkClean(cUnit, rlDest.lowReg);
    263             dvmCompilerMarkClean(cUnit, rlDest.highReg);
    264             defEnd = (LIR *)cUnit->lastLIRInsn;
    265             dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
    266         }
    267     }
    268 }
    269