blob: 0be162180bd2b627f442c39a36ddaf6ad10e74d1 [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);
Ben Cheng0fd31e42009-09-03 14:40:16 -070065static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
66 ArmConditionCode cond,
67 int reg1, int reg2, int dOffset,
68 ArmLIR *pcrLabel);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070069ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
Bill Buzbee270c1d62009-08-13 16:58:07 -070070static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
71static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070072
Bill Buzbee270c1d62009-08-13 16:58:07 -070073static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
74static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
75static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
76 int value2);
77static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
78static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
79 int rSrc2);
80static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
81 int value, int rScratch);
82static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
83 int rSrc1, int value, int rScratch);
84static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
85 int rSrc1, int rSrc2);
86static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
87 int rIndex, int rDest, int scale, OpSize size);
Bill Buzbeea4a7f072009-08-27 13:58:09 -070088static void genCmpLong(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
89 int vSrc2);
Bill Buzbee270c1d62009-08-13 16:58:07 -070090
91static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
92static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
93static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
94static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
95static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
96static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
97static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070098
99/*
100 * Support for register allocation
101 */
102
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700103/* get the next register in r0..r3 in a round-robin fashion */
104#define NEXT_REG(reg) ((reg + 1) & 3)
105/*
106 * The following are utility routines to help maintain the RegisterScoreboard
107 * state to facilitate register renaming.
108 */
109
110/* Reset the tracker to unknown state */
111static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
112{
113 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
114
115 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
116 registerScoreboard->liveDalvikReg = vNone;
117 registerScoreboard->nativeReg = vNone;
118 registerScoreboard->nativeRegHi = vNone;
119}
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 }
175
176}
177
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700178ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
179{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700180 ArmLIR* res;
181 ArmOpCode opCode;
182 res = dvmCompilerNew(sizeof(ArmLIR), true);
183 if (LOWREG(rDest) && LOWREG(rSrc))
184 opCode = THUMB_MOV_RR;
185 else if (!LOWREG(rDest) && !LOWREG(rSrc))
186 opCode = THUMB_MOV_RR_H2H;
187 else if (LOWREG(rDest))
188 opCode = THUMB_MOV_RR_H2L;
189 else
190 opCode = THUMB_MOV_RR_L2H;
191 rDest &= THUMB_REG_MASK;
192 rSrc &= THUMB_REG_MASK;
193
194 res->operands[0] = rDest & THUMB_REG_MASK;
195 res->operands[1] = rSrc & THUMB_REG_MASK;
196 res->opCode = opCode;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700197 if (rDest == rSrc) {
198 res->isNop = true;
199 }
200 return res;
201}
202
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700203/*
204 * Load a immediate using a shortcut if possible; otherwise
205 * grab from the per-translation literal pool
206 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700207static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700208{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700209 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700210 /* See if the value can be constructed cheaply */
211 if ((value >= 0) && (value <= 255)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700212 return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700213 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700214 res = newLIR2(cUnit, THUMB_MOV_IMM, rDest, ~value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700215 newLIR2(cUnit, THUMB_MVN, rDest, rDest);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700216 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700217 }
218 /* No shortcut - go ahead and use literal pool */
219 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
220 if (dataTarget == NULL) {
221 dataTarget = addWordData(cUnit, value, false);
222 }
223 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
224 loadPcRel->opCode = THUMB_LDR_PC_REL;
225 loadPcRel->generic.target = (LIR *) dataTarget;
226 loadPcRel->operands[0] = rDest;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700227 res = loadPcRel;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700228 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
229
230 /*
231 * To save space in the constant pool, we use the ADD_RRI8 instruction to
232 * add up to 255 to an existing constant value.
233 */
234 if (dataTarget->operands[0] != value) {
235 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
236 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700237 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700238}
239
240/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700241static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
242 int rAddr)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700243{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700244 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700245 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700246 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700247 newLIR2(cUnit, THUMB_MOV_RR, rAddr, rFP);
248 newLIR2(cUnit, THUMB_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700249 storeWordDisp( cUnit, rAddr, 0, rDPC, -1);
250 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700251}
252
Bill Buzbee270c1d62009-08-13 16:58:07 -0700253/* Load value from base + scaled index. Note: index reg killed */
254static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
255 int rIndex, int rDest, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700256{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700257 ArmLIR *first = NULL;
258 ArmLIR *res;
259 ArmOpCode opCode = THUMB_BKPT;
260 if (scale)
261 first = opRegRegImm(cUnit, OP_LSL, rIndex, rIndex, scale, rNone);
262 switch (size) {
263 case WORD:
264 opCode = THUMB_LDR_RRR;
265 break;
266 case UNSIGNED_HALF:
267 opCode = THUMB_LDRH_RRR;
268 break;
269 case SIGNED_HALF:
270 opCode = THUMB_LDRSH_RRR;
271 break;
272 case UNSIGNED_BYTE:
273 opCode = THUMB_LDRB_RRR;
274 break;
275 case SIGNED_BYTE:
276 opCode = THUMB_LDRSB_RRR;
277 break;
278 default:
279 assert(0);
280 }
281 res = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
282 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700283}
284
Bill Buzbee270c1d62009-08-13 16:58:07 -0700285/* store value base base + scaled index. Note: index reg killed */
286static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
287 int rIndex, int rSrc, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700288{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700289 ArmLIR *first = NULL;
290 ArmLIR *res;
291 ArmOpCode opCode = THUMB_BKPT;
292 if (scale)
293 first = opRegRegImm(cUnit, OP_LSL, rIndex, rIndex, scale, rNone);
294 switch (size) {
295 case WORD:
296 opCode = THUMB_STR_RRR;
297 break;
298 case UNSIGNED_HALF:
299 case SIGNED_HALF:
300 opCode = THUMB_STRH_RRR;
301 break;
302 case UNSIGNED_BYTE:
303 case SIGNED_BYTE:
304 opCode = THUMB_STRB_RRR;
305 break;
306 default:
307 assert(0);
308 }
309 res = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
310 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700311}
312
313/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700314 * Load value from base + displacement. Optionally perform null check
315 * on base (which must have an associated vReg and MIR). If not
316 * performing null check, incoming MIR can be null. Note: base and
317 * dest must not be the same if there is any chance that the long
318 * form must be used.
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700319 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700320static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
321 int displacement, int rDest, OpSize size,
322 bool nullCheck, int vReg)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700323{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700324 ArmLIR *first = NULL;
325 ArmLIR *res;
326 ArmOpCode opCode = THUMB_BKPT;
327 bool shortForm = false;
328 int shortMax = 128;
329 switch (size) {
330 case WORD:
331 if (LOWREG(rDest) && (rBase == rpc) &&
332 (displacement <= 1020) && (displacement >= 0)) {
333 shortForm = true;
334 displacement >>= 2;
335 opCode = THUMB_LDR_PC_REL;
336 } else if (LOWREG(rDest) && (rBase == r13) &&
337 (displacement <= 1020) && (displacement >= 0)) {
338 shortForm = true;
339 displacement >>= 2;
340 opCode = THUMB_LDR_SP_REL;
341 } else if (displacement < 128 && displacement >= 0) {
342 assert((displacement & 0x3) == 0);
343 shortForm = true;
344 displacement >>= 2;
345 opCode = THUMB_LDR_RRI5;
346 } else {
347 opCode = THUMB_LDR_RRR;
348 }
349 break;
350 case UNSIGNED_HALF:
351 if (displacement < 64 && displacement >= 0) {
352 assert((displacement & 0x1) == 0);
353 shortForm = true;
354 displacement >>= 1;
355 opCode = THUMB_LDRH_RRI5;
356 } else {
357 opCode = THUMB_LDRH_RRR;
358 }
359 break;
360 case SIGNED_HALF:
361 opCode = THUMB_LDRSH_RRR;
362 break;
363 case UNSIGNED_BYTE:
364 if (displacement < 32 && displacement >= 0) {
365 shortForm = true;
366 opCode = THUMB_LDRB_RRI5;
367 } else {
368 opCode = THUMB_LDRB_RRR;
369 }
370 break;
371 case SIGNED_BYTE:
372 opCode = THUMB_LDRSB_RRR;
373 break;
374 default:
375 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700376 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700377 if (nullCheck)
378 first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
379 if (shortForm) {
380 res = newLIR3(cUnit, opCode, rDest, rBase, displacement);
381 } else {
382 assert(rBase != rDest);
383 res = loadConstant(cUnit, rDest, displacement);
384 newLIR3(cUnit, opCode, rDest, rBase, rDest);
385 }
386 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700387}
388
Bill Buzbee270c1d62009-08-13 16:58:07 -0700389static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
390 int displacement, int rSrc, OpSize size,
391 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700392{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700393 ArmLIR *res;
394 ArmOpCode opCode = THUMB_BKPT;
395 bool shortForm = false;
396 int shortMax = 128;
397 switch (size) {
398 case WORD:
399 if (displacement < 128 && displacement >= 0) {
400 assert((displacement & 0x3) == 0);
401 shortForm = true;
402 displacement >>= 2;
403 opCode = THUMB_STR_RRI5;
404 } else {
405 opCode = THUMB_STR_RRR;
406 }
407 break;
408 case UNSIGNED_HALF:
409 case SIGNED_HALF:
410 if (displacement < 64 && displacement >= 0) {
411 assert((displacement & 0x1) == 0);
412 shortForm = true;
413 displacement >>= 1;
414 opCode = THUMB_STRH_RRI5;
415 } else {
416 opCode = THUMB_STRH_RRR;
417 }
418 break;
419 case UNSIGNED_BYTE:
420 case SIGNED_BYTE:
421 if (displacement < 32 && displacement >= 0) {
422 shortForm = true;
423 opCode = THUMB_STRB_RRI5;
424 } else {
425 opCode = THUMB_STRB_RRR;
426 }
427 break;
428 default:
429 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700430 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700431 if (shortForm) {
432 res = newLIR3(cUnit, opCode, rSrc, rBase, displacement);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700433 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700434 assert(rScratch != -1);
435 res = loadConstant(cUnit, rScratch, displacement);
436 newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700437 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700438 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700439}
440
441/*
442 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
443 * satisfies.
444 */
445static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
446 ArmConditionCode cond, int reg,
447 int checkValue, int dOffset,
448 ArmLIR *pcrLabel)
449{
Ben Cheng0fd31e42009-09-03 14:40:16 -0700450 if ((checkValue & 0xff) != checkValue) {
451 /* NOTE: direct use of hot temp r7 here. Revisit. */
452 loadConstant(cUnit, r7, checkValue);
453 return genRegRegCheck(cUnit, cond, reg, r7, dOffset, pcrLabel);
454 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700455 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
456 ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
457 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
458}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700459
460static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
461{
462 return newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
463}
464
465static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
466{
467 return newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
468}
469
470static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
471{
472 ArmOpCode opCode = THUMB_BKPT;
473 switch (op) {
474 case OP_UNCOND_BR:
475 opCode = THUMB_B_UNCOND;
476 break;
477 default:
478 assert(0);
479 }
480 return newLIR0(cUnit, opCode);
481}
482
483static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
484 int value2)
485{
486 ArmOpCode opCode = THUMB_BKPT;
487 switch (op) {
488 case OP_COND_BR:
489 opCode = THUMB_B_COND;
490 break;
491 default:
492 assert(0);
493 }
494 return newLIR2(cUnit, opCode, value1, value2);
495}
496
497static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
498{
499 ArmOpCode opCode = THUMB_BKPT;
500 switch (op) {
501 case OP_PUSH:
502 opCode = THUMB_PUSH;
503 break;
504 case OP_POP:
505 opCode = THUMB_POP;
506 break;
507 default:
508 assert(0);
509 }
510 return newLIR1(cUnit, opCode, value);
511}
512
513static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
514{
515 ArmOpCode opCode = THUMB_BKPT;
516 switch (op) {
517 case OP_BLX:
518 opCode = THUMB_BLX_R;
519 break;
520 default:
521 assert(0);
522 }
523 return newLIR1(cUnit, opCode, rDestSrc);
524}
525
526static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
527 int rSrc2)
528{
529 ArmLIR *res;
530 ArmOpCode opCode = THUMB_BKPT;
531 switch (op) {
532 case OP_ADC:
533 opCode = THUMB_ADC;
534 break;
535 case OP_AND:
536 opCode = THUMB_AND_RR;
537 break;
538 case OP_BIC:
539 opCode = THUMB_BIC;
540 break;
541 case OP_CMN:
542 opCode = THUMB_CMN;
543 break;
544 case OP_CMP:
545 opCode = THUMB_CMP_RR;
546 break;
547 case OP_XOR:
548 opCode = THUMB_EOR;
549 break;
550 case OP_MOV:
551 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
552 opCode = THUMB_MOV_RR;
553 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
554 opCode = THUMB_MOV_RR_H2H;
555 else if (LOWREG(rDestSrc1))
556 opCode = THUMB_MOV_RR_H2L;
557 else
558 opCode = THUMB_MOV_RR_L2H;
559 rDestSrc1 &= THUMB_REG_MASK;
560 rSrc2 &= THUMB_REG_MASK;
561 break;
562 case OP_MUL:
563 opCode = THUMB_MUL;
564 break;
565 case OP_MVN:
566 opCode = THUMB_MVN;
567 break;
568 case OP_NEG:
569 opCode = THUMB_NEG;
570 break;
571 case OP_OR:
572 opCode = THUMB_ORR;
573 break;
574 case OP_SBC:
575 opCode = THUMB_SBC;
576 break;
577 case OP_TST:
578 opCode = THUMB_TST;
579 break;
580 case OP_LSL:
581 opCode = THUMB_LSLV;
582 break;
583 case OP_LSR:
584 opCode = THUMB_LSRV;
585 break;
586 case OP_ASR:
587 opCode = THUMB_ASRV;
588 break;
589 case OP_ROR:
590 opCode = THUMB_RORV;
591 case OP_ADD:
592 case OP_SUB:
593 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
594 case OP_2BYTE:
595 res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 24, rNone);
596 opRegRegImm(cUnit, OP_ASR, rDestSrc1, rDestSrc1, 24, rNone);
597 return res;
598 case OP_2SHORT:
599 res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 16, rNone);
600 opRegRegImm(cUnit, OP_ASR, rDestSrc1, rDestSrc1, 16, rNone);
601 return res;
602 case OP_2CHAR:
603 res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 16, rNone);
604 opRegRegImm(cUnit, OP_LSR, rDestSrc1, rDestSrc1, 16, rNone);
605 return res;
606 default:
607 assert(0);
608 break;
609 }
610 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
611}
612
613static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
614 int value, int rScratch)
615{
616 ArmLIR *res;
617 bool neg = (value < 0);
618 int absValue = (neg) ? -value : value;
619 bool shortForm = (absValue & 0xff) == absValue;
620 ArmOpCode opCode = THUMB_BKPT;
621 switch (op) {
622 case OP_ADD:
623 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
624 assert((value & 0x3) == 0);
625 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
626 } else if (shortForm) {
627 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
628 } else
629 opCode = THUMB_ADD_RRR;
630 break;
631 case OP_SUB:
632 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
633 assert((value & 0x3) == 0);
634 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
635 } else if (shortForm) {
636 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
637 } else
638 opCode = THUMB_SUB_RRR;
639 break;
640 case OP_CMP:
641 if (LOWREG(rDestSrc1) && shortForm)
642 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
643 else if (LOWREG(rDestSrc1))
644 opCode = THUMB_CMP_RR;
645 else {
646 shortForm = false;
647 opCode = THUMB_CMP_HL;
648 }
649 break;
650 default:
651 assert(0);
652 break;
653 }
654 if (shortForm)
655 res = newLIR2(cUnit, opCode, rDestSrc1, absValue);
656 else {
657 assert(rScratch != rNone);
658 res = loadConstant(cUnit, rScratch, value);
659 newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch);
660 }
661 return res;
662}
663
664static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
665 int rSrc1, int rSrc2)
666{
667 ArmOpCode opCode = THUMB_BKPT;
668 switch (op) {
669 case OP_ADD:
670 opCode = THUMB_ADD_RRR;
671 break;
672 case OP_SUB:
673 opCode = THUMB_SUB_RRR;
674 break;
675 default:
676 assert(0);
677 break;
678 }
679 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
680}
681
682static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
683 int rSrc1, int value, int rScratch)
684{
685 ArmLIR *res;
686 bool neg = (value < 0);
687 int absValue = (neg) ? -value : value;
688 ArmOpCode opCode = THUMB_BKPT;
689 bool shortForm = (absValue & 0x7) == absValue;
690 switch(op) {
691 case OP_ADD:
692 if ((rSrc1 == 13) && (value <= 1020)) { /* sp */
693 assert((value & 0x3) == 0);
694 shortForm = true;
695 opCode = THUMB_ADD_SP_REL;
696 value >>= 2;
697 } else if ((rSrc1 == 15) && (value <= 1020)) { /* pc */
698 assert((value & 0x3) == 0);
699 shortForm = true;
700 opCode = THUMB_ADD_PC_REL;
701 value >>= 2;
702 } else if (shortForm) {
703 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
704 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
705 /* Two shots - 1st handle the 7 */
706 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
707 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
708 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
709 newLIR2(cUnit, opCode, rDest, absValue - 7);
710 return res;
711 } else
712 opCode = THUMB_ADD_RRR;
713 break;
714
715 case OP_SUB:
716 if (shortForm) {
717 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
718 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
719 /* Two shots - 1st handle the 7 */
720 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
721 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
722 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
723 newLIR2(cUnit, opCode, rDest, absValue - 7);
724 return res;
725 } else
726 opCode = THUMB_SUB_RRR;
727 break;
728 case OP_LSL:
729 shortForm = (!neg && value <= 31);
730 opCode = THUMB_LSL;
731 break;
732 case OP_LSR:
733 shortForm = (!neg && value <= 31);
734 opCode = THUMB_LSR;
735 break;
736 case OP_ASR:
737 shortForm = (!neg && value <= 31);
738 opCode = THUMB_ASR;
739 break;
740 case OP_MUL:
741 case OP_AND:
742 case OP_OR:
743 case OP_XOR:
744 if (rDest == rSrc1) {
745 res = loadConstant(cUnit, rScratch, value);
746 opRegReg(cUnit, op, rDest, rScratch);
747 } else {
748 res = loadConstant(cUnit, rDest, value);
749 opRegReg(cUnit, op, rDest, rSrc1);
750 }
751 return res;
752 default:
753 assert(0);
754 break;
755 }
756 if (shortForm)
757 res = newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
758 else {
759 if (rDest != rSrc1) {
760 res = loadConstant(cUnit, rDest, value);
761 newLIR3(cUnit, opCode, rDest, rSrc1, rDest);
762 } else {
763 assert(rScratch != rNone);
764 res = loadConstant(cUnit, rScratch, value);
765 newLIR3(cUnit, opCode, rDest, rSrc1, rScratch);
766 }
767 }
768 return res;
769}
770
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700771static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
772 int vDest, int vSrc1, int vSrc2)
773{
774 loadValuePair(cUnit, vSrc1, r0, r1);
775 loadValuePair(cUnit, vSrc2, r2, r3);
776 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
777 storeValue(cUnit, r0, vDest, r1);
778}
779
Bill Buzbee270c1d62009-08-13 16:58:07 -0700780static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
781{
782 DecodedInstruction *dInsn = &mir->dalvikInsn;
783 int offset = offsetof(InterpState, retval);
784 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
785 int reg1 = NEXT_REG(regObj);
786 loadValue(cUnit, dInsn->arg[0], regObj);
787 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
788 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
789 storeWordDisp(cUnit, rGLUE, offset, reg1, regObj);
790 return false;
791}
792
793static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
794{
795 DecodedInstruction *dInsn = &mir->dalvikInsn;
796 int offset = offsetof(InterpState, retval);
797 int contents = offsetof(ArrayObject, contents);
798 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
799 int regIdx = NEXT_REG(regObj);
800 int regMax = NEXT_REG(regIdx);
801 int regOff = NEXT_REG(regMax);
802 loadValue(cUnit, dInsn->arg[0], regObj);
803 loadValue(cUnit, dInsn->arg[1], regIdx);
804 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
805 mir->offset, NULL);
806 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
807 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
808 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
809 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
810
811 newLIR2(cUnit, THUMB_ADD_RI8, regObj, contents);
812 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regOff);
813 newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regIdx);
814 newLIR3(cUnit, THUMB_LDRH_RRR, regMax, regObj, regIdx);
815 storeWordDisp(cUnit, rGLUE, offset, regMax, regObj);
816 return false;
817}
818
819static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
820{
821 int offset = offsetof(InterpState, retval);
822 DecodedInstruction *dInsn = &mir->dalvikInsn;
823 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
824 int sign = NEXT_REG(reg0);
825 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
826 loadValue(cUnit, dInsn->arg[0], reg0);
827 newLIR3(cUnit, THUMB_ASR, sign, reg0, 31);
828 newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, sign);
829 newLIR2(cUnit, THUMB_EOR, reg0, sign);
830 storeWordDisp(cUnit, rGLUE, offset, reg0, sign);
831 return false;
832}
833
834static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
835{
836 int offset = offsetof(InterpState, retval);
837 DecodedInstruction *dInsn = &mir->dalvikInsn;
838 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
839 int signMask = NEXT_REG(reg0);
840 loadValue(cUnit, dInsn->arg[0], reg0);
841 loadConstant(cUnit, signMask, 0x7fffffff);
842 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
843 storeWordDisp(cUnit, rGLUE, offset, reg0, signMask);
844 return false;
845}
846
847static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
848{
849 int offset = offsetof(InterpState, retval);
850 DecodedInstruction *dInsn = &mir->dalvikInsn;
851 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
852 int ophi = NEXT_REG(oplo);
853 int signMask = NEXT_REG(ophi);
854 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
855 loadConstant(cUnit, signMask, 0x7fffffff);
856 storeWordDisp(cUnit, rGLUE, offset, oplo, ophi);
857 newLIR2(cUnit, THUMB_AND_RR, ophi, signMask);
858 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, oplo);
859 return false;
860}
861
862 /* No select in thumb, so we need to branch. Thumb2 will do better */
863static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
864{
865 int offset = offsetof(InterpState, retval);
866 DecodedInstruction *dInsn = &mir->dalvikInsn;
867 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
868 int reg1 = NEXT_REG(reg0);
869 loadValue(cUnit, dInsn->arg[0], reg0);
870 loadValue(cUnit, dInsn->arg[1], reg1);
871 newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
872 ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 2,
873 isMin ? ARM_COND_LT : ARM_COND_GT);
874 newLIR2(cUnit, THUMB_MOV_RR, reg0, reg1);
875 ArmLIR *target =
876 newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
877 branch1->generic.target = (LIR *)target;
878 return false;
879}
880
881static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
882{
883 int offset = offsetof(InterpState, retval);
884 DecodedInstruction *dInsn = &mir->dalvikInsn;
885 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
886 int ophi = NEXT_REG(oplo);
887 int sign = NEXT_REG(ophi);
888 /* abs(x) = y<=x>>31, (x+y)^y. Shorter in ARM/THUMB2, no skip in THUMB */
889 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
890 newLIR3(cUnit, THUMB_ASR, sign, ophi, 31);
891 newLIR3(cUnit, THUMB_ADD_RRR, oplo, oplo, sign);
892 newLIR2(cUnit, THUMB_ADC, ophi, sign);
893 newLIR2(cUnit, THUMB_EOR, oplo, sign);
894 newLIR2(cUnit, THUMB_EOR, ophi, sign);
895 storeWordDisp(cUnit, rGLUE, offset, oplo, sign);
896 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, sign);
897 return false;
898}