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