blob: dfbb0308eaa0431411ebf4031b446822c78b1d58 [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);
Ben Cheng4f489172009-09-27 17:08:35 -070071static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc);
Bill Buzbee270c1d62009-08-13 16:58:07 -070072static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
73static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
74 int rSrc2);
75static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
76 int value, int rScratch);
77static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
78 int rSrc1, int value, int rScratch);
79static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
80 int rSrc1, int rSrc2);
81static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
82 int rIndex, int rDest, int scale, OpSize size);
Bill Buzbeea4a7f072009-08-27 13:58:09 -070083static void genCmpLong(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
84 int vSrc2);
Bill Buzbee270c1d62009-08-13 16:58:07 -070085
86static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
87static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
88static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
89static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
90static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
91static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
92static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070093
94/*
95 * Support for register allocation
96 */
97
Bill Buzbee9bc3df32009-07-30 10:52:29 -070098/* get the next register in r0..r3 in a round-robin fashion */
99#define NEXT_REG(reg) ((reg + 1) & 3)
100/*
101 * The following are utility routines to help maintain the RegisterScoreboard
102 * state to facilitate register renaming.
103 */
104
105/* Reset the tracker to unknown state */
106static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
107{
108 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
Ben Chengd7d426a2009-09-22 11:23:36 -0700109 int i;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700110
111 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
112 registerScoreboard->liveDalvikReg = vNone;
113 registerScoreboard->nativeReg = vNone;
114 registerScoreboard->nativeRegHi = vNone;
Ben Chengd7d426a2009-09-22 11:23:36 -0700115 for (i = 0; i < 32; i++) {
116 registerScoreboard->fp[i] = vNone;
117 }
118 registerScoreboard->nextFP = 0;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700119}
120
121/* Kill the corresponding bit in the null-checked register list */
122static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
123{
124 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
125}
126
127/* The Dalvik register pair held in native registers have changed */
128static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
129 int vReg, int mRegLo, int mRegHi)
130{
131 cUnit->registerScoreboard.liveDalvikReg = vReg;
132 cUnit->registerScoreboard.nativeReg = mRegLo;
133 cUnit->registerScoreboard.nativeRegHi = mRegHi;
134 cUnit->registerScoreboard.isWide = true;
135}
136
137/* The Dalvik register held in a native register has changed */
138static inline void updateLiveRegister(CompilationUnit *cUnit,
139 int vReg, int mReg)
140{
141 cUnit->registerScoreboard.liveDalvikReg = vReg;
142 cUnit->registerScoreboard.nativeReg = mReg;
143 cUnit->registerScoreboard.isWide = false;
144}
145
146/*
147 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
148 * the lifetime of cached Dalvik value in a native register.
149 */
150static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
151 bool isWide)
152{
153 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
154
155 /* No live value - suggest to use r0 */
156 if (registerScoreboard->liveDalvikReg == vNone)
157 return r0;
158
159 /* Reuse the previously used native reg */
160 if (registerScoreboard->liveDalvikReg == vSrc) {
161 if (isWide != true) {
162 return registerScoreboard->nativeReg;
163 } else {
164 /* Return either r0 or r2 */
165 return (registerScoreboard->nativeReg + 1) & 2;
166 }
167 }
168
169 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
170 if (isWide) {
171 return (registerScoreboard->nativeReg + 2) & 2;
172 } else {
173 return (registerScoreboard->nativeReg + 1) & 3;
174 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700175}
176
177/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700178 * Generate a Thumb2 IT instruction, which can nullify up to
179 * four subsequent instructions based on a condition and its
180 * inverse. The condition applies to the first instruction, which
181 * is executed if the condition is met. The string "guide" consists
182 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
183 * A "T" means the instruction is executed if the condition is
184 * met, and an "E" means the instruction is executed if the condition
185 * is not met.
186 */
187static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
188 char *guide)
189{
190 int mask;
191 int condBit = code & 1;
192 int altBit = condBit ^ 1;
193 int mask3 = 0;
194 int mask2 = 0;
195 int mask1 = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700196
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700197 //Note: case fallthroughs intentional
198 switch(strlen(guide)) {
199 case 3:
200 mask1 = (guide[2] == 'T') ? condBit : altBit;
201 case 2:
202 mask2 = (guide[1] == 'T') ? condBit : altBit;
203 case 1:
204 mask3 = (guide[0] == 'T') ? condBit : altBit;
205 break;
206 case 0:
207 break;
208 default:
209 assert(0);
210 dvmAbort();
211 }
212 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
213 (1 << (3 - strlen(guide)));
214 return newLIR2(cUnit, THUMB2_IT, code, mask);
215}
216
217
Bill Buzbee270c1d62009-08-13 16:58:07 -0700218static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700219{
220 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
221 res->operands[0] = rDest;
222 res->operands[1] = rSrc;
223 if (rDest == rSrc) {
224 res->isNop = true;
225 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700226 // TODO: support copy between FP and gen regs
227 if (DOUBLEREG(rDest)) {
228 assert(DOUBLEREG(rSrc));
229 res->opCode = THUMB2_VMOVD;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700230 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700231 assert(SINGLEREG(rSrc));
232 res->opCode = THUMB2_VMOVS;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700233 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700234 res->operands[0] = rDest;
235 res->operands[1] = rSrc;
236 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700237 setupResourceMasks(res);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700238 return res;
239}
240
241ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
242{
243 ArmLIR* res;
244 ArmOpCode opCode;
245 if (FPREG(rDest) || FPREG(rSrc))
246 return fpRegCopy(cUnit, rDest, rSrc);
247 res = dvmCompilerNew(sizeof(ArmLIR), true);
248 if (LOWREG(rDest) && LOWREG(rSrc))
249 opCode = THUMB_MOV_RR;
250 else if (!LOWREG(rDest) && !LOWREG(rSrc))
251 opCode = THUMB_MOV_RR_H2H;
252 else if (LOWREG(rDest))
253 opCode = THUMB_MOV_RR_H2L;
254 else
255 opCode = THUMB_MOV_RR_L2H;
256
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700257 res->operands[0] = rDest;
258 res->operands[1] = rSrc;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700259 res->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700260 setupResourceMasks(res);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700261 if (rDest == rSrc) {
262 res->isNop = true;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700263 }
264 return res;
265}
266
267static int leadingZeros(u4 val)
268{
269 u4 alt;
270 int n;
271 int count;
272
273 count = 16;
274 n = 32;
275 do {
276 alt = val >> count;
277 if (alt != 0) {
278 n = n - count;
279 val = alt;
280 }
281 count >>= 1;
282 } while (count);
283 return n - val;
284}
285
286/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700287 * Determine whether value can be encoded as a Thumb2 modified
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700288 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
289 */
290static int modifiedImmediate(u4 value)
291{
292 int zLeading;
293 int zTrailing;
294 u4 b0 = value & 0xff;
295
296 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
297 if (value <= 0xFF)
298 return b0; // 0:000:a:bcdefgh
299 if (value == ((b0 << 16) | b0))
300 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
301 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
302 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
303 b0 = (value >> 8) & 0xff;
304 if (value == ((b0 << 24) | (b0 << 8)))
305 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
306 /* Can we do it with rotation? */
307 zLeading = leadingZeros(value);
308 zTrailing = 32 - leadingZeros(~value & (value - 1));
309 /* A run of eight or fewer active bits? */
310 if ((zLeading + zTrailing) < 24)
311 return -1; /* No - bail */
312 /* left-justify the constant, discarding msb (known to be 1) */
313 value <<= zLeading + 1;
314 /* Create bcdefgh */
315 value >>= 25;
316 /* Put it all together */
317 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
318}
319
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700320/*
321 * Load a immediate using a shortcut if possible; otherwise
322 * grab from the per-translation literal pool
323 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700324static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700325{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700326 ArmLIR *res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700327 int modImm;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700328 /* See if the value can be constructed cheaply */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700329 if ((value >= 0) && (value <= 255)) {
330 return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700331 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700332 /* Check Modified immediate special cases */
333 modImm = modifiedImmediate(value);
334 if (modImm >= 0) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700335 res = newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, rDest, modImm);
336 return res;
337 }
338 modImm = modifiedImmediate(~value);
339 if (modImm >= 0) {
340 res = newLIR2(cUnit, THUMB2_MVN_IMM_SHIFT, rDest, modImm);
341 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700342 }
343 /* 16-bit immediate? */
344 if ((value & 0xffff) == value) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700345 res = newLIR2(cUnit, THUMB2_MOV_IMM16, rDest, value);
346 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700347 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700348 /* No shortcut - go ahead and use literal pool */
349 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
350 if (dataTarget == NULL) {
351 dataTarget = addWordData(cUnit, value, false);
352 }
353 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
354 loadPcRel->opCode = THUMB_LDR_PC_REL;
355 loadPcRel->generic.target = (LIR *) dataTarget;
356 loadPcRel->operands[0] = rDest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700357 setupResourceMasks(loadPcRel);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700358 res = loadPcRel;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700359 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
360
361 /*
362 * To save space in the constant pool, we use the ADD_RRI8 instruction to
363 * add up to 255 to an existing constant value.
364 */
365 if (dataTarget->operands[0] != value) {
366 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
367 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700368 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700369}
370
371/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700372static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
373 int rAddr)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700374{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700375 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700376 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700377 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700378 newLIR3(cUnit, THUMB2_STR_RRI8_PREDEC, rDPC, rFP,
379 sizeof(StackSaveArea) - offset);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700380 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700381}
382
Bill Buzbee270c1d62009-08-13 16:58:07 -0700383/* Load value from base + scaled index. Note: index reg killed */
384static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
385 int rIndex, int rDest, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700386{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700387 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
388 ArmOpCode opCode = THUMB_BKPT;
389 bool thumbForm = (allLowRegs && (scale == 0));
390 switch (size) {
391 case WORD:
392 opCode = (thumbForm) ? THUMB_LDR_RRR : THUMB2_LDR_RRR;
393 break;
394 case UNSIGNED_HALF:
395 opCode = (thumbForm) ? THUMB_LDRH_RRR : THUMB2_LDRH_RRR;
396 break;
397 case SIGNED_HALF:
398 opCode = (thumbForm) ? THUMB_LDRSH_RRR : THUMB2_LDRSH_RRR;
399 break;
400 case UNSIGNED_BYTE:
401 opCode = (thumbForm) ? THUMB_LDRB_RRR : THUMB2_LDRB_RRR;
402 break;
403 case SIGNED_BYTE:
404 opCode = (thumbForm) ? THUMB_LDRSB_RRR : THUMB2_LDRSB_RRR;
405 break;
406 default:
407 assert(0);
408 }
409 if (thumbForm)
410 return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
411 else
412 return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700413}
414
Bill Buzbee270c1d62009-08-13 16:58:07 -0700415/* store value base base + scaled index. Note: index reg killed */
416static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
417 int rIndex, int rSrc, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700418{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700419 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
420 ArmOpCode opCode = THUMB_BKPT;
421 bool thumbForm = (allLowRegs && (scale == 0));
422 switch (size) {
423 case WORD:
424 opCode = (thumbForm) ? THUMB_STR_RRR : THUMB2_STR_RRR;
425 break;
426 case UNSIGNED_HALF:
427 case SIGNED_HALF:
428 opCode = (thumbForm) ? THUMB_STRH_RRR : THUMB2_STRH_RRR;
429 break;
430 case UNSIGNED_BYTE:
431 case SIGNED_BYTE:
432 opCode = (thumbForm) ? THUMB_STRB_RRR : THUMB2_STRB_RRR;
433 break;
434 default:
435 assert(0);
436 }
437 if (thumbForm)
438 return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
439 else
440 return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700441}
442
443/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700444 * Load a float from a Dalvik register. Note: using fixed r7 here
445 * when operation is out of range. Revisit this when registor allocation
446 * strategy changes.
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700447 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700448static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
449 int rSrcDest, ArmOpCode opCode)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700450{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700451 ArmLIR *res;
452 if (vSrcDest > 255) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700453 opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
454 res = newLIR3(cUnit, opCode, rSrcDest, r7, 0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700455 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700456 res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700457 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700458 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700459}
Ben Chengd7d426a2009-09-22 11:23:36 -0700460
461static int nextFPReg(CompilationUnit *cUnit, int dalvikReg, bool isDouble)
462{
463 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
464 int reg;
465
466 if (isDouble) {
467 reg = ((registerScoreboard->nextFP + 1) & ~1) % 32;
468 registerScoreboard->nextFP = reg + 2;
469 registerScoreboard->nextFP %= 32;
470 registerScoreboard->fp[reg] = dalvikReg;
471 return dr0 + reg;
472 }
473 else {
474 reg = registerScoreboard->nextFP++;
475 registerScoreboard->nextFP %= 32;
476 registerScoreboard->fp[reg] = dalvikReg;
477 return fr0 + reg;
478 }
479}
480
481/*
482 * Select a SFP register for the dalvikReg
483 */
484static int selectSFPReg(CompilationUnit *cUnit, int dalvikReg)
485{
486 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
487 int i;
488
489 if (dalvikReg == vNone) {
490 return nextFPReg(cUnit, dalvikReg, false);;
491 }
492
493 for (i = 0; i < 32; i++) {
494 if (registerScoreboard->fp[i] == dalvikReg) {
495 return fr0 + i;
496 }
497 }
498 return nextFPReg(cUnit, dalvikReg, false);;
499}
500
501/*
502 * Select a DFP register for the dalvikReg
503 */
504static int selectDFPReg(CompilationUnit *cUnit, int dalvikReg)
505{
506 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
507 int i;
508
509 if (dalvikReg == vNone) {
510 return nextFPReg(cUnit, dalvikReg, true);;
511 }
512
513 for (i = 0; i < 32; i += 2) {
514 if (registerScoreboard->fp[i] == dalvikReg) {
515 return dr0 + i;
516 }
517 }
518 return nextFPReg(cUnit, dalvikReg, true);
519}
520
Bill Buzbee270c1d62009-08-13 16:58:07 -0700521static ArmLIR *loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700522{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700523 assert(SINGLEREG(rDest));
Ben Chengd7d426a2009-09-22 11:23:36 -0700524 ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
525 annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
526 return lir;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700527}
528
529/* Store a float to a Dalvik register */
Ben Chengd7d426a2009-09-22 11:23:36 -0700530static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700531{
Ben Chengd7d426a2009-09-22 11:23:36 -0700532 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
533
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700534 assert(SINGLEREG(rSrc));
Ben Chengd7d426a2009-09-22 11:23:36 -0700535 registerScoreboard->fp[rSrc % 32] = vDest;
536
537 ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
538 annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
539 return lir;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700540}
541
542/* Load a double from a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700543static ArmLIR *loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700544{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700545 assert(DOUBLEREG(rDest));
Ben Chengd7d426a2009-09-22 11:23:36 -0700546 ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
547 annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
548 return lir;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700549}
550
551/* Store a double to a Dalvik register */
Ben Chengd7d426a2009-09-22 11:23:36 -0700552static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700553{
Ben Chengd7d426a2009-09-22 11:23:36 -0700554 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700555
Ben Chengd7d426a2009-09-22 11:23:36 -0700556 assert(DOUBLEREG(rSrc));
557 registerScoreboard->fp[rSrc % 32] = vDest;
558
559 ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
560 annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
561 return lir;
562}
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700563
Bill Buzbee270c1d62009-08-13 16:58:07 -0700564/*
565 * Load value from base + displacement. Optionally perform null check
566 * on base (which must have an associated vReg and MIR). If not
567 * performing null check, incoming MIR can be null. Note: base and
568 * dest must not be the same if there is any chance that the long
569 * form must be used.
570 * TODO: revisit, perhaps use hot temp reg in (base == dest) case.
571 */
572static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
573 int displacement, int rDest, OpSize size,
574 bool nullCheck, int vReg)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700575{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700576 ArmLIR *first = NULL;
Ben Chengd7d426a2009-09-22 11:23:36 -0700577 ArmLIR *res, *load;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700578 ArmOpCode opCode = THUMB_BKPT;
579 bool shortForm = false;
580 bool thumb2Form = (displacement < 4092 && displacement >= 0);
581 int shortMax = 128;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700582 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
Ben Chengd7d426a2009-09-22 11:23:36 -0700583 int encodedDisp = displacement;
584
Bill Buzbee270c1d62009-08-13 16:58:07 -0700585 switch (size) {
586 case WORD:
587 if (LOWREG(rDest) && (rBase == rpc) &&
588 (displacement <= 1020) && (displacement >= 0)) {
589 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700590 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700591 opCode = THUMB_LDR_PC_REL;
592 } else if (LOWREG(rDest) && (rBase == r13) &&
593 (displacement <= 1020) && (displacement >= 0)) {
594 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700595 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700596 opCode = THUMB_LDR_SP_REL;
597 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
598 assert((displacement & 0x3) == 0);
599 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700600 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700601 opCode = THUMB_LDR_RRI5;
602 } else if (thumb2Form) {
603 shortForm = true;
604 opCode = THUMB2_LDR_RRI12;
605 }
606 break;
607 case UNSIGNED_HALF:
608 if (allLowRegs && displacement < 64 && displacement >= 0) {
609 assert((displacement & 0x1) == 0);
610 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700611 encodedDisp >>= 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700612 opCode = THUMB_LDRH_RRI5;
613 } else if (displacement < 4092 && displacement >= 0) {
614 shortForm = true;
615 opCode = THUMB2_LDRH_RRI12;
616 }
617 break;
618 case SIGNED_HALF:
619 if (thumb2Form) {
620 shortForm = true;
621 opCode = THUMB2_LDRSH_RRI12;
622 }
623 break;
624 case UNSIGNED_BYTE:
625 if (allLowRegs && displacement < 32 && displacement >= 0) {
626 shortForm = true;
627 opCode = THUMB_LDRB_RRI5;
628 } else if (thumb2Form) {
629 shortForm = true;
630 opCode = THUMB2_LDRB_RRI12;
631 }
632 break;
633 case SIGNED_BYTE:
634 if (thumb2Form) {
635 shortForm = true;
636 opCode = THUMB2_LDRSB_RRI12;
637 }
638 break;
639 default:
640 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700641 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700642 if (nullCheck)
643 first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
644 if (shortForm) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700645 load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700646 } else {
647 assert(rBase != rDest);
Ben Chengd7d426a2009-09-22 11:23:36 -0700648 res = loadConstant(cUnit, rDest, encodedDisp);
649 load = loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
650 }
651
652 if (rBase == rFP) {
653 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700654 }
655 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700656}
657
Bill Buzbee270c1d62009-08-13 16:58:07 -0700658static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
659 int displacement, int rSrc, OpSize size,
660 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700661{
Ben Chengd7d426a2009-09-22 11:23:36 -0700662 ArmLIR *res, *store;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700663 ArmOpCode opCode = THUMB_BKPT;
664 bool shortForm = false;
665 bool thumb2Form = (displacement < 4092 && displacement >= 0);
666 int shortMax = 128;
667 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
Ben Chengd7d426a2009-09-22 11:23:36 -0700668 int encodedDisp = displacement;
669
Bill Buzbee270c1d62009-08-13 16:58:07 -0700670 if (rScratch != -1)
671 allLowRegs &= LOWREG(rScratch);
672 switch (size) {
673 case WORD:
674 if (allLowRegs && displacement < 128 && displacement >= 0) {
675 assert((displacement & 0x3) == 0);
676 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700677 encodedDisp >>= 2;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700678 opCode = THUMB_STR_RRI5;
679 } else if (thumb2Form) {
680 shortForm = true;
681 opCode = THUMB2_STR_RRI12;
682 }
683 break;
684 case UNSIGNED_HALF:
685 case SIGNED_HALF:
686 if (displacement < 64 && displacement >= 0) {
687 assert((displacement & 0x1) == 0);
688 shortForm = true;
Ben Chengd7d426a2009-09-22 11:23:36 -0700689 encodedDisp >>= 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700690 opCode = THUMB_STRH_RRI5;
691 } else if (thumb2Form) {
692 shortForm = true;
693 opCode = THUMB2_STRH_RRI12;
694 }
695 break;
696 case UNSIGNED_BYTE:
697 case SIGNED_BYTE:
698 if (displacement < 32 && displacement >= 0) {
699 shortForm = true;
700 opCode = THUMB_STRB_RRI5;
701 } else if (thumb2Form) {
702 shortForm = true;
703 opCode = THUMB2_STRH_RRI12;
704 }
705 break;
706 default:
707 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700708 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700709 if (shortForm) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700710 store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700711 } else {
712 assert(rScratch != -1);
Ben Chengd7d426a2009-09-22 11:23:36 -0700713 res = loadConstant(cUnit, rScratch, encodedDisp);
714 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
715 }
716
717 if (rBase == rFP) {
718 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700719 }
720 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700721}
722
723/*
724 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
725 * satisfies.
726 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700727static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700728 ArmConditionCode cond, int reg,
729 int checkValue, int dOffset,
730 ArmLIR *pcrLabel)
731{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700732 ArmLIR *branch;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700733 int modImm;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700734 /*
Ben Cheng0fd31e42009-09-03 14:40:16 -0700735 * TODO: re-enable usage of THUMB2_CBZ & THUMB2_CBNZ once assembler is
736 * enhanced to allow us to replace code patterns when instructions don't
737 * reach. Currently, CB[N]Z is causing too many assembler aborts.
738 * What we want to do is emit the short forms, and then replace them with
739 * longer versions when needed.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700740 */
741 if (0 && (LOWREG(reg)) && (checkValue == 0) &&
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700742 ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
743 branch = newLIR2(cUnit,
744 (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
745 reg, 0);
746 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700747 modImm = modifiedImmediate(checkValue);
748 if ((checkValue & 0xff) == checkValue) {
749 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
750 } else if (modImm >= 0) {
751 newLIR2(cUnit, THUMB2_CMP_RI8, reg, modImm);
752 } else {
753 /* Note: direct use of hot temp r7 here. Revisit. */
754 loadConstant(cUnit, r7, checkValue);
755 newLIR2(cUnit, THUMB_CMP_RR, reg, r7);
756 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700757 branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
758 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700759 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
760}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700761
762static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
763{
764 ArmLIR *res;
765 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
766 res = newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
767 } else {
768 res = newLIR2(cUnit, THUMB2_LDMIA, rBase, rMask);
769 }
770 return res;
771}
772
773static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
774{
775 ArmLIR *res;
776 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
777 res = newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
778 } else {
779 res = newLIR2(cUnit, THUMB2_STMIA, rBase, rMask);
780 }
781 return res;
782}
783
784static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
785{
786 ArmOpCode opCode = THUMB_BKPT;
787 switch (op) {
788 case OP_UNCOND_BR:
789 opCode = THUMB_B_UNCOND;
790 break;
791 default:
792 assert(0);
793 }
794 return newLIR0(cUnit, opCode);
795}
796
Ben Cheng4f489172009-09-27 17:08:35 -0700797static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700798{
Ben Cheng4f489172009-09-27 17:08:35 -0700799 return newLIR2(cUnit, THUMB_B_COND, 0 /* offset to be patched */, cc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700800}
801
802static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
803{
804 ArmOpCode opCode = THUMB_BKPT;
805 switch (op) {
806 case OP_PUSH:
807 opCode = ((value & 0xff00) != 0) ? THUMB2_PUSH : THUMB_PUSH;
808 break;
809 case OP_POP:
810 opCode = ((value & 0xff00) != 0) ? THUMB2_POP : THUMB_POP;
811 break;
812 default:
813 assert(0);
814 }
815 return newLIR1(cUnit, opCode, value);
816}
817
818static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
819{
820 ArmOpCode opCode = THUMB_BKPT;
821 switch (op) {
822 case OP_BLX:
823 opCode = THUMB_BLX_R;
824 break;
825 default:
826 assert(0);
827 }
828 return newLIR1(cUnit, opCode, rDestSrc);
829}
830
831static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
832 int rSrc2, int shift)
833{
834 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
835 ArmOpCode opCode = THUMB_BKPT;
836 switch (op) {
837 case OP_ADC:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700838 opCode = (thumbForm) ? THUMB_ADC_RR : THUMB2_ADC_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700839 break;
840 case OP_AND:
841 opCode = (thumbForm) ? THUMB_AND_RR : THUMB2_AND_RRR;
842 break;
843 case OP_BIC:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700844 opCode = (thumbForm) ? THUMB_BIC_RR : THUMB2_BIC_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700845 break;
846 case OP_CMN:
847 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700848 opCode = (thumbForm) ? THUMB_CMN_RR : THUMB2_CMN_RR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700849 break;
850 case OP_CMP:
851 if (thumbForm)
852 opCode = THUMB_CMP_RR;
853 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
854 opCode = THUMB_CMP_HH;
855 else if ((shift == 0) && LOWREG(rDestSrc1))
856 opCode = THUMB_CMP_LH;
857 else if (shift == 0)
858 opCode = THUMB_CMP_HL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700859 else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700860 opCode = THUMB2_CMP_RR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700861 break;
862 case OP_XOR:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700863 opCode = (thumbForm) ? THUMB_EOR_RR : THUMB2_EOR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700864 break;
865 case OP_MOV:
866 assert(shift == 0);
867 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
868 opCode = THUMB_MOV_RR;
869 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
870 opCode = THUMB_MOV_RR_H2H;
871 else if (LOWREG(rDestSrc1))
872 opCode = THUMB_MOV_RR_H2L;
873 else
874 opCode = THUMB_MOV_RR_L2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700875 break;
876 case OP_MUL:
877 assert(shift == 0);
878 opCode = (thumbForm) ? THUMB_MUL : THUMB2_MUL_RRR;
879 break;
880 case OP_MVN:
881 opCode = (thumbForm) ? THUMB_MVN : THUMB2_MVN_RR;
882 break;
883 case OP_NEG:
884 assert(shift == 0);
885 opCode = (thumbForm) ? THUMB_NEG : THUMB2_NEG_RR;
886 break;
887 case OP_OR:
888 opCode = (thumbForm) ? THUMB_ORR : THUMB2_ORR_RRR;
889 break;
890 case OP_SBC:
891 opCode = (thumbForm) ? THUMB_SBC : THUMB2_SBC_RRR;
892 break;
893 case OP_TST:
894 opCode = (thumbForm) ? THUMB_TST : THUMB2_TST_RR;
895 break;
896 case OP_LSL:
897 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700898 opCode = (thumbForm) ? THUMB_LSL_RR : THUMB2_LSL_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700899 break;
900 case OP_LSR:
901 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700902 opCode = (thumbForm) ? THUMB_LSR_RR : THUMB2_LSR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700903 break;
904 case OP_ASR:
905 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700906 opCode = (thumbForm) ? THUMB_ASR_RR : THUMB2_ASR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700907 break;
908 case OP_ROR:
909 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700910 opCode = (thumbForm) ? THUMB_ROR_RR : THUMB2_ROR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700911 break;
912 case OP_ADD:
913 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
914 break;
915 case OP_SUB:
916 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
917 break;
918 case OP_2BYTE:
919 assert(shift == 0);
920 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 8);
921 case OP_2SHORT:
922 assert(shift == 0);
923 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 16);
924 case OP_2CHAR:
925 assert(shift == 0);
926 return newLIR4(cUnit, THUMB2_UBFX, rDestSrc1, rSrc2, 0, 16);
927 default:
928 assert(0);
929 break;
930 }
931 assert(opCode >= 0);
932 if (EncodingMap[opCode].flags & IS_BINARY_OP)
933 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
934 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
935 if (EncodingMap[opCode].fieldLoc[2].kind == SHIFT)
936 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
937 else
938 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
939 } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
940 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
941 else {
942 assert(0);
943 return NULL;
944 }
945}
946
947static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
948 int rSrc2)
949{
950 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
951}
952
953/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
954static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
955 int value, int rScratch)
956{
957 ArmLIR *res;
958 bool neg = (value < 0);
959 int absValue = (neg) ? -value : value;
960 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
961 ArmOpCode opCode = THUMB_BKPT;
962 switch (op) {
963 case OP_ADD:
964 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
965 assert((value & 0x3) == 0);
966 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
967 } else if (shortForm) {
968 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
969 }
970 break;
971 case OP_SUB:
972 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
973 assert((value & 0x3) == 0);
974 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
975 } else if (shortForm) {
976 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
977 }
978 break;
979 case OP_CMP:
980 if (LOWREG(rDestSrc1) && shortForm)
981 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
982 else if (LOWREG(rDestSrc1))
983 opCode = THUMB_CMP_RR;
984 else {
985 shortForm = false;
986 opCode = THUMB_CMP_HL;
987 }
988 break;
989 default:
990 /* Punt to opRegRegImm - if bad case catch it there */
991 shortForm = false;
992 break;
993 }
994 if (shortForm)
995 return newLIR2(cUnit, opCode, rDestSrc1, absValue);
996 else
997 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value, rScratch);
998}
999
1000static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
1001 int rDest, int rSrc1, int rSrc2, int shift)
1002{
1003 ArmOpCode opCode = THUMB_BKPT;
1004 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
1005 LOWREG(rSrc2);
1006 switch (op) {
1007 case OP_ADD:
1008 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
1009 break;
1010 case OP_SUB:
1011 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
1012 break;
1013 case OP_ADC:
1014 opCode = THUMB2_ADC_RRR;
1015 break;
1016 case OP_AND:
1017 opCode = THUMB2_AND_RRR;
1018 break;
1019 case OP_BIC:
1020 opCode = THUMB2_BIC_RRR;
1021 break;
1022 case OP_XOR:
1023 opCode = THUMB2_EOR_RRR;
1024 break;
1025 case OP_MUL:
1026 assert(shift == 0);
1027 opCode = THUMB2_MUL_RRR;
1028 break;
1029 case OP_OR:
1030 opCode = THUMB2_ORR_RRR;
1031 break;
1032 case OP_SBC:
1033 opCode = THUMB2_SBC_RRR;
1034 break;
1035 case OP_LSL:
1036 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001037 opCode = THUMB2_LSL_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001038 break;
1039 case OP_LSR:
1040 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001041 opCode = THUMB2_LSR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001042 break;
1043 case OP_ASR:
1044 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001045 opCode = THUMB2_ASR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001046 break;
1047 case OP_ROR:
1048 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001049 opCode = THUMB2_ROR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001050 break;
1051 default:
1052 assert(0);
1053 break;
1054 }
1055 assert(opCode >= 0);
1056 if (EncodingMap[opCode].flags & IS_QUAD_OP)
1057 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
1058 else {
1059 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
1060 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
1061 }
1062}
1063
1064static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
1065 int rSrc1, int rSrc2)
1066{
1067 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
1068}
1069
1070static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
1071 int rSrc1, int value, int rScratch)
1072{
1073 ArmLIR *res;
1074 bool neg = (value < 0);
1075 int absValue = (neg) ? -value : value;
1076 ArmOpCode opCode = THUMB_BKPT;
1077 ArmOpCode altOpCode = THUMB_BKPT;
1078 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
1079 int modImm = modifiedImmediate(value);
1080 int modImmNeg = modifiedImmediate(-value);
1081
1082 switch(op) {
1083 case OP_LSL:
1084 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001085 return newLIR3(cUnit, THUMB_LSL_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001086 else
1087 return newLIR3(cUnit, THUMB2_LSL_RRI5, rDest, rSrc1, value);
1088 case OP_LSR:
1089 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001090 return newLIR3(cUnit, THUMB_LSR_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001091 else
1092 return newLIR3(cUnit, THUMB2_LSR_RRI5, rDest, rSrc1, value);
1093 case OP_ASR:
1094 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001095 return newLIR3(cUnit, THUMB_ASR_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001096 else
1097 return newLIR3(cUnit, THUMB2_ASR_RRI5, rDest, rSrc1, value);
1098 case OP_ROR:
1099 return newLIR3(cUnit, THUMB2_ROR_RRI5, rDest, rSrc1, value);
1100 case OP_ADD:
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001101 if (LOWREG(rDest) && (rSrc1 == 13) &&
1102 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001103 return newLIR3(cUnit, THUMB_ADD_SP_REL, rDest, rSrc1,
1104 value >> 2);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001105 } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
1106 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001107 return newLIR3(cUnit, THUMB_ADD_PC_REL, rDest, rSrc1,
1108 value >> 2);
1109 }
1110 opCode = THUMB2_ADD_RRI8;
1111 altOpCode = THUMB2_ADD_RRR;
1112 // Note: intentional fallthrough
1113 case OP_SUB:
1114 if (allLowRegs && ((absValue & 0x7) == absValue)) {
1115 if (op == OP_ADD)
1116 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
1117 else
1118 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
1119 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1120 } else if ((absValue & 0xff) == absValue) {
1121 if (op == OP_ADD)
1122 opCode = (neg) ? THUMB2_SUB_RRI12 : THUMB2_ADD_RRI12;
1123 else
1124 opCode = (neg) ? THUMB2_ADD_RRI12 : THUMB2_SUB_RRI12;
1125 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1126 }
1127 if (modImmNeg >= 0) {
1128 op = (op == OP_ADD) ? OP_SUB : OP_ADD;
1129 modImm = modImmNeg;
1130 }
1131 if (op == OP_SUB) {
1132 opCode = THUMB2_SUB_RRI8;
1133 altOpCode = THUMB2_SUB_RRR;
1134 }
1135 break;
1136 case OP_ADC:
1137 opCode = THUMB2_ADC_RRI8;
1138 altOpCode = THUMB2_ADC_RRR;
1139 break;
1140 case OP_SBC:
1141 opCode = THUMB2_SBC_RRI8;
1142 altOpCode = THUMB2_SBC_RRR;
1143 break;
1144 case OP_OR:
1145 opCode = THUMB2_ORR_RRI8;
1146 altOpCode = THUMB2_ORR_RRR;
1147 break;
1148 case OP_AND:
1149 opCode = THUMB2_AND_RRI8;
1150 altOpCode = THUMB2_AND_RRR;
1151 break;
1152 case OP_XOR:
1153 opCode = THUMB2_EOR_RRI8;
1154 altOpCode = THUMB2_EOR_RRR;
1155 break;
1156 case OP_MUL:
1157 //TUNING: power of 2, shift & add
1158 modImm = -1;
1159 altOpCode = THUMB2_MUL_RRR;
1160 break;
1161 default:
1162 assert(0);
1163 }
1164
1165 if (modImm >= 0) {
1166 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
1167 } else {
1168 loadConstant(cUnit, rScratch, value);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001169 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001170 return newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
1171 else
1172 return newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
1173 }
1174}
1175
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001176/*
1177 * 64-bit 3way compare function.
1178 * mov r7, #-1
1179 * cmp op1hi, op2hi
1180 * blt done
1181 * bgt flip
1182 * sub r7, op1lo, op2lo (treat as unsigned)
1183 * beq done
1184 * ite hi
1185 * mov(hi) r7, #-1
1186 * mov(!hi) r7, #1
1187 * flip:
1188 * neg r7
1189 * done:
1190 */
1191static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
1192 int vDest, int vSrc1, int vSrc2)
1193{
1194 int op1lo = selectFirstRegister(cUnit, vSrc1, true);
1195 int op1hi = NEXT_REG(op1lo);
1196 int op2lo = NEXT_REG(op1hi);
1197 int op2hi = NEXT_REG(op2lo);
1198 loadValuePair(cUnit, vSrc1, op1lo, op1hi);
1199 loadValuePair(cUnit, vSrc2, op2lo, op2hi);
1200 /* Note: using hardcoded r7 & r4PC for now. revisit */
1201 loadConstant(cUnit, r7, -1);
1202 opRegReg(cUnit, OP_CMP, op1hi, op2hi);
Ben Cheng4f489172009-09-27 17:08:35 -07001203 ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_LT);
1204 ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_GT);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001205 opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
Ben Cheng4f489172009-09-27 17:08:35 -07001206 ArmLIR *branch3 = opCondBranch(cUnit, ARM_COND_EQ);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001207
1208 // TODO: need assert mechanism to verify IT block size
1209 branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
1210 newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
1211 newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
Ben Chengd7d426a2009-09-22 11:23:36 -07001212 genBarrier(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001213
1214 branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
1215 branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
1216 branch3->generic.target = branch1->generic.target;
1217}
1218
Bill Buzbee270c1d62009-08-13 16:58:07 -07001219static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1220{
1221 DecodedInstruction *dInsn = &mir->dalvikInsn;
1222 int offset = offsetof(InterpState, retval);
1223 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1224 int reg1 = NEXT_REG(regObj);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001225 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001226 loadValue(cUnit, dInsn->arg[0], regObj);
1227 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
1228 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001229 if (vDest >= 0)
1230 storeValue(cUnit, reg1, vDest, regObj);
1231 else
1232 storeWordDisp(cUnit, rGLUE, offset, reg1, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001233 return false;
1234}
1235
1236static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
1237{
1238 DecodedInstruction *dInsn = &mir->dalvikInsn;
1239 int offset = offsetof(InterpState, retval);
1240 int contents = offsetof(ArrayObject, contents);
1241 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1242 int regIdx = NEXT_REG(regObj);
1243 int regMax = NEXT_REG(regIdx);
1244 int regOff = NEXT_REG(regMax);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001245 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001246 loadValue(cUnit, dInsn->arg[0], regObj);
1247 loadValue(cUnit, dInsn->arg[1], regIdx);
1248 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
1249 mir->offset, NULL);
1250 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
1251 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
1252 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
1253 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001254 opRegImm(cUnit, OP_ADD, regObj, contents, rNone);
1255 opRegReg(cUnit, OP_ADD, regIdx, regOff);
1256 loadBaseIndexed(cUnit, regObj, regIdx, regMax, 1, UNSIGNED_HALF);
1257 if (vDest >= 0)
1258 storeValue(cUnit, regMax, vDest, regObj);
1259 else
1260 storeWordDisp(cUnit, rGLUE, offset, regMax, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001261 return false;
1262}
1263
1264static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
1265{
1266 int offset = offsetof(InterpState, retval);
1267 DecodedInstruction *dInsn = &mir->dalvikInsn;
1268 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1269 int sign = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001270 int vDest = inlinedTarget(mir);
1271 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001272 loadValue(cUnit, dInsn->arg[0], reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001273 /*
1274 * Thumb2's IT block also yields 3 instructions, but imposes
1275 * scheduling constraints.
1276 */
1277 opRegRegImm(cUnit, OP_ASR, sign, reg0, 31, rNone);
1278 opRegReg(cUnit, OP_ADD, reg0, sign);
1279 opRegReg(cUnit, OP_XOR, reg0, sign);
1280 if (vDest >= 0)
1281 storeValue(cUnit, reg0, vDest, sign);
1282 else
1283 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001284 return false;
1285}
1286
1287static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
1288{
1289 int offset = offsetof(InterpState, retval);
1290 DecodedInstruction *dInsn = &mir->dalvikInsn;
1291 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1292 int signMask = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001293 int vDest = inlinedTarget(mir);
1294 // TUNING: handle case of src already in FP reg
Bill Buzbee270c1d62009-08-13 16:58:07 -07001295 loadValue(cUnit, dInsn->arg[0], reg0);
1296 loadConstant(cUnit, signMask, 0x7fffffff);
1297 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001298 if (vDest >= 0)
1299 storeValue(cUnit, reg0, vDest, signMask);
1300 else
1301 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001302 return false;
1303}
1304
1305static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
1306{
1307 int offset = offsetof(InterpState, retval);
1308 DecodedInstruction *dInsn = &mir->dalvikInsn;
1309 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1310 int ophi = NEXT_REG(oplo);
1311 int signMask = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001312 int vSrc = dInsn->arg[0];
1313 int vDest = inlinedTarget(mir);
1314 // TUNING: handle case of src already in FP reg
1315 if (vDest >= 0) {
Bill Buzbee7fb2edd2009-08-31 10:25:55 -07001316 /*
1317 * FIXME: disable this case to to work around bug until after
1318 * new schedule/ralloc mechanisms are done.
1319 */
1320 if (0 && (vDest == vSrc)) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001321 loadValue(cUnit, vSrc+1, ophi);
1322 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1323 storeValue(cUnit, ophi, vDest + 1, signMask);
1324 } else {
1325 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1326 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1327 storeValuePair(cUnit, oplo, ophi, vDest, signMask);
1328 }
1329 } else {
1330 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1331 loadConstant(cUnit, signMask, 0x7fffffff);
1332 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1333 opRegReg(cUnit, OP_AND, ophi, signMask);
1334 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1335 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001336 return false;
1337}
1338
Bill Buzbee270c1d62009-08-13 16:58:07 -07001339static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1340{
1341 int offset = offsetof(InterpState, retval);
1342 DecodedInstruction *dInsn = &mir->dalvikInsn;
1343 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1344 int reg1 = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001345 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001346 loadValue(cUnit, dInsn->arg[0], reg0);
1347 loadValue(cUnit, dInsn->arg[1], reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001348 opRegReg(cUnit, OP_CMP, reg0, reg1);
1349 //TODO: need assertion mechanism to validate IT region size
1350 genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
1351 opRegReg(cUnit, OP_MOV, reg0, reg1);
Ben Chengd7d426a2009-09-22 11:23:36 -07001352 genBarrier(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001353 if (vDest >= 0)
1354 storeValue(cUnit, reg0, vDest, reg1);
1355 else
1356 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001357 return false;
1358}
1359
1360static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1361{
1362 int offset = offsetof(InterpState, retval);
1363 DecodedInstruction *dInsn = &mir->dalvikInsn;
1364 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1365 int ophi = NEXT_REG(oplo);
1366 int sign = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001367 int vDest = inlinedTarget(mir);
1368 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001369 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001370 /*
1371 * Thumb2 IT block allows slightly shorter sequence,
1372 * but introduces a scheduling barrier. Stick with this
1373 * mechanism for now.
1374 */
1375 opRegRegImm(cUnit, OP_ASR, sign, ophi, 31, rNone);
1376 opRegReg(cUnit, OP_ADD, oplo, sign);
1377 opRegReg(cUnit, OP_ADC, ophi, sign);
1378 opRegReg(cUnit, OP_XOR, oplo, sign);
1379 opRegReg(cUnit, OP_XOR, ophi, sign);
1380 if (vDest >= 0) {
1381 storeValuePair(cUnit, oplo, ophi, vDest, sign);
1382 } else {
1383 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1384 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1385 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001386 return false;
1387}