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