| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 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 for the Thumb ISA and is intended to be |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 19 | * includes by: |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 20 | * |
| 21 | * Codegen-$(TARGET_ARCH_VARIANT).c |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #include "Codegen.h" |
| Bill Buzbee | 7ea0f64 | 2009-08-10 17:06:51 -0700 | [diff] [blame] | 26 | |
| 27 | static int leadingZeros(u4 val) |
| 28 | { |
| 29 | u4 alt; |
| 30 | int n; |
| 31 | int count; |
| 32 | |
| 33 | count = 16; |
| 34 | n = 32; |
| 35 | do { |
| 36 | alt = val >> count; |
| 37 | if (alt != 0) { |
| 38 | n = n - count; |
| 39 | val = alt; |
| 40 | } |
| 41 | count >>= 1; |
| 42 | } while (count); |
| 43 | return n - val; |
| 44 | } |
| 45 | |
| 46 | /* |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 47 | * Determine whether value can be encoded as a Thumb2 modified |
| Bill Buzbee | 7ea0f64 | 2009-08-10 17:06:51 -0700 | [diff] [blame] | 48 | * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form. |
| 49 | */ |
| 50 | static int modifiedImmediate(u4 value) |
| 51 | { |
| 52 | int zLeading; |
| 53 | int zTrailing; |
| 54 | u4 b0 = value & 0xff; |
| 55 | |
| 56 | /* Note: case of value==0 must use 0:000:0:0000000 encoding */ |
| 57 | if (value <= 0xFF) |
| 58 | return b0; // 0:000:a:bcdefgh |
| 59 | if (value == ((b0 << 16) | b0)) |
| 60 | return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */ |
| 61 | if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0)) |
| 62 | return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */ |
| 63 | b0 = (value >> 8) & 0xff; |
| 64 | if (value == ((b0 << 24) | (b0 << 8))) |
| 65 | return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */ |
| 66 | /* Can we do it with rotation? */ |
| 67 | zLeading = leadingZeros(value); |
| 68 | zTrailing = 32 - leadingZeros(~value & (value - 1)); |
| 69 | /* A run of eight or fewer active bits? */ |
| 70 | if ((zLeading + zTrailing) < 24) |
| 71 | return -1; /* No - bail */ |
| 72 | /* left-justify the constant, discarding msb (known to be 1) */ |
| 73 | value <<= zLeading + 1; |
| 74 | /* Create bcdefgh */ |
| 75 | value >>= 25; |
| 76 | /* Put it all together */ |
| 77 | return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */ |
| 78 | } |
| 79 | |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 80 | /* |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 81 | * Determine whether value can be encoded as a Thumb2 floating point |
| 82 | * immediate. If not, return -1. If so return encoded 8-bit value. |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 83 | */ |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 84 | static int encodeImmDoubleHigh(int value) |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 85 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 86 | int res; |
| 87 | int bitA = (value & 0x80000000) >> 31; |
| 88 | int notBitB = (value & 0x40000000) >> 30; |
| 89 | int bitB = (value & 0x20000000) >> 29; |
| 90 | int bSmear = (value & 0x3fc00000) >> 22; |
| 91 | int slice = (value & 0x003f0000) >> 16; |
| 92 | int zeroes = (value & 0x0000ffff); |
| 93 | if (zeroes != 0) |
| 94 | return -1; |
| 95 | if (bitB) { |
| 96 | if ((notBitB != 0) || (bSmear != 0x1f)) |
| 97 | return -1; |
| 98 | } else { |
| 99 | if ((notBitB != 1) || (bSmear != 0x0)) |
| 100 | return -1; |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 101 | } |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 102 | res = (bitA << 7) | (bitB << 6) | slice; |
| 103 | return res; |
| 104 | } |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 105 | |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 106 | static int encodeImmSingle(int value) |
| 107 | { |
| 108 | int res; |
| 109 | int bitA = (value & 0x80000000) >> 31; |
| 110 | int notBitB = (value & 0x40000000) >> 30; |
| 111 | int bitB = (value & 0x20000000) >> 29; |
| 112 | int bSmear = (value & 0x3e000000) >> 25; |
| 113 | int slice = (value & 0x01f80000) >> 19; |
| 114 | int zeroes = (value & 0x0007ffff); |
| 115 | if (zeroes != 0) |
| 116 | return -1; |
| 117 | if (bitB) { |
| 118 | if ((notBitB != 0) || (bSmear != 0x1f)) |
| 119 | return -1; |
| 120 | } else { |
| 121 | if ((notBitB != 1) || (bSmear != 0x0)) |
| 122 | return -1; |
| 123 | } |
| 124 | res = (bitA << 7) | (bitB << 6) | slice; |
| 125 | return res; |
| 126 | } |
| 127 | |
| 128 | static int encodeImmDouble(int valLo, int valHi) |
| 129 | { |
| 130 | int res = -1; |
| 131 | if (valLo == 0) |
| 132 | res = encodeImmDoubleHigh(valHi); |
| 133 | return res; |
| 134 | } |
| 135 | void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi, |
| 136 | int srcLo, int srcHi) |
| 137 | { |
| 138 | bool destFP = FPREG(destLo) && FPREG(destHi); |
| 139 | bool srcFP = FPREG(srcLo) && FPREG(srcHi); |
| 140 | assert(FPREG(srcLo) == FPREG(srcHi)); |
| 141 | assert(FPREG(destLo) == FPREG(destHi)); |
| 142 | if (destFP) { |
| 143 | if (srcFP) { |
| 144 | genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi)); |
| 145 | } else { |
| 146 | newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi); |
| 147 | } |
| 148 | } else { |
| 149 | if (srcFP) { |
| 150 | newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi)); |
| 151 | } else { |
| 152 | // Handle overlap |
| 153 | if (srcHi == destLo) { |
| 154 | genRegCopy(cUnit, destHi, srcHi); |
| 155 | genRegCopy(cUnit, destLo, srcLo); |
| 156 | } else { |
| 157 | genRegCopy(cUnit, destLo, srcLo); |
| 158 | genRegCopy(cUnit, destHi, srcHi); |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | |
| 165 | static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12}; |
| 166 | static int corePreserved[] = {}; |
| 167 | static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23, |
| 168 | fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31}; |
| 169 | static int fpPreserved[] = {}; |
| 170 | void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit) |
| 171 | { |
| 172 | int i; |
| 173 | int numTemps = sizeof(coreTemps)/sizeof(int); |
| 174 | int numFPTemps = sizeof(fpTemps)/sizeof(int); |
| 175 | RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true); |
| 176 | cUnit->regPool = pool; |
| 177 | pool->numCoreTemps = numTemps; |
| 178 | pool->coreTemps = |
| 179 | dvmCompilerNew(numTemps * sizeof(*cUnit->regPool->coreTemps), true); |
| 180 | pool->numFPTemps = numFPTemps; |
| 181 | pool->FPTemps = |
| 182 | dvmCompilerNew(numFPTemps * sizeof(*cUnit->regPool->FPTemps), true); |
| 183 | pool->numCoreRegs = 0; |
| 184 | pool->coreRegs = NULL; |
| 185 | pool->numFPRegs = 0; |
| 186 | pool->FPRegs = NULL; |
| 187 | initPool(pool->coreTemps, coreTemps, pool->numCoreTemps); |
| 188 | initPool(pool->FPTemps, fpTemps, pool->numFPTemps); |
| 189 | initPool(pool->coreRegs, NULL, 0); |
| 190 | initPool(pool->FPRegs, NULL, 0); |
| 191 | pool->nullCheckedRegs = |
| 192 | dvmCompilerAllocBitVector(cUnit->numSSARegs, false); |
| 193 | } |
| 194 | |
| 195 | |
| 196 | /* |
| 197 | * Alloc a pair of core registers, or a double. Low reg in low byte, |
| 198 | * high reg in next byte. |
| 199 | */ |
| 200 | static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint, int regClass) |
| 201 | { |
| 202 | int highReg; |
| 203 | int lowReg; |
| 204 | int res = 0; |
| 205 | if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) { |
| 206 | lowReg = allocTempDouble(cUnit); |
| 207 | highReg = lowReg + 1; |
| 208 | } else { |
| 209 | lowReg = allocTemp(cUnit); |
| 210 | highReg = allocTemp(cUnit); |
| 211 | } |
| 212 | res = (lowReg & 0xff) | ((highReg & 0xff) << 8); |
| 213 | return res; |
| 214 | } |
| 215 | |
| 216 | static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass) |
| 217 | { |
| 218 | if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) |
| 219 | return allocTempFloat(cUnit); |
| 220 | return allocTemp(cUnit); |
| 221 | } |
| 222 | |
| 223 | static int encodeShift(int code, int amount) { |
| 224 | return ((amount & 0x1f) << 2) | code; |
| 225 | } |
| 226 | |
| 227 | /* |
| 228 | * Generate a Thumb2 IT instruction, which can nullify up to |
| 229 | * four subsequent instructions based on a condition and its |
| 230 | * inverse. The condition applies to the first instruction, which |
| 231 | * is executed if the condition is met. The string "guide" consists |
| 232 | * of 0 to 3 chars, and applies to the 2nd through 4th instruction. |
| 233 | * A "T" means the instruction is executed if the condition is |
| 234 | * met, and an "E" means the instruction is executed if the condition |
| 235 | * is not met. |
| 236 | */ |
| 237 | static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code, |
| 238 | char *guide) |
| 239 | { |
| 240 | int mask; |
| 241 | int condBit = code & 1; |
| 242 | int altBit = condBit ^ 1; |
| 243 | int mask3 = 0; |
| 244 | int mask2 = 0; |
| 245 | int mask1 = 0; |
| 246 | |
| 247 | //Note: case fallthroughs intentional |
| 248 | switch(strlen(guide)) { |
| 249 | case 3: |
| 250 | mask1 = (guide[2] == 'T') ? condBit : altBit; |
| 251 | case 2: |
| 252 | mask2 = (guide[1] == 'T') ? condBit : altBit; |
| 253 | case 1: |
| 254 | mask3 = (guide[0] == 'T') ? condBit : altBit; |
| 255 | break; |
| 256 | case 0: |
| 257 | break; |
| 258 | default: |
| 259 | assert(0); |
| 260 | dvmAbort(); |
| 261 | } |
| 262 | mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) | |
| 263 | (1 << (3 - strlen(guide))); |
| 264 | return newLIR2(cUnit, kThumb2It, code, mask); |
| 265 | } |
| 266 | |
| 267 | |
| 268 | static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) |
| 269 | { |
| 270 | ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true); |
| 271 | res->operands[0] = rDest; |
| 272 | res->operands[1] = rSrc; |
| 273 | if (rDest == rSrc) { |
| 274 | res->isNop = true; |
| 275 | } else { |
| 276 | assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc)); |
| 277 | if (DOUBLEREG(rDest)) { |
| 278 | res->opCode = kThumb2Vmovd; |
| 279 | } else { |
| 280 | if (SINGLEREG(rDest)) { |
| 281 | res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr; |
| 282 | } else { |
| 283 | assert(SINGLEREG(rSrc)); |
| 284 | res->opCode = kThumb2Fmrs; |
| 285 | } |
| 286 | } |
| 287 | res->operands[0] = rDest; |
| 288 | res->operands[1] = rSrc; |
| 289 | } |
| 290 | setupResourceMasks(res); |
| 291 | return res; |
| 292 | } |
| 293 | |
| 294 | ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc) |
| 295 | { |
| 296 | ArmLIR* res; |
| 297 | ArmOpCode opCode; |
| 298 | if (FPREG(rDest) || FPREG(rSrc)) |
| 299 | return fpRegCopy(cUnit, rDest, rSrc); |
| 300 | res = dvmCompilerNew(sizeof(ArmLIR), true); |
| 301 | if (LOWREG(rDest) && LOWREG(rSrc)) |
| 302 | opCode = kThumbMovRR; |
| 303 | else if (!LOWREG(rDest) && !LOWREG(rSrc)) |
| 304 | opCode = kThumbMovRR_H2H; |
| 305 | else if (LOWREG(rDest)) |
| 306 | opCode = kThumbMovRR_H2L; |
| 307 | else |
| 308 | opCode = kThumbMovRR_L2H; |
| 309 | |
| 310 | res->operands[0] = rDest; |
| 311 | res->operands[1] = rSrc; |
| 312 | res->opCode = opCode; |
| 313 | setupResourceMasks(res); |
| 314 | if (rDest == rSrc) { |
| 315 | res->isNop = true; |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 316 | } |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 317 | return res; |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 318 | } |
| 319 | |
| 320 | /* Export the Dalvik PC assicated with an instruction to the StackSave area */ |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 321 | static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir) |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 322 | { |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 323 | ArmLIR *res; |
| Bill Buzbee | 9bc3df3 | 2009-07-30 10:52:29 -0700 | [diff] [blame] | 324 | int offset = offsetof(StackSaveArea, xtra.currentPc); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 325 | int rDPC = allocTemp(cUnit); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 326 | res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset)); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 327 | newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, rFP, |
| Bill Buzbee | 7ea0f64 | 2009-08-10 17:06:51 -0700 | [diff] [blame] | 328 | sizeof(StackSaveArea) - offset); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 329 | freeTemp(cUnit, rDPC); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 330 | return res; |
| 331 | } |
| 332 | |
| 333 | static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op) |
| 334 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 335 | ArmOpCode opCode = kThumbBkpt; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 336 | switch (op) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 337 | case kOpUncondBr: |
| 338 | opCode = kThumbBUncond; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 339 | break; |
| 340 | default: |
| 341 | assert(0); |
| 342 | } |
| 343 | return newLIR0(cUnit, opCode); |
| 344 | } |
| 345 | |
| Ben Cheng | 4f48917 | 2009-09-27 17:08:35 -0700 | [diff] [blame] | 346 | static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc) |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 347 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 348 | return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 349 | } |
| 350 | |
| 351 | static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value) |
| 352 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 353 | ArmOpCode opCode = kThumbBkpt; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 354 | switch (op) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 355 | case kOpPush: |
| 356 | opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 357 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 358 | case kOpPop: |
| 359 | opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 360 | break; |
| 361 | default: |
| 362 | assert(0); |
| 363 | } |
| 364 | return newLIR1(cUnit, opCode, value); |
| 365 | } |
| 366 | |
| 367 | static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc) |
| 368 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 369 | ArmOpCode opCode = kThumbBkpt; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 370 | switch (op) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 371 | case kOpBlx: |
| 372 | opCode = kThumbBlxR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 373 | break; |
| 374 | default: |
| 375 | assert(0); |
| 376 | } |
| 377 | return newLIR1(cUnit, opCode, rDestSrc); |
| 378 | } |
| 379 | |
| 380 | static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1, |
| 381 | int rSrc2, int shift) |
| 382 | { |
| 383 | bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2)); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 384 | ArmOpCode opCode = kThumbBkpt; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 385 | switch (op) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 386 | case kOpAdc: |
| 387 | opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 388 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 389 | case kOpAnd: |
| 390 | opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 391 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 392 | case kOpBic: |
| 393 | opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 394 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 395 | case kOpCmn: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 396 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 397 | opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 398 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 399 | case kOpCmp: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 400 | if (thumbForm) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 401 | opCode = kThumbCmpRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 402 | else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2)) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 403 | opCode = kThumbCmpHH; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 404 | else if ((shift == 0) && LOWREG(rDestSrc1)) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 405 | opCode = kThumbCmpLH; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 406 | else if (shift == 0) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 407 | opCode = kThumbCmpHL; |
| Ben Cheng | dcf3e5d | 2009-09-11 13:42:05 -0700 | [diff] [blame] | 408 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 409 | opCode = kThumb2CmpRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 410 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 411 | case kOpXor: |
| 412 | opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 413 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 414 | case kOpMov: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 415 | assert(shift == 0); |
| 416 | if (LOWREG(rDestSrc1) && LOWREG(rSrc2)) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 417 | opCode = kThumbMovRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 418 | else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2)) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 419 | opCode = kThumbMovRR_H2H; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 420 | else if (LOWREG(rDestSrc1)) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 421 | opCode = kThumbMovRR_H2L; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 422 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 423 | opCode = kThumbMovRR_L2H; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 424 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 425 | case kOpMul: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 426 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 427 | opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 428 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 429 | case kOpMvn: |
| 430 | opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 431 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 432 | case kOpNeg: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 433 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 434 | opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 435 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 436 | case kOpOr: |
| 437 | opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 438 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 439 | case kOpSbc: |
| 440 | opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 441 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 442 | case kOpTst: |
| 443 | opCode = (thumbForm) ? kThumbTst : kThumb2TstRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 444 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 445 | case kOpLsl: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 446 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 447 | opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 448 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 449 | case kOpLsr: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 450 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 451 | opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 452 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 453 | case kOpAsr: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 454 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 455 | opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 456 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 457 | case kOpRor: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 458 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 459 | opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 460 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 461 | case kOpAdd: |
| 462 | opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 463 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 464 | case kOpSub: |
| 465 | opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 466 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 467 | case kOp2Byte: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 468 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 469 | return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8); |
| 470 | case kOp2Short: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 471 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 472 | return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16); |
| 473 | case kOp2Char: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 474 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 475 | return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 476 | default: |
| 477 | assert(0); |
| 478 | break; |
| 479 | } |
| 480 | assert(opCode >= 0); |
| 481 | if (EncodingMap[opCode].flags & IS_BINARY_OP) |
| 482 | return newLIR2(cUnit, opCode, rDestSrc1, rSrc2); |
| 483 | else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 484 | if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift) |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 485 | return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift); |
| 486 | else |
| 487 | return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2); |
| 488 | } else if (EncodingMap[opCode].flags & IS_QUAD_OP) |
| 489 | return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift); |
| 490 | else { |
| 491 | assert(0); |
| 492 | return NULL; |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1, |
| 497 | int rSrc2) |
| 498 | { |
| 499 | return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0); |
| 500 | } |
| 501 | |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 502 | static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op, |
| 503 | int rDest, int rSrc1, int rSrc2, int shift) |
| 504 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 505 | ArmOpCode opCode = kThumbBkpt; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 506 | bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) && |
| 507 | LOWREG(rSrc2); |
| 508 | switch (op) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 509 | case kOpAdd: |
| 510 | opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 511 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 512 | case kOpSub: |
| 513 | opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 514 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 515 | case kOpAdc: |
| 516 | opCode = kThumb2AdcRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 517 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 518 | case kOpAnd: |
| 519 | opCode = kThumb2AndRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 520 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 521 | case kOpBic: |
| 522 | opCode = kThumb2BicRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 523 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 524 | case kOpXor: |
| 525 | opCode = kThumb2EorRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 526 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 527 | case kOpMul: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 528 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 529 | opCode = kThumb2MulRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 530 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 531 | case kOpOr: |
| 532 | opCode = kThumb2OrrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 533 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 534 | case kOpSbc: |
| 535 | opCode = kThumb2SbcRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 536 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 537 | case kOpLsl: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 538 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 539 | opCode = kThumb2LslRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 540 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 541 | case kOpLsr: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 542 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 543 | opCode = kThumb2LsrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 544 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 545 | case kOpAsr: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 546 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 547 | opCode = kThumb2AsrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 548 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 549 | case kOpRor: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 550 | assert(shift == 0); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 551 | opCode = kThumb2RorRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 552 | break; |
| 553 | default: |
| 554 | assert(0); |
| 555 | break; |
| 556 | } |
| 557 | assert(opCode >= 0); |
| 558 | if (EncodingMap[opCode].flags & IS_QUAD_OP) |
| 559 | return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift); |
| 560 | else { |
| 561 | assert(EncodingMap[opCode].flags & IS_TERTIARY_OP); |
| 562 | return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2); |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest, |
| 567 | int rSrc1, int rSrc2) |
| 568 | { |
| 569 | return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0); |
| 570 | } |
| 571 | |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 572 | static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp, |
| 573 | OpKind secondOp, RegLocation rlDest, |
| 574 | RegLocation rlSrc1, RegLocation rlSrc2) |
| 575 | { |
| 576 | RegLocation rlResult; |
| 577 | rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); |
| 578 | rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); |
| 579 | rlResult = evalLoc(cUnit, rlDest, kCoreReg, true); |
| 580 | opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); |
| 581 | opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, |
| 582 | rlSrc2.highReg); |
| 583 | storeValueWide(cUnit, rlDest, rlResult); |
| 584 | } |
| 585 | |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 586 | static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest, |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 587 | int rSrc1, int value) |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 588 | { |
| 589 | ArmLIR *res; |
| 590 | bool neg = (value < 0); |
| 591 | int absValue = (neg) ? -value : value; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 592 | ArmOpCode opCode = kThumbBkpt; |
| 593 | ArmOpCode altOpCode = kThumbBkpt; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 594 | bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1)); |
| 595 | int modImm = modifiedImmediate(value); |
| 596 | int modImmNeg = modifiedImmediate(-value); |
| 597 | |
| 598 | switch(op) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 599 | case kOpLsl: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 600 | if (allLowRegs) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 601 | return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 602 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 603 | return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value); |
| 604 | case kOpLsr: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 605 | if (allLowRegs) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 606 | return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 607 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 608 | return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value); |
| 609 | case kOpAsr: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 610 | if (allLowRegs) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 611 | return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 612 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 613 | return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value); |
| 614 | case kOpRor: |
| 615 | return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value); |
| 616 | case kOpAdd: |
| Ben Cheng | dcf3e5d | 2009-09-11 13:42:05 -0700 | [diff] [blame] | 617 | if (LOWREG(rDest) && (rSrc1 == 13) && |
| 618 | (value <= 1020) && ((value & 0x3)==0)) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 619 | return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1, |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 620 | value >> 2); |
| Ben Cheng | dcf3e5d | 2009-09-11 13:42:05 -0700 | [diff] [blame] | 621 | } else if (LOWREG(rDest) && (rSrc1 == rpc) && |
| 622 | (value <= 1020) && ((value & 0x3)==0)) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 623 | return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1, |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 624 | value >> 2); |
| 625 | } |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 626 | opCode = kThumb2AddRRI8; |
| 627 | altOpCode = kThumb2AddRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 628 | // Note: intentional fallthrough |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 629 | case kOpSub: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 630 | if (allLowRegs && ((absValue & 0x7) == absValue)) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 631 | if (op == kOpAdd) |
| 632 | opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 633 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 634 | opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 635 | return newLIR3(cUnit, opCode, rDest, rSrc1, absValue); |
| 636 | } else if ((absValue & 0xff) == absValue) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 637 | if (op == kOpAdd) |
| 638 | opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 639 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 640 | opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 641 | return newLIR3(cUnit, opCode, rDest, rSrc1, absValue); |
| 642 | } |
| 643 | if (modImmNeg >= 0) { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 644 | op = (op == kOpAdd) ? kOpSub : kOpAdd; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 645 | modImm = modImmNeg; |
| 646 | } |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 647 | if (op == kOpSub) { |
| 648 | opCode = kThumb2SubRRI8; |
| 649 | altOpCode = kThumb2SubRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 650 | } |
| 651 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 652 | case kOpAdc: |
| 653 | opCode = kThumb2AdcRRI8; |
| 654 | altOpCode = kThumb2AdcRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 655 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 656 | case kOpSbc: |
| 657 | opCode = kThumb2SbcRRI8; |
| 658 | altOpCode = kThumb2SbcRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 659 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 660 | case kOpOr: |
| 661 | opCode = kThumb2OrrRRI8; |
| 662 | altOpCode = kThumb2OrrRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 663 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 664 | case kOpAnd: |
| 665 | opCode = kThumb2AndRRI8; |
| 666 | altOpCode = kThumb2AndRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 667 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 668 | case kOpXor: |
| 669 | opCode = kThumb2EorRRI8; |
| 670 | altOpCode = kThumb2EorRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 671 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 672 | case kOpMul: |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 673 | //TUNING: power of 2, shift & add |
| 674 | modImm = -1; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 675 | altOpCode = kThumb2MulRRR; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 676 | break; |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 677 | case kOpCmp: { |
| 678 | int modImm = modifiedImmediate(value); |
| 679 | ArmLIR *res; |
| 680 | if (modImm >= 0) { |
| 681 | res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm); |
| 682 | } else { |
| 683 | int rTmp = allocTemp(cUnit); |
| 684 | res = loadConstant(cUnit, rTmp, value); |
| 685 | opRegReg(cUnit, kOpCmp, rSrc1, rTmp); |
| 686 | freeTemp(cUnit, rTmp); |
| 687 | } |
| 688 | return res; |
| 689 | } |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 690 | default: |
| 691 | assert(0); |
| 692 | } |
| 693 | |
| 694 | if (modImm >= 0) { |
| 695 | return newLIR3(cUnit, opCode, rDest, rSrc1, modImm); |
| 696 | } else { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 697 | int rScratch = allocTemp(cUnit); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 698 | loadConstant(cUnit, rScratch, value); |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 699 | if (EncodingMap[altOpCode].flags & IS_QUAD_OP) |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 700 | res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 701 | else |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 702 | res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch); |
| 703 | freeTemp(cUnit, rScratch); |
| 704 | return res; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 705 | } |
| 706 | } |
| 707 | |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 708 | /* Handle Thumb-only variants here - otherwise punt to opRegRegImm */ |
| 709 | static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1, |
| 710 | int value) |
| 711 | { |
| 712 | ArmLIR *res; |
| 713 | bool neg = (value < 0); |
| 714 | int absValue = (neg) ? -value : value; |
| 715 | bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1)); |
| 716 | ArmOpCode opCode = kThumbBkpt; |
| 717 | switch (op) { |
| 718 | case kOpAdd: |
| 719 | if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */ |
| 720 | assert((value & 0x3) == 0); |
| 721 | return newLIR1(cUnit, kThumbAddSpI7, value >> 2); |
| 722 | } else if (shortForm) { |
| 723 | opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8; |
| 724 | } |
| 725 | break; |
| 726 | case kOpSub: |
| 727 | if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */ |
| 728 | assert((value & 0x3) == 0); |
| 729 | return newLIR1(cUnit, kThumbSubSpI7, value >> 2); |
| 730 | } else if (shortForm) { |
| 731 | opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8; |
| 732 | } |
| 733 | break; |
| 734 | case kOpCmp: |
| 735 | if (LOWREG(rDestSrc1) && shortForm) |
| 736 | opCode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR; |
| 737 | else if (LOWREG(rDestSrc1)) |
| 738 | opCode = kThumbCmpRR; |
| 739 | else { |
| 740 | shortForm = false; |
| 741 | opCode = kThumbCmpHL; |
| 742 | } |
| 743 | break; |
| 744 | default: |
| 745 | /* Punt to opRegRegImm - if bad case catch it there */ |
| 746 | shortForm = false; |
| 747 | break; |
| 748 | } |
| 749 | if (shortForm) |
| 750 | return newLIR2(cUnit, opCode, rDestSrc1, absValue); |
| 751 | else { |
| 752 | return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value); |
| 753 | } |
| 754 | } |
| 755 | |
| 756 | static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, |
| 757 | RegLocation rlSrc) |
| 758 | { |
| 759 | RegLocation rlResult; |
| 760 | rlSrc = loadValue(cUnit, rlSrc, kFPReg); |
| 761 | rlResult = evalLoc(cUnit, rlDest, kFPReg, true); |
| 762 | newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg); |
| 763 | storeValue(cUnit, rlDest, rlResult); |
| 764 | } |
| 765 | |
| 766 | static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, |
| 767 | RegLocation rlSrc) |
| 768 | { |
| 769 | RegLocation rlResult; |
| 770 | rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); |
| 771 | rlResult = evalLoc(cUnit, rlDest, kFPReg, true); |
| 772 | newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg), |
| 773 | S2D(rlSrc.lowReg, rlSrc.highReg)); |
| 774 | storeValueWide(cUnit, rlDest, rlResult); |
| 775 | } |
| 776 | |
| 777 | /* |
| 778 | * To avoid possible conflicts, we use a lot of temps here. Note that |
| 779 | * our usage of Thumb2 instruction forms avoids the problems with register |
| 780 | * reuse for multiply instructions prior to arm6. |
| 781 | */ |
| 782 | static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest, |
| 783 | RegLocation rlSrc1, RegLocation rlSrc2) |
| 784 | { |
| 785 | RegLocation rlResult; |
| 786 | int resLo = allocTemp(cUnit); |
| 787 | int resHi = allocTemp(cUnit); |
| 788 | int tmp1 = allocTemp(cUnit); |
| 789 | |
| 790 | rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); |
| 791 | rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); |
| 792 | |
| 793 | newLIR3(cUnit, kThumb2MulRRR, tmp1, rlSrc2.lowReg, rlSrc1.highReg); |
| 794 | newLIR4(cUnit, kThumb2Umull, resLo, resHi, rlSrc2.lowReg, rlSrc1.lowReg); |
| 795 | newLIR4(cUnit, kThumb2Mla, tmp1, rlSrc1.lowReg, rlSrc2.highReg, tmp1); |
| 796 | newLIR4(cUnit, kThumb2AddRRR, resHi, tmp1, resHi, 0); |
| 797 | freeTemp(cUnit, tmp1); |
| 798 | |
| 799 | rlResult = getReturnLocWide(cUnit); // Just as a template, will patch |
| 800 | rlResult.lowReg = resLo; |
| 801 | rlResult.highReg = resHi; |
| 802 | storeValueWide(cUnit, rlDest, rlResult); |
| 803 | } |
| 804 | |
| 805 | /* |
| 806 | * Handle simple case (thin lock) inline. If it's complicated, bail |
| 807 | * out to the heavyweight lock/unlock routines. We'll use dedicated |
| 808 | * registers here in order to be in the right position in case we |
| 809 | * to bail to dvm[Lock/Unlock]Object(self, object) |
| 810 | * |
| 811 | * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object |
| 812 | * r1 -> object [arg1 for dvm[Lock/Unlock]Object |
| 813 | * r2 -> intial contents of object->lock.thin, later result of strex |
| 814 | * r3 -> self->threadId |
| 815 | * r7 -> temp to hold new lock value [unlock only] |
| 816 | * r4 -> allow to be used by utilities as general temp |
| 817 | * |
| 818 | * The result of the strex is 0 if we acquire the lock. |
| 819 | */ |
| 820 | static void handleMonitor(CompilationUnit *cUnit, MIR *mir) |
| 821 | { |
| 822 | #if defined (THIN_LOCKING) |
| 823 | RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); |
| 824 | bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER); |
| 825 | ArmLIR *target; |
| 826 | ArmLIR *branch; |
| 827 | |
| 828 | loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj |
| 829 | lockAllTemps(cUnit); // Prepare for explicit register usage |
| 830 | freeTemp(cUnit, r4PC); // Free up r4 for general use |
| 831 | loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self |
| 832 | genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); |
| 833 | loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId |
| 834 | newLIR3(cUnit, kThumb2Ldrex, r2, r1, |
| 835 | offsetof(Object, lock.thin) >> 2); // Get object->lock.thin |
| 836 | // Is lock.thin unheld on lock or held by us (==threadId) on unlock? |
| 837 | if (enter) { |
| 838 | opRegImm(cUnit, kOpSub, r2, DVM_LOCK_INITIAL_THIN_VALUE); |
| 839 | } else { |
| 840 | loadConstant(cUnit, r7, DVM_LOCK_INITIAL_THIN_VALUE); |
| 841 | opRegReg(cUnit, kOpSub, r2, r3); |
| 842 | } |
| 843 | // Note: start of IT block. If last sub result != clear, else strex |
| 844 | genIT(cUnit, kArmCondNe, "E"); |
| 845 | newLIR0(cUnit, kThumb2Clrex); |
| 846 | if (enter) { |
| 847 | newLIR4(cUnit, kThumb2Strex, r2, r3, r1, |
| 848 | offsetof(Object, lock.thin) >> 2); |
| 849 | } else { |
| 850 | newLIR4(cUnit, kThumb2Strex, r2, r7, r1, |
| 851 | offsetof(Object, lock.thin) >> 2); |
| 852 | } |
| 853 | // Note: end of IT block |
| 854 | |
| 855 | branch = newLIR2(cUnit, kThumb2Cbz, r2, 0); |
| 856 | |
| 857 | if (enter) { |
| 858 | loadConstant(cUnit, r7, (int)dvmLockObject); |
| 859 | } else { |
| 860 | loadConstant(cUnit, r7, (int)dvmUnlockObject); |
| 861 | } |
| 862 | genExportPC(cUnit, mir); |
| 863 | opReg(cUnit, kOpBlx, r7); |
| 864 | |
| 865 | clobberCallRegs(cUnit); |
| 866 | |
| 867 | // Resume here |
| 868 | target = newLIR0(cUnit, kArmPseudoTargetLabel); |
| 869 | target->defMask = ENCODE_ALL; |
| 870 | branch->generic.target = (LIR *)target; |
| 871 | #else |
| 872 | handleMonitorPortable(cUnit, mir); |
| 873 | #endif |
| 874 | } |
| 875 | |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 876 | /* |
| 877 | * 64-bit 3way compare function. |
| 878 | * mov r7, #-1 |
| 879 | * cmp op1hi, op2hi |
| 880 | * blt done |
| 881 | * bgt flip |
| 882 | * sub r7, op1lo, op2lo (treat as unsigned) |
| 883 | * beq done |
| 884 | * ite hi |
| 885 | * mov(hi) r7, #-1 |
| 886 | * mov(!hi) r7, #1 |
| 887 | * flip: |
| 888 | * neg r7 |
| 889 | * done: |
| 890 | */ |
| 891 | static void genCmpLong(CompilationUnit *cUnit, MIR *mir, |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 892 | RegLocation rlDest, RegLocation rlSrc1, |
| 893 | RegLocation rlSrc2) |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 894 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 895 | RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change |
| 896 | ArmLIR *target1; |
| 897 | ArmLIR *target2; |
| 898 | rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg); |
| 899 | rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg); |
| 900 | rlTemp.lowReg = allocTemp(cUnit); |
| 901 | loadConstant(cUnit, rlTemp.lowReg, -1); |
| 902 | opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg); |
| 903 | ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt); |
| 904 | ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt); |
| 905 | opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg); |
| 906 | ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq); |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 907 | |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 908 | genIT(cUnit, kArmCondHi, "E"); |
| 909 | newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1)); |
| 910 | loadConstant(cUnit, rlTemp.lowReg, 1); |
| Ben Cheng | d7d426a | 2009-09-22 11:23:36 -0700 | [diff] [blame] | 911 | genBarrier(cUnit); |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 912 | |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 913 | target2 = newLIR0(cUnit, kArmPseudoTargetLabel); |
| 914 | target2->defMask = -1; |
| 915 | opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg); |
| 916 | |
| 917 | target1 = newLIR0(cUnit, kArmPseudoTargetLabel); |
| 918 | target1->defMask = -1; |
| 919 | |
| 920 | storeValue(cUnit, rlDest, rlTemp); |
| 921 | |
| 922 | branch1->generic.target = (LIR *)target1; |
| 923 | branch2->generic.target = (LIR *)target2; |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 924 | branch3->generic.target = branch1->generic.target; |
| 925 | } |
| 926 | |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 927 | static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase, |
| 928 | int rIndex, int rDest, int scale, OpSize size) |
| 929 | { |
| 930 | bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest); |
| 931 | ArmOpCode opCode = kThumbBkpt; |
| 932 | bool thumbForm = (allLowRegs && (scale == 0)); |
| 933 | int regPtr; |
| 934 | |
| 935 | if (FPREG(rDest)) { |
| 936 | assert(SINGLEREG(rDest)); |
| 937 | assert((size == kWord) || (size == kSingle)); |
| 938 | opCode = kThumb2Vldrs; |
| 939 | size = kSingle; |
| 940 | } else { |
| 941 | if (size == kSingle) |
| 942 | size = kWord; |
| 943 | } |
| 944 | |
| 945 | switch (size) { |
| 946 | case kSingle: |
| 947 | regPtr = allocTemp(cUnit); |
| 948 | if (scale) { |
| 949 | newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex, |
| 950 | encodeShift(kArmLsl, scale)); |
| 951 | } else { |
| 952 | opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex); |
| 953 | } |
| 954 | return newLIR3(cUnit, opCode, rDest, regPtr, 0); |
| 955 | case kWord: |
| 956 | opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR; |
| 957 | break; |
| 958 | case kUnsignedHalf: |
| 959 | opCode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR; |
| 960 | break; |
| 961 | case kSignedHalf: |
| 962 | opCode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR; |
| 963 | break; |
| 964 | case kUnsignedByte: |
| 965 | opCode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR; |
| 966 | break; |
| 967 | case kSignedByte: |
| 968 | opCode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR; |
| 969 | break; |
| 970 | default: |
| 971 | assert(0); |
| 972 | } |
| 973 | if (thumbForm) |
| 974 | return newLIR3(cUnit, opCode, rDest, rBase, rIndex); |
| 975 | else |
| 976 | return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale); |
| 977 | } |
| 978 | |
| 979 | static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase, |
| 980 | int rIndex, int rSrc, int scale, OpSize size) |
| 981 | { |
| 982 | bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc); |
| 983 | ArmOpCode opCode = kThumbBkpt; |
| 984 | bool thumbForm = (allLowRegs && (scale == 0)); |
| 985 | int regPtr; |
| 986 | |
| 987 | if (FPREG(rSrc)) { |
| 988 | assert(SINGLEREG(rSrc)); |
| 989 | assert((size == kWord) || (size == kSingle)); |
| 990 | opCode = kThumb2Vstrs; |
| 991 | size = kSingle; |
| 992 | } else { |
| 993 | if (size == kSingle) |
| 994 | size = kWord; |
| 995 | } |
| 996 | |
| 997 | switch (size) { |
| 998 | case kSingle: |
| 999 | regPtr = allocTemp(cUnit); |
| 1000 | if (scale) { |
| 1001 | newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex, |
| 1002 | encodeShift(kArmLsl, scale)); |
| 1003 | } else { |
| 1004 | opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex); |
| 1005 | } |
| 1006 | return newLIR3(cUnit, opCode, rSrc, regPtr, 0); |
| 1007 | case kWord: |
| 1008 | opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR; |
| 1009 | break; |
| 1010 | case kUnsignedHalf: |
| 1011 | case kSignedHalf: |
| 1012 | opCode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR; |
| 1013 | break; |
| 1014 | case kUnsignedByte: |
| 1015 | case kSignedByte: |
| 1016 | opCode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR; |
| 1017 | break; |
| 1018 | default: |
| 1019 | assert(0); |
| 1020 | } |
| 1021 | if (thumbForm) |
| 1022 | return newLIR3(cUnit, opCode, rSrc, rBase, rIndex); |
| 1023 | else |
| 1024 | return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale); |
| 1025 | } |
| 1026 | |
| 1027 | /* Load a float to a Dalvik register. */ |
| 1028 | static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest, |
| 1029 | int rSrcDest, ArmOpCode opCode) |
| 1030 | { |
| 1031 | ArmLIR *res; |
| 1032 | if (vSrcDest > 255) { |
| 1033 | int rTmp = allocTemp(cUnit); |
| 1034 | opRegRegImm(cUnit, kOpAdd, rTmp, rFP, vSrcDest * 4); |
| 1035 | res = newLIR3(cUnit, opCode, rSrcDest, rTmp, 0); |
| 1036 | freeTemp(cUnit, rTmp); |
| 1037 | } else { |
| 1038 | res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest); |
| 1039 | } |
| 1040 | return res; |
| 1041 | } |
| 1042 | |
| 1043 | /* |
| 1044 | * Load value from base + displacement. Optionally perform null check |
| 1045 | * on base (which must have an associated sReg and MIR). If not |
| 1046 | * performing null check, incoming MIR can be null. |
| 1047 | */ |
| 1048 | static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase, |
| 1049 | int displacement, int rDest, int rDestHi, |
| 1050 | OpSize size, bool nullCheck, int sReg) |
| 1051 | { |
| 1052 | ArmLIR *first = NULL; |
| 1053 | ArmLIR *res, *load; |
| 1054 | ArmOpCode opCode = kThumbBkpt; |
| 1055 | bool shortForm = false; |
| 1056 | bool thumb2Form = (displacement < 4092 && displacement >= 0); |
| 1057 | int shortMax = 128; |
| 1058 | bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest)); |
| 1059 | int encodedDisp = displacement; |
| 1060 | |
| 1061 | switch (size) { |
| 1062 | case kDouble: |
| 1063 | case kLong: |
| 1064 | if (FPREG(rDest)) { |
| 1065 | if (SINGLEREG(rDest)) { |
| 1066 | assert(FPREG(rDestHi)); |
| 1067 | rDest = S2D(rDest, rDestHi); |
| 1068 | } |
| 1069 | opCode = kThumb2Vldrd; |
| 1070 | if (displacement <= 1020) { |
| 1071 | shortForm = true; |
| 1072 | encodedDisp >>= 2; |
| 1073 | } |
| 1074 | break; |
| 1075 | } else { |
| 1076 | res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, |
| 1077 | -1, kWord, nullCheck, sReg); |
| 1078 | loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi, |
| 1079 | -1, kWord, false, INVALID_SREG); |
| 1080 | return res; |
| 1081 | } |
| 1082 | case kSingle: |
| 1083 | case kWord: |
| 1084 | if (FPREG(rDest)) { |
| 1085 | opCode = kThumb2Vldrs; |
| 1086 | if (displacement <= 1020) { |
| 1087 | shortForm = true; |
| 1088 | encodedDisp >>= 2; |
| 1089 | } |
| 1090 | break; |
| 1091 | } |
| 1092 | if (LOWREG(rDest) && (rBase == rpc) && |
| 1093 | (displacement <= 1020) && (displacement >= 0)) { |
| 1094 | shortForm = true; |
| 1095 | encodedDisp >>= 2; |
| 1096 | opCode = kThumbLdrPcRel; |
| 1097 | } else if (LOWREG(rDest) && (rBase == r13) && |
| 1098 | (displacement <= 1020) && (displacement >= 0)) { |
| 1099 | shortForm = true; |
| 1100 | encodedDisp >>= 2; |
| 1101 | opCode = kThumbLdrSpRel; |
| 1102 | } else if (allLowRegs && displacement < 128 && displacement >= 0) { |
| 1103 | assert((displacement & 0x3) == 0); |
| 1104 | shortForm = true; |
| 1105 | encodedDisp >>= 2; |
| 1106 | opCode = kThumbLdrRRI5; |
| 1107 | } else if (thumb2Form) { |
| 1108 | shortForm = true; |
| 1109 | opCode = kThumb2LdrRRI12; |
| 1110 | } |
| 1111 | break; |
| 1112 | case kUnsignedHalf: |
| 1113 | if (allLowRegs && displacement < 64 && displacement >= 0) { |
| 1114 | assert((displacement & 0x1) == 0); |
| 1115 | shortForm = true; |
| 1116 | encodedDisp >>= 1; |
| 1117 | opCode = kThumbLdrhRRI5; |
| 1118 | } else if (displacement < 4092 && displacement >= 0) { |
| 1119 | shortForm = true; |
| 1120 | opCode = kThumb2LdrhRRI12; |
| 1121 | } |
| 1122 | break; |
| 1123 | case kSignedHalf: |
| 1124 | if (thumb2Form) { |
| 1125 | shortForm = true; |
| 1126 | opCode = kThumb2LdrshRRI12; |
| 1127 | } |
| 1128 | break; |
| 1129 | case kUnsignedByte: |
| 1130 | if (allLowRegs && displacement < 32 && displacement >= 0) { |
| 1131 | shortForm = true; |
| 1132 | opCode = kThumbLdrbRRI5; |
| 1133 | } else if (thumb2Form) { |
| 1134 | shortForm = true; |
| 1135 | opCode = kThumb2LdrbRRI12; |
| 1136 | } |
| 1137 | break; |
| 1138 | case kSignedByte: |
| 1139 | if (thumb2Form) { |
| 1140 | shortForm = true; |
| 1141 | opCode = kThumb2LdrsbRRI12; |
| 1142 | } |
| 1143 | break; |
| 1144 | default: |
| 1145 | assert(0); |
| 1146 | } |
| 1147 | if (nullCheck) |
| 1148 | first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL); |
| 1149 | if (shortForm) { |
| 1150 | load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp); |
| 1151 | } else { |
| 1152 | int regOffset = allocTemp(cUnit); |
| 1153 | res = loadConstant(cUnit, regOffset, encodedDisp); |
| 1154 | load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size); |
| 1155 | freeTemp(cUnit, regOffset); |
| 1156 | } |
| 1157 | |
| 1158 | if (rBase == rFP) { |
| 1159 | annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */); |
| 1160 | } |
| 1161 | return (first) ? first : res; |
| 1162 | } |
| 1163 | |
| 1164 | static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase, |
| 1165 | int displacement, int rDest, OpSize size, |
| 1166 | bool nullCheck, int sReg) |
| 1167 | { |
| 1168 | return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1, |
| 1169 | size, nullCheck, sReg); |
| 1170 | } |
| 1171 | |
| 1172 | static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase, |
| 1173 | int displacement, int rDestLo, int rDestHi, |
| 1174 | bool nullCheck, int sReg) |
| 1175 | { |
| 1176 | return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi, |
| 1177 | kLong, nullCheck, sReg); |
| 1178 | } |
| 1179 | |
| 1180 | |
| 1181 | static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase, |
| 1182 | int displacement, int rSrc, int rSrcHi, |
| 1183 | OpSize size) |
| 1184 | { |
| 1185 | ArmLIR *res, *store; |
| 1186 | ArmOpCode opCode = kThumbBkpt; |
| 1187 | bool shortForm = false; |
| 1188 | bool thumb2Form = (displacement < 4092 && displacement >= 0); |
| 1189 | int shortMax = 128; |
| 1190 | bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc)); |
| 1191 | int encodedDisp = displacement; |
| 1192 | |
| 1193 | switch (size) { |
| 1194 | case kLong: |
| 1195 | case kDouble: |
| 1196 | if (!FPREG(rSrc)) { |
| 1197 | res = storeBaseDispBody(cUnit, rBase, displacement, rSrc, |
| 1198 | -1, kWord); |
| 1199 | storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi, |
| 1200 | -1, kWord); |
| 1201 | return res; |
| 1202 | } |
| 1203 | if (SINGLEREG(rSrc)) { |
| 1204 | assert(FPREG(rSrcHi)); |
| 1205 | rSrc = S2D(rSrc, rSrcHi); |
| 1206 | } |
| 1207 | opCode = kThumb2Vstrd; |
| 1208 | if (displacement <= 1020) { |
| 1209 | shortForm = true; |
| 1210 | encodedDisp >>= 2; |
| 1211 | } |
| 1212 | break; |
| 1213 | case kSingle: |
| 1214 | case kWord: |
| 1215 | if (FPREG(rSrc)) { |
| 1216 | assert(SINGLEREG(rSrc)); |
| 1217 | opCode = kThumb2Vstrs; |
| 1218 | if (displacement <= 1020) { |
| 1219 | shortForm = true; |
| 1220 | encodedDisp >>= 2; |
| 1221 | } |
| 1222 | break; |
| 1223 | } |
| 1224 | if (allLowRegs && displacement < 128 && displacement >= 0) { |
| 1225 | assert((displacement & 0x3) == 0); |
| 1226 | shortForm = true; |
| 1227 | encodedDisp >>= 2; |
| 1228 | opCode = kThumbStrRRI5; |
| 1229 | } else if (thumb2Form) { |
| 1230 | shortForm = true; |
| 1231 | opCode = kThumb2StrRRI12; |
| 1232 | } |
| 1233 | break; |
| 1234 | case kUnsignedHalf: |
| 1235 | case kSignedHalf: |
| 1236 | if (allLowRegs && displacement < 64 && displacement >= 0) { |
| 1237 | assert((displacement & 0x1) == 0); |
| 1238 | shortForm = true; |
| 1239 | encodedDisp >>= 1; |
| 1240 | opCode = kThumbStrhRRI5; |
| 1241 | } else if (thumb2Form) { |
| 1242 | shortForm = true; |
| 1243 | opCode = kThumb2StrhRRI12; |
| 1244 | } |
| 1245 | break; |
| 1246 | case kUnsignedByte: |
| 1247 | case kSignedByte: |
| 1248 | if (allLowRegs && displacement < 32 && displacement >= 0) { |
| 1249 | shortForm = true; |
| 1250 | opCode = kThumbStrbRRI5; |
| 1251 | } else if (thumb2Form) { |
| 1252 | shortForm = true; |
| 1253 | opCode = kThumb2StrhRRI12; |
| 1254 | } |
| 1255 | break; |
| 1256 | default: |
| 1257 | assert(0); |
| 1258 | } |
| 1259 | if (shortForm) { |
| 1260 | store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp); |
| 1261 | } else { |
| 1262 | int rScratch = allocTemp(cUnit); |
| 1263 | res = loadConstant(cUnit, rScratch, encodedDisp); |
| 1264 | store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size); |
| 1265 | freeTemp(cUnit, rScratch); |
| 1266 | } |
| 1267 | |
| 1268 | if (rBase == rFP) { |
| 1269 | annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */); |
| 1270 | } |
| 1271 | return res; |
| 1272 | } |
| 1273 | |
| 1274 | static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase, |
| 1275 | int displacement, int rSrc, OpSize size) |
| 1276 | { |
| 1277 | return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size); |
| 1278 | } |
| 1279 | |
| 1280 | static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase, |
| 1281 | int displacement, int rSrcLo, int rSrcHi) |
| 1282 | { |
| 1283 | return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong); |
| 1284 | } |
| 1285 | |
| 1286 | static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask) |
| 1287 | { |
| 1288 | ArmLIR *res; |
| 1289 | genBarrier(cUnit); |
| 1290 | if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) { |
| 1291 | res = newLIR2(cUnit, kThumbLdmia, rBase, rMask); |
| 1292 | } else { |
| 1293 | res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask); |
| 1294 | } |
| 1295 | genBarrier(cUnit); |
| 1296 | return res; |
| 1297 | } |
| 1298 | |
| 1299 | static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask) |
| 1300 | { |
| 1301 | ArmLIR *res; |
| 1302 | genBarrier(cUnit); |
| 1303 | if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) { |
| 1304 | res = newLIR2(cUnit, kThumbStmia, rBase, rMask); |
| 1305 | } else { |
| 1306 | res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask); |
| 1307 | } |
| 1308 | genBarrier(cUnit); |
| 1309 | return res; |
| 1310 | } |
| 1311 | |
| 1312 | static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest, |
| 1313 | int value) |
| 1314 | { |
| 1315 | int encodedImm = encodeImmSingle(value); |
| 1316 | assert(SINGLEREG(rDest)); |
| 1317 | if (encodedImm >= 0) { |
| 1318 | return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm); |
| 1319 | } |
| 1320 | ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0); |
| 1321 | if (dataTarget == NULL) { |
| 1322 | dataTarget = addWordData(cUnit, value, false); |
| 1323 | } |
| 1324 | ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true); |
| 1325 | loadPcRel->opCode = kThumb2Vldrs; |
| 1326 | loadPcRel->generic.target = (LIR *) dataTarget; |
| 1327 | loadPcRel->operands[0] = rDest; |
| 1328 | loadPcRel->operands[1] = rpc; |
| 1329 | setupResourceMasks(loadPcRel); |
| 1330 | dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); |
| 1331 | return loadPcRel; |
| 1332 | } |
| 1333 | |
| 1334 | static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg) |
| 1335 | { |
| 1336 | storeBaseDispWide(cUnit, base, 0, lowReg, highReg); |
| 1337 | } |
| 1338 | |
| 1339 | static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg) |
| 1340 | { |
| 1341 | loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, false, |
| 1342 | INVALID_SREG); |
| 1343 | } |
| 1344 | |
| 1345 | |
| 1346 | /* |
| 1347 | * Load a immediate using a shortcut if possible; otherwise |
| 1348 | * grab from the per-translation literal pool. |
| 1349 | */ |
| 1350 | static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value) |
| 1351 | { |
| 1352 | ArmLIR *res; |
| 1353 | int modImm; |
| 1354 | |
| 1355 | if (FPREG(rDest)) { |
| 1356 | return loadFPConstantValue(cUnit, rDest, value); |
| 1357 | } |
| 1358 | |
| 1359 | /* See if the value can be constructed cheaply */ |
| 1360 | if (LOWREG(rDest) && (value >= 0) && (value <= 255)) { |
| 1361 | return newLIR2(cUnit, kThumbMovImm, rDest, value); |
| 1362 | } |
| 1363 | /* Check Modified immediate special cases */ |
| 1364 | modImm = modifiedImmediate(value); |
| 1365 | if (modImm >= 0) { |
| 1366 | res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm); |
| 1367 | return res; |
| 1368 | } |
| 1369 | modImm = modifiedImmediate(~value); |
| 1370 | if (modImm >= 0) { |
| 1371 | res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm); |
| 1372 | return res; |
| 1373 | } |
| 1374 | /* 16-bit immediate? */ |
| 1375 | if ((value & 0xffff) == value) { |
| 1376 | res = newLIR2(cUnit, kThumb2MovImm16, rDest, value); |
| 1377 | return res; |
| 1378 | } |
| 1379 | /* No shortcut - go ahead and use literal pool */ |
| 1380 | ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255); |
| 1381 | if (dataTarget == NULL) { |
| 1382 | dataTarget = addWordData(cUnit, value, false); |
| 1383 | } |
| 1384 | ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true); |
| 1385 | loadPcRel->opCode = LOWREG(rDest) ? kThumbLdrPcRel : kThumb2LdrPcRel12; |
| 1386 | loadPcRel->generic.target = (LIR *) dataTarget; |
| 1387 | loadPcRel->operands[0] = rDest; |
| 1388 | setupResourceMasks(loadPcRel); |
| 1389 | res = loadPcRel; |
| 1390 | dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel); |
| 1391 | |
| 1392 | /* |
| 1393 | * To save space in the constant pool, we use the ADD_RRI8 instruction to |
| 1394 | * add up to 255 to an existing constant value. |
| 1395 | */ |
| 1396 | if (dataTarget->operands[0] != value) { |
| 1397 | opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]); |
| 1398 | } |
| 1399 | return res; |
| 1400 | } |
| 1401 | |
| 1402 | static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo, |
| 1403 | int rDestHi, int valLo, int valHi) |
| 1404 | { |
| 1405 | int encodedImm = encodeImmDouble(valLo, valHi); |
| 1406 | ArmLIR *res; |
| 1407 | if (FPREG(rDestLo) && (encodedImm >= 0)) { |
| 1408 | res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi), |
| 1409 | encodedImm); |
| 1410 | } else { |
| 1411 | res = loadConstantValue(cUnit, rDestLo, valLo); |
| 1412 | loadConstantValue(cUnit, rDestHi, valHi); |
| 1413 | } |
| 1414 | return res; |
| 1415 | } |
| 1416 | |
| 1417 | /* |
| 1418 | * Perform a "reg cmp imm" operation and jump to the PCR region if condition |
| 1419 | * satisfies. |
| 1420 | */ |
| 1421 | static ArmLIR *genRegImmCheck(CompilationUnit *cUnit, |
| 1422 | ArmConditionCode cond, int reg, |
| 1423 | int checkValue, int dOffset, |
| 1424 | ArmLIR *pcrLabel) |
| 1425 | { |
| 1426 | ArmLIR *branch; |
| 1427 | int modImm; |
| 1428 | /* |
| 1429 | * TODO: re-enable usage of kThumb2Cbz & kThumb2Cbnz once assembler is |
| 1430 | * enhanced to allow us to replace code patterns when instructions don't |
| 1431 | * reach. Currently, CB[N]Z is causing too many assembler aborts. |
| 1432 | * What we want to do is emit the short forms, and then replace them with |
| 1433 | * longer versions when needed. |
| 1434 | */ |
| 1435 | |
| 1436 | if (0 && (LOWREG(reg)) && (checkValue == 0) && |
| 1437 | ((cond == kArmCondEq) || (cond == kArmCondNe))) { |
| 1438 | branch = newLIR2(cUnit, |
| 1439 | (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz, |
| 1440 | reg, 0); |
| 1441 | } else { |
| 1442 | modImm = modifiedImmediate(checkValue); |
| 1443 | if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) { |
| 1444 | newLIR2(cUnit, kThumbCmpRI8, reg, checkValue); |
| 1445 | } else if (modImm >= 0) { |
| 1446 | newLIR2(cUnit, kThumb2CmpRI8, reg, modImm); |
| 1447 | } else { |
| 1448 | int tReg = allocTemp(cUnit); |
| 1449 | loadConstant(cUnit, tReg, checkValue); |
| 1450 | opRegReg(cUnit, kOpCmp, reg, tReg); |
| 1451 | } |
| 1452 | branch = newLIR2(cUnit, kThumbBCond, 0, cond); |
| 1453 | } |
| 1454 | return genCheckCommon(cUnit, dOffset, branch, pcrLabel); |
| 1455 | } |
| 1456 | |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1457 | static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir) |
| 1458 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1459 | RegLocation rlObj = getSrcLoc(cUnit, mir, 0); |
| 1460 | RegLocation rlDest = inlinedTarget(cUnit, mir, false); |
| 1461 | rlObj = loadValue(cUnit, rlObj, kCoreReg); |
| 1462 | RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true); |
| 1463 | genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL); |
| 1464 | loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, |
| 1465 | rlResult.lowReg); |
| 1466 | storeValue(cUnit, rlDest, rlResult); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1467 | return false; |
| 1468 | } |
| 1469 | |
| 1470 | static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir) |
| 1471 | { |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1472 | int contents = offsetof(ArrayObject, contents); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1473 | RegLocation rlObj = getSrcLoc(cUnit, mir, 0); |
| 1474 | RegLocation rlIdx = getSrcLoc(cUnit, mir, 1); |
| 1475 | RegLocation rlDest = inlinedTarget(cUnit, mir, false); |
| 1476 | RegLocation rlResult; |
| 1477 | rlObj = loadValue(cUnit, rlObj, kCoreReg); |
| 1478 | rlIdx = loadValue(cUnit, rlIdx, kCoreReg); |
| 1479 | int regMax = allocTemp(cUnit); |
| 1480 | int regOff = allocTemp(cUnit); |
| 1481 | int regPtr = allocTemp(cUnit); |
| 1482 | ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, |
| 1483 | mir->offset, NULL); |
| 1484 | loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax); |
| 1485 | loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff); |
| 1486 | loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr); |
| 1487 | genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel); |
| 1488 | freeTemp(cUnit, regMax); |
| 1489 | opRegImm(cUnit, kOpAdd, regPtr, contents); |
| 1490 | opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg); |
| 1491 | rlResult = evalLoc(cUnit, rlDest, kCoreReg, true); |
| 1492 | loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf); |
| 1493 | storeValue(cUnit, rlDest, rlResult); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1494 | return false; |
| 1495 | } |
| 1496 | |
| 1497 | static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir) |
| 1498 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1499 | RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); |
| 1500 | rlSrc = loadValue(cUnit, rlSrc, kCoreReg); |
| 1501 | RegLocation rlDest = inlinedTarget(cUnit, mir, false);; |
| 1502 | RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true); |
| 1503 | int signReg = allocTemp(cUnit); |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 1504 | /* |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1505 | * abs(x) = y<=x>>31, (x+y)^y. |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 1506 | * Thumb2's IT block also yields 3 instructions, but imposes |
| 1507 | * scheduling constraints. |
| 1508 | */ |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1509 | opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31); |
| 1510 | opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); |
| 1511 | opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); |
| 1512 | storeValue(cUnit, rlDest, rlResult); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1513 | return false; |
| 1514 | } |
| 1515 | |
| 1516 | static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir) |
| 1517 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1518 | RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); |
| 1519 | RegLocation rlDest = inlinedTarget(cUnit, mir, true); |
| 1520 | rlSrc = loadValue(cUnit, rlSrc, kFPReg); |
| 1521 | RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true); |
| 1522 | newLIR2(cUnit, kThumb2Vabss, rlResult.lowReg, rlSrc.lowReg); |
| 1523 | storeValue(cUnit, rlDest, rlResult); |
| 1524 | return true; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1525 | } |
| 1526 | |
| 1527 | static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir) |
| 1528 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1529 | RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1); |
| 1530 | RegLocation rlDest = inlinedTargetWide(cUnit, mir, true); |
| 1531 | rlSrc = loadValueWide(cUnit, rlSrc, kFPReg); |
| 1532 | RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true); |
| 1533 | newLIR2(cUnit, kThumb2Vabsd, S2D(rlResult.lowReg, rlResult.highReg), |
| 1534 | S2D(rlSrc.lowReg, rlSrc.highReg)); |
| 1535 | storeValueWide(cUnit, rlDest, rlResult); |
| 1536 | return true; |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1537 | } |
| 1538 | |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1539 | static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin) |
| 1540 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1541 | RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0); |
| 1542 | RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1); |
| 1543 | rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg); |
| 1544 | rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg); |
| 1545 | RegLocation rlDest = inlinedTarget(cUnit, mir, false); |
| 1546 | RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true); |
| 1547 | opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg); |
| 1548 | genIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E"); |
| 1549 | opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg); |
| 1550 | opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg); |
| Ben Cheng | d7d426a | 2009-09-22 11:23:36 -0700 | [diff] [blame] | 1551 | genBarrier(cUnit); |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1552 | storeValue(cUnit, rlDest, rlResult); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1553 | return false; |
| 1554 | } |
| 1555 | |
| 1556 | static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir) |
| 1557 | { |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1558 | RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1); |
| 1559 | RegLocation rlDest = inlinedTargetWide(cUnit, mir, false); |
| 1560 | rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg); |
| 1561 | RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true); |
| 1562 | int signReg = allocTemp(cUnit); |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 1563 | /* |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1564 | * abs(x) = y<=x>>31, (x+y)^y. |
| Bill Buzbee | a4a7f07 | 2009-08-27 13:58:09 -0700 | [diff] [blame] | 1565 | * Thumb2 IT block allows slightly shorter sequence, |
| 1566 | * but introduces a scheduling barrier. Stick with this |
| 1567 | * mechanism for now. |
| 1568 | */ |
| Bill Buzbee | 1465db5 | 2009-09-23 17:17:35 -0700 | [diff] [blame^] | 1569 | opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31); |
| 1570 | opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg); |
| 1571 | opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg); |
| 1572 | opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg); |
| 1573 | opRegReg(cUnit, kOpXor, rlResult.highReg, signReg); |
| 1574 | storeValueWide(cUnit, rlDest, rlResult); |
| Bill Buzbee | 270c1d6 | 2009-08-13 16:58:07 -0700 | [diff] [blame] | 1575 | return false; |
| 1576 | } |