blob: d553aaec4ef6ad1e259f280e7f720bc6e117e6ee [file] [log] [blame]
Bill Buzbee9bc3df32009-07-30 10:52:29 -07001/*
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 Buzbee270c1d62009-08-13 16:58:07 -070019 * includes by:
Bill Buzbee9bc3df32009-07-30 10:52:29 -070020 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25#include "Codegen.h"
Bill Buzbee7ea0f642009-08-10 17:06:51 -070026
27static 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 Buzbee270c1d62009-08-13 16:58:07 -070047 * Determine whether value can be encoded as a Thumb2 modified
Bill Buzbee7ea0f642009-08-10 17:06:51 -070048 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
49 */
50static 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 Buzbee9bc3df32009-07-30 10:52:29 -070080/*
Bill Buzbee1465db52009-09-23 17:17:35 -070081 * 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 Buzbee9bc3df32009-07-30 10:52:29 -070083 */
Bill Buzbee1465db52009-09-23 17:17:35 -070084static int encodeImmDoubleHigh(int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -070085{
Bill Buzbee1465db52009-09-23 17:17:35 -070086 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 Buzbee9bc3df32009-07-30 10:52:29 -0700101 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700102 res = (bitA << 7) | (bitB << 6) | slice;
103 return res;
104}
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700105
Bill Buzbee1465db52009-09-23 17:17:35 -0700106static 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
128static int encodeImmDouble(int valLo, int valHi)
129{
130 int res = -1;
131 if (valLo == 0)
132 res = encodeImmDoubleHigh(valHi);
133 return res;
134}
135void 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
165static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
166static int corePreserved[] = {};
167static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
168 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
169static int fpPreserved[] = {};
170void 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 */
200static 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
216static 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
223static 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 */
237static 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
268static 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
294ArmLIR* 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 Buzbee9bc3df32009-07-30 10:52:29 -0700316 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700317 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700318}
319
320/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee1465db52009-09-23 17:17:35 -0700321static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700322{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700323 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700324 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee1465db52009-09-23 17:17:35 -0700325 int rDPC = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700326 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -0700327 newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, rFP,
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700328 sizeof(StackSaveArea) - offset);
Bill Buzbee1465db52009-09-23 17:17:35 -0700329 freeTemp(cUnit, rDPC);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700330 return res;
331}
332
333static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
334{
Bill Buzbee1465db52009-09-23 17:17:35 -0700335 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700336 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700337 case kOpUncondBr:
338 opCode = kThumbBUncond;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700339 break;
340 default:
341 assert(0);
342 }
343 return newLIR0(cUnit, opCode);
344}
345
Ben Cheng4f489172009-09-27 17:08:35 -0700346static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700347{
Bill Buzbee1465db52009-09-23 17:17:35 -0700348 return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700349}
350
351static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
352{
Bill Buzbee1465db52009-09-23 17:17:35 -0700353 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700354 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700355 case kOpPush:
356 opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700357 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700358 case kOpPop:
359 opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700360 break;
361 default:
362 assert(0);
363 }
364 return newLIR1(cUnit, opCode, value);
365}
366
367static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
368{
Bill Buzbee1465db52009-09-23 17:17:35 -0700369 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700370 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700371 case kOpBlx:
372 opCode = kThumbBlxR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700373 break;
374 default:
375 assert(0);
376 }
377 return newLIR1(cUnit, opCode, rDestSrc);
378}
379
380static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
381 int rSrc2, int shift)
382{
383 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
Bill Buzbee1465db52009-09-23 17:17:35 -0700384 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700385 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700386 case kOpAdc:
387 opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700388 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700389 case kOpAnd:
390 opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700391 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700392 case kOpBic:
393 opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700394 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700395 case kOpCmn:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700396 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700397 opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700398 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700399 case kOpCmp:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700400 if (thumbForm)
Bill Buzbee1465db52009-09-23 17:17:35 -0700401 opCode = kThumbCmpRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700402 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
Bill Buzbee1465db52009-09-23 17:17:35 -0700403 opCode = kThumbCmpHH;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700404 else if ((shift == 0) && LOWREG(rDestSrc1))
Bill Buzbee1465db52009-09-23 17:17:35 -0700405 opCode = kThumbCmpLH;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700406 else if (shift == 0)
Bill Buzbee1465db52009-09-23 17:17:35 -0700407 opCode = kThumbCmpHL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700408 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700409 opCode = kThumb2CmpRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700410 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700411 case kOpXor:
412 opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700413 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700414 case kOpMov:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700415 assert(shift == 0);
416 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
Bill Buzbee1465db52009-09-23 17:17:35 -0700417 opCode = kThumbMovRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700418 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
Bill Buzbee1465db52009-09-23 17:17:35 -0700419 opCode = kThumbMovRR_H2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700420 else if (LOWREG(rDestSrc1))
Bill Buzbee1465db52009-09-23 17:17:35 -0700421 opCode = kThumbMovRR_H2L;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700422 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700423 opCode = kThumbMovRR_L2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700424 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700425 case kOpMul:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700426 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700427 opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700428 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700429 case kOpMvn:
430 opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700431 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700432 case kOpNeg:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700433 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700434 opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700435 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700436 case kOpOr:
437 opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700438 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700439 case kOpSbc:
440 opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700441 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700442 case kOpTst:
443 opCode = (thumbForm) ? kThumbTst : kThumb2TstRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700444 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700445 case kOpLsl:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700446 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700447 opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700448 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700449 case kOpLsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700450 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700451 opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700452 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700453 case kOpAsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700454 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700455 opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700456 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700457 case kOpRor:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700458 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700459 opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700460 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700461 case kOpAdd:
462 opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700463 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700464 case kOpSub:
465 opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700466 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700467 case kOp2Byte:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700468 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700469 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
470 case kOp2Short:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700471 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700472 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
473 case kOp2Char:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700474 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700475 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700476 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 Buzbee1465db52009-09-23 17:17:35 -0700484 if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700485 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
496static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
497 int rSrc2)
498{
499 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
500}
501
Bill Buzbee270c1d62009-08-13 16:58:07 -0700502static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
503 int rDest, int rSrc1, int rSrc2, int shift)
504{
Bill Buzbee1465db52009-09-23 17:17:35 -0700505 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700506 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
507 LOWREG(rSrc2);
508 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700509 case kOpAdd:
510 opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700511 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700512 case kOpSub:
513 opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700514 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700515 case kOpAdc:
516 opCode = kThumb2AdcRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700517 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700518 case kOpAnd:
519 opCode = kThumb2AndRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700520 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700521 case kOpBic:
522 opCode = kThumb2BicRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700523 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700524 case kOpXor:
525 opCode = kThumb2EorRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700526 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700527 case kOpMul:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700528 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700529 opCode = kThumb2MulRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700530 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700531 case kOpOr:
532 opCode = kThumb2OrrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700533 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700534 case kOpSbc:
535 opCode = kThumb2SbcRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700536 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700537 case kOpLsl:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700538 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700539 opCode = kThumb2LslRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700540 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700541 case kOpLsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700542 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700543 opCode = kThumb2LsrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700544 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700545 case kOpAsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700546 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700547 opCode = kThumb2AsrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700548 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700549 case kOpRor:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700550 assert(shift == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700551 opCode = kThumb2RorRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700552 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
566static 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 Buzbee1465db52009-09-23 17:17:35 -0700572static 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 Buzbee270c1d62009-08-13 16:58:07 -0700586static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
Bill Buzbee1465db52009-09-23 17:17:35 -0700587 int rSrc1, int value)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700588{
589 ArmLIR *res;
590 bool neg = (value < 0);
591 int absValue = (neg) ? -value : value;
Bill Buzbee1465db52009-09-23 17:17:35 -0700592 ArmOpCode opCode = kThumbBkpt;
593 ArmOpCode altOpCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700594 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
595 int modImm = modifiedImmediate(value);
596 int modImmNeg = modifiedImmediate(-value);
597
598 switch(op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700599 case kOpLsl:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700600 if (allLowRegs)
Bill Buzbee1465db52009-09-23 17:17:35 -0700601 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700602 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700603 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
604 case kOpLsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700605 if (allLowRegs)
Bill Buzbee1465db52009-09-23 17:17:35 -0700606 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700607 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700608 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
609 case kOpAsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700610 if (allLowRegs)
Bill Buzbee1465db52009-09-23 17:17:35 -0700611 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700612 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700613 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
614 case kOpRor:
615 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
616 case kOpAdd:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700617 if (LOWREG(rDest) && (rSrc1 == 13) &&
618 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700619 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
Bill Buzbee270c1d62009-08-13 16:58:07 -0700620 value >> 2);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700621 } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
622 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700623 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
Bill Buzbee270c1d62009-08-13 16:58:07 -0700624 value >> 2);
625 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700626 opCode = kThumb2AddRRI8;
627 altOpCode = kThumb2AddRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700628 // Note: intentional fallthrough
Bill Buzbee1465db52009-09-23 17:17:35 -0700629 case kOpSub:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700630 if (allLowRegs && ((absValue & 0x7) == absValue)) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700631 if (op == kOpAdd)
632 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700633 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700634 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700635 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
636 } else if ((absValue & 0xff) == absValue) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700637 if (op == kOpAdd)
638 opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700639 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700640 opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700641 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
642 }
643 if (modImmNeg >= 0) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700644 op = (op == kOpAdd) ? kOpSub : kOpAdd;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700645 modImm = modImmNeg;
646 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700647 if (op == kOpSub) {
648 opCode = kThumb2SubRRI8;
649 altOpCode = kThumb2SubRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700650 }
651 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700652 case kOpAdc:
653 opCode = kThumb2AdcRRI8;
654 altOpCode = kThumb2AdcRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700655 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700656 case kOpSbc:
657 opCode = kThumb2SbcRRI8;
658 altOpCode = kThumb2SbcRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700659 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700660 case kOpOr:
661 opCode = kThumb2OrrRRI8;
662 altOpCode = kThumb2OrrRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700663 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700664 case kOpAnd:
665 opCode = kThumb2AndRRI8;
666 altOpCode = kThumb2AndRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700667 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700668 case kOpXor:
669 opCode = kThumb2EorRRI8;
670 altOpCode = kThumb2EorRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700671 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700672 case kOpMul:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700673 //TUNING: power of 2, shift & add
674 modImm = -1;
Bill Buzbee1465db52009-09-23 17:17:35 -0700675 altOpCode = kThumb2MulRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700676 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700677 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 Buzbee270c1d62009-08-13 16:58:07 -0700690 default:
691 assert(0);
692 }
693
694 if (modImm >= 0) {
695 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
696 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700697 int rScratch = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700698 loadConstant(cUnit, rScratch, value);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700699 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
Bill Buzbee1465db52009-09-23 17:17:35 -0700700 res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700701 else
Bill Buzbee1465db52009-09-23 17:17:35 -0700702 res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
703 freeTemp(cUnit, rScratch);
704 return res;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700705 }
706}
707
Bill Buzbee1465db52009-09-23 17:17:35 -0700708/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
709static 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
756static 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
766static 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 */
782static 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 */
820static 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 Buzbeea4a7f072009-08-27 13:58:09 -0700876/*
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 */
891static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee1465db52009-09-23 17:17:35 -0700892 RegLocation rlDest, RegLocation rlSrc1,
893 RegLocation rlSrc2)
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700894{
Bill Buzbee1465db52009-09-23 17:17:35 -0700895 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 Buzbeea4a7f072009-08-27 13:58:09 -0700907
Bill Buzbee1465db52009-09-23 17:17:35 -0700908 genIT(cUnit, kArmCondHi, "E");
909 newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1));
910 loadConstant(cUnit, rlTemp.lowReg, 1);
Ben Chengd7d426a2009-09-22 11:23:36 -0700911 genBarrier(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700912
Bill Buzbee1465db52009-09-23 17:17:35 -0700913 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 Buzbeea4a7f072009-08-27 13:58:09 -0700924 branch3->generic.target = branch1->generic.target;
925}
926
Bill Buzbee1465db52009-09-23 17:17:35 -0700927static 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
979static 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. */
1028static 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 */
1048static 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
1164static 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
1172static 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
1181static 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
1274static 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
1280static 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
1286static 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
1299static 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
1312static 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
1334static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1335{
1336 storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1337}
1338
1339static 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 */
1350static 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
1402static 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 */
1421static 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 Buzbee270c1d62009-08-13 16:58:07 -07001457static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1458{
Bill Buzbee1465db52009-09-23 17:17:35 -07001459 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 Buzbee270c1d62009-08-13 16:58:07 -07001467 return false;
1468}
1469
1470static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
1471{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001472 int contents = offsetof(ArrayObject, contents);
Bill Buzbee1465db52009-09-23 17:17:35 -07001473 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 Buzbee270c1d62009-08-13 16:58:07 -07001494 return false;
1495}
1496
1497static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
1498{
Bill Buzbee1465db52009-09-23 17:17:35 -07001499 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 Buzbeea4a7f072009-08-27 13:58:09 -07001504 /*
Bill Buzbee1465db52009-09-23 17:17:35 -07001505 * abs(x) = y<=x>>31, (x+y)^y.
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001506 * Thumb2's IT block also yields 3 instructions, but imposes
1507 * scheduling constraints.
1508 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001509 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 Buzbee270c1d62009-08-13 16:58:07 -07001513 return false;
1514}
1515
1516static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
1517{
Bill Buzbee1465db52009-09-23 17:17:35 -07001518 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 Buzbee270c1d62009-08-13 16:58:07 -07001525}
1526
1527static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
1528{
Bill Buzbee1465db52009-09-23 17:17:35 -07001529 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 Buzbee270c1d62009-08-13 16:58:07 -07001537}
1538
Bill Buzbee270c1d62009-08-13 16:58:07 -07001539static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1540{
Bill Buzbee1465db52009-09-23 17:17:35 -07001541 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 Chengd7d426a2009-09-22 11:23:36 -07001551 genBarrier(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001552 storeValue(cUnit, rlDest, rlResult);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001553 return false;
1554}
1555
1556static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1557{
Bill Buzbee1465db52009-09-23 17:17:35 -07001558 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 Buzbeea4a7f072009-08-27 13:58:09 -07001563 /*
Bill Buzbee1465db52009-09-23 17:17:35 -07001564 * abs(x) = y<=x>>31, (x+y)^y.
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001565 * Thumb2 IT block allows slightly shorter sequence,
1566 * but introduces a scheduling barrier. Stick with this
1567 * mechanism for now.
1568 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001569 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 Buzbee270c1d62009-08-13 16:58:07 -07001575 return false;
1576}