blob: cde1f713a52a92f86cac716fd3fc9946d5af4e88 [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);
48
Bill Buzbee9bc3df32009-07-30 10:52:29 -070049
50/* Routines which must be supplied here */
Bill Buzbee270c1d62009-08-13 16:58:07 -070051static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
52static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
53 int rAddr);
54static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
55 int displacement, int rDest, OpSize size,
56 bool nullCheck, int vReg);
57static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
58 int displacement, int rSrc, OpSize size,
59 int rScratch);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070060static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee270c1d62009-08-13 16:58:07 -070061 ArmConditionCode cond, int reg,
62 int checkValue, int dOffset,
63 ArmLIR *pcrLabel);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070064ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
Bill Buzbee270c1d62009-08-13 16:58:07 -070065static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
66static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070067
Bill Buzbee270c1d62009-08-13 16:58:07 -070068static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
69static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
70static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
71 int value2);
72static 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);
83
84static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
85static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
86static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
87static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
88static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
89static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
90static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070091
92/*
93 * Support for register allocation
94 */
95
Bill Buzbee9bc3df32009-07-30 10:52:29 -070096/* get the next register in r0..r3 in a round-robin fashion */
97#define NEXT_REG(reg) ((reg + 1) & 3)
98/*
99 * The following are utility routines to help maintain the RegisterScoreboard
100 * state to facilitate register renaming.
101 */
102
103/* Reset the tracker to unknown state */
104static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
105{
106 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
107
108 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
109 registerScoreboard->liveDalvikReg = vNone;
110 registerScoreboard->nativeReg = vNone;
111 registerScoreboard->nativeRegHi = vNone;
112}
113
114/* Kill the corresponding bit in the null-checked register list */
115static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
116{
117 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
118}
119
120/* The Dalvik register pair held in native registers have changed */
121static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
122 int vReg, int mRegLo, int mRegHi)
123{
124 cUnit->registerScoreboard.liveDalvikReg = vReg;
125 cUnit->registerScoreboard.nativeReg = mRegLo;
126 cUnit->registerScoreboard.nativeRegHi = mRegHi;
127 cUnit->registerScoreboard.isWide = true;
128}
129
130/* The Dalvik register held in a native register has changed */
131static inline void updateLiveRegister(CompilationUnit *cUnit,
132 int vReg, int mReg)
133{
134 cUnit->registerScoreboard.liveDalvikReg = vReg;
135 cUnit->registerScoreboard.nativeReg = mReg;
136 cUnit->registerScoreboard.isWide = false;
137}
138
139/*
140 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
141 * the lifetime of cached Dalvik value in a native register.
142 */
143static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
144 bool isWide)
145{
146 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
147
148 /* No live value - suggest to use r0 */
149 if (registerScoreboard->liveDalvikReg == vNone)
150 return r0;
151
152 /* Reuse the previously used native reg */
153 if (registerScoreboard->liveDalvikReg == vSrc) {
154 if (isWide != true) {
155 return registerScoreboard->nativeReg;
156 } else {
157 /* Return either r0 or r2 */
158 return (registerScoreboard->nativeReg + 1) & 2;
159 }
160 }
161
162 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
163 if (isWide) {
164 return (registerScoreboard->nativeReg + 2) & 2;
165 } else {
166 return (registerScoreboard->nativeReg + 1) & 3;
167 }
168
169}
170
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700171ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
172{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700173 ArmLIR* res;
174 ArmOpCode opCode;
175 res = dvmCompilerNew(sizeof(ArmLIR), true);
176 if (LOWREG(rDest) && LOWREG(rSrc))
177 opCode = THUMB_MOV_RR;
178 else if (!LOWREG(rDest) && !LOWREG(rSrc))
179 opCode = THUMB_MOV_RR_H2H;
180 else if (LOWREG(rDest))
181 opCode = THUMB_MOV_RR_H2L;
182 else
183 opCode = THUMB_MOV_RR_L2H;
184 rDest &= THUMB_REG_MASK;
185 rSrc &= THUMB_REG_MASK;
186
187 res->operands[0] = rDest & THUMB_REG_MASK;
188 res->operands[1] = rSrc & THUMB_REG_MASK;
189 res->opCode = opCode;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700190 if (rDest == rSrc) {
191 res->isNop = true;
192 }
193 return res;
194}
195
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700196/*
197 * Load a immediate using a shortcut if possible; otherwise
198 * grab from the per-translation literal pool
199 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700200static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700201{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700202 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700203 /* See if the value can be constructed cheaply */
204 if ((value >= 0) && (value <= 255)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700205 return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700206 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700207 res = newLIR2(cUnit, THUMB_MOV_IMM, rDest, ~value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700208 newLIR2(cUnit, THUMB_MVN, rDest, rDest);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700209 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700210 }
211 /* No shortcut - go ahead and use literal pool */
212 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
213 if (dataTarget == NULL) {
214 dataTarget = addWordData(cUnit, value, false);
215 }
216 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
217 loadPcRel->opCode = THUMB_LDR_PC_REL;
218 loadPcRel->generic.target = (LIR *) dataTarget;
219 loadPcRel->operands[0] = rDest;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700220 res = loadPcRel;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700221 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
222
223 /*
224 * To save space in the constant pool, we use the ADD_RRI8 instruction to
225 * add up to 255 to an existing constant value.
226 */
227 if (dataTarget->operands[0] != value) {
228 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
229 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700230 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700231}
232
233/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700234static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
235 int rAddr)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700236{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700237 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700238 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700239 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700240 newLIR2(cUnit, THUMB_MOV_RR, rAddr, rFP);
241 newLIR2(cUnit, THUMB_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700242 storeWordDisp( cUnit, rAddr, 0, rDPC, -1);
243 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700244}
245
Bill Buzbee270c1d62009-08-13 16:58:07 -0700246/* Load value from base + scaled index. Note: index reg killed */
247static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
248 int rIndex, int rDest, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700249{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700250 ArmLIR *first = NULL;
251 ArmLIR *res;
252 ArmOpCode opCode = THUMB_BKPT;
253 if (scale)
254 first = opRegRegImm(cUnit, OP_LSL, rIndex, rIndex, scale, rNone);
255 switch (size) {
256 case WORD:
257 opCode = THUMB_LDR_RRR;
258 break;
259 case UNSIGNED_HALF:
260 opCode = THUMB_LDRH_RRR;
261 break;
262 case SIGNED_HALF:
263 opCode = THUMB_LDRSH_RRR;
264 break;
265 case UNSIGNED_BYTE:
266 opCode = THUMB_LDRB_RRR;
267 break;
268 case SIGNED_BYTE:
269 opCode = THUMB_LDRSB_RRR;
270 break;
271 default:
272 assert(0);
273 }
274 res = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
275 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700276}
277
Bill Buzbee270c1d62009-08-13 16:58:07 -0700278/* store value base base + scaled index. Note: index reg killed */
279static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
280 int rIndex, int rSrc, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700281{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700282 ArmLIR *first = NULL;
283 ArmLIR *res;
284 ArmOpCode opCode = THUMB_BKPT;
285 if (scale)
286 first = opRegRegImm(cUnit, OP_LSL, rIndex, rIndex, scale, rNone);
287 switch (size) {
288 case WORD:
289 opCode = THUMB_STR_RRR;
290 break;
291 case UNSIGNED_HALF:
292 case SIGNED_HALF:
293 opCode = THUMB_STRH_RRR;
294 break;
295 case UNSIGNED_BYTE:
296 case SIGNED_BYTE:
297 opCode = THUMB_STRB_RRR;
298 break;
299 default:
300 assert(0);
301 }
302 res = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
303 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700304}
305
306/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700307 * Load value from base + displacement. Optionally perform null check
308 * on base (which must have an associated vReg and MIR). If not
309 * performing null check, incoming MIR can be null. Note: base and
310 * dest must not be the same if there is any chance that the long
311 * form must be used.
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700312 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700313static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
314 int displacement, int rDest, OpSize size,
315 bool nullCheck, int vReg)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700316{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700317 ArmLIR *first = NULL;
318 ArmLIR *res;
319 ArmOpCode opCode = THUMB_BKPT;
320 bool shortForm = false;
321 int shortMax = 128;
322 switch (size) {
323 case WORD:
324 if (LOWREG(rDest) && (rBase == rpc) &&
325 (displacement <= 1020) && (displacement >= 0)) {
326 shortForm = true;
327 displacement >>= 2;
328 opCode = THUMB_LDR_PC_REL;
329 } else if (LOWREG(rDest) && (rBase == r13) &&
330 (displacement <= 1020) && (displacement >= 0)) {
331 shortForm = true;
332 displacement >>= 2;
333 opCode = THUMB_LDR_SP_REL;
334 } else if (displacement < 128 && displacement >= 0) {
335 assert((displacement & 0x3) == 0);
336 shortForm = true;
337 displacement >>= 2;
338 opCode = THUMB_LDR_RRI5;
339 } else {
340 opCode = THUMB_LDR_RRR;
341 }
342 break;
343 case UNSIGNED_HALF:
344 if (displacement < 64 && displacement >= 0) {
345 assert((displacement & 0x1) == 0);
346 shortForm = true;
347 displacement >>= 1;
348 opCode = THUMB_LDRH_RRI5;
349 } else {
350 opCode = THUMB_LDRH_RRR;
351 }
352 break;
353 case SIGNED_HALF:
354 opCode = THUMB_LDRSH_RRR;
355 break;
356 case UNSIGNED_BYTE:
357 if (displacement < 32 && displacement >= 0) {
358 shortForm = true;
359 opCode = THUMB_LDRB_RRI5;
360 } else {
361 opCode = THUMB_LDRB_RRR;
362 }
363 break;
364 case SIGNED_BYTE:
365 opCode = THUMB_LDRSB_RRR;
366 break;
367 default:
368 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700369 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700370 if (nullCheck)
371 first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
372 if (shortForm) {
373 res = newLIR3(cUnit, opCode, rDest, rBase, displacement);
374 } else {
375 assert(rBase != rDest);
376 res = loadConstant(cUnit, rDest, displacement);
377 newLIR3(cUnit, opCode, rDest, rBase, rDest);
378 }
379 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700380}
381
Bill Buzbee270c1d62009-08-13 16:58:07 -0700382static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
383 int displacement, int rSrc, OpSize size,
384 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700385{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700386 ArmLIR *res;
387 ArmOpCode opCode = THUMB_BKPT;
388 bool shortForm = false;
389 int shortMax = 128;
390 switch (size) {
391 case WORD:
392 if (displacement < 128 && displacement >= 0) {
393 assert((displacement & 0x3) == 0);
394 shortForm = true;
395 displacement >>= 2;
396 opCode = THUMB_STR_RRI5;
397 } else {
398 opCode = THUMB_STR_RRR;
399 }
400 break;
401 case UNSIGNED_HALF:
402 case SIGNED_HALF:
403 if (displacement < 64 && displacement >= 0) {
404 assert((displacement & 0x1) == 0);
405 shortForm = true;
406 displacement >>= 1;
407 opCode = THUMB_STRH_RRI5;
408 } else {
409 opCode = THUMB_STRH_RRR;
410 }
411 break;
412 case UNSIGNED_BYTE:
413 case SIGNED_BYTE:
414 if (displacement < 32 && displacement >= 0) {
415 shortForm = true;
416 opCode = THUMB_STRB_RRI5;
417 } else {
418 opCode = THUMB_STRB_RRR;
419 }
420 break;
421 default:
422 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700423 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700424 if (shortForm) {
425 res = newLIR3(cUnit, opCode, rSrc, rBase, displacement);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700426 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700427 assert(rScratch != -1);
428 res = loadConstant(cUnit, rScratch, displacement);
429 newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700430 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700431 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700432}
433
434/*
435 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
436 * satisfies.
437 */
438static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
439 ArmConditionCode cond, int reg,
440 int checkValue, int dOffset,
441 ArmLIR *pcrLabel)
442{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700443 assert((checkValue & 0xff) == checkValue);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700444 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
445 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
446 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
447}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700448
449static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
450{
451 return newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
452}
453
454static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
455{
456 return newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
457}
458
459static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
460{
461 ArmOpCode opCode = THUMB_BKPT;
462 switch (op) {
463 case OP_UNCOND_BR:
464 opCode = THUMB_B_UNCOND;
465 break;
466 default:
467 assert(0);
468 }
469 return newLIR0(cUnit, opCode);
470}
471
472static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
473 int value2)
474{
475 ArmOpCode opCode = THUMB_BKPT;
476 switch (op) {
477 case OP_COND_BR:
478 opCode = THUMB_B_COND;
479 break;
480 default:
481 assert(0);
482 }
483 return newLIR2(cUnit, opCode, value1, value2);
484}
485
486static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
487{
488 ArmOpCode opCode = THUMB_BKPT;
489 switch (op) {
490 case OP_PUSH:
491 opCode = THUMB_PUSH;
492 break;
493 case OP_POP:
494 opCode = THUMB_POP;
495 break;
496 default:
497 assert(0);
498 }
499 return newLIR1(cUnit, opCode, value);
500}
501
502static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
503{
504 ArmOpCode opCode = THUMB_BKPT;
505 switch (op) {
506 case OP_BLX:
507 opCode = THUMB_BLX_R;
508 break;
509 default:
510 assert(0);
511 }
512 return newLIR1(cUnit, opCode, rDestSrc);
513}
514
515static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
516 int rSrc2)
517{
518 ArmLIR *res;
519 ArmOpCode opCode = THUMB_BKPT;
520 switch (op) {
521 case OP_ADC:
522 opCode = THUMB_ADC;
523 break;
524 case OP_AND:
525 opCode = THUMB_AND_RR;
526 break;
527 case OP_BIC:
528 opCode = THUMB_BIC;
529 break;
530 case OP_CMN:
531 opCode = THUMB_CMN;
532 break;
533 case OP_CMP:
534 opCode = THUMB_CMP_RR;
535 break;
536 case OP_XOR:
537 opCode = THUMB_EOR;
538 break;
539 case OP_MOV:
540 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
541 opCode = THUMB_MOV_RR;
542 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
543 opCode = THUMB_MOV_RR_H2H;
544 else if (LOWREG(rDestSrc1))
545 opCode = THUMB_MOV_RR_H2L;
546 else
547 opCode = THUMB_MOV_RR_L2H;
548 rDestSrc1 &= THUMB_REG_MASK;
549 rSrc2 &= THUMB_REG_MASK;
550 break;
551 case OP_MUL:
552 opCode = THUMB_MUL;
553 break;
554 case OP_MVN:
555 opCode = THUMB_MVN;
556 break;
557 case OP_NEG:
558 opCode = THUMB_NEG;
559 break;
560 case OP_OR:
561 opCode = THUMB_ORR;
562 break;
563 case OP_SBC:
564 opCode = THUMB_SBC;
565 break;
566 case OP_TST:
567 opCode = THUMB_TST;
568 break;
569 case OP_LSL:
570 opCode = THUMB_LSLV;
571 break;
572 case OP_LSR:
573 opCode = THUMB_LSRV;
574 break;
575 case OP_ASR:
576 opCode = THUMB_ASRV;
577 break;
578 case OP_ROR:
579 opCode = THUMB_RORV;
580 case OP_ADD:
581 case OP_SUB:
582 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
583 case OP_2BYTE:
584 res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 24, rNone);
585 opRegRegImm(cUnit, OP_ASR, rDestSrc1, rDestSrc1, 24, rNone);
586 return res;
587 case OP_2SHORT:
588 res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 16, rNone);
589 opRegRegImm(cUnit, OP_ASR, rDestSrc1, rDestSrc1, 16, rNone);
590 return res;
591 case OP_2CHAR:
592 res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 16, rNone);
593 opRegRegImm(cUnit, OP_LSR, rDestSrc1, rDestSrc1, 16, rNone);
594 return res;
595 default:
596 assert(0);
597 break;
598 }
599 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
600}
601
602static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
603 int value, int rScratch)
604{
605 ArmLIR *res;
606 bool neg = (value < 0);
607 int absValue = (neg) ? -value : value;
608 bool shortForm = (absValue & 0xff) == absValue;
609 ArmOpCode opCode = THUMB_BKPT;
610 switch (op) {
611 case OP_ADD:
612 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
613 assert((value & 0x3) == 0);
614 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
615 } else if (shortForm) {
616 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
617 } else
618 opCode = THUMB_ADD_RRR;
619 break;
620 case OP_SUB:
621 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
622 assert((value & 0x3) == 0);
623 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
624 } else if (shortForm) {
625 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
626 } else
627 opCode = THUMB_SUB_RRR;
628 break;
629 case OP_CMP:
630 if (LOWREG(rDestSrc1) && shortForm)
631 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
632 else if (LOWREG(rDestSrc1))
633 opCode = THUMB_CMP_RR;
634 else {
635 shortForm = false;
636 opCode = THUMB_CMP_HL;
637 }
638 break;
639 default:
640 assert(0);
641 break;
642 }
643 if (shortForm)
644 res = newLIR2(cUnit, opCode, rDestSrc1, absValue);
645 else {
646 assert(rScratch != rNone);
647 res = loadConstant(cUnit, rScratch, value);
648 newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch);
649 }
650 return res;
651}
652
653static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
654 int rSrc1, int rSrc2)
655{
656 ArmOpCode opCode = THUMB_BKPT;
657 switch (op) {
658 case OP_ADD:
659 opCode = THUMB_ADD_RRR;
660 break;
661 case OP_SUB:
662 opCode = THUMB_SUB_RRR;
663 break;
664 default:
665 assert(0);
666 break;
667 }
668 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
669}
670
671static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
672 int rSrc1, int value, int rScratch)
673{
674 ArmLIR *res;
675 bool neg = (value < 0);
676 int absValue = (neg) ? -value : value;
677 ArmOpCode opCode = THUMB_BKPT;
678 bool shortForm = (absValue & 0x7) == absValue;
679 switch(op) {
680 case OP_ADD:
681 if ((rSrc1 == 13) && (value <= 1020)) { /* sp */
682 assert((value & 0x3) == 0);
683 shortForm = true;
684 opCode = THUMB_ADD_SP_REL;
685 value >>= 2;
686 } else if ((rSrc1 == 15) && (value <= 1020)) { /* pc */
687 assert((value & 0x3) == 0);
688 shortForm = true;
689 opCode = THUMB_ADD_PC_REL;
690 value >>= 2;
691 } else if (shortForm) {
692 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
693 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
694 /* Two shots - 1st handle the 7 */
695 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
696 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
697 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
698 newLIR2(cUnit, opCode, rDest, absValue - 7);
699 return res;
700 } else
701 opCode = THUMB_ADD_RRR;
702 break;
703
704 case OP_SUB:
705 if (shortForm) {
706 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
707 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
708 /* Two shots - 1st handle the 7 */
709 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
710 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
711 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
712 newLIR2(cUnit, opCode, rDest, absValue - 7);
713 return res;
714 } else
715 opCode = THUMB_SUB_RRR;
716 break;
717 case OP_LSL:
718 shortForm = (!neg && value <= 31);
719 opCode = THUMB_LSL;
720 break;
721 case OP_LSR:
722 shortForm = (!neg && value <= 31);
723 opCode = THUMB_LSR;
724 break;
725 case OP_ASR:
726 shortForm = (!neg && value <= 31);
727 opCode = THUMB_ASR;
728 break;
729 case OP_MUL:
730 case OP_AND:
731 case OP_OR:
732 case OP_XOR:
733 if (rDest == rSrc1) {
734 res = loadConstant(cUnit, rScratch, value);
735 opRegReg(cUnit, op, rDest, rScratch);
736 } else {
737 res = loadConstant(cUnit, rDest, value);
738 opRegReg(cUnit, op, rDest, rSrc1);
739 }
740 return res;
741 default:
742 assert(0);
743 break;
744 }
745 if (shortForm)
746 res = newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
747 else {
748 if (rDest != rSrc1) {
749 res = loadConstant(cUnit, rDest, value);
750 newLIR3(cUnit, opCode, rDest, rSrc1, rDest);
751 } else {
752 assert(rScratch != rNone);
753 res = loadConstant(cUnit, rScratch, value);
754 newLIR3(cUnit, opCode, rDest, rSrc1, rScratch);
755 }
756 }
757 return res;
758}
759
760static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
761{
762 DecodedInstruction *dInsn = &mir->dalvikInsn;
763 int offset = offsetof(InterpState, retval);
764 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
765 int reg1 = NEXT_REG(regObj);
766 loadValue(cUnit, dInsn->arg[0], regObj);
767 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
768 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
769 storeWordDisp(cUnit, rGLUE, offset, reg1, regObj);
770 return false;
771}
772
773static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
774{
775 DecodedInstruction *dInsn = &mir->dalvikInsn;
776 int offset = offsetof(InterpState, retval);
777 int contents = offsetof(ArrayObject, contents);
778 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
779 int regIdx = NEXT_REG(regObj);
780 int regMax = NEXT_REG(regIdx);
781 int regOff = NEXT_REG(regMax);
782 loadValue(cUnit, dInsn->arg[0], regObj);
783 loadValue(cUnit, dInsn->arg[1], regIdx);
784 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
785 mir->offset, NULL);
786 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
787 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
788 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
789 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
790
791 newLIR2(cUnit, THUMB_ADD_RI8, regObj, contents);
792 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regOff);
793 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regIdx);
794 newLIR3(cUnit, THUMB_LDRH_RRR, regMax, regObj, regIdx);
795 storeWordDisp(cUnit, rGLUE, offset, regMax, regObj);
796 return false;
797}
798
799static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
800{
801 int offset = offsetof(InterpState, retval);
802 DecodedInstruction *dInsn = &mir->dalvikInsn;
803 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
804 int sign = NEXT_REG(reg0);
805 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
806 loadValue(cUnit, dInsn->arg[0], reg0);
807 newLIR3(cUnit, THUMB_ASR, sign, reg0, 31);
808 newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, sign);
809 newLIR2(cUnit, THUMB_EOR, reg0, sign);
810 storeWordDisp(cUnit, rGLUE, offset, reg0, sign);
811 return false;
812}
813
814static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
815{
816 int offset = offsetof(InterpState, retval);
817 DecodedInstruction *dInsn = &mir->dalvikInsn;
818 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
819 int signMask = NEXT_REG(reg0);
820 loadValue(cUnit, dInsn->arg[0], reg0);
821 loadConstant(cUnit, signMask, 0x7fffffff);
822 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
823 storeWordDisp(cUnit, rGLUE, offset, reg0, signMask);
824 return false;
825}
826
827static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
828{
829 int offset = offsetof(InterpState, retval);
830 DecodedInstruction *dInsn = &mir->dalvikInsn;
831 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
832 int ophi = NEXT_REG(oplo);
833 int signMask = NEXT_REG(ophi);
834 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
835 loadConstant(cUnit, signMask, 0x7fffffff);
836 storeWordDisp(cUnit, rGLUE, offset, oplo, ophi);
837 newLIR2(cUnit, THUMB_AND_RR, ophi, signMask);
838 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, oplo);
839 return false;
840}
841
842 /* No select in thumb, so we need to branch. Thumb2 will do better */
843static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
844{
845 int offset = offsetof(InterpState, retval);
846 DecodedInstruction *dInsn = &mir->dalvikInsn;
847 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
848 int reg1 = NEXT_REG(reg0);
849 loadValue(cUnit, dInsn->arg[0], reg0);
850 loadValue(cUnit, dInsn->arg[1], reg1);
851 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
852 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 2,
853 isMin ? ARM_COND_LT : ARM_COND_GT);
854 newLIR2(cUnit, THUMB_MOV_RR, reg0, reg1);
855 ArmLIR *target =
856 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
857 branch1->generic.target = (LIR *)target;
858 return false;
859}
860
861static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
862{
863 int offset = offsetof(InterpState, retval);
864 DecodedInstruction *dInsn = &mir->dalvikInsn;
865 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
866 int ophi = NEXT_REG(oplo);
867 int sign = NEXT_REG(ophi);
868 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
869 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
870 newLIR3(cUnit, THUMB_ASR, sign, ophi, 31);
871 newLIR3(cUnit, THUMB_ADD_RRR, oplo, oplo, sign);
872 newLIR2(cUnit, THUMB_ADC, ophi, sign);
873 newLIR2(cUnit, THUMB_EOR, oplo, sign);
874 newLIR2(cUnit, THUMB_EOR, ophi, sign);
875 storeWordDisp(cUnit, rGLUE, offset, oplo, sign);
876 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, sign);
877 return false;
878}