blob: b9d1a239e05d22be170e454ef079170718ea7f97 [file] [log] [blame]
Bill Buzbee9bc3df32009-07-30 10:52:29 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This file contains codegen for the Thumb ISA and is intended to be
Bill Buzbee270c1d62009-08-13 16:58:07 -070019 * includes by:
Bill Buzbee9bc3df32009-07-30 10:52:29 -070020 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25#include "Codegen.h"
Bill Buzbee270c1d62009-08-13 16:58:07 -070026/* Forward decls */
27static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
28 int dOffset, ArmLIR *pcrLabel);
29static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest);
30static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest);
31static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
32 int displacement, int rDest);
33static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
34 int displacement, int rSrc, int rScratch);
35static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
36 int rScratch);
37static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
38 ArmConditionCode cond,
39 ArmLIR *target);
40static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target);
41static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
42 int rDestHi);
43static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
44 int vDest, int rScratch);
45static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
46 int rBound, int dOffset, ArmLIR *pcrLabel);
47static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
Bill Buzbeea4a7f072009-08-27 13:58:09 -070048static int inlinedTarget(MIR *mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -070049
Bill Buzbee9bc3df32009-07-30 10:52:29 -070050
51/* Routines which must be supplied here */
Bill Buzbee270c1d62009-08-13 16:58:07 -070052static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
53static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
54 int rAddr);
55static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
56 int displacement, int rDest, OpSize size,
57 bool nullCheck, int vReg);
58static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
59 int displacement, int rSrc, OpSize size,
60 int rScratch);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070061static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee270c1d62009-08-13 16:58:07 -070062 ArmConditionCode cond, int reg,
63 int checkValue, int dOffset,
64 ArmLIR *pcrLabel);
Bill Buzbee7ea0f642009-08-10 17:06:51 -070065ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
Bill Buzbee270c1d62009-08-13 16:58:07 -070066static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
67static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070068
Bill Buzbee270c1d62009-08-13 16:58:07 -070069static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
70static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
71static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
72 int value2);
73static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
74static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
75 int rSrc2);
76static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
77 int value, int rScratch);
78static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
79 int rSrc1, int value, int rScratch);
80static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
81 int rSrc1, int rSrc2);
82static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
83 int rIndex, int rDest, int scale, OpSize size);
Bill Buzbeea4a7f072009-08-27 13:58:09 -070084static void genCmpLong(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
85 int vSrc2);
Bill Buzbee270c1d62009-08-13 16:58:07 -070086
87static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
88static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
89static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
90static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
91static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
92static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
93static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
Bill Buzbee9bc3df32009-07-30 10:52:29 -070094
95/*
96 * Support for register allocation
97 */
98
Bill Buzbee9bc3df32009-07-30 10:52:29 -070099/* get the next register in r0..r3 in a round-robin fashion */
100#define NEXT_REG(reg) ((reg + 1) & 3)
101/*
102 * The following are utility routines to help maintain the RegisterScoreboard
103 * state to facilitate register renaming.
104 */
105
106/* Reset the tracker to unknown state */
107static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
108{
109 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
110
111 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
112 registerScoreboard->liveDalvikReg = vNone;
113 registerScoreboard->nativeReg = vNone;
114 registerScoreboard->nativeRegHi = vNone;
115}
116
117/* Kill the corresponding bit in the null-checked register list */
118static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
119{
120 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
121}
122
123/* The Dalvik register pair held in native registers have changed */
124static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
125 int vReg, int mRegLo, int mRegHi)
126{
127 cUnit->registerScoreboard.liveDalvikReg = vReg;
128 cUnit->registerScoreboard.nativeReg = mRegLo;
129 cUnit->registerScoreboard.nativeRegHi = mRegHi;
130 cUnit->registerScoreboard.isWide = true;
131}
132
133/* The Dalvik register held in a native register has changed */
134static inline void updateLiveRegister(CompilationUnit *cUnit,
135 int vReg, int mReg)
136{
137 cUnit->registerScoreboard.liveDalvikReg = vReg;
138 cUnit->registerScoreboard.nativeReg = mReg;
139 cUnit->registerScoreboard.isWide = false;
140}
141
142/*
143 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
144 * the lifetime of cached Dalvik value in a native register.
145 */
146static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
147 bool isWide)
148{
149 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
150
151 /* No live value - suggest to use r0 */
152 if (registerScoreboard->liveDalvikReg == vNone)
153 return r0;
154
155 /* Reuse the previously used native reg */
156 if (registerScoreboard->liveDalvikReg == vSrc) {
157 if (isWide != true) {
158 return registerScoreboard->nativeReg;
159 } else {
160 /* Return either r0 or r2 */
161 return (registerScoreboard->nativeReg + 1) & 2;
162 }
163 }
164
165 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
166 if (isWide) {
167 return (registerScoreboard->nativeReg + 2) & 2;
168 } else {
169 return (registerScoreboard->nativeReg + 1) & 3;
170 }
171
172}
173
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700174/*
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700175 * Generate a ARM_PSEUDO_IT_BOTTOM marker to indicate the end of an IT block
176 */
177static void genITBottom(CompilationUnit *cUnit)
178{
179 ArmLIR *itBottom = newLIR0(cUnit, ARM_PSEUDO_IT_BOTTOM);
180 /* Mark all resources as being clobbered */
181 itBottom->defMask = -1;
182}
183
184/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700185 * Generate a Thumb2 IT instruction, which can nullify up to
186 * four subsequent instructions based on a condition and its
187 * inverse. The condition applies to the first instruction, which
188 * is executed if the condition is met. The string "guide" consists
189 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
190 * A "T" means the instruction is executed if the condition is
191 * met, and an "E" means the instruction is executed if the condition
192 * is not met.
193 */
194static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
195 char *guide)
196{
197 int mask;
198 int condBit = code & 1;
199 int altBit = condBit ^ 1;
200 int mask3 = 0;
201 int mask2 = 0;
202 int mask1 = 0;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700203
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700204 //Note: case fallthroughs intentional
205 switch(strlen(guide)) {
206 case 3:
207 mask1 = (guide[2] == 'T') ? condBit : altBit;
208 case 2:
209 mask2 = (guide[1] == 'T') ? condBit : altBit;
210 case 1:
211 mask3 = (guide[0] == 'T') ? condBit : altBit;
212 break;
213 case 0:
214 break;
215 default:
216 assert(0);
217 dvmAbort();
218 }
219 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
220 (1 << (3 - strlen(guide)));
221 return newLIR2(cUnit, THUMB2_IT, code, mask);
222}
223
224
Bill Buzbee270c1d62009-08-13 16:58:07 -0700225static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700226{
227 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
228 res->operands[0] = rDest;
229 res->operands[1] = rSrc;
230 if (rDest == rSrc) {
231 res->isNop = true;
232 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700233 // TODO: support copy between FP and gen regs
234 if (DOUBLEREG(rDest)) {
235 assert(DOUBLEREG(rSrc));
236 res->opCode = THUMB2_VMOVD;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700237 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700238 assert(SINGLEREG(rSrc));
239 res->opCode = THUMB2_VMOVS;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700240 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700241 res->operands[0] = rDest;
242 res->operands[1] = rSrc;
243 }
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700244 setupResourceMasks(res);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700245 return res;
246}
247
248ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
249{
250 ArmLIR* res;
251 ArmOpCode opCode;
252 if (FPREG(rDest) || FPREG(rSrc))
253 return fpRegCopy(cUnit, rDest, rSrc);
254 res = dvmCompilerNew(sizeof(ArmLIR), true);
255 if (LOWREG(rDest) && LOWREG(rSrc))
256 opCode = THUMB_MOV_RR;
257 else if (!LOWREG(rDest) && !LOWREG(rSrc))
258 opCode = THUMB_MOV_RR_H2H;
259 else if (LOWREG(rDest))
260 opCode = THUMB_MOV_RR_H2L;
261 else
262 opCode = THUMB_MOV_RR_L2H;
263
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700264 res->operands[0] = rDest;
265 res->operands[1] = rSrc;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700266 res->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700267 setupResourceMasks(res);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700268 if (rDest == rSrc) {
269 res->isNop = true;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700270 }
271 return res;
272}
273
274static int leadingZeros(u4 val)
275{
276 u4 alt;
277 int n;
278 int count;
279
280 count = 16;
281 n = 32;
282 do {
283 alt = val >> count;
284 if (alt != 0) {
285 n = n - count;
286 val = alt;
287 }
288 count >>= 1;
289 } while (count);
290 return n - val;
291}
292
293/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700294 * Determine whether value can be encoded as a Thumb2 modified
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700295 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
296 */
297static int modifiedImmediate(u4 value)
298{
299 int zLeading;
300 int zTrailing;
301 u4 b0 = value & 0xff;
302
303 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
304 if (value <= 0xFF)
305 return b0; // 0:000:a:bcdefgh
306 if (value == ((b0 << 16) | b0))
307 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
308 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
309 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
310 b0 = (value >> 8) & 0xff;
311 if (value == ((b0 << 24) | (b0 << 8)))
312 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
313 /* Can we do it with rotation? */
314 zLeading = leadingZeros(value);
315 zTrailing = 32 - leadingZeros(~value & (value - 1));
316 /* A run of eight or fewer active bits? */
317 if ((zLeading + zTrailing) < 24)
318 return -1; /* No - bail */
319 /* left-justify the constant, discarding msb (known to be 1) */
320 value <<= zLeading + 1;
321 /* Create bcdefgh */
322 value >>= 25;
323 /* Put it all together */
324 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
325}
326
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700327/*
328 * Load a immediate using a shortcut if possible; otherwise
329 * grab from the per-translation literal pool
330 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700331static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700332{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700333 ArmLIR *res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700334 int modImm;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700335 /* See if the value can be constructed cheaply */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700336 if ((value >= 0) && (value <= 255)) {
337 return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700338 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700339 /* Check Modified immediate special cases */
340 modImm = modifiedImmediate(value);
341 if (modImm >= 0) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700342 res = newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, rDest, modImm);
343 return res;
344 }
345 modImm = modifiedImmediate(~value);
346 if (modImm >= 0) {
347 res = newLIR2(cUnit, THUMB2_MVN_IMM_SHIFT, rDest, modImm);
348 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700349 }
350 /* 16-bit immediate? */
351 if ((value & 0xffff) == value) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700352 res = newLIR2(cUnit, THUMB2_MOV_IMM16, rDest, value);
353 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700354 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700355 /* No shortcut - go ahead and use literal pool */
356 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
357 if (dataTarget == NULL) {
358 dataTarget = addWordData(cUnit, value, false);
359 }
360 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
361 loadPcRel->opCode = THUMB_LDR_PC_REL;
362 loadPcRel->generic.target = (LIR *) dataTarget;
363 loadPcRel->operands[0] = rDest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700364 setupResourceMasks(loadPcRel);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700365 res = loadPcRel;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700366 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
367
368 /*
369 * To save space in the constant pool, we use the ADD_RRI8 instruction to
370 * add up to 255 to an existing constant value.
371 */
372 if (dataTarget->operands[0] != value) {
373 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
374 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700375 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700376}
377
378/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700379static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
380 int rAddr)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700381{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700382 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700383 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700384 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700385 newLIR3(cUnit, THUMB2_STR_RRI8_PREDEC, rDPC, rFP,
386 sizeof(StackSaveArea) - offset);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700387 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700388}
389
Bill Buzbee270c1d62009-08-13 16:58:07 -0700390/* Load value from base + scaled index. Note: index reg killed */
391static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
392 int rIndex, int rDest, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700393{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700394 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
395 ArmOpCode opCode = THUMB_BKPT;
396 bool thumbForm = (allLowRegs && (scale == 0));
397 switch (size) {
398 case WORD:
399 opCode = (thumbForm) ? THUMB_LDR_RRR : THUMB2_LDR_RRR;
400 break;
401 case UNSIGNED_HALF:
402 opCode = (thumbForm) ? THUMB_LDRH_RRR : THUMB2_LDRH_RRR;
403 break;
404 case SIGNED_HALF:
405 opCode = (thumbForm) ? THUMB_LDRSH_RRR : THUMB2_LDRSH_RRR;
406 break;
407 case UNSIGNED_BYTE:
408 opCode = (thumbForm) ? THUMB_LDRB_RRR : THUMB2_LDRB_RRR;
409 break;
410 case SIGNED_BYTE:
411 opCode = (thumbForm) ? THUMB_LDRSB_RRR : THUMB2_LDRSB_RRR;
412 break;
413 default:
414 assert(0);
415 }
416 if (thumbForm)
417 return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
418 else
419 return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700420}
421
Bill Buzbee270c1d62009-08-13 16:58:07 -0700422/* store value base base + scaled index. Note: index reg killed */
423static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
424 int rIndex, int rSrc, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700425{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700426 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
427 ArmOpCode opCode = THUMB_BKPT;
428 bool thumbForm = (allLowRegs && (scale == 0));
429 switch (size) {
430 case WORD:
431 opCode = (thumbForm) ? THUMB_STR_RRR : THUMB2_STR_RRR;
432 break;
433 case UNSIGNED_HALF:
434 case SIGNED_HALF:
435 opCode = (thumbForm) ? THUMB_STRH_RRR : THUMB2_STRH_RRR;
436 break;
437 case UNSIGNED_BYTE:
438 case SIGNED_BYTE:
439 opCode = (thumbForm) ? THUMB_STRB_RRR : THUMB2_STRB_RRR;
440 break;
441 default:
442 assert(0);
443 }
444 if (thumbForm)
445 return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
446 else
447 return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700448}
449
450/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700451 * Load a float from a Dalvik register. Note: using fixed r7 here
452 * when operation is out of range. Revisit this when registor allocation
453 * strategy changes.
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700454 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700455static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
456 int rSrcDest, ArmOpCode opCode)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700457{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700458 ArmLIR *res;
459 if (vSrcDest > 255) {
460 res = opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
461 newLIR3(cUnit, opCode, rSrcDest, r7, 0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700462 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700463 res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700464 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700465 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700466}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700467static ArmLIR *loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700468{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700469 assert(SINGLEREG(rDest));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700470 return fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700471}
472
473/* Store a float to a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700474static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest,
475 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700476{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700477 assert(SINGLEREG(rSrc));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700478 return fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700479}
480
481/* Load a double from a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700482static ArmLIR *loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700483{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700484 assert(DOUBLEREG(rDest));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700485 return fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700486}
487
488/* Store a double to a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700489static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest,
490 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700491{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700492 assert(DOUBLEREG(rSrc));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700493 return fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700494}
495
496
Bill Buzbee270c1d62009-08-13 16:58:07 -0700497/*
498 * Load value from base + displacement. Optionally perform null check
499 * on base (which must have an associated vReg and MIR). If not
500 * performing null check, incoming MIR can be null. Note: base and
501 * dest must not be the same if there is any chance that the long
502 * form must be used.
503 * TODO: revisit, perhaps use hot temp reg in (base == dest) case.
504 */
505static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
506 int displacement, int rDest, OpSize size,
507 bool nullCheck, int vReg)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700508{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700509 ArmLIR *first = NULL;
510 ArmLIR *res;
511 ArmOpCode opCode = THUMB_BKPT;
512 bool shortForm = false;
513 bool thumb2Form = (displacement < 4092 && displacement >= 0);
514 int shortMax = 128;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700515 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700516 switch (size) {
517 case WORD:
518 if (LOWREG(rDest) && (rBase == rpc) &&
519 (displacement <= 1020) && (displacement >= 0)) {
520 shortForm = true;
521 displacement >>= 2;
522 opCode = THUMB_LDR_PC_REL;
523 } else if (LOWREG(rDest) && (rBase == r13) &&
524 (displacement <= 1020) && (displacement >= 0)) {
525 shortForm = true;
526 displacement >>= 2;
527 opCode = THUMB_LDR_SP_REL;
528 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
529 assert((displacement & 0x3) == 0);
530 shortForm = true;
531 displacement >>= 2;
532 opCode = THUMB_LDR_RRI5;
533 } else if (thumb2Form) {
534 shortForm = true;
535 opCode = THUMB2_LDR_RRI12;
536 }
537 break;
538 case UNSIGNED_HALF:
539 if (allLowRegs && displacement < 64 && displacement >= 0) {
540 assert((displacement & 0x1) == 0);
541 shortForm = true;
542 displacement >>= 1;
543 opCode = THUMB_LDRH_RRI5;
544 } else if (displacement < 4092 && displacement >= 0) {
545 shortForm = true;
546 opCode = THUMB2_LDRH_RRI12;
547 }
548 break;
549 case SIGNED_HALF:
550 if (thumb2Form) {
551 shortForm = true;
552 opCode = THUMB2_LDRSH_RRI12;
553 }
554 break;
555 case UNSIGNED_BYTE:
556 if (allLowRegs && displacement < 32 && displacement >= 0) {
557 shortForm = true;
558 opCode = THUMB_LDRB_RRI5;
559 } else if (thumb2Form) {
560 shortForm = true;
561 opCode = THUMB2_LDRB_RRI12;
562 }
563 break;
564 case SIGNED_BYTE:
565 if (thumb2Form) {
566 shortForm = true;
567 opCode = THUMB2_LDRSB_RRI12;
568 }
569 break;
570 default:
571 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700572 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700573 if (nullCheck)
574 first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
575 if (shortForm) {
576 res = newLIR3(cUnit, opCode, rDest, rBase, displacement);
577 } else {
578 assert(rBase != rDest);
579 res = loadConstant(cUnit, rDest, displacement);
580 loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
581 }
582 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700583}
584
Bill Buzbee270c1d62009-08-13 16:58:07 -0700585static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
586 int displacement, int rSrc, OpSize size,
587 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700588{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700589 ArmLIR *res;
590 ArmOpCode opCode = THUMB_BKPT;
591 bool shortForm = false;
592 bool thumb2Form = (displacement < 4092 && displacement >= 0);
593 int shortMax = 128;
594 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
595 if (rScratch != -1)
596 allLowRegs &= LOWREG(rScratch);
597 switch (size) {
598 case WORD:
599 if (allLowRegs && displacement < 128 && displacement >= 0) {
600 assert((displacement & 0x3) == 0);
601 shortForm = true;
602 displacement >>= 2;
603 opCode = THUMB_STR_RRI5;
604 } else if (thumb2Form) {
605 shortForm = true;
606 opCode = THUMB2_STR_RRI12;
607 }
608 break;
609 case UNSIGNED_HALF:
610 case SIGNED_HALF:
611 if (displacement < 64 && displacement >= 0) {
612 assert((displacement & 0x1) == 0);
613 shortForm = true;
614 displacement >>= 1;
615 opCode = THUMB_STRH_RRI5;
616 } else if (thumb2Form) {
617 shortForm = true;
618 opCode = THUMB2_STRH_RRI12;
619 }
620 break;
621 case UNSIGNED_BYTE:
622 case SIGNED_BYTE:
623 if (displacement < 32 && displacement >= 0) {
624 shortForm = true;
625 opCode = THUMB_STRB_RRI5;
626 } else if (thumb2Form) {
627 shortForm = true;
628 opCode = THUMB2_STRH_RRI12;
629 }
630 break;
631 default:
632 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700633 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700634 if (shortForm) {
635 res = newLIR3(cUnit, opCode, rSrc, rBase, displacement);
636 } else {
637 assert(rScratch != -1);
638 res = loadConstant(cUnit, rScratch, displacement);
639 storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
640 }
641 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700642}
643
644/*
645 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
646 * satisfies.
647 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700648static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700649 ArmConditionCode cond, int reg,
650 int checkValue, int dOffset,
651 ArmLIR *pcrLabel)
652{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700653 ArmLIR *branch;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700654 int modImm;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700655 /*
Ben Cheng0fd31e42009-09-03 14:40:16 -0700656 * TODO: re-enable usage of THUMB2_CBZ & THUMB2_CBNZ once assembler is
657 * enhanced to allow us to replace code patterns when instructions don't
658 * reach. Currently, CB[N]Z is causing too many assembler aborts.
659 * What we want to do is emit the short forms, and then replace them with
660 * longer versions when needed.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700661 */
662 if (0 && (LOWREG(reg)) && (checkValue == 0) &&
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700663 ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
664 branch = newLIR2(cUnit,
665 (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
666 reg, 0);
667 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700668 modImm = modifiedImmediate(checkValue);
669 if ((checkValue & 0xff) == checkValue) {
670 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
671 } else if (modImm >= 0) {
672 newLIR2(cUnit, THUMB2_CMP_RI8, reg, modImm);
673 } else {
674 /* Note: direct use of hot temp r7 here. Revisit. */
675 loadConstant(cUnit, r7, checkValue);
676 newLIR2(cUnit, THUMB_CMP_RR, reg, r7);
677 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700678 branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
679 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700680 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
681}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700682
683static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
684{
685 ArmLIR *res;
686 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
687 res = newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
688 } else {
689 res = newLIR2(cUnit, THUMB2_LDMIA, rBase, rMask);
690 }
691 return res;
692}
693
694static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
695{
696 ArmLIR *res;
697 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
698 res = newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
699 } else {
700 res = newLIR2(cUnit, THUMB2_STMIA, rBase, rMask);
701 }
702 return res;
703}
704
705static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
706{
707 ArmOpCode opCode = THUMB_BKPT;
708 switch (op) {
709 case OP_UNCOND_BR:
710 opCode = THUMB_B_UNCOND;
711 break;
712 default:
713 assert(0);
714 }
715 return newLIR0(cUnit, opCode);
716}
717
718static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
719 int value2)
720{
721 ArmOpCode opCode = THUMB_BKPT;
722 switch (op) {
723 case OP_COND_BR:
724 opCode = THUMB_B_COND;
725 break;
726 default:
727 assert(0);
728 }
729 return newLIR2(cUnit, opCode, value1, value2);
730}
731
732static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
733{
734 ArmOpCode opCode = THUMB_BKPT;
735 switch (op) {
736 case OP_PUSH:
737 opCode = ((value & 0xff00) != 0) ? THUMB2_PUSH : THUMB_PUSH;
738 break;
739 case OP_POP:
740 opCode = ((value & 0xff00) != 0) ? THUMB2_POP : THUMB_POP;
741 break;
742 default:
743 assert(0);
744 }
745 return newLIR1(cUnit, opCode, value);
746}
747
748static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
749{
750 ArmOpCode opCode = THUMB_BKPT;
751 switch (op) {
752 case OP_BLX:
753 opCode = THUMB_BLX_R;
754 break;
755 default:
756 assert(0);
757 }
758 return newLIR1(cUnit, opCode, rDestSrc);
759}
760
761static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
762 int rSrc2, int shift)
763{
764 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
765 ArmOpCode opCode = THUMB_BKPT;
766 switch (op) {
767 case OP_ADC:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700768 opCode = (thumbForm) ? THUMB_ADC_RR : THUMB2_ADC_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700769 break;
770 case OP_AND:
771 opCode = (thumbForm) ? THUMB_AND_RR : THUMB2_AND_RRR;
772 break;
773 case OP_BIC:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700774 opCode = (thumbForm) ? THUMB_BIC_RR : THUMB2_BIC_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700775 break;
776 case OP_CMN:
777 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700778 opCode = (thumbForm) ? THUMB_CMN_RR : THUMB2_CMN_RR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700779 break;
780 case OP_CMP:
781 if (thumbForm)
782 opCode = THUMB_CMP_RR;
783 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
784 opCode = THUMB_CMP_HH;
785 else if ((shift == 0) && LOWREG(rDestSrc1))
786 opCode = THUMB_CMP_LH;
787 else if (shift == 0)
788 opCode = THUMB_CMP_HL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700789 else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700790 opCode = THUMB2_CMP_RR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700791 break;
792 case OP_XOR:
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700793 opCode = (thumbForm) ? THUMB_EOR_RR : THUMB2_EOR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700794 break;
795 case OP_MOV:
796 assert(shift == 0);
797 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
798 opCode = THUMB_MOV_RR;
799 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
800 opCode = THUMB_MOV_RR_H2H;
801 else if (LOWREG(rDestSrc1))
802 opCode = THUMB_MOV_RR_H2L;
803 else
804 opCode = THUMB_MOV_RR_L2H;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700805 break;
806 case OP_MUL:
807 assert(shift == 0);
808 opCode = (thumbForm) ? THUMB_MUL : THUMB2_MUL_RRR;
809 break;
810 case OP_MVN:
811 opCode = (thumbForm) ? THUMB_MVN : THUMB2_MVN_RR;
812 break;
813 case OP_NEG:
814 assert(shift == 0);
815 opCode = (thumbForm) ? THUMB_NEG : THUMB2_NEG_RR;
816 break;
817 case OP_OR:
818 opCode = (thumbForm) ? THUMB_ORR : THUMB2_ORR_RRR;
819 break;
820 case OP_SBC:
821 opCode = (thumbForm) ? THUMB_SBC : THUMB2_SBC_RRR;
822 break;
823 case OP_TST:
824 opCode = (thumbForm) ? THUMB_TST : THUMB2_TST_RR;
825 break;
826 case OP_LSL:
827 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700828 opCode = (thumbForm) ? THUMB_LSL_RR : THUMB2_LSL_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700829 break;
830 case OP_LSR:
831 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700832 opCode = (thumbForm) ? THUMB_LSR_RR : THUMB2_LSR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700833 break;
834 case OP_ASR:
835 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700836 opCode = (thumbForm) ? THUMB_ASR_RR : THUMB2_ASR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700837 break;
838 case OP_ROR:
839 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700840 opCode = (thumbForm) ? THUMB_ROR_RR : THUMB2_ROR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700841 break;
842 case OP_ADD:
843 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
844 break;
845 case OP_SUB:
846 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
847 break;
848 case OP_2BYTE:
849 assert(shift == 0);
850 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 8);
851 case OP_2SHORT:
852 assert(shift == 0);
853 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 16);
854 case OP_2CHAR:
855 assert(shift == 0);
856 return newLIR4(cUnit, THUMB2_UBFX, rDestSrc1, rSrc2, 0, 16);
857 default:
858 assert(0);
859 break;
860 }
861 assert(opCode >= 0);
862 if (EncodingMap[opCode].flags & IS_BINARY_OP)
863 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
864 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
865 if (EncodingMap[opCode].fieldLoc[2].kind == SHIFT)
866 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
867 else
868 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
869 } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
870 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
871 else {
872 assert(0);
873 return NULL;
874 }
875}
876
877static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
878 int rSrc2)
879{
880 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
881}
882
883/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
884static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
885 int value, int rScratch)
886{
887 ArmLIR *res;
888 bool neg = (value < 0);
889 int absValue = (neg) ? -value : value;
890 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
891 ArmOpCode opCode = THUMB_BKPT;
892 switch (op) {
893 case OP_ADD:
894 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
895 assert((value & 0x3) == 0);
896 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
897 } else if (shortForm) {
898 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
899 }
900 break;
901 case OP_SUB:
902 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
903 assert((value & 0x3) == 0);
904 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
905 } else if (shortForm) {
906 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
907 }
908 break;
909 case OP_CMP:
910 if (LOWREG(rDestSrc1) && shortForm)
911 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
912 else if (LOWREG(rDestSrc1))
913 opCode = THUMB_CMP_RR;
914 else {
915 shortForm = false;
916 opCode = THUMB_CMP_HL;
917 }
918 break;
919 default:
920 /* Punt to opRegRegImm - if bad case catch it there */
921 shortForm = false;
922 break;
923 }
924 if (shortForm)
925 return newLIR2(cUnit, opCode, rDestSrc1, absValue);
926 else
927 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value, rScratch);
928}
929
930static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
931 int rDest, int rSrc1, int rSrc2, int shift)
932{
933 ArmOpCode opCode = THUMB_BKPT;
934 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
935 LOWREG(rSrc2);
936 switch (op) {
937 case OP_ADD:
938 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
939 break;
940 case OP_SUB:
941 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
942 break;
943 case OP_ADC:
944 opCode = THUMB2_ADC_RRR;
945 break;
946 case OP_AND:
947 opCode = THUMB2_AND_RRR;
948 break;
949 case OP_BIC:
950 opCode = THUMB2_BIC_RRR;
951 break;
952 case OP_XOR:
953 opCode = THUMB2_EOR_RRR;
954 break;
955 case OP_MUL:
956 assert(shift == 0);
957 opCode = THUMB2_MUL_RRR;
958 break;
959 case OP_OR:
960 opCode = THUMB2_ORR_RRR;
961 break;
962 case OP_SBC:
963 opCode = THUMB2_SBC_RRR;
964 break;
965 case OP_LSL:
966 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700967 opCode = THUMB2_LSL_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700968 break;
969 case OP_LSR:
970 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700971 opCode = THUMB2_LSR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700972 break;
973 case OP_ASR:
974 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700975 opCode = THUMB2_ASR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700976 break;
977 case OP_ROR:
978 assert(shift == 0);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700979 opCode = THUMB2_ROR_RRR;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700980 break;
981 default:
982 assert(0);
983 break;
984 }
985 assert(opCode >= 0);
986 if (EncodingMap[opCode].flags & IS_QUAD_OP)
987 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
988 else {
989 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
990 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
991 }
992}
993
994static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
995 int rSrc1, int rSrc2)
996{
997 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
998}
999
1000static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
1001 int rSrc1, int value, int rScratch)
1002{
1003 ArmLIR *res;
1004 bool neg = (value < 0);
1005 int absValue = (neg) ? -value : value;
1006 ArmOpCode opCode = THUMB_BKPT;
1007 ArmOpCode altOpCode = THUMB_BKPT;
1008 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
1009 int modImm = modifiedImmediate(value);
1010 int modImmNeg = modifiedImmediate(-value);
1011
1012 switch(op) {
1013 case OP_LSL:
1014 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001015 return newLIR3(cUnit, THUMB_LSL_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001016 else
1017 return newLIR3(cUnit, THUMB2_LSL_RRI5, rDest, rSrc1, value);
1018 case OP_LSR:
1019 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001020 return newLIR3(cUnit, THUMB_LSR_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001021 else
1022 return newLIR3(cUnit, THUMB2_LSR_RRI5, rDest, rSrc1, value);
1023 case OP_ASR:
1024 if (allLowRegs)
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001025 return newLIR3(cUnit, THUMB_ASR_RRI5, rDest, rSrc1, value);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001026 else
1027 return newLIR3(cUnit, THUMB2_ASR_RRI5, rDest, rSrc1, value);
1028 case OP_ROR:
1029 return newLIR3(cUnit, THUMB2_ROR_RRI5, rDest, rSrc1, value);
1030 case OP_ADD:
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001031 if (LOWREG(rDest) && (rSrc1 == 13) &&
1032 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001033 return newLIR3(cUnit, THUMB_ADD_SP_REL, rDest, rSrc1,
1034 value >> 2);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001035 } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
1036 (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001037 return newLIR3(cUnit, THUMB_ADD_PC_REL, rDest, rSrc1,
1038 value >> 2);
1039 }
1040 opCode = THUMB2_ADD_RRI8;
1041 altOpCode = THUMB2_ADD_RRR;
1042 // Note: intentional fallthrough
1043 case OP_SUB:
1044 if (allLowRegs && ((absValue & 0x7) == absValue)) {
1045 if (op == OP_ADD)
1046 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
1047 else
1048 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
1049 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1050 } else if ((absValue & 0xff) == absValue) {
1051 if (op == OP_ADD)
1052 opCode = (neg) ? THUMB2_SUB_RRI12 : THUMB2_ADD_RRI12;
1053 else
1054 opCode = (neg) ? THUMB2_ADD_RRI12 : THUMB2_SUB_RRI12;
1055 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1056 }
1057 if (modImmNeg >= 0) {
1058 op = (op == OP_ADD) ? OP_SUB : OP_ADD;
1059 modImm = modImmNeg;
1060 }
1061 if (op == OP_SUB) {
1062 opCode = THUMB2_SUB_RRI8;
1063 altOpCode = THUMB2_SUB_RRR;
1064 }
1065 break;
1066 case OP_ADC:
1067 opCode = THUMB2_ADC_RRI8;
1068 altOpCode = THUMB2_ADC_RRR;
1069 break;
1070 case OP_SBC:
1071 opCode = THUMB2_SBC_RRI8;
1072 altOpCode = THUMB2_SBC_RRR;
1073 break;
1074 case OP_OR:
1075 opCode = THUMB2_ORR_RRI8;
1076 altOpCode = THUMB2_ORR_RRR;
1077 break;
1078 case OP_AND:
1079 opCode = THUMB2_AND_RRI8;
1080 altOpCode = THUMB2_AND_RRR;
1081 break;
1082 case OP_XOR:
1083 opCode = THUMB2_EOR_RRI8;
1084 altOpCode = THUMB2_EOR_RRR;
1085 break;
1086 case OP_MUL:
1087 //TUNING: power of 2, shift & add
1088 modImm = -1;
1089 altOpCode = THUMB2_MUL_RRR;
1090 break;
1091 default:
1092 assert(0);
1093 }
1094
1095 if (modImm >= 0) {
1096 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
1097 } else {
1098 loadConstant(cUnit, rScratch, value);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001099 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001100 return newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
1101 else
1102 return newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
1103 }
1104}
1105
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001106/*
1107 * 64-bit 3way compare function.
1108 * mov r7, #-1
1109 * cmp op1hi, op2hi
1110 * blt done
1111 * bgt flip
1112 * sub r7, op1lo, op2lo (treat as unsigned)
1113 * beq done
1114 * ite hi
1115 * mov(hi) r7, #-1
1116 * mov(!hi) r7, #1
1117 * flip:
1118 * neg r7
1119 * done:
1120 */
1121static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
1122 int vDest, int vSrc1, int vSrc2)
1123{
1124 int op1lo = selectFirstRegister(cUnit, vSrc1, true);
1125 int op1hi = NEXT_REG(op1lo);
1126 int op2lo = NEXT_REG(op1hi);
1127 int op2hi = NEXT_REG(op2lo);
1128 loadValuePair(cUnit, vSrc1, op1lo, op1hi);
1129 loadValuePair(cUnit, vSrc2, op2lo, op2hi);
1130 /* Note: using hardcoded r7 & r4PC for now. revisit */
1131 loadConstant(cUnit, r7, -1);
1132 opRegReg(cUnit, OP_CMP, op1hi, op2hi);
1133 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_LT);
1134 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
1135 opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
1136 ArmLIR *branch3 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
1137
1138 // TODO: need assert mechanism to verify IT block size
1139 branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
1140 newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
1141 newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001142 genITBottom(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001143
1144 branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
1145 branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
1146 branch3->generic.target = branch1->generic.target;
1147}
1148
Bill Buzbee270c1d62009-08-13 16:58:07 -07001149static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1150{
1151 DecodedInstruction *dInsn = &mir->dalvikInsn;
1152 int offset = offsetof(InterpState, retval);
1153 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1154 int reg1 = NEXT_REG(regObj);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001155 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001156 loadValue(cUnit, dInsn->arg[0], regObj);
1157 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
1158 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001159 if (vDest >= 0)
1160 storeValue(cUnit, reg1, vDest, regObj);
1161 else
1162 storeWordDisp(cUnit, rGLUE, offset, reg1, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001163 return false;
1164}
1165
1166static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
1167{
1168 DecodedInstruction *dInsn = &mir->dalvikInsn;
1169 int offset = offsetof(InterpState, retval);
1170 int contents = offsetof(ArrayObject, contents);
1171 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1172 int regIdx = NEXT_REG(regObj);
1173 int regMax = NEXT_REG(regIdx);
1174 int regOff = NEXT_REG(regMax);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001175 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001176 loadValue(cUnit, dInsn->arg[0], regObj);
1177 loadValue(cUnit, dInsn->arg[1], regIdx);
1178 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
1179 mir->offset, NULL);
1180 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
1181 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
1182 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
1183 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001184 opRegImm(cUnit, OP_ADD, regObj, contents, rNone);
1185 opRegReg(cUnit, OP_ADD, regIdx, regOff);
1186 loadBaseIndexed(cUnit, regObj, regIdx, regMax, 1, UNSIGNED_HALF);
1187 if (vDest >= 0)
1188 storeValue(cUnit, regMax, vDest, regObj);
1189 else
1190 storeWordDisp(cUnit, rGLUE, offset, regMax, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001191 return false;
1192}
1193
1194static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
1195{
1196 int offset = offsetof(InterpState, retval);
1197 DecodedInstruction *dInsn = &mir->dalvikInsn;
1198 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1199 int sign = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001200 int vDest = inlinedTarget(mir);
1201 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001202 loadValue(cUnit, dInsn->arg[0], reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001203 /*
1204 * Thumb2's IT block also yields 3 instructions, but imposes
1205 * scheduling constraints.
1206 */
1207 opRegRegImm(cUnit, OP_ASR, sign, reg0, 31, rNone);
1208 opRegReg(cUnit, OP_ADD, reg0, sign);
1209 opRegReg(cUnit, OP_XOR, reg0, sign);
1210 if (vDest >= 0)
1211 storeValue(cUnit, reg0, vDest, sign);
1212 else
1213 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001214 return false;
1215}
1216
1217static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
1218{
1219 int offset = offsetof(InterpState, retval);
1220 DecodedInstruction *dInsn = &mir->dalvikInsn;
1221 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1222 int signMask = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001223 int vDest = inlinedTarget(mir);
1224 // TUNING: handle case of src already in FP reg
Bill Buzbee270c1d62009-08-13 16:58:07 -07001225 loadValue(cUnit, dInsn->arg[0], reg0);
1226 loadConstant(cUnit, signMask, 0x7fffffff);
1227 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001228 if (vDest >= 0)
1229 storeValue(cUnit, reg0, vDest, signMask);
1230 else
1231 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001232 return false;
1233}
1234
1235static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
1236{
1237 int offset = offsetof(InterpState, retval);
1238 DecodedInstruction *dInsn = &mir->dalvikInsn;
1239 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1240 int ophi = NEXT_REG(oplo);
1241 int signMask = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001242 int vSrc = dInsn->arg[0];
1243 int vDest = inlinedTarget(mir);
1244 // TUNING: handle case of src already in FP reg
1245 if (vDest >= 0) {
Bill Buzbee7fb2edd2009-08-31 10:25:55 -07001246 /*
1247 * FIXME: disable this case to to work around bug until after
1248 * new schedule/ralloc mechanisms are done.
1249 */
1250 if (0 && (vDest == vSrc)) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001251 loadValue(cUnit, vSrc+1, ophi);
1252 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1253 storeValue(cUnit, ophi, vDest + 1, signMask);
1254 } else {
1255 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1256 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1257 storeValuePair(cUnit, oplo, ophi, vDest, signMask);
1258 }
1259 } else {
1260 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1261 loadConstant(cUnit, signMask, 0x7fffffff);
1262 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1263 opRegReg(cUnit, OP_AND, ophi, signMask);
1264 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1265 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001266 return false;
1267}
1268
Bill Buzbee270c1d62009-08-13 16:58:07 -07001269static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1270{
1271 int offset = offsetof(InterpState, retval);
1272 DecodedInstruction *dInsn = &mir->dalvikInsn;
1273 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1274 int reg1 = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001275 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001276 loadValue(cUnit, dInsn->arg[0], reg0);
1277 loadValue(cUnit, dInsn->arg[1], reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001278 opRegReg(cUnit, OP_CMP, reg0, reg1);
1279 //TODO: need assertion mechanism to validate IT region size
1280 genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
1281 opRegReg(cUnit, OP_MOV, reg0, reg1);
Ben Chengdcf3e5d2009-09-11 13:42:05 -07001282 genITBottom(cUnit);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001283 if (vDest >= 0)
1284 storeValue(cUnit, reg0, vDest, reg1);
1285 else
1286 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001287 return false;
1288}
1289
1290static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1291{
1292 int offset = offsetof(InterpState, retval);
1293 DecodedInstruction *dInsn = &mir->dalvikInsn;
1294 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1295 int ophi = NEXT_REG(oplo);
1296 int sign = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001297 int vDest = inlinedTarget(mir);
1298 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001299 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001300 /*
1301 * Thumb2 IT block allows slightly shorter sequence,
1302 * but introduces a scheduling barrier. Stick with this
1303 * mechanism for now.
1304 */
1305 opRegRegImm(cUnit, OP_ASR, sign, ophi, 31, rNone);
1306 opRegReg(cUnit, OP_ADD, oplo, sign);
1307 opRegReg(cUnit, OP_ADC, ophi, sign);
1308 opRegReg(cUnit, OP_XOR, oplo, sign);
1309 opRegReg(cUnit, OP_XOR, ophi, sign);
1310 if (vDest >= 0) {
1311 storeValuePair(cUnit, oplo, ophi, vDest, sign);
1312 } else {
1313 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1314 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1315 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001316 return false;
1317}