blob: a626fc7f6b584b499bdd2496fe35276088355de6 [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 Buzbee270c1d62009-08-13 16:58:07 -070026
Bill Buzbee1465db52009-09-23 17:17:35 -070027static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
28static int corePreserved[] = {};
29void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
Bill Buzbee9bc3df32009-07-30 10:52:29 -070030{
Bill Buzbee1465db52009-09-23 17:17:35 -070031 int i;
32 int numTemps = sizeof(coreTemps)/sizeof(int);
33 RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
34 cUnit->regPool = pool;
35 pool->numCoreTemps = numTemps;
36 pool->coreTemps =
37 dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
38 pool->numFPTemps = 0;
39 pool->FPTemps = NULL;
40 pool->numCoreRegs = 0;
41 pool->coreRegs = NULL;
42 pool->numFPRegs = 0;
43 pool->FPRegs = NULL;
44 initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
45 initPool(pool->FPTemps, NULL, 0);
46 initPool(pool->coreRegs, NULL, 0);
47 initPool(pool->FPRegs, NULL, 0);
48 pool->nullCheckedRegs =
49 dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070050}
51
52/*
Bill Buzbee1465db52009-09-23 17:17:35 -070053 * Alloc a pair of core registers, or a double. Low reg in low byte,
54 * high reg in next byte.
Bill Buzbee9bc3df32009-07-30 10:52:29 -070055 */
Bill Buzbee1465db52009-09-23 17:17:35 -070056static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint, int regClass)
Bill Buzbee9bc3df32009-07-30 10:52:29 -070057{
Bill Buzbee1465db52009-09-23 17:17:35 -070058 int highReg;
59 int lowReg;
60 int res = 0;
61 lowReg = allocTemp(cUnit);
62 highReg = allocTemp(cUnit);
63 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
64 return res;
65}
Bill Buzbee9bc3df32009-07-30 10:52:29 -070066
Bill Buzbee1465db52009-09-23 17:17:35 -070067static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
68{
69 return allocTemp(cUnit);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070070}
71
Bill Buzbee7ea0f642009-08-10 17:06:51 -070072ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
73{
Bill Buzbee270c1d62009-08-13 16:58:07 -070074 ArmLIR* res;
75 ArmOpCode opCode;
76 res = dvmCompilerNew(sizeof(ArmLIR), true);
77 if (LOWREG(rDest) && LOWREG(rSrc))
Bill Buzbee1465db52009-09-23 17:17:35 -070078 opCode = kThumbMovRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -070079 else if (!LOWREG(rDest) && !LOWREG(rSrc))
Bill Buzbee1465db52009-09-23 17:17:35 -070080 opCode = kThumbMovRR_H2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -070081 else if (LOWREG(rDest))
Bill Buzbee1465db52009-09-23 17:17:35 -070082 opCode = kThumbMovRR_H2L;
Bill Buzbee270c1d62009-08-13 16:58:07 -070083 else
Bill Buzbee1465db52009-09-23 17:17:35 -070084 opCode = kThumbMovRR_L2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -070085
Ben Chengdcf3e5d2009-09-11 13:42:05 -070086 res->operands[0] = rDest;
87 res->operands[1] = rSrc;
Bill Buzbee270c1d62009-08-13 16:58:07 -070088 res->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -070089 setupResourceMasks(res);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070090 if (rDest == rSrc) {
91 res->isNop = true;
92 }
93 return res;
94}
95
Bill Buzbee1465db52009-09-23 17:17:35 -070096void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
97 int srcLo, int srcHi)
Bill Buzbee9bc3df32009-07-30 10:52:29 -070098{
Bill Buzbee1465db52009-09-23 17:17:35 -070099 // Handle overlap
100 if (srcHi == destLo) {
101 genRegCopy(cUnit, destHi, srcHi);
102 genRegCopy(cUnit, destLo, srcLo);
103 } else {
104 genRegCopy(cUnit, destLo, srcLo);
105 genRegCopy(cUnit, destHi, srcHi);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700106 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700107}
108
109/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee1465db52009-09-23 17:17:35 -0700110static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700111{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700112 ArmLIR *res;
Bill Buzbee1465db52009-09-23 17:17:35 -0700113 int rDPC = allocTemp(cUnit);
114 int rAddr = allocTemp(cUnit);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700115 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700116 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -0700117 newLIR2(cUnit, kThumbMovRR, rAddr, rFP);
118 newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset);
119 storeWordDisp( cUnit, rAddr, 0, rDPC);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700120 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700121}
122
Bill Buzbee270c1d62009-08-13 16:58:07 -0700123static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
124{
Bill Buzbee1465db52009-09-23 17:17:35 -0700125 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700126 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700127 case kOpUncondBr:
128 opCode = kThumbBUncond;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700129 break;
130 default:
131 assert(0);
132 }
133 return newLIR0(cUnit, opCode);
134}
135
Ben Cheng4f489172009-09-27 17:08:35 -0700136static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700137{
Bill Buzbee1465db52009-09-23 17:17:35 -0700138 return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700139}
140
141static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
142{
Bill Buzbee1465db52009-09-23 17:17:35 -0700143 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700144 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700145 case kOpPush:
146 opCode = kThumbPush;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700147 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700148 case kOpPop:
149 opCode = kThumbPop;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700150 break;
151 default:
152 assert(0);
153 }
154 return newLIR1(cUnit, opCode, value);
155}
156
157static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
158{
Bill Buzbee1465db52009-09-23 17:17:35 -0700159 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700160 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700161 case kOpBlx:
162 opCode = kThumbBlxR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700163 break;
164 default:
165 assert(0);
166 }
167 return newLIR1(cUnit, opCode, rDestSrc);
168}
169
Bill Buzbee270c1d62009-08-13 16:58:07 -0700170static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
Bill Buzbee1465db52009-09-23 17:17:35 -0700171 int value)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700172{
173 ArmLIR *res;
174 bool neg = (value < 0);
175 int absValue = (neg) ? -value : value;
176 bool shortForm = (absValue & 0xff) == absValue;
Bill Buzbee1465db52009-09-23 17:17:35 -0700177 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700178 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700179 case kOpAdd:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700180 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
181 assert((value & 0x3) == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700182 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700183 } else if (shortForm) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700184 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700185 } else
Bill Buzbee1465db52009-09-23 17:17:35 -0700186 opCode = kThumbAddRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700187 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700188 case kOpSub:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700189 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
190 assert((value & 0x3) == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700191 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700192 } else if (shortForm) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700193 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700194 } else
Bill Buzbee1465db52009-09-23 17:17:35 -0700195 opCode = kThumbSubRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700196 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700197 case kOpCmp:
198 if (neg)
199 shortForm = false;
200 if (LOWREG(rDestSrc1) && shortForm) {
201 opCode = kThumbCmpRI8;
202 } else if (LOWREG(rDestSrc1)) {
203 opCode = kThumbCmpRR;
204 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700205 shortForm = false;
Bill Buzbee1465db52009-09-23 17:17:35 -0700206 opCode = kThumbCmpHL;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700207 }
208 break;
209 default:
210 assert(0);
211 break;
212 }
213 if (shortForm)
214 res = newLIR2(cUnit, opCode, rDestSrc1, absValue);
215 else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700216 int rScratch = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700217 res = loadConstant(cUnit, rScratch, value);
Bill Buzbee1465db52009-09-23 17:17:35 -0700218 if (op == kOpCmp)
219 newLIR2(cUnit, opCode, rDestSrc1, rScratch);
220 else
221 newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700222 }
223 return res;
224}
225
Bill Buzbee1465db52009-09-23 17:17:35 -0700226static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
227 int rSrc);
228
Bill Buzbee270c1d62009-08-13 16:58:07 -0700229static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
230 int rSrc1, int rSrc2)
231{
Bill Buzbee1465db52009-09-23 17:17:35 -0700232 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700233 switch (op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700234 case kOpAdd:
235 opCode = kThumbAddRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700236 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700237 case kOpSub:
238 opCode = kThumbSubRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700239 break;
240 default:
Bill Buzbee1465db52009-09-23 17:17:35 -0700241 if (rDest == rSrc1) {
242 return opRegReg(cUnit, op, rDest, rSrc2);
243 } else if (rDest == rSrc2) {
244 assert(isTemp(cUnit, rSrc1));
245 clobberReg(cUnit, rSrc1);
246 opRegReg(cUnit, op, rSrc1, rSrc2);
247 return opRegReg(cUnit, kOpMov, rDest, rSrc1);
248 } else {
249 opRegReg(cUnit, kOpMov, rDest, rSrc1);
250 return opRegReg(cUnit, op, rDest, rSrc2);
251 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700252 break;
253 }
254 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
255}
256
Bill Buzbee1465db52009-09-23 17:17:35 -0700257static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
258 OpKind secondOp, RegLocation rlDest,
259 RegLocation rlSrc1, RegLocation rlSrc2)
260{
261 RegLocation rlResult;
262 if (rlDest.sRegLow == rlSrc1.sRegLow) {
263 // Already 2-operand
264 rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
265 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
266 opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
267 opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
268 storeValueWide(cUnit, rlDest, rlResult);
269 } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
270 // Bad case - must use/clobber Src1 and reassign Dest
271 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
272 rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
273 opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
274 opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
275 // Old reg assignments are now invalid
276 clobberReg(cUnit, rlResult.lowReg);
277 clobberReg(cUnit, rlResult.highReg);
278 clobberReg(cUnit, rlSrc1.lowReg);
279 clobberReg(cUnit, rlSrc1.highReg);
280 rlDest.location = kLocDalvikFrame;
281 assert(rlSrc1.location == kLocPhysReg);
282 // Reassign registers - rlDest will now get rlSrc1's old regs
283 storeValueWide(cUnit, rlDest, rlSrc1);
284 } else {
285 // Copy Src1 to Dest
286 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
287 rlResult = evalLoc(cUnit, rlDest, kCoreReg, false);
288 loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
289 rlResult.highReg);
290 rlResult.location = kLocPhysReg;
291 opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
292 opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
293 storeValueWide(cUnit, rlDest, rlResult);
294 }
295}
296
Bill Buzbee270c1d62009-08-13 16:58:07 -0700297static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
Bill Buzbee1465db52009-09-23 17:17:35 -0700298 int rSrc1, int value)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700299{
300 ArmLIR *res;
301 bool neg = (value < 0);
302 int absValue = (neg) ? -value : value;
Bill Buzbee1465db52009-09-23 17:17:35 -0700303 ArmOpCode opCode = kThumbBkpt;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700304 bool shortForm = (absValue & 0x7) == absValue;
305 switch(op) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700306 case kOpAdd:
307 if (rDest == rSrc1)
308 return opRegImm(cUnit, op, rDest, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700309 if ((rSrc1 == 13) && (value <= 1020)) { /* sp */
310 assert((value & 0x3) == 0);
311 shortForm = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700312 opCode = kThumbAddSpRel;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700313 value >>= 2;
314 } else if ((rSrc1 == 15) && (value <= 1020)) { /* pc */
315 assert((value & 0x3) == 0);
316 shortForm = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700317 opCode = kThumbAddPcRel;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700318 value >>= 2;
319 } else if (shortForm) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700320 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700321 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
322 /* Two shots - 1st handle the 7 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700323 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700324 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
Bill Buzbee1465db52009-09-23 17:17:35 -0700325 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700326 newLIR2(cUnit, opCode, rDest, absValue - 7);
327 return res;
328 } else
Bill Buzbee1465db52009-09-23 17:17:35 -0700329 opCode = kThumbAddRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700330 break;
331
Bill Buzbee1465db52009-09-23 17:17:35 -0700332 case kOpSub:
333 if (rDest == rSrc1)
334 return opRegImm(cUnit, op, rDest, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700335 if (shortForm) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700336 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700337 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
338 /* Two shots - 1st handle the 7 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700339 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700340 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
Bill Buzbee1465db52009-09-23 17:17:35 -0700341 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700342 newLIR2(cUnit, opCode, rDest, absValue - 7);
343 return res;
344 } else
Bill Buzbee1465db52009-09-23 17:17:35 -0700345 opCode = kThumbSubRRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700346 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700347 case kOpLsl:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700348 shortForm = (!neg && value <= 31);
Bill Buzbee1465db52009-09-23 17:17:35 -0700349 opCode = kThumbLslRRI5;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700350 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700351 case kOpLsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700352 shortForm = (!neg && value <= 31);
Bill Buzbee1465db52009-09-23 17:17:35 -0700353 opCode = kThumbLsrRRI5;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700354 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700355 case kOpAsr:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700356 shortForm = (!neg && value <= 31);
Bill Buzbee1465db52009-09-23 17:17:35 -0700357 opCode = kThumbAsrRRI5;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700358 break;
Bill Buzbee1465db52009-09-23 17:17:35 -0700359 case kOpMul:
360 case kOpAnd:
361 case kOpOr:
362 case kOpXor:
Bill Buzbee270c1d62009-08-13 16:58:07 -0700363 if (rDest == rSrc1) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700364 int rScratch = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700365 res = loadConstant(cUnit, rScratch, value);
366 opRegReg(cUnit, op, rDest, rScratch);
367 } else {
368 res = loadConstant(cUnit, rDest, value);
369 opRegReg(cUnit, op, rDest, rSrc1);
370 }
371 return res;
372 default:
373 assert(0);
374 break;
375 }
376 if (shortForm)
377 res = newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
378 else {
379 if (rDest != rSrc1) {
380 res = loadConstant(cUnit, rDest, value);
381 newLIR3(cUnit, opCode, rDest, rSrc1, rDest);
382 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700383 int rScratch = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700384 res = loadConstant(cUnit, rScratch, value);
385 newLIR3(cUnit, opCode, rDest, rSrc1, rScratch);
386 }
387 }
388 return res;
389}
390
Bill Buzbee1465db52009-09-23 17:17:35 -0700391static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
392 int rSrc2)
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700393{
Bill Buzbee1465db52009-09-23 17:17:35 -0700394 ArmLIR *res;
395 ArmOpCode opCode = kThumbBkpt;
396 switch (op) {
397 case kOpAdc:
398 opCode = kThumbAdcRR;
399 break;
400 case kOpAnd:
401 opCode = kThumbAndRR;
402 break;
403 case kOpBic:
404 opCode = kThumbBicRR;
405 break;
406 case kOpCmn:
407 opCode = kThumbCmnRR;
408 break;
409 case kOpCmp:
410 opCode = kThumbCmpRR;
411 break;
412 case kOpXor:
413 opCode = kThumbEorRR;
414 break;
415 case kOpMov:
416 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
417 opCode = kThumbMovRR;
418 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
419 opCode = kThumbMovRR_H2H;
420 else if (LOWREG(rDestSrc1))
421 opCode = kThumbMovRR_H2L;
422 else
423 opCode = kThumbMovRR_L2H;
424 break;
425 case kOpMul:
426 opCode = kThumbMul;
427 break;
428 case kOpMvn:
429 opCode = kThumbMvn;
430 break;
431 case kOpNeg:
432 opCode = kThumbNeg;
433 break;
434 case kOpOr:
435 opCode = kThumbOrr;
436 break;
437 case kOpSbc:
438 opCode = kThumbSbc;
439 break;
440 case kOpTst:
441 opCode = kThumbTst;
442 break;
443 case kOpLsl:
444 opCode = kThumbLslRR;
445 break;
446 case kOpLsr:
447 opCode = kThumbLsrRR;
448 break;
449 case kOpAsr:
450 opCode = kThumbAsrRR;
451 break;
452 case kOpRor:
453 opCode = kThumbRorRR;
454 case kOpAdd:
455 case kOpSub:
456 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
457 case kOp2Byte:
458 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
459 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
460 return res;
461 case kOp2Short:
462 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
463 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
464 return res;
465 case kOp2Char:
466 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
467 opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
468 return res;
469 default:
470 assert(0);
471 break;
472 }
473 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
474}
475
476
477static void handleMonitor(CompilationUnit *cUnit, MIR *mir)
478{
479 handleMonitorPortable(cUnit, mir);
480}
481
482static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
483 RegLocation rlSrc)
484{
485 RegLocation rlResult;
486 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
487 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
488 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
489 rlSrc.lowReg, 0x80000000);
490 storeValue(cUnit, rlDest, rlResult);
491}
492
493static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
494 RegLocation rlSrc)
495{
496 RegLocation rlResult;
497 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
498 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
499 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
500 0x80000000);
501 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
502 storeValueWide(cUnit, rlDest, rlResult);
503}
504
505static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
506 RegLocation rlSrc1, RegLocation rlSrc2)
507{
508 RegLocation rlResult;
509 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
510 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
511 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
512 rlResult = getReturnLocWide(cUnit);
513 storeValueWide(cUnit, rlDest, rlResult);
514}
515
516static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
517 RegLocation rlSrc1, RegLocation rlSrc2)
518{
519 RegLocation rlResult;
520 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
521 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700522 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
Bill Buzbee1465db52009-09-23 17:17:35 -0700523 rlResult = getReturnLoc(cUnit);
524 storeValue(cUnit, rlDest, rlResult);
525}
526
527/* Load value from base + scaled index. */
528static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
529 int rIndex, int rDest, int scale, OpSize size)
530{
531 ArmLIR *first = NULL;
532 ArmLIR *res;
533 ArmOpCode opCode = kThumbBkpt;
534 int rNewIndex = rIndex;
535 if (scale) {
536 // Scale the index, but can't trash the original.
537 rNewIndex = allocTemp(cUnit);
538 first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
539 }
540 switch (size) {
541 case kWord:
542 opCode = kThumbLdrRRR;
543 break;
544 case kUnsignedHalf:
545 opCode = kThumbLdrhRRR;
546 break;
547 case kSignedHalf:
548 opCode = kThumbLdrshRRR;
549 break;
550 case kUnsignedByte:
551 opCode = kThumbLdrbRRR;
552 break;
553 case kSignedByte:
554 opCode = kThumbLdrsbRRR;
555 break;
556 default:
557 assert(0);
558 }
559 res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex);
560 if (scale)
561 freeTemp(cUnit, rNewIndex);
562 return (first) ? first : res;
563}
564
565/* store value base base + scaled index. */
566static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
567 int rIndex, int rSrc, int scale, OpSize size)
568{
569 ArmLIR *first = NULL;
570 ArmLIR *res;
571 ArmOpCode opCode = kThumbBkpt;
572 int rNewIndex = rIndex;
573 if (scale) {
574 rNewIndex = allocTemp(cUnit);
575 first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
576 }
577 switch (size) {
578 case kWord:
579 opCode = kThumbStrRRR;
580 break;
581 case kUnsignedHalf:
582 case kSignedHalf:
583 opCode = kThumbStrhRRR;
584 break;
585 case kUnsignedByte:
586 case kSignedByte:
587 opCode = kThumbStrbRRR;
588 break;
589 default:
590 assert(0);
591 }
592 res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex);
593 if (scale)
594 freeTemp(cUnit, rNewIndex);
595 return (first) ? first : res;
596}
597
598static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
599{
600 ArmLIR *res;
601 genBarrier(cUnit);
602 res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
603 genBarrier(cUnit);
604 return res;
605}
606
607static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
608{
609 ArmLIR *res;
610 genBarrier(cUnit);
611 res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
612 genBarrier(cUnit);
613 return res;
614}
615
616
617static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
618{
619 if (lowReg < highReg) {
620 loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
621 } else {
622 loadWordDisp(cUnit, base, 0 , lowReg);
623 loadWordDisp(cUnit, base, 4 , highReg);
624 }
625}
626
627static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
628 int displacement, int rDest, int rDestHi,
629 OpSize size, bool nullCheck, int sReg)
630/*
631 * Load value from base + displacement. Optionally perform null check
632 * on base (which must have an associated sReg and MIR). If not
633 * performing null check, incoming MIR can be null. IMPORTANT: this
634 * code must not allocate any new temps. If a new register is needed
635 * and base and dest are the same, spill some other register to
636 * rlp and then restore.
637 */
638{
639 ArmLIR *first = NULL;
640 ArmLIR *res;
641 ArmLIR *load = NULL;
642 ArmLIR *load2 = NULL;
643 ArmOpCode opCode = kThumbBkpt;
644 bool shortForm = false;
645 int shortMax = 128;
646 int encodedDisp = displacement;
647 bool pair = false;
648
649 switch (size) {
650 case kLong:
651 case kDouble:
652 pair = true;
653 if ((displacement < 124) && (displacement >= 0)) {
654 assert((displacement & 0x3) == 0);
655 shortForm = true;
656 encodedDisp >>= 2;
657 opCode = kThumbLdrRRI5;
658 } else {
659 opCode = kThumbLdrRRR;
660 }
661 break;
662 case kWord:
663 if (LOWREG(rDest) && (rBase == rpc) &&
664 (displacement <= 1020) && (displacement >= 0)) {
665 shortForm = true;
666 encodedDisp >>= 2;
667 opCode = kThumbLdrPcRel;
668 } else if (LOWREG(rDest) && (rBase == r13) &&
669 (displacement <= 1020) && (displacement >= 0)) {
670 shortForm = true;
671 encodedDisp >>= 2;
672 opCode = kThumbLdrSpRel;
673 } else if (displacement < 128 && displacement >= 0) {
674 assert((displacement & 0x3) == 0);
675 shortForm = true;
676 encodedDisp >>= 2;
677 opCode = kThumbLdrRRI5;
678 } else {
679 opCode = kThumbLdrRRR;
680 }
681 break;
682 case kUnsignedHalf:
683 if (displacement < 64 && displacement >= 0) {
684 assert((displacement & 0x1) == 0);
685 shortForm = true;
686 encodedDisp >>= 1;
687 opCode = kThumbLdrhRRI5;
688 } else {
689 opCode = kThumbLdrhRRR;
690 }
691 break;
692 case kSignedHalf:
693 opCode = kThumbLdrshRRR;
694 break;
695 case kUnsignedByte:
696 if (displacement < 32 && displacement >= 0) {
697 shortForm = true;
698 opCode = kThumbLdrbRRI5;
699 } else {
700 opCode = kThumbLdrbRRR;
701 }
702 break;
703 case kSignedByte:
704 opCode = kThumbLdrsbRRR;
705 break;
706 default:
707 assert(0);
708 }
709 if (nullCheck)
710 first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL);
711 if (shortForm) {
712 load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
713 if (pair) {
714 load2 = newLIR3(cUnit, opCode, rDestHi, rBase, encodedDisp+1);
715 }
716 } else {
717 if (pair) {
718 int rTmp = allocFreeTemp(cUnit);
719 if (rTmp < 0) {
720 //UNIMP: need to spill if no temps.
721 assert(0);
722 }
723 res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
724 //TUNING: how to mark loadPair if Dalvik access?
725 loadPair(cUnit, rTmp, rDest, rDestHi);
726 freeTemp(cUnit, rTmp);
727 } else {
728 int rTmp = (rBase == rDest) ? allocFreeTemp(cUnit) : rDest;
729 if (rTmp < 0) {
730 //UNIMP: need to spill if no temps.
731 assert(0);
732 }
733 res = loadConstant(cUnit, rTmp, displacement);
734 load = newLIR3(cUnit, opCode, rDest, rBase, rTmp);
735 if (rBase == rFP)
736 annotateDalvikRegAccess(load, displacement >> 2,
737 true /* isLoad */);
738 if (rTmp != rDest)
739 freeTemp(cUnit, rTmp);
740 }
741 }
742
743 return (first) ? first : res;
744}
745
746static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
747 int displacement, int rDest, OpSize size,
748 bool nullCheck, int sReg)
749{
750 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
751 size, nullCheck, sReg);
752}
753
754static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
755 int displacement, int rDestLo, int rDestHi,
756 bool nullCheck, int sReg)
757{
758 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
759 kLong, nullCheck, sReg);
760}
761
762static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
763{
764 if (lowReg < highReg) {
765 storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
766 } else {
767 storeWordDisp(cUnit, base, 0, lowReg);
768 storeWordDisp(cUnit, base, 4, highReg);
769 }
770}
771
772
773static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
774 int displacement, int rSrc, int rSrcHi,
775 OpSize size)
776{
777 ArmLIR *res;
778 ArmLIR *store = NULL;
779 ArmLIR *store2 = NULL;
780 ArmOpCode opCode = kThumbBkpt;
781 bool shortForm = false;
782 int shortMax = 128;
783 int encodedDisp = displacement;
784 bool pair = false;
785
786 switch (size) {
787 case kLong:
788 case kDouble:
789 pair = true;
790 if ((displacement < 124) && (displacement >= 0)) {
791 assert((displacement & 0x3) == 0);
792 pair = true;
793 shortForm = true;
794 encodedDisp >>= 2;
795 opCode = kThumbStrRRI5;
796 } else {
797 opCode = kThumbStrRRR;
798 }
799 break;
800 case kWord:
801 if (displacement < 128 && displacement >= 0) {
802 assert((displacement & 0x3) == 0);
803 shortForm = true;
804 encodedDisp >>= 2;
805 opCode = kThumbStrRRI5;
806 } else {
807 opCode = kThumbStrRRR;
808 }
809 break;
810 case kUnsignedHalf:
811 case kSignedHalf:
812 if (displacement < 64 && displacement >= 0) {
813 assert((displacement & 0x1) == 0);
814 shortForm = true;
815 encodedDisp >>= 1;
816 opCode = kThumbStrhRRI5;
817 } else {
818 opCode = kThumbStrhRRR;
819 }
820 break;
821 case kUnsignedByte:
822 case kSignedByte:
823 if (displacement < 32 && displacement >= 0) {
824 shortForm = true;
825 opCode = kThumbStrbRRI5;
826 } else {
827 opCode = kThumbStrbRRR;
828 }
829 break;
830 default:
831 assert(0);
832 }
833 if (shortForm) {
834 store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
835 if (pair) {
836 store2 = newLIR3(cUnit, opCode, rSrcHi, rBase, encodedDisp + 1);
837 }
838 } else {
839 int rScratch = allocTemp(cUnit);
840 if (pair) {
841 //TUNING: how to mark storePair as Dalvik access if it is?
842 res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
843 storePair(cUnit, rScratch, rSrc, rSrcHi);
844 } else {
845 res = loadConstant(cUnit, rScratch, displacement);
846 store = newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
847 if (rBase == rFP) {
848 annotateDalvikRegAccess(store, displacement >> 2,
849 false /* isLoad */);
850 }
851 }
852 freeTemp(cUnit, rScratch);
853 }
854 return res;
855}
856
857static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
858 int displacement, int rSrc, OpSize size)
859{
860 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
861}
862
863static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
864 int displacement, int rSrcLo, int rSrcHi)
865{
866 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
867}
868
869
870/*
871 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
872 * satisfies.
873 */
874static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
875 ArmConditionCode cond, int reg,
876 int checkValue, int dOffset,
877 ArmLIR *pcrLabel)
878{
879 int tReg;
880 ArmLIR *res;
881 if ((checkValue & 0xff) != checkValue) {
882 tReg = allocTemp(cUnit);
883 loadConstant(cUnit, tReg, checkValue);
884 res = genRegRegCheck(cUnit, cond, reg, tReg, dOffset, pcrLabel);
885 freeTemp(cUnit, tReg);
886 return res;
887 }
888 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
889 ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
890 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700891}
892
Bill Buzbee270c1d62009-08-13 16:58:07 -0700893static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
894{
895 DecodedInstruction *dInsn = &mir->dalvikInsn;
896 int offset = offsetof(InterpState, retval);
Bill Buzbee1465db52009-09-23 17:17:35 -0700897 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
898 int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
899 int reg1 = allocTemp(cUnit);
900 genNullCheck(cUnit, getSrcSSAName(mir, 0), regObj, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700901 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbee1465db52009-09-23 17:17:35 -0700902 storeWordDisp(cUnit, rGLUE, offset, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700903 return false;
904}
905
906static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
907{
908 DecodedInstruction *dInsn = &mir->dalvikInsn;
909 int offset = offsetof(InterpState, retval);
910 int contents = offsetof(ArrayObject, contents);
Bill Buzbee1465db52009-09-23 17:17:35 -0700911 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
912 RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
913 int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
914 int regIdx = loadValue(cUnit, rlIdx, kCoreReg).lowReg;
915 int regMax = allocTemp(cUnit);
916 int regOff = allocTemp(cUnit);
917 ArmLIR * pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0),
918 regObj, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700919 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
920 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
921 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
922 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
923
Bill Buzbee1465db52009-09-23 17:17:35 -0700924 newLIR2(cUnit, kThumbAddRI8, regObj, contents);
925 newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regOff);
926 newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regIdx);
927 newLIR3(cUnit, kThumbLdrhRRR, regMax, regObj, regIdx);
928 freeTemp(cUnit, regOff);
929 storeWordDisp(cUnit, rGLUE, offset, regMax);
930//FIXME: rewrite this to not clobber
931 clobberReg(cUnit, regObj);
932 clobberReg(cUnit, regIdx);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700933 return false;
934}
935
936static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
937{
938 int offset = offsetof(InterpState, retval);
Bill Buzbee1465db52009-09-23 17:17:35 -0700939 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
940 int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
941 int sign = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700942 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
Bill Buzbee1465db52009-09-23 17:17:35 -0700943 newLIR3(cUnit, kThumbAsrRRI5, sign, reg0, 31);
944 newLIR3(cUnit, kThumbAddRRR, reg0, reg0, sign);
945 newLIR2(cUnit, kThumbEorRR, reg0, sign);
946 freeTemp(cUnit, sign);
947 storeWordDisp(cUnit, rGLUE, offset, reg0);
948//FIXME: rewrite this to not clobber
949 clobberReg(cUnit, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700950 return false;
951}
952
953static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
954{
955 int offset = offsetof(InterpState, retval);
Bill Buzbee1465db52009-09-23 17:17:35 -0700956 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
957 int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
958 int signMask = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700959 loadConstant(cUnit, signMask, 0x7fffffff);
Bill Buzbee1465db52009-09-23 17:17:35 -0700960 newLIR2(cUnit, kThumbAndRR, reg0, signMask);
961 freeTemp(cUnit, signMask);
962 storeWordDisp(cUnit, rGLUE, offset, reg0);
963//FIXME: rewrite this to not clobber
964 clobberReg(cUnit, reg0);
965 return true;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700966}
967
968static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
969{
970 int offset = offsetof(InterpState, retval);
Bill Buzbee1465db52009-09-23 17:17:35 -0700971 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
972 RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
973 int reglo = regSrc.lowReg;
974 int reghi = regSrc.highReg;
975 int signMask = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700976 loadConstant(cUnit, signMask, 0x7fffffff);
Bill Buzbee1465db52009-09-23 17:17:35 -0700977 storeWordDisp(cUnit, rGLUE, offset, reglo);
978 newLIR2(cUnit, kThumbAndRR, reghi, signMask);
979 freeTemp(cUnit, signMask);
980 storeWordDisp(cUnit, rGLUE, offset + 4, reghi);
981//FIXME: rewrite this to not clobber
982 clobberReg(cUnit, reghi);
983 return true;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700984}
985
Bill Buzbee1465db52009-09-23 17:17:35 -0700986/* No select in thumb, so we need to branch. Thumb2 will do better */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700987static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
988{
989 int offset = offsetof(InterpState, retval);
Bill Buzbee1465db52009-09-23 17:17:35 -0700990 RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
991 RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
992 int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
993 int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
994 newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
995 ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
996 isMin ? kArmCondLt : kArmCondGt);
997 newLIR2(cUnit, kThumbMovRR, reg0, reg1);
998 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
999 target->defMask = ENCODE_ALL;
1000 newLIR3(cUnit, kThumbStrRRI5, reg0, rGLUE, offset >> 2);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001001 branch1->generic.target = (LIR *)target;
Bill Buzbee1465db52009-09-23 17:17:35 -07001002//FIXME: rewrite this to not clobber
1003 clobberReg(cUnit,reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001004 return false;
1005}
1006
1007static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1008{
1009 int offset = offsetof(InterpState, retval);
Bill Buzbee1465db52009-09-23 17:17:35 -07001010 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1011 RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
1012 int oplo = regSrc.lowReg;
1013 int ophi = regSrc.highReg;
1014 int sign = allocTemp(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001015 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
Bill Buzbee1465db52009-09-23 17:17:35 -07001016 newLIR3(cUnit, kThumbAsrRRI5, sign, ophi, 31);
1017 newLIR3(cUnit, kThumbAddRRR, oplo, oplo, sign);
1018 newLIR2(cUnit, kThumbAdcRR, ophi, sign);
1019 newLIR2(cUnit, kThumbEorRR, oplo, sign);
1020 newLIR2(cUnit, kThumbEorRR, ophi, sign);
1021 freeTemp(cUnit, sign);
1022 storeWordDisp(cUnit, rGLUE, offset, oplo);
1023 storeWordDisp(cUnit, rGLUE, offset + 4, ophi);
1024//FIXME: rewrite this to not clobber
1025 clobberReg(cUnit, oplo);
1026 clobberReg(cUnit, ophi);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001027 return false;
1028}
Bill Buzbee1465db52009-09-23 17:17:35 -07001029
1030
1031/*
1032 * Load a immediate using a shortcut if possible; otherwise
1033 * grab from the per-translation literal pool. If target is
1034 * a high register, build constant into a low register and copy.
1035 */
1036static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
1037{
1038 ArmLIR *res;
1039 int tDest = LOWREG(rDest) ? rDest : allocTemp(cUnit);
1040 /* See if the value can be constructed cheaply */
1041 if ((value >= 0) && (value <= 255)) {
1042 res = newLIR2(cUnit, kThumbMovImm, tDest, value);
1043 if (rDest != tDest) {
1044 opRegReg(cUnit, kOpMov, rDest, tDest);
1045 freeTemp(cUnit, tDest);
1046 }
1047 return res;
1048 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
1049 res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
1050 newLIR2(cUnit, kThumbMvn, tDest, tDest);
1051 if (rDest != tDest) {
1052 opRegReg(cUnit, kOpMov, rDest, tDest);
1053 freeTemp(cUnit, tDest);
1054 }
1055 return res;
1056 }
1057 /* No shortcut - go ahead and use literal pool */
1058 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
1059 if (dataTarget == NULL) {
1060 dataTarget = addWordData(cUnit, value, false);
1061 }
1062 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
1063 loadPcRel->opCode = kThumbLdrPcRel;
1064 loadPcRel->generic.target = (LIR *) dataTarget;
1065 loadPcRel->operands[0] = tDest;
1066 setupResourceMasks(loadPcRel);
1067 res = loadPcRel;
1068 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
1069
1070 /*
1071 * To save space in the constant pool, we use the ADD_RRI8 instruction to
1072 * add up to 255 to an existing constant value.
1073 */
1074 if (dataTarget->operands[0] != value) {
1075 newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
1076 }
1077 if (rDest != tDest) {
1078 opRegReg(cUnit, kOpMov, rDest, tDest);
1079 freeTemp(cUnit, tDest);
1080 }
1081 return res;
1082}
1083
1084static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
1085 int rDestHi, int valLo, int valHi)
1086{
1087 ArmLIR *res;
1088 res = loadConstantValue(cUnit, rDestLo, valLo);
1089 loadConstantValue(cUnit, rDestHi, valHi);
1090 return res;
1091}