blob: b40656de3bb9b8e1c0ede6054a7dcbca64d2a0b3 [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/* Forward decls */
27static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
28 int dOffset, ArmLIR *pcrLabel);
29static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest);
30static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest);
31static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
32 int displacement, int rDest);
33static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
34 int displacement, int rSrc, int rScratch);
35static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
36 int rScratch);
37static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
38 ArmConditionCode cond,
39 ArmLIR *target);
40static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target);
41static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
42 int rDestHi);
43static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
44 int vDest, int rScratch);
45static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
46 int rBound, int dOffset, ArmLIR *pcrLabel);
47static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
Bill Buzbeea4a7f072009-08-27 13:58:09 -070048static int inlinedTarget(MIR *mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -070049
Bill Buzbee9bc3df32009-07-30 10:52:29 -070050
51/* Routines which must be supplied here */
Bill Buzbee270c1d62009-08-13 16:58:07 -070052static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
53static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
54 int rAddr);
55static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
56 int displacement, int rDest, OpSize size,
57 bool nullCheck, int vReg);
58static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
59 int displacement, int rSrc, OpSize size,
60 int rScratch);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070061static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee270c1d62009-08-13 16:58:07 -070062 ArmConditionCode cond, int reg,
63 int checkValue, int dOffset,
64 ArmLIR *pcrLabel);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070065ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
Bill Buzbee270c1d62009-08-13 16:58:07 -070066static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
67static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070068
Bill Buzbee270c1d62009-08-13 16:58:07 -070069static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
70static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
71static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
72 int value2);
73static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
74static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
75 int rSrc2);
76static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
77 int value, int rScratch);
78static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
79 int rSrc1, int value, int rScratch);
80static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
81 int rSrc1, int rSrc2);
82static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
83 int rIndex, int rDest, int scale, OpSize size);
Bill Buzbeea4a7f072009-08-27 13:58:09 -070084static void genCmpLong(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
85 int vSrc2);
Bill Buzbee270c1d62009-08-13 16:58:07 -070086
87static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
88static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
89static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
90static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
91static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
92static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
93static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070094
95/*
96 * Support for register allocation
97 */
98
Bill Buzbee9bc3df32009-07-30 10:52:29 -070099/* get the next register in r0..r3 in a round-robin fashion */
100#define NEXT_REG(reg) ((reg + 1) & 3)
101/*
102 * The following are utility routines to help maintain the RegisterScoreboard
103 * state to facilitate register renaming.
104 */
105
106/* Reset the tracker to unknown state */
107static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
108{
109 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
Ben Chengd7d426a2009-09-22 11:23:36 -0700110 int i;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700111
112 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
113 registerScoreboard->liveDalvikReg = vNone;
114 registerScoreboard->nativeReg = vNone;
115 registerScoreboard->nativeRegHi = vNone;
Ben Chengd7d426a2009-09-22 11:23:36 -0700116 for (i = 0; i < 32; i++) {
117 registerScoreboard->fp[i] = vNone;
118 }
119 registerScoreboard->nextFP = 0;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700120}
121
122/* Kill the corresponding bit in the null-checked register list */
123static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
124{
125 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
126}
127
128/* The Dalvik register pair held in native registers have changed */
129static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
130 int vReg, int mRegLo, int mRegHi)
131{
132 cUnit->registerScoreboard.liveDalvikReg = vReg;
133 cUnit->registerScoreboard.nativeReg = mRegLo;
134 cUnit->registerScoreboard.nativeRegHi = mRegHi;
135 cUnit->registerScoreboard.isWide = true;
136}
137
138/* The Dalvik register held in a native register has changed */
139static inline void updateLiveRegister(CompilationUnit *cUnit,
140 int vReg, int mReg)
141{
142 cUnit->registerScoreboard.liveDalvikReg = vReg;
143 cUnit->registerScoreboard.nativeReg = mReg;
144 cUnit->registerScoreboard.isWide = false;
145}
146
147/*
148 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
149 * the lifetime of cached Dalvik value in a native register.
150 */
151static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
152 bool isWide)
153{
154 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
155
156 /* No live value - suggest to use r0 */
157 if (registerScoreboard->liveDalvikReg == vNone)
158 return r0;
159
160 /* Reuse the previously used native reg */
161 if (registerScoreboard->liveDalvikReg == vSrc) {
162 if (isWide != true) {
163 return registerScoreboard->nativeReg;
164 } else {
165 /* Return either r0 or r2 */
166 return (registerScoreboard->nativeReg + 1) & 2;
167 }
168 }
169
170 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
171 if (isWide) {
172 return (registerScoreboard->nativeReg + 2) & 2;
173 } else {
174 return (registerScoreboard->nativeReg + 1) & 3;
175 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700176}
177
178/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700179 * Generate a Thumb2 IT instruction, which can nullify up to
180 * four subsequent instructions based on a condition and its
181 * inverse. The condition applies to the first instruction, which
182 * is executed if the condition is met. The string "guide" consists
183 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
184 * A "T" means the instruction is executed if the condition is
185 * met, and an "E" means the instruction is executed if the condition
186 * is not met.
187 */
188static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
189 char *guide)
190{
191 int mask;
192 int condBit = code & 1;
193 int altBit = condBit ^ 1;
194 int mask3 = 0;
195 int mask2 = 0;
196 int mask1 = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700197
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700198 //Note: case fallthroughs intentional
199 switch(strlen(guide)) {
200 case 3:
201 mask1 = (guide[2] == 'T') ? condBit : altBit;
202 case 2:
203 mask2 = (guide[1] == 'T') ? condBit : altBit;
204 case 1:
205 mask3 = (guide[0] == 'T') ? condBit : altBit;
206 break;
207 case 0:
208 break;
209 default:
210 assert(0);
211 dvmAbort();
212 }
213 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
214 (1 << (3 - strlen(guide)));
215 return newLIR2(cUnit, THUMB2_IT, code, mask);
216}
217
218
Bill Buzbee270c1d62009-08-13 16:58:07 -0700219static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700220{
221 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
222 res->operands[0] = rDest;
223 res->operands[1] = rSrc;
224 if (rDest == rSrc) {
225 res->isNop = true;
226 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700227 // TODO: support copy between FP and gen regs
228 if (DOUBLEREG(rDest)) {
229 assert(DOUBLEREG(rSrc));
230 res->opCode = THUMB2_VMOVD;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700231 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700232 assert(SINGLEREG(rSrc));
233 res->opCode = THUMB2_VMOVS;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700234 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700235 res->operands[0] = rDest;
236 res->operands[1] = rSrc;
237 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700238 setupResourceMasks(res);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700239 return res;
240}
241
242ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
243{
244 ArmLIR* res;
245 ArmOpCode opCode;
246 if (FPREG(rDest) || FPREG(rSrc))
247 return fpRegCopy(cUnit, rDest, rSrc);
248 res = dvmCompilerNew(sizeof(ArmLIR), true);
249 if (LOWREG(rDest) && LOWREG(rSrc))
250 opCode = THUMB_MOV_RR;
251 else if (!LOWREG(rDest) && !LOWREG(rSrc))
252 opCode = THUMB_MOV_RR_H2H;
253 else if (LOWREG(rDest))
254 opCode = THUMB_MOV_RR_H2L;
255 else
256 opCode = THUMB_MOV_RR_L2H;
257
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700258 res->operands[0] = rDest;
259 res->operands[1] = rSrc;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700260 res->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700261 setupResourceMasks(res);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700262 if (rDest == rSrc) {
263 res->isNop = true;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700264 }
265 return res;
266}
267
268static int leadingZeros(u4 val)
269{
270 u4 alt;
271 int n;
272 int count;
273
274 count = 16;
275 n = 32;
276 do {
277 alt = val >> count;
278 if (alt != 0) {
279 n = n - count;
280 val = alt;
281 }
282 count >>= 1;
283 } while (count);
284 return n - val;
285}
286
287/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700288 * Determine whether value can be encoded as a Thumb2 modified
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700289 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
290 */
291static int modifiedImmediate(u4 value)
292{
293 int zLeading;
294 int zTrailing;
295 u4 b0 = value & 0xff;
296
297 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
298 if (value <= 0xFF)
299 return b0; // 0:000:a:bcdefgh
300 if (value == ((b0 << 16) | b0))
301 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
302 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
303 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
304 b0 = (value >> 8) & 0xff;
305 if (value == ((b0 << 24) | (b0 << 8)))
306 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
307 /* Can we do it with rotation? */
308 zLeading = leadingZeros(value);
309 zTrailing = 32 - leadingZeros(~value & (value - 1));
310 /* A run of eight or fewer active bits? */
311 if ((zLeading + zTrailing) < 24)
312 return -1; /* No - bail */
313 /* left-justify the constant, discarding msb (known to be 1) */
314 value <<= zLeading + 1;
315 /* Create bcdefgh */
316 value >>= 25;
317 /* Put it all together */
318 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
319}
320
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700321/*
322 * Load a immediate using a shortcut if possible; otherwise
323 * grab from the per-translation literal pool
324 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700325static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700326{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700327 ArmLIR *res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700328 int modImm;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700329 /* See if the value can be constructed cheaply */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700330 if ((value >= 0) && (value <= 255)) {
331 return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700332 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700333 /* Check Modified immediate special cases */
334 modImm = modifiedImmediate(value);
335 if (modImm >= 0) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700336 res = newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, rDest, modImm);
337 return res;
338 }
339 modImm = modifiedImmediate(~value);
340 if (modImm >= 0) {
341 res = newLIR2(cUnit, THUMB2_MVN_IMM_SHIFT, rDest, modImm);
342 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700343 }
344 /* 16-bit immediate? */
345 if ((value & 0xffff) == value) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700346 res = newLIR2(cUnit, THUMB2_MOV_IMM16, rDest, value);
347 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700348 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700349 /* No shortcut - go ahead and use literal pool */
350 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
351 if (dataTarget == NULL) {
352 dataTarget = addWordData(cUnit, value, false);
353 }
354 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
355 loadPcRel->opCode = THUMB_LDR_PC_REL;
356 loadPcRel->generic.target = (LIR *) dataTarget;
357 loadPcRel->operands[0] = rDest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700358 setupResourceMasks(loadPcRel);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700359 res = loadPcRel;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700360 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
361
362 /*
363 * To save space in the constant pool, we use the ADD_RRI8 instruction to
364 * add up to 255 to an existing constant value.
365 */
366 if (dataTarget->operands[0] != value) {
367 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
368 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700369 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700370}
371
372/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700373static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
374 int rAddr)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700375{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700376 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700377 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700378 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700379 newLIR3(cUnit, THUMB2_STR_RRI8_PREDEC, rDPC, rFP,
380 sizeof(StackSaveArea) - offset);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700381 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700382}
383
Bill Buzbee270c1d62009-08-13 16:58:07 -0700384/* Load value from base + scaled index. Note: index reg killed */
385static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
386 int rIndex, int rDest, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700387{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700388 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
389 ArmOpCode opCode = THUMB_BKPT;
390 bool thumbForm = (allLowRegs && (scale == 0));
391 switch (size) {
392 case WORD:
393 opCode = (thumbForm) ? THUMB_LDR_RRR : THUMB2_LDR_RRR;
394 break;
395 case UNSIGNED_HALF:
396 opCode = (thumbForm) ? THUMB_LDRH_RRR : THUMB2_LDRH_RRR;
397 break;
398 case SIGNED_HALF:
399 opCode = (thumbForm) ? THUMB_LDRSH_RRR : THUMB2_LDRSH_RRR;
400 break;
401 case UNSIGNED_BYTE:
402 opCode = (thumbForm) ? THUMB_LDRB_RRR : THUMB2_LDRB_RRR;
403 break;
404 case SIGNED_BYTE:
405 opCode = (thumbForm) ? THUMB_LDRSB_RRR : THUMB2_LDRSB_RRR;
406 break;
407 default:
408 assert(0);
409 }
410 if (thumbForm)
411 return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
412 else
413 return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700414}
415
Bill Buzbee270c1d62009-08-13 16:58:07 -0700416/* store value base base + scaled index. Note: index reg killed */
417static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
418 int rIndex, int rSrc, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700419{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700420 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
421 ArmOpCode opCode = THUMB_BKPT;
422 bool thumbForm = (allLowRegs && (scale == 0));
423 switch (size) {
424 case WORD:
425 opCode = (thumbForm) ? THUMB_STR_RRR : THUMB2_STR_RRR;
426 break;
427 case UNSIGNED_HALF:
428 case SIGNED_HALF:
429 opCode = (thumbForm) ? THUMB_STRH_RRR : THUMB2_STRH_RRR;
430 break;
431 case UNSIGNED_BYTE:
432 case SIGNED_BYTE:
433 opCode = (thumbForm) ? THUMB_STRB_RRR : THUMB2_STRB_RRR;
434 break;
435 default:
436 assert(0);
437 }
438 if (thumbForm)
439 return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
440 else
441 return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700442}
443
444/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700445 * Load a float from a Dalvik register. Note: using fixed r7 here
446 * when operation is out of range. Revisit this when registor allocation
447 * strategy changes.
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700448 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700449static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
450 int rSrcDest, ArmOpCode opCode)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700451{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700452 ArmLIR *res;
453 if (vSrcDest > 255) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700454 opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
455 res = newLIR3(cUnit, opCode, rSrcDest, r7, 0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700456 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700457 res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700458 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700459 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700460}
Ben Chengd7d426a2009-09-22 11:23:36 -0700461
462static int nextFPReg(CompilationUnit *cUnit, int dalvikReg, bool isDouble)
463{
464 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
465 int reg;
466
467 if (isDouble) {
468 reg = ((registerScoreboard->nextFP + 1) & ~1) % 32;
469 registerScoreboard->nextFP = reg + 2;
470 registerScoreboard->nextFP %= 32;
471 registerScoreboard->fp[reg] = dalvikReg;
472 return dr0 + reg;
473 }
474 else {
475 reg = registerScoreboard->nextFP++;
476 registerScoreboard->nextFP %= 32;
477 registerScoreboard->fp[reg] = dalvikReg;
478 return fr0 + reg;
479 }
480}
481
482/*
483 * Select a SFP register for the dalvikReg
484 */
485static int selectSFPReg(CompilationUnit *cUnit, int dalvikReg)
486{
487 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
488 int i;
489
490 if (dalvikReg == vNone) {
491 return nextFPReg(cUnit, dalvikReg, false);;
492 }
493
494 for (i = 0; i < 32; i++) {
495 if (registerScoreboard->fp[i] == dalvikReg) {
496 return fr0 + i;
497 }
498 }
499 return nextFPReg(cUnit, dalvikReg, false);;
500}
501
502/*
503 * Select a DFP register for the dalvikReg
504 */
505static int selectDFPReg(CompilationUnit *cUnit, int dalvikReg)
506{
507 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
508 int i;
509
510 if (dalvikReg == vNone) {
511 return nextFPReg(cUnit, dalvikReg, true);;
512 }
513
514 for (i = 0; i < 32; i += 2) {
515 if (registerScoreboard->fp[i] == dalvikReg) {
516 return dr0 + i;
517 }
518 }
519 return nextFPReg(cUnit, dalvikReg, true);
520}
521
Bill Buzbee270c1d62009-08-13 16:58:07 -0700522static ArmLIR *loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700523{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700524 assert(SINGLEREG(rDest));
Ben Chengd7d426a2009-09-22 11:23:36 -0700525 ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
526 annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
527 return lir;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700528}
529
530/* Store a float to a Dalvik register */
Ben Chengd7d426a2009-09-22 11:23:36 -0700531static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700532{
Ben Chengd7d426a2009-09-22 11:23:36 -0700533 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
534
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700535 assert(SINGLEREG(rSrc));
Ben Chengd7d426a2009-09-22 11:23:36 -0700536 registerScoreboard->fp[rSrc % 32] = vDest;
537
538 ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
539 annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
540 return lir;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700541}
542
543/* Load a double from a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700544static ArmLIR *loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700545{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700546 assert(DOUBLEREG(rDest));
Ben Chengd7d426a2009-09-22 11:23:36 -0700547 ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
548 annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
549 return lir;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700550}
551
552/* Store a double to a Dalvik register */
Ben Chengd7d426a2009-09-22 11:23:36 -0700553static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700554{
Ben Chengd7d426a2009-09-22 11:23:36 -0700555 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700556
Ben Chengd7d426a2009-09-22 11:23:36 -0700557 assert(DOUBLEREG(rSrc));
558 registerScoreboard->fp[rSrc % 32] = vDest;
559
560 ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
561 annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
562 return lir;
563}
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700564
Bill Buzbee270c1d62009-08-13 16:58:07 -0700565/*
566 * Load value from base + displacement. Optionally perform null check
567 * on base (which must have an associated vReg and MIR). If not
568 * performing null check, incoming MIR can be null. Note: base and
569 * dest must not be the same if there is any chance that the long
570 * form must be used.
571 * TODO: revisit, perhaps use hot temp reg in (base == dest) case.
572 */
573static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
574 int displacement, int rDest, OpSize size,
575 bool nullCheck, int vReg)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700576{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700577 ArmLIR *first = NULL;
Ben Chengd7d426a2009-09-22 11:23:36 -0700578 ArmLIR *res, *load;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700579 ArmOpCode opCode = THUMB_BKPT;
580 bool shortForm = false;
581 bool thumb2Form = (displacement < 4092 && displacement >= 0);
582 int shortMax = 128;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700583 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
Ben Chengd7d426a2009-09-22 11:23:36 -0700584 int encodedDisp = displacement;
585
Bill Buzbee270c1d62009-08-13 16:58:07 -0700586 switch (size) {
587 case WORD:
588 if (LOWREG(rDest) && (rBase == rpc) &&
589 (displacement <= 1020) && (displacement >= 0)) {
590 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700591 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700592 opCode = THUMB_LDR_PC_REL;
593 } else if (LOWREG(rDest) && (rBase == r13) &&
594 (displacement <= 1020) && (displacement >= 0)) {
595 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700596 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700597 opCode = THUMB_LDR_SP_REL;
598 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
599 assert((displacement & 0x3) == 0);
600 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700601 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700602 opCode = THUMB_LDR_RRI5;
603 } else if (thumb2Form) {
604 shortForm = true;
605 opCode = THUMB2_LDR_RRI12;
606 }
607 break;
608 case UNSIGNED_HALF:
609 if (allLowRegs && displacement < 64 && displacement >= 0) {
610 assert((displacement & 0x1) == 0);
611 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700612 encodedDisp >>= 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700613 opCode = THUMB_LDRH_RRI5;
614 } else if (displacement < 4092 && displacement >= 0) {
615 shortForm = true;
616 opCode = THUMB2_LDRH_RRI12;
617 }
618 break;
619 case SIGNED_HALF:
620 if (thumb2Form) {
621 shortForm = true;
622 opCode = THUMB2_LDRSH_RRI12;
623 }
624 break;
625 case UNSIGNED_BYTE:
626 if (allLowRegs && displacement < 32 && displacement >= 0) {
627 shortForm = true;
628 opCode = THUMB_LDRB_RRI5;
629 } else if (thumb2Form) {
630 shortForm = true;
631 opCode = THUMB2_LDRB_RRI12;
632 }
633 break;
634 case SIGNED_BYTE:
635 if (thumb2Form) {
636 shortForm = true;
637 opCode = THUMB2_LDRSB_RRI12;
638 }
639 break;
640 default:
641 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700642 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700643 if (nullCheck)
644 first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
645 if (shortForm) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700646 load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700647 } else {
648 assert(rBase != rDest);
Ben Chengd7d426a2009-09-22 11:23:36 -0700649 res = loadConstant(cUnit, rDest, encodedDisp);
650 load = loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
651 }
652
653 if (rBase == rFP) {
654 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700655 }
656 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700657}
658
Bill Buzbee270c1d62009-08-13 16:58:07 -0700659static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
660 int displacement, int rSrc, OpSize size,
661 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700662{
Ben Chengd7d426a2009-09-22 11:23:36 -0700663 ArmLIR *res, *store;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700664 ArmOpCode opCode = THUMB_BKPT;
665 bool shortForm = false;
666 bool thumb2Form = (displacement < 4092 && displacement >= 0);
667 int shortMax = 128;
668 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
Ben Chengd7d426a2009-09-22 11:23:36 -0700669 int encodedDisp = displacement;
670
Bill Buzbee270c1d62009-08-13 16:58:07 -0700671 if (rScratch != -1)
672 allLowRegs &= LOWREG(rScratch);
673 switch (size) {
674 case WORD:
675 if (allLowRegs && displacement < 128 && displacement >= 0) {
676 assert((displacement & 0x3) == 0);
677 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700678 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700679 opCode = THUMB_STR_RRI5;
680 } else if (thumb2Form) {
681 shortForm = true;
682 opCode = THUMB2_STR_RRI12;
683 }
684 break;
685 case UNSIGNED_HALF:
686 case SIGNED_HALF:
687 if (displacement < 64 && displacement >= 0) {
688 assert((displacement & 0x1) == 0);
689 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700690 encodedDisp >>= 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700691 opCode = THUMB_STRH_RRI5;
692 } else if (thumb2Form) {
693 shortForm = true;
694 opCode = THUMB2_STRH_RRI12;
695 }
696 break;
697 case UNSIGNED_BYTE:
698 case SIGNED_BYTE:
699 if (displacement < 32 && displacement >= 0) {
700 shortForm = true;
701 opCode = THUMB_STRB_RRI5;
702 } else if (thumb2Form) {
703 shortForm = true;
704 opCode = THUMB2_STRH_RRI12;
705 }
706 break;
707 default:
708 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700709 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700710 if (shortForm) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700711 store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700712 } else {
713 assert(rScratch != -1);
Ben Chengd7d426a2009-09-22 11:23:36 -0700714 res = loadConstant(cUnit, rScratch, encodedDisp);
715 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
716 }
717
718 if (rBase == rFP) {
719 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700720 }
721 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700722}
723
724/*
725 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
726 * satisfies.
727 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700728static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700729 ArmConditionCode cond, int reg,
730 int checkValue, int dOffset,
731 ArmLIR *pcrLabel)
732{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700733 ArmLIR *branch;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700734 int modImm;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700735 /*
Ben Cheng0fd31e42009-09-03 14:40:16 -0700736 * TODO: re-enable usage of THUMB2_CBZ & THUMB2_CBNZ once assembler is
737 * enhanced to allow us to replace code patterns when instructions don't
738 * reach. Currently, CB[N]Z is causing too many assembler aborts.
739 * What we want to do is emit the short forms, and then replace them with
740 * longer versions when needed.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700741 */
742 if (0 && (LOWREG(reg)) && (checkValue == 0) &&
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700743 ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
744 branch = newLIR2(cUnit,
745 (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
746 reg, 0);
747 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700748 modImm = modifiedImmediate(checkValue);
749 if ((checkValue & 0xff) == checkValue) {
750 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
751 } else if (modImm >= 0) {
752 newLIR2(cUnit, THUMB2_CMP_RI8, reg, modImm);
753 } else {
754 /* Note: direct use of hot temp r7 here. Revisit. */
755 loadConstant(cUnit, r7, checkValue);
756 newLIR2(cUnit, THUMB_CMP_RR, reg, r7);
757 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700758 branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
759 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700760 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
761}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700762
763static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
764{
765 ArmLIR *res;
766 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
767 res = newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
768 } else {
769 res = newLIR2(cUnit, THUMB2_LDMIA, rBase, rMask);
770 }
771 return res;
772}
773
774static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
775{
776 ArmLIR *res;
777 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
778 res = newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
779 } else {
780 res = newLIR2(cUnit, THUMB2_STMIA, rBase, rMask);
781 }
782 return res;
783}
784
785static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
786{
787 ArmOpCode opCode = THUMB_BKPT;
788 switch (op) {
789 case OP_UNCOND_BR:
790 opCode = THUMB_B_UNCOND;
791 break;
792 default:
793 assert(0);
794 }
795 return newLIR0(cUnit, opCode);
796}
797
798static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
799 int value2)
800{
801 ArmOpCode opCode = THUMB_BKPT;
802 switch (op) {
803 case OP_COND_BR:
804 opCode = THUMB_B_COND;
805 break;
806 default:
807 assert(0);
808 }
809 return newLIR2(cUnit, opCode, value1, value2);
810}
811
812static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
813{
814 ArmOpCode opCode = THUMB_BKPT;
815 switch (op) {
816 case OP_PUSH:
817 opCode = ((value & 0xff00) != 0) ? THUMB2_PUSH : THUMB_PUSH;
818 break;
819 case OP_POP:
820 opCode = ((value & 0xff00) != 0) ? THUMB2_POP : THUMB_POP;
821 break;
822 default:
823 assert(0);
824 }
825 return newLIR1(cUnit, opCode, value);
826}
827
828static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
829{
830 ArmOpCode opCode = THUMB_BKPT;
831 switch (op) {
832 case OP_BLX:
833 opCode = THUMB_BLX_R;
834 break;
835 default:
836 assert(0);
837 }
838 return newLIR1(cUnit, opCode, rDestSrc);
839}
840
841static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
842 int rSrc2, int shift)
843{
844 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
845 ArmOpCode opCode = THUMB_BKPT;
846 switch (op) {
847 case OP_ADC:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700848 opCode = (thumbForm) ? THUMB_ADC_RR : THUMB2_ADC_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700849 break;
850 case OP_AND:
851 opCode = (thumbForm) ? THUMB_AND_RR : THUMB2_AND_RRR;
852 break;
853 case OP_BIC:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700854 opCode = (thumbForm) ? THUMB_BIC_RR : THUMB2_BIC_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700855 break;
856 case OP_CMN:
857 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700858 opCode = (thumbForm) ? THUMB_CMN_RR : THUMB2_CMN_RR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700859 break;
860 case OP_CMP:
861 if (thumbForm)
862 opCode = THUMB_CMP_RR;
863 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
864 opCode = THUMB_CMP_HH;
865 else if ((shift == 0) && LOWREG(rDestSrc1))
866 opCode = THUMB_CMP_LH;
867 else if (shift == 0)
868 opCode = THUMB_CMP_HL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700869 else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700870 opCode = THUMB2_CMP_RR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700871 break;
872 case OP_XOR:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700873 opCode = (thumbForm) ? THUMB_EOR_RR : THUMB2_EOR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700874 break;
875 case OP_MOV:
876 assert(shift == 0);
877 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
878 opCode = THUMB_MOV_RR;
879 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
880 opCode = THUMB_MOV_RR_H2H;
881 else if (LOWREG(rDestSrc1))
882 opCode = THUMB_MOV_RR_H2L;
883 else
884 opCode = THUMB_MOV_RR_L2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700885 break;
886 case OP_MUL:
887 assert(shift == 0);
888 opCode = (thumbForm) ? THUMB_MUL : THUMB2_MUL_RRR;
889 break;
890 case OP_MVN:
891 opCode = (thumbForm) ? THUMB_MVN : THUMB2_MVN_RR;
892 break;
893 case OP_NEG:
894 assert(shift == 0);
895 opCode = (thumbForm) ? THUMB_NEG : THUMB2_NEG_RR;
896 break;
897 case OP_OR:
898 opCode = (thumbForm) ? THUMB_ORR : THUMB2_ORR_RRR;
899 break;
900 case OP_SBC:
901 opCode = (thumbForm) ? THUMB_SBC : THUMB2_SBC_RRR;
902 break;
903 case OP_TST:
904 opCode = (thumbForm) ? THUMB_TST : THUMB2_TST_RR;
905 break;
906 case OP_LSL:
907 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700908 opCode = (thumbForm) ? THUMB_LSL_RR : THUMB2_LSL_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700909 break;
910 case OP_LSR:
911 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700912 opCode = (thumbForm) ? THUMB_LSR_RR : THUMB2_LSR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700913 break;
914 case OP_ASR:
915 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700916 opCode = (thumbForm) ? THUMB_ASR_RR : THUMB2_ASR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700917 break;
918 case OP_ROR:
919 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700920 opCode = (thumbForm) ? THUMB_ROR_RR : THUMB2_ROR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700921 break;
922 case OP_ADD:
923 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
924 break;
925 case OP_SUB:
926 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
927 break;
928 case OP_2BYTE:
929 assert(shift == 0);
930 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 8);
931 case OP_2SHORT:
932 assert(shift == 0);
933 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 16);
934 case OP_2CHAR:
935 assert(shift == 0);
936 return newLIR4(cUnit, THUMB2_UBFX, rDestSrc1, rSrc2, 0, 16);
937 default:
938 assert(0);
939 break;
940 }
941 assert(opCode >= 0);
942 if (EncodingMap[opCode].flags & IS_BINARY_OP)
943 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
944 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
945 if (EncodingMap[opCode].fieldLoc[2].kind == SHIFT)
946 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
947 else
948 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
949 } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
950 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
951 else {
952 assert(0);
953 return NULL;
954 }
955}
956
957static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
958 int rSrc2)
959{
960 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
961}
962
963/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
964static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
965 int value, int rScratch)
966{
967 ArmLIR *res;
968 bool neg = (value < 0);
969 int absValue = (neg) ? -value : value;
970 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
971 ArmOpCode opCode = THUMB_BKPT;
972 switch (op) {
973 case OP_ADD:
974 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
975 assert((value & 0x3) == 0);
976 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
977 } else if (shortForm) {
978 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
979 }
980 break;
981 case OP_SUB:
982 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
983 assert((value & 0x3) == 0);
984 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
985 } else if (shortForm) {
986 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
987 }
988 break;
989 case OP_CMP:
990 if (LOWREG(rDestSrc1) && shortForm)
991 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
992 else if (LOWREG(rDestSrc1))
993 opCode = THUMB_CMP_RR;
994 else {
995 shortForm = false;
996 opCode = THUMB_CMP_HL;
997 }
998 break;
999 default:
1000 /* Punt to opRegRegImm - if bad case catch it there */
1001 shortForm = false;
1002 break;
1003 }
1004 if (shortForm)
1005 return newLIR2(cUnit, opCode, rDestSrc1, absValue);
1006 else
1007 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value, rScratch);
1008}
1009
1010static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
1011 int rDest, int rSrc1, int rSrc2, int shift)
1012{
1013 ArmOpCode opCode = THUMB_BKPT;
1014 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
1015 LOWREG(rSrc2);
1016 switch (op) {
1017 case OP_ADD:
1018 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
1019 break;
1020 case OP_SUB:
1021 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
1022 break;
1023 case OP_ADC:
1024 opCode = THUMB2_ADC_RRR;
1025 break;
1026 case OP_AND:
1027 opCode = THUMB2_AND_RRR;
1028 break;
1029 case OP_BIC:
1030 opCode = THUMB2_BIC_RRR;
1031 break;
1032 case OP_XOR:
1033 opCode = THUMB2_EOR_RRR;
1034 break;
1035 case OP_MUL:
1036 assert(shift == 0);
1037 opCode = THUMB2_MUL_RRR;
1038 break;
1039 case OP_OR:
1040 opCode = THUMB2_ORR_RRR;
1041 break;
1042 case OP_SBC:
1043 opCode = THUMB2_SBC_RRR;
1044 break;
1045 case OP_LSL:
1046 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001047 opCode = THUMB2_LSL_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001048 break;
1049 case OP_LSR:
1050 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001051 opCode = THUMB2_LSR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001052 break;
1053 case OP_ASR:
1054 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001055 opCode = THUMB2_ASR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001056 break;
1057 case OP_ROR:
1058 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001059 opCode = THUMB2_ROR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001060 break;
1061 default:
1062 assert(0);
1063 break;
1064 }
1065 assert(opCode >= 0);
1066 if (EncodingMap[opCode].flags & IS_QUAD_OP)
1067 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
1068 else {
1069 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
1070 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
1071 }
1072}
1073
1074static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
1075 int rSrc1, int rSrc2)
1076{
1077 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
1078}
1079
1080static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
1081 int rSrc1, int value, int rScratch)
1082{
1083 ArmLIR *res;
1084 bool neg = (value < 0);
1085 int absValue = (neg) ? -value : value;
1086 ArmOpCode opCode = THUMB_BKPT;
1087 ArmOpCode altOpCode = THUMB_BKPT;
1088 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
1089 int modImm = modifiedImmediate(value);
1090 int modImmNeg = modifiedImmediate(-value);
1091
1092 switch(op) {
1093 case OP_LSL:
1094 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001095 return newLIR3(cUnit, THUMB_LSL_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001096 else
1097 return newLIR3(cUnit, THUMB2_LSL_RRI5, rDest, rSrc1, value);
1098 case OP_LSR:
1099 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001100 return newLIR3(cUnit, THUMB_LSR_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001101 else
1102 return newLIR3(cUnit, THUMB2_LSR_RRI5, rDest, rSrc1, value);
1103 case OP_ASR:
1104 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001105 return newLIR3(cUnit, THUMB_ASR_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001106 else
1107 return newLIR3(cUnit, THUMB2_ASR_RRI5, rDest, rSrc1, value);
1108 case OP_ROR:
1109 return newLIR3(cUnit, THUMB2_ROR_RRI5, rDest, rSrc1, value);
1110 case OP_ADD:
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001111 if (LOWREG(rDest) && (rSrc1 == 13) &&
1112 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001113 return newLIR3(cUnit, THUMB_ADD_SP_REL, rDest, rSrc1,
1114 value >> 2);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001115 } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
1116 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001117 return newLIR3(cUnit, THUMB_ADD_PC_REL, rDest, rSrc1,
1118 value >> 2);
1119 }
1120 opCode = THUMB2_ADD_RRI8;
1121 altOpCode = THUMB2_ADD_RRR;
1122 // Note: intentional fallthrough
1123 case OP_SUB:
1124 if (allLowRegs && ((absValue & 0x7) == absValue)) {
1125 if (op == OP_ADD)
1126 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
1127 else
1128 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
1129 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1130 } else if ((absValue & 0xff) == absValue) {
1131 if (op == OP_ADD)
1132 opCode = (neg) ? THUMB2_SUB_RRI12 : THUMB2_ADD_RRI12;
1133 else
1134 opCode = (neg) ? THUMB2_ADD_RRI12 : THUMB2_SUB_RRI12;
1135 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1136 }
1137 if (modImmNeg >= 0) {
1138 op = (op == OP_ADD) ? OP_SUB : OP_ADD;
1139 modImm = modImmNeg;
1140 }
1141 if (op == OP_SUB) {
1142 opCode = THUMB2_SUB_RRI8;
1143 altOpCode = THUMB2_SUB_RRR;
1144 }
1145 break;
1146 case OP_ADC:
1147 opCode = THUMB2_ADC_RRI8;
1148 altOpCode = THUMB2_ADC_RRR;
1149 break;
1150 case OP_SBC:
1151 opCode = THUMB2_SBC_RRI8;
1152 altOpCode = THUMB2_SBC_RRR;
1153 break;
1154 case OP_OR:
1155 opCode = THUMB2_ORR_RRI8;
1156 altOpCode = THUMB2_ORR_RRR;
1157 break;
1158 case OP_AND:
1159 opCode = THUMB2_AND_RRI8;
1160 altOpCode = THUMB2_AND_RRR;
1161 break;
1162 case OP_XOR:
1163 opCode = THUMB2_EOR_RRI8;
1164 altOpCode = THUMB2_EOR_RRR;
1165 break;
1166 case OP_MUL:
1167 //TUNING: power of 2, shift & add
1168 modImm = -1;
1169 altOpCode = THUMB2_MUL_RRR;
1170 break;
1171 default:
1172 assert(0);
1173 }
1174
1175 if (modImm >= 0) {
1176 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
1177 } else {
1178 loadConstant(cUnit, rScratch, value);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001179 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001180 return newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
1181 else
1182 return newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
1183 }
1184}
1185
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001186/*
1187 * 64-bit 3way compare function.
1188 * mov r7, #-1
1189 * cmp op1hi, op2hi
1190 * blt done
1191 * bgt flip
1192 * sub r7, op1lo, op2lo (treat as unsigned)
1193 * beq done
1194 * ite hi
1195 * mov(hi) r7, #-1
1196 * mov(!hi) r7, #1
1197 * flip:
1198 * neg r7
1199 * done:
1200 */
1201static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
1202 int vDest, int vSrc1, int vSrc2)
1203{
1204 int op1lo = selectFirstRegister(cUnit, vSrc1, true);
1205 int op1hi = NEXT_REG(op1lo);
1206 int op2lo = NEXT_REG(op1hi);
1207 int op2hi = NEXT_REG(op2lo);
1208 loadValuePair(cUnit, vSrc1, op1lo, op1hi);
1209 loadValuePair(cUnit, vSrc2, op2lo, op2hi);
1210 /* Note: using hardcoded r7 & r4PC for now. revisit */
1211 loadConstant(cUnit, r7, -1);
1212 opRegReg(cUnit, OP_CMP, op1hi, op2hi);
1213 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_LT);
1214 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
1215 opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
1216 ArmLIR *branch3 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
1217
1218 // TODO: need assert mechanism to verify IT block size
1219 branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
1220 newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
1221 newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
Ben Chengd7d426a2009-09-22 11:23:36 -07001222 genBarrier(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001223
1224 branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
1225 branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
1226 branch3->generic.target = branch1->generic.target;
1227}
1228
Bill Buzbee270c1d62009-08-13 16:58:07 -07001229static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1230{
1231 DecodedInstruction *dInsn = &mir->dalvikInsn;
1232 int offset = offsetof(InterpState, retval);
1233 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1234 int reg1 = NEXT_REG(regObj);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001235 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001236 loadValue(cUnit, dInsn->arg[0], regObj);
1237 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
1238 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001239 if (vDest >= 0)
1240 storeValue(cUnit, reg1, vDest, regObj);
1241 else
1242 storeWordDisp(cUnit, rGLUE, offset, reg1, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001243 return false;
1244}
1245
1246static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
1247{
1248 DecodedInstruction *dInsn = &mir->dalvikInsn;
1249 int offset = offsetof(InterpState, retval);
1250 int contents = offsetof(ArrayObject, contents);
1251 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1252 int regIdx = NEXT_REG(regObj);
1253 int regMax = NEXT_REG(regIdx);
1254 int regOff = NEXT_REG(regMax);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001255 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001256 loadValue(cUnit, dInsn->arg[0], regObj);
1257 loadValue(cUnit, dInsn->arg[1], regIdx);
1258 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
1259 mir->offset, NULL);
1260 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
1261 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
1262 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
1263 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001264 opRegImm(cUnit, OP_ADD, regObj, contents, rNone);
1265 opRegReg(cUnit, OP_ADD, regIdx, regOff);
1266 loadBaseIndexed(cUnit, regObj, regIdx, regMax, 1, UNSIGNED_HALF);
1267 if (vDest >= 0)
1268 storeValue(cUnit, regMax, vDest, regObj);
1269 else
1270 storeWordDisp(cUnit, rGLUE, offset, regMax, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001271 return false;
1272}
1273
1274static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
1275{
1276 int offset = offsetof(InterpState, retval);
1277 DecodedInstruction *dInsn = &mir->dalvikInsn;
1278 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1279 int sign = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001280 int vDest = inlinedTarget(mir);
1281 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001282 loadValue(cUnit, dInsn->arg[0], reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001283 /*
1284 * Thumb2's IT block also yields 3 instructions, but imposes
1285 * scheduling constraints.
1286 */
1287 opRegRegImm(cUnit, OP_ASR, sign, reg0, 31, rNone);
1288 opRegReg(cUnit, OP_ADD, reg0, sign);
1289 opRegReg(cUnit, OP_XOR, reg0, sign);
1290 if (vDest >= 0)
1291 storeValue(cUnit, reg0, vDest, sign);
1292 else
1293 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001294 return false;
1295}
1296
1297static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
1298{
1299 int offset = offsetof(InterpState, retval);
1300 DecodedInstruction *dInsn = &mir->dalvikInsn;
1301 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1302 int signMask = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001303 int vDest = inlinedTarget(mir);
1304 // TUNING: handle case of src already in FP reg
Bill Buzbee270c1d62009-08-13 16:58:07 -07001305 loadValue(cUnit, dInsn->arg[0], reg0);
1306 loadConstant(cUnit, signMask, 0x7fffffff);
1307 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001308 if (vDest >= 0)
1309 storeValue(cUnit, reg0, vDest, signMask);
1310 else
1311 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001312 return false;
1313}
1314
1315static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
1316{
1317 int offset = offsetof(InterpState, retval);
1318 DecodedInstruction *dInsn = &mir->dalvikInsn;
1319 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1320 int ophi = NEXT_REG(oplo);
1321 int signMask = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001322 int vSrc = dInsn->arg[0];
1323 int vDest = inlinedTarget(mir);
1324 // TUNING: handle case of src already in FP reg
1325 if (vDest >= 0) {
Bill Buzbee7fb2edd2009-08-31 10:25:55 -07001326 /*
1327 * FIXME: disable this case to to work around bug until after
1328 * new schedule/ralloc mechanisms are done.
1329 */
1330 if (0 && (vDest == vSrc)) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001331 loadValue(cUnit, vSrc+1, ophi);
1332 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1333 storeValue(cUnit, ophi, vDest + 1, signMask);
1334 } else {
1335 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1336 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1337 storeValuePair(cUnit, oplo, ophi, vDest, signMask);
1338 }
1339 } else {
1340 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1341 loadConstant(cUnit, signMask, 0x7fffffff);
1342 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1343 opRegReg(cUnit, OP_AND, ophi, signMask);
1344 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1345 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001346 return false;
1347}
1348
Bill Buzbee270c1d62009-08-13 16:58:07 -07001349static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1350{
1351 int offset = offsetof(InterpState, retval);
1352 DecodedInstruction *dInsn = &mir->dalvikInsn;
1353 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1354 int reg1 = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001355 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001356 loadValue(cUnit, dInsn->arg[0], reg0);
1357 loadValue(cUnit, dInsn->arg[1], reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001358 opRegReg(cUnit, OP_CMP, reg0, reg1);
1359 //TODO: need assertion mechanism to validate IT region size
1360 genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
1361 opRegReg(cUnit, OP_MOV, reg0, reg1);
Ben Chengd7d426a2009-09-22 11:23:36 -07001362 genBarrier(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001363 if (vDest >= 0)
1364 storeValue(cUnit, reg0, vDest, reg1);
1365 else
1366 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001367 return false;
1368}
1369
1370static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1371{
1372 int offset = offsetof(InterpState, retval);
1373 DecodedInstruction *dInsn = &mir->dalvikInsn;
1374 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1375 int ophi = NEXT_REG(oplo);
1376 int sign = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001377 int vDest = inlinedTarget(mir);
1378 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001379 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001380 /*
1381 * Thumb2 IT block allows slightly shorter sequence,
1382 * but introduces a scheduling barrier. Stick with this
1383 * mechanism for now.
1384 */
1385 opRegRegImm(cUnit, OP_ASR, sign, ophi, 31, rNone);
1386 opRegReg(cUnit, OP_ADD, oplo, sign);
1387 opRegReg(cUnit, OP_ADC, ophi, sign);
1388 opRegReg(cUnit, OP_XOR, oplo, sign);
1389 opRegReg(cUnit, OP_XOR, ophi, sign);
1390 if (vDest >= 0) {
1391 storeValuePair(cUnit, oplo, ophi, vDest, sign);
1392 } else {
1393 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1394 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1395 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001396 return false;
1397}