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 */ 29static 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 36static 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 */ 47static 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 */ 67static 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 */ 80static 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 */ 102static 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 112static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc, 113 RegisterClass opKind) 114{ 115 RegisterInfo *pReg; 116 rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false); 117 if (rlSrc.location == kLocDalvikFrame) { 118 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg); 119 rlSrc.location = kLocPhysReg; 120 dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); 121 } else if (rlSrc.location == kLocRetval) { 122 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg); 123 rlSrc.location = kLocPhysReg; 124 dvmCompilerClobber(cUnit, rlSrc.lowReg); 125 } 126 return rlSrc; 127} 128 129static void storeValue(CompilationUnit *cUnit, RegLocation rlDest, 130 RegLocation rlSrc) 131{ 132 RegisterInfo *pRegLo; 133 LIR *defStart; 134 LIR *defEnd; 135 assert(!rlDest.wide); 136 assert(!rlSrc.wide); 137 dvmCompilerKillNullCheckedLoc(cUnit, rlDest); 138 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc); 139 rlDest = dvmCompilerUpdateLoc(cUnit, rlDest); 140 if (rlSrc.location == kLocPhysReg) { 141 if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || 142 (rlDest.location == kLocPhysReg)) { 143 // Src is live or Dest has assigned reg. 144 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); 145 genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg); 146 } else { 147 // Just re-assign the registers. Dest gets Src's regs 148 rlDest.lowReg = rlSrc.lowReg; 149 dvmCompilerClobber(cUnit, rlSrc.lowReg); 150 } 151 } else { 152 // Load Src either into promoted Dest or temps allocated for Dest 153 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); 154 loadValueDirect(cUnit, rlSrc, rlDest.lowReg); 155 } 156 157 // Dest is now live and dirty (until/if we flush it to home location) 158 dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); 159 dvmCompilerMarkDirty(cUnit, rlDest.lowReg); 160 161 162 if (rlDest.location == kLocRetval) { 163 storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval), 164 rlDest.lowReg, kWord); 165 dvmCompilerClobber(cUnit, rlDest.lowReg); 166 } else { 167 dvmCompilerResetDefLoc(cUnit, rlDest); 168 if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) { 169 defStart = (LIR *)cUnit->lastLIRInsn; 170 int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow); 171 storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord); 172 dvmCompilerMarkClean(cUnit, rlDest.lowReg); 173 defEnd = (LIR *)cUnit->lastLIRInsn; 174 dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd); 175 } 176 } 177} 178 179static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc, 180 RegisterClass opKind) 181{ 182 RegisterInfo *pRegLo; 183 RegisterInfo *pRegHi; 184 assert(rlSrc.wide); 185 rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false); 186 if (rlSrc.location == kLocDalvikFrame) { 187 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg); 188 rlSrc.location = kLocPhysReg; 189 dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow); 190 dvmCompilerMarkLive(cUnit, rlSrc.highReg, 191 dvmCompilerSRegHi(rlSrc.sRegLow)); 192 } else if (rlSrc.location == kLocRetval) { 193 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval), 194 rlSrc.lowReg, rlSrc.highReg, INVALID_SREG); 195 rlSrc.location = kLocPhysReg; 196 dvmCompilerClobber(cUnit, rlSrc.lowReg); 197 dvmCompilerClobber(cUnit, rlSrc.highReg); 198 } 199 return rlSrc; 200} 201 202static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest, 203 RegLocation rlSrc) 204{ 205 RegisterInfo *pRegLo; 206 RegisterInfo *pRegHi; 207 LIR *defStart; 208 LIR *defEnd; 209 bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg); 210 assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg)); 211 assert(rlDest.wide); 212 assert(rlSrc.wide); 213 dvmCompilerKillNullCheckedLoc(cUnit, rlDest); 214 if (rlSrc.location == kLocPhysReg) { 215 if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) || 216 dvmCompilerIsLive(cUnit, rlSrc.highReg) || 217 (rlDest.location == kLocPhysReg)) { 218 // Src is live or Dest has assigned reg. 219 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); 220 genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg, 221 rlSrc.lowReg, rlSrc.highReg); 222 } else { 223 // Just re-assign the registers. Dest gets Src's regs 224 rlDest.lowReg = rlSrc.lowReg; 225 rlDest.highReg = rlSrc.highReg; 226 dvmCompilerClobber(cUnit, rlSrc.lowReg); 227 dvmCompilerClobber(cUnit, rlSrc.highReg); 228 } 229 } else { 230 // Load Src either into promoted Dest or temps allocated for Dest 231 rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false); 232 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg, 233 rlDest.highReg); 234 } 235 236 // Dest is now live and dirty (until/if we flush it to home location) 237 dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow); 238 dvmCompilerMarkLive(cUnit, rlDest.highReg, 239 dvmCompilerSRegHi(rlDest.sRegLow)); 240 dvmCompilerMarkDirty(cUnit, rlDest.lowReg); 241 dvmCompilerMarkDirty(cUnit, rlDest.highReg); 242 dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg); 243 244 245 if (rlDest.location == kLocRetval) { 246 storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval), 247 rlDest.lowReg, rlDest.highReg); 248 dvmCompilerClobber(cUnit, rlDest.lowReg); 249 dvmCompilerClobber(cUnit, rlDest.highReg); 250 } else { 251 dvmCompilerResetDefLocWide(cUnit, rlDest); 252 if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) || 253 dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) { 254 defStart = (LIR *)cUnit->lastLIRInsn; 255 int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow); 256 assert((vReg+1) == dvmCompilerS2VReg(cUnit, 257 dvmCompilerSRegHi(rlDest.sRegLow))); 258 storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg, 259 rlDest.highReg); 260 dvmCompilerMarkClean(cUnit, rlDest.lowReg); 261 dvmCompilerMarkClean(cUnit, rlDest.highReg); 262 defEnd = (LIR *)cUnit->lastLIRInsn; 263 dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd); 264 } 265 } 266} 267/* 268 * Perform null-check on a register. sReg is the ssa register being checked, 269 * and mReg is the machine register holding the actual value. If internal state 270 * indicates that sReg has been checked before the check request is ignored. 271 */ 272static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg, 273 int dOffset, ArmLIR *pcrLabel) 274{ 275 /* This particular Dalvik register has been null-checked */ 276 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) { 277 return pcrLabel; 278 } 279 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg); 280 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel); 281} 282 283 284 285/* 286 * Perform a "reg cmp reg" operation and jump to the PCR region if condition 287 * satisfies. 288 */ 289static ArmLIR *genRegRegCheck(CompilationUnit *cUnit, 290 ArmConditionCode cond, 291 int reg1, int reg2, int dOffset, 292 ArmLIR *pcrLabel) 293{ 294 ArmLIR *res; 295 res = opRegReg(cUnit, kOpCmp, reg1, reg2); 296 ArmLIR *branch = opCondBranch(cUnit, cond); 297 genCheckCommon(cUnit, dOffset, branch, pcrLabel); 298 return res; 299} 300 301/* 302 * Perform zero-check on a register. Similar to genNullCheck but the value being 303 * checked does not have a corresponding Dalvik register. 304 */ 305static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg, 306 int dOffset, ArmLIR *pcrLabel) 307{ 308 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel); 309} 310 311/* Perform bound check on two registers */ 312static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex, 313 int rBound, int dOffset, ArmLIR *pcrLabel) 314{ 315 return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset, 316 pcrLabel); 317} 318 319/* 320 * Jump to the out-of-line handler in ARM mode to finish executing the 321 * remaining of more complex instructions. 322 */ 323static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode) 324{ 325 /* 326 * NOTE - In practice BLX only needs one operand, but since the assembler 327 * may abort itself and retry due to other out-of-range conditions we 328 * cannot really use operand[0] to store the absolute target address since 329 * it may get clobbered by the final relative offset. Therefore, 330 * we fake BLX_1 is a two operand instruction and the absolute target 331 * address is stored in operand[1]. 332 */ 333 dvmCompilerClobberHandlerRegs(cUnit); 334 newLIR2(cUnit, kThumbBlx1, 335 (int) gDvmJit.codeCache + templateEntryOffsets[opCode], 336 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); 337 newLIR2(cUnit, kThumbBlx2, 338 (int) gDvmJit.codeCache + templateEntryOffsets[opCode], 339 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]); 340} 341