blob: 806bd02d00de2aea2e274eabd5f961e3be6bf2e7 [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/*
175 * Generate a Thumb2 IT instruction, which can nullify up to
176 * four subsequent instructions based on a condition and its
177 * inverse. The condition applies to the first instruction, which
178 * is executed if the condition is met. The string "guide" consists
179 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
180 * A "T" means the instruction is executed if the condition is
181 * met, and an "E" means the instruction is executed if the condition
182 * is not met.
183 */
184static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
185 char *guide)
186{
187 int mask;
188 int condBit = code & 1;
189 int altBit = condBit ^ 1;
190 int mask3 = 0;
191 int mask2 = 0;
192 int mask1 = 0;
193 //Note: case fallthroughs intentional
194 switch(strlen(guide)) {
195 case 3:
196 mask1 = (guide[2] == 'T') ? condBit : altBit;
197 case 2:
198 mask2 = (guide[1] == 'T') ? condBit : altBit;
199 case 1:
200 mask3 = (guide[0] == 'T') ? condBit : altBit;
201 break;
202 case 0:
203 break;
204 default:
205 assert(0);
206 dvmAbort();
207 }
208 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
209 (1 << (3 - strlen(guide)));
210 return newLIR2(cUnit, THUMB2_IT, code, mask);
211}
212
213
Bill Buzbee270c1d62009-08-13 16:58:07 -0700214static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700215{
216 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
217 res->operands[0] = rDest;
218 res->operands[1] = rSrc;
219 if (rDest == rSrc) {
220 res->isNop = true;
221 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700222 // TODO: support copy between FP and gen regs
223 if (DOUBLEREG(rDest)) {
224 assert(DOUBLEREG(rSrc));
225 res->opCode = THUMB2_VMOVD;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700226 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700227 assert(SINGLEREG(rSrc));
228 res->opCode = THUMB2_VMOVS;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700229 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700230 res->operands[0] = rDest;
231 res->operands[1] = rSrc;
232 }
233 return res;
234}
235
236ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
237{
238 ArmLIR* res;
239 ArmOpCode opCode;
240 if (FPREG(rDest) || FPREG(rSrc))
241 return fpRegCopy(cUnit, rDest, rSrc);
242 res = dvmCompilerNew(sizeof(ArmLIR), true);
243 if (LOWREG(rDest) && LOWREG(rSrc))
244 opCode = THUMB_MOV_RR;
245 else if (!LOWREG(rDest) && !LOWREG(rSrc))
246 opCode = THUMB_MOV_RR_H2H;
247 else if (LOWREG(rDest))
248 opCode = THUMB_MOV_RR_H2L;
249 else
250 opCode = THUMB_MOV_RR_L2H;
251
252 res->operands[0] = rDest & THUMB_REG_MASK;
253 res->operands[1] = rSrc & THUMB_REG_MASK;
254 res->opCode = opCode;
255 if (rDest == rSrc) {
256 res->isNop = true;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700257 }
258 return res;
259}
260
261static int leadingZeros(u4 val)
262{
263 u4 alt;
264 int n;
265 int count;
266
267 count = 16;
268 n = 32;
269 do {
270 alt = val >> count;
271 if (alt != 0) {
272 n = n - count;
273 val = alt;
274 }
275 count >>= 1;
276 } while (count);
277 return n - val;
278}
279
280/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700281 * Determine whether value can be encoded as a Thumb2 modified
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700282 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
283 */
284static int modifiedImmediate(u4 value)
285{
286 int zLeading;
287 int zTrailing;
288 u4 b0 = value & 0xff;
289
290 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
291 if (value <= 0xFF)
292 return b0; // 0:000:a:bcdefgh
293 if (value == ((b0 << 16) | b0))
294 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
295 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
296 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
297 b0 = (value >> 8) & 0xff;
298 if (value == ((b0 << 24) | (b0 << 8)))
299 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
300 /* Can we do it with rotation? */
301 zLeading = leadingZeros(value);
302 zTrailing = 32 - leadingZeros(~value & (value - 1));
303 /* A run of eight or fewer active bits? */
304 if ((zLeading + zTrailing) < 24)
305 return -1; /* No - bail */
306 /* left-justify the constant, discarding msb (known to be 1) */
307 value <<= zLeading + 1;
308 /* Create bcdefgh */
309 value >>= 25;
310 /* Put it all together */
311 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
312}
313
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700314/*
315 * Load a immediate using a shortcut if possible; otherwise
316 * grab from the per-translation literal pool
317 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700318static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700319{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700320 ArmLIR *res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700321 int modImm;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700322 /* See if the value can be constructed cheaply */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700323 if ((value >= 0) && (value <= 255)) {
324 return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700325 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700326 /* Check Modified immediate special cases */
327 modImm = modifiedImmediate(value);
328 if (modImm >= 0) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700329 res = newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, rDest, modImm);
330 return res;
331 }
332 modImm = modifiedImmediate(~value);
333 if (modImm >= 0) {
334 res = newLIR2(cUnit, THUMB2_MVN_IMM_SHIFT, rDest, modImm);
335 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700336 }
337 /* 16-bit immediate? */
338 if ((value & 0xffff) == value) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700339 res = newLIR2(cUnit, THUMB2_MOV_IMM16, rDest, value);
340 return res;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700341 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700342 /* No shortcut - go ahead and use literal pool */
343 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
344 if (dataTarget == NULL) {
345 dataTarget = addWordData(cUnit, value, false);
346 }
347 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
348 loadPcRel->opCode = THUMB_LDR_PC_REL;
349 loadPcRel->generic.target = (LIR *) dataTarget;
350 loadPcRel->operands[0] = rDest;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700351 res = loadPcRel;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700352 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
353
354 /*
355 * To save space in the constant pool, we use the ADD_RRI8 instruction to
356 * add up to 255 to an existing constant value.
357 */
358 if (dataTarget->operands[0] != value) {
359 newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
360 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700361 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700362}
363
364/* Export the Dalvik PC assicated with an instruction to the StackSave area */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700365static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
366 int rAddr)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700367{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700368 ArmLIR *res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700369 int offset = offsetof(StackSaveArea, xtra.currentPc);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700370 res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700371 newLIR3(cUnit, THUMB2_STR_RRI8_PREDEC, rDPC, rFP,
372 sizeof(StackSaveArea) - offset);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700373 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700374}
375
Bill Buzbee270c1d62009-08-13 16:58:07 -0700376/* Load value from base + scaled index. Note: index reg killed */
377static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
378 int rIndex, int rDest, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700379{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700380 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
381 ArmOpCode opCode = THUMB_BKPT;
382 bool thumbForm = (allLowRegs && (scale == 0));
383 switch (size) {
384 case WORD:
385 opCode = (thumbForm) ? THUMB_LDR_RRR : THUMB2_LDR_RRR;
386 break;
387 case UNSIGNED_HALF:
388 opCode = (thumbForm) ? THUMB_LDRH_RRR : THUMB2_LDRH_RRR;
389 break;
390 case SIGNED_HALF:
391 opCode = (thumbForm) ? THUMB_LDRSH_RRR : THUMB2_LDRSH_RRR;
392 break;
393 case UNSIGNED_BYTE:
394 opCode = (thumbForm) ? THUMB_LDRB_RRR : THUMB2_LDRB_RRR;
395 break;
396 case SIGNED_BYTE:
397 opCode = (thumbForm) ? THUMB_LDRSB_RRR : THUMB2_LDRSB_RRR;
398 break;
399 default:
400 assert(0);
401 }
402 if (thumbForm)
403 return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
404 else
405 return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700406}
407
Bill Buzbee270c1d62009-08-13 16:58:07 -0700408/* store value base base + scaled index. Note: index reg killed */
409static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
410 int rIndex, int rSrc, int scale, OpSize size)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700411{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700412 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
413 ArmOpCode opCode = THUMB_BKPT;
414 bool thumbForm = (allLowRegs && (scale == 0));
415 switch (size) {
416 case WORD:
417 opCode = (thumbForm) ? THUMB_STR_RRR : THUMB2_STR_RRR;
418 break;
419 case UNSIGNED_HALF:
420 case SIGNED_HALF:
421 opCode = (thumbForm) ? THUMB_STRH_RRR : THUMB2_STRH_RRR;
422 break;
423 case UNSIGNED_BYTE:
424 case SIGNED_BYTE:
425 opCode = (thumbForm) ? THUMB_STRB_RRR : THUMB2_STRB_RRR;
426 break;
427 default:
428 assert(0);
429 }
430 if (thumbForm)
431 return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
432 else
433 return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700434}
435
436/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700437 * Load a float from a Dalvik register. Note: using fixed r7 here
438 * when operation is out of range. Revisit this when registor allocation
439 * strategy changes.
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700440 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700441static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
442 int rSrcDest, ArmOpCode opCode)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700443{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700444 ArmLIR *res;
445 if (vSrcDest > 255) {
446 res = opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
447 newLIR3(cUnit, opCode, rSrcDest, r7, 0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700448 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700449 res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700450 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700451 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700452}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700453static ArmLIR *loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700454{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700455 assert(SINGLEREG(rDest));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700456 return fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700457}
458
459/* Store a float to a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700460static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest,
461 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700462{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700463 assert(SINGLEREG(rSrc));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700464 return fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700465}
466
467/* Load a double from a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700468static ArmLIR *loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700469{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700470 assert(DOUBLEREG(rDest));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700471 return fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700472}
473
474/* Store a double to a Dalvik register */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700475static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest,
476 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700477{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700478 assert(DOUBLEREG(rSrc));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700479 return fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700480}
481
482
Bill Buzbee270c1d62009-08-13 16:58:07 -0700483/*
484 * Load value from base + displacement. Optionally perform null check
485 * on base (which must have an associated vReg and MIR). If not
486 * performing null check, incoming MIR can be null. Note: base and
487 * dest must not be the same if there is any chance that the long
488 * form must be used.
489 * TODO: revisit, perhaps use hot temp reg in (base == dest) case.
490 */
491static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
492 int displacement, int rDest, OpSize size,
493 bool nullCheck, int vReg)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700494{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700495 ArmLIR *first = NULL;
496 ArmLIR *res;
497 ArmOpCode opCode = THUMB_BKPT;
498 bool shortForm = false;
499 bool thumb2Form = (displacement < 4092 && displacement >= 0);
500 int shortMax = 128;
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700501 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
Bill Buzbee270c1d62009-08-13 16:58:07 -0700502 switch (size) {
503 case WORD:
504 if (LOWREG(rDest) && (rBase == rpc) &&
505 (displacement <= 1020) && (displacement >= 0)) {
506 shortForm = true;
507 displacement >>= 2;
508 opCode = THUMB_LDR_PC_REL;
509 } else if (LOWREG(rDest) && (rBase == r13) &&
510 (displacement <= 1020) && (displacement >= 0)) {
511 shortForm = true;
512 displacement >>= 2;
513 opCode = THUMB_LDR_SP_REL;
514 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
515 assert((displacement & 0x3) == 0);
516 shortForm = true;
517 displacement >>= 2;
518 opCode = THUMB_LDR_RRI5;
519 } else if (thumb2Form) {
520 shortForm = true;
521 opCode = THUMB2_LDR_RRI12;
522 }
523 break;
524 case UNSIGNED_HALF:
525 if (allLowRegs && displacement < 64 && displacement >= 0) {
526 assert((displacement & 0x1) == 0);
527 shortForm = true;
528 displacement >>= 1;
529 opCode = THUMB_LDRH_RRI5;
530 } else if (displacement < 4092 && displacement >= 0) {
531 shortForm = true;
532 opCode = THUMB2_LDRH_RRI12;
533 }
534 break;
535 case SIGNED_HALF:
536 if (thumb2Form) {
537 shortForm = true;
538 opCode = THUMB2_LDRSH_RRI12;
539 }
540 break;
541 case UNSIGNED_BYTE:
542 if (allLowRegs && displacement < 32 && displacement >= 0) {
543 shortForm = true;
544 opCode = THUMB_LDRB_RRI5;
545 } else if (thumb2Form) {
546 shortForm = true;
547 opCode = THUMB2_LDRB_RRI12;
548 }
549 break;
550 case SIGNED_BYTE:
551 if (thumb2Form) {
552 shortForm = true;
553 opCode = THUMB2_LDRSB_RRI12;
554 }
555 break;
556 default:
557 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700558 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700559 if (nullCheck)
560 first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
561 if (shortForm) {
562 res = newLIR3(cUnit, opCode, rDest, rBase, displacement);
563 } else {
564 assert(rBase != rDest);
565 res = loadConstant(cUnit, rDest, displacement);
566 loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
567 }
568 return (first) ? first : res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700569}
570
Bill Buzbee270c1d62009-08-13 16:58:07 -0700571static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
572 int displacement, int rSrc, OpSize size,
573 int rScratch)
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700574{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700575 ArmLIR *res;
576 ArmOpCode opCode = THUMB_BKPT;
577 bool shortForm = false;
578 bool thumb2Form = (displacement < 4092 && displacement >= 0);
579 int shortMax = 128;
580 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
581 if (rScratch != -1)
582 allLowRegs &= LOWREG(rScratch);
583 switch (size) {
584 case WORD:
585 if (allLowRegs && displacement < 128 && displacement >= 0) {
586 assert((displacement & 0x3) == 0);
587 shortForm = true;
588 displacement >>= 2;
589 opCode = THUMB_STR_RRI5;
590 } else if (thumb2Form) {
591 shortForm = true;
592 opCode = THUMB2_STR_RRI12;
593 }
594 break;
595 case UNSIGNED_HALF:
596 case SIGNED_HALF:
597 if (displacement < 64 && displacement >= 0) {
598 assert((displacement & 0x1) == 0);
599 shortForm = true;
600 displacement >>= 1;
601 opCode = THUMB_STRH_RRI5;
602 } else if (thumb2Form) {
603 shortForm = true;
604 opCode = THUMB2_STRH_RRI12;
605 }
606 break;
607 case UNSIGNED_BYTE:
608 case SIGNED_BYTE:
609 if (displacement < 32 && displacement >= 0) {
610 shortForm = true;
611 opCode = THUMB_STRB_RRI5;
612 } else if (thumb2Form) {
613 shortForm = true;
614 opCode = THUMB2_STRH_RRI12;
615 }
616 break;
617 default:
618 assert(0);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700619 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700620 if (shortForm) {
621 res = newLIR3(cUnit, opCode, rSrc, rBase, displacement);
622 } else {
623 assert(rScratch != -1);
624 res = loadConstant(cUnit, rScratch, displacement);
625 storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
626 }
627 return res;
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700628}
629
630/*
631 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
632 * satisfies.
633 */
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700634static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700635 ArmConditionCode cond, int reg,
636 int checkValue, int dOffset,
637 ArmLIR *pcrLabel)
638{
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700639 ArmLIR *branch;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700640 int modImm;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700641 /*
Ben Cheng0fd31e42009-09-03 14:40:16 -0700642 * TODO: re-enable usage of THUMB2_CBZ & THUMB2_CBNZ once assembler is
643 * enhanced to allow us to replace code patterns when instructions don't
644 * reach. Currently, CB[N]Z is causing too many assembler aborts.
645 * What we want to do is emit the short forms, and then replace them with
646 * longer versions when needed.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700647 */
648 if (0 && (LOWREG(reg)) && (checkValue == 0) &&
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700649 ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
650 branch = newLIR2(cUnit,
651 (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
652 reg, 0);
653 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700654 modImm = modifiedImmediate(checkValue);
655 if ((checkValue & 0xff) == checkValue) {
656 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
657 } else if (modImm >= 0) {
658 newLIR2(cUnit, THUMB2_CMP_RI8, reg, modImm);
659 } else {
660 /* Note: direct use of hot temp r7 here. Revisit. */
661 loadConstant(cUnit, r7, checkValue);
662 newLIR2(cUnit, THUMB_CMP_RR, reg, r7);
663 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700664 branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
665 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700666 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
667}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700668
669static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
670{
671 ArmLIR *res;
672 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
673 res = newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
674 } else {
675 res = newLIR2(cUnit, THUMB2_LDMIA, rBase, rMask);
676 }
677 return res;
678}
679
680static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
681{
682 ArmLIR *res;
683 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
684 res = newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
685 } else {
686 res = newLIR2(cUnit, THUMB2_STMIA, rBase, rMask);
687 }
688 return res;
689}
690
691static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
692{
693 ArmOpCode opCode = THUMB_BKPT;
694 switch (op) {
695 case OP_UNCOND_BR:
696 opCode = THUMB_B_UNCOND;
697 break;
698 default:
699 assert(0);
700 }
701 return newLIR0(cUnit, opCode);
702}
703
704static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
705 int value2)
706{
707 ArmOpCode opCode = THUMB_BKPT;
708 switch (op) {
709 case OP_COND_BR:
710 opCode = THUMB_B_COND;
711 break;
712 default:
713 assert(0);
714 }
715 return newLIR2(cUnit, opCode, value1, value2);
716}
717
718static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
719{
720 ArmOpCode opCode = THUMB_BKPT;
721 switch (op) {
722 case OP_PUSH:
723 opCode = ((value & 0xff00) != 0) ? THUMB2_PUSH : THUMB_PUSH;
724 break;
725 case OP_POP:
726 opCode = ((value & 0xff00) != 0) ? THUMB2_POP : THUMB_POP;
727 break;
728 default:
729 assert(0);
730 }
731 return newLIR1(cUnit, opCode, value);
732}
733
734static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
735{
736 ArmOpCode opCode = THUMB_BKPT;
737 switch (op) {
738 case OP_BLX:
739 opCode = THUMB_BLX_R;
740 break;
741 default:
742 assert(0);
743 }
744 return newLIR1(cUnit, opCode, rDestSrc);
745}
746
747static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
748 int rSrc2, int shift)
749{
750 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
751 ArmOpCode opCode = THUMB_BKPT;
752 switch (op) {
753 case OP_ADC:
754 opCode = (thumbForm) ? THUMB_ADC : THUMB2_ADC_RRR;
755 break;
756 case OP_AND:
757 opCode = (thumbForm) ? THUMB_AND_RR : THUMB2_AND_RRR;
758 break;
759 case OP_BIC:
760 opCode = (thumbForm) ? THUMB_BIC : THUMB2_BIC_RRR;
761 break;
762 case OP_CMN:
763 assert(shift == 0);
764 opCode = (thumbForm) ? THUMB_CMN : THUMB2_CMN_RR;
765 break;
766 case OP_CMP:
767 if (thumbForm)
768 opCode = THUMB_CMP_RR;
769 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
770 opCode = THUMB_CMP_HH;
771 else if ((shift == 0) && LOWREG(rDestSrc1))
772 opCode = THUMB_CMP_LH;
773 else if (shift == 0)
774 opCode = THUMB_CMP_HL;
775 if (shift == 0) {
776 rDestSrc1 &= THUMB_REG_MASK;
777 rSrc2 &= THUMB_REG_MASK;
778 } else {
779 opCode = THUMB2_CMP_RR;
780 }
781 break;
782 case OP_XOR:
783 opCode = (thumbForm) ? THUMB_EOR : THUMB2_EOR_RRR;
784 break;
785 case OP_MOV:
786 assert(shift == 0);
787 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
788 opCode = THUMB_MOV_RR;
789 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
790 opCode = THUMB_MOV_RR_H2H;
791 else if (LOWREG(rDestSrc1))
792 opCode = THUMB_MOV_RR_H2L;
793 else
794 opCode = THUMB_MOV_RR_L2H;
795 rDestSrc1 &= THUMB_REG_MASK;
796 rSrc2 &= THUMB_REG_MASK;
797 break;
798 case OP_MUL:
799 assert(shift == 0);
800 opCode = (thumbForm) ? THUMB_MUL : THUMB2_MUL_RRR;
801 break;
802 case OP_MVN:
803 opCode = (thumbForm) ? THUMB_MVN : THUMB2_MVN_RR;
804 break;
805 case OP_NEG:
806 assert(shift == 0);
807 opCode = (thumbForm) ? THUMB_NEG : THUMB2_NEG_RR;
808 break;
809 case OP_OR:
810 opCode = (thumbForm) ? THUMB_ORR : THUMB2_ORR_RRR;
811 break;
812 case OP_SBC:
813 opCode = (thumbForm) ? THUMB_SBC : THUMB2_SBC_RRR;
814 break;
815 case OP_TST:
816 opCode = (thumbForm) ? THUMB_TST : THUMB2_TST_RR;
817 break;
818 case OP_LSL:
819 assert(shift == 0);
820 opCode = (thumbForm) ? THUMB_LSLV : THUMB2_LSLV_RRR;
821 break;
822 case OP_LSR:
823 assert(shift == 0);
824 opCode = (thumbForm) ? THUMB_LSRV : THUMB2_LSRV_RRR;
825 break;
826 case OP_ASR:
827 assert(shift == 0);
828 opCode = (thumbForm) ? THUMB_ASRV : THUMB2_ASRV_RRR;
829 break;
830 case OP_ROR:
831 assert(shift == 0);
832 opCode = (thumbForm) ? THUMB_RORV : THUMB2_RORV_RRR;
833 break;
834 case OP_ADD:
835 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
836 break;
837 case OP_SUB:
838 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
839 break;
840 case OP_2BYTE:
841 assert(shift == 0);
842 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 8);
843 case OP_2SHORT:
844 assert(shift == 0);
845 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 16);
846 case OP_2CHAR:
847 assert(shift == 0);
848 return newLIR4(cUnit, THUMB2_UBFX, rDestSrc1, rSrc2, 0, 16);
849 default:
850 assert(0);
851 break;
852 }
853 assert(opCode >= 0);
854 if (EncodingMap[opCode].flags & IS_BINARY_OP)
855 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
856 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
857 if (EncodingMap[opCode].fieldLoc[2].kind == SHIFT)
858 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
859 else
860 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
861 } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
862 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
863 else {
864 assert(0);
865 return NULL;
866 }
867}
868
869static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
870 int rSrc2)
871{
872 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
873}
874
875/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
876static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
877 int value, int rScratch)
878{
879 ArmLIR *res;
880 bool neg = (value < 0);
881 int absValue = (neg) ? -value : value;
882 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
883 ArmOpCode opCode = THUMB_BKPT;
884 switch (op) {
885 case OP_ADD:
886 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
887 assert((value & 0x3) == 0);
888 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
889 } else if (shortForm) {
890 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
891 }
892 break;
893 case OP_SUB:
894 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
895 assert((value & 0x3) == 0);
896 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
897 } else if (shortForm) {
898 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
899 }
900 break;
901 case OP_CMP:
902 if (LOWREG(rDestSrc1) && shortForm)
903 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
904 else if (LOWREG(rDestSrc1))
905 opCode = THUMB_CMP_RR;
906 else {
907 shortForm = false;
908 opCode = THUMB_CMP_HL;
909 }
910 break;
911 default:
912 /* Punt to opRegRegImm - if bad case catch it there */
913 shortForm = false;
914 break;
915 }
916 if (shortForm)
917 return newLIR2(cUnit, opCode, rDestSrc1, absValue);
918 else
919 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value, rScratch);
920}
921
922static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
923 int rDest, int rSrc1, int rSrc2, int shift)
924{
925 ArmOpCode opCode = THUMB_BKPT;
926 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
927 LOWREG(rSrc2);
928 switch (op) {
929 case OP_ADD:
930 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
931 break;
932 case OP_SUB:
933 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
934 break;
935 case OP_ADC:
936 opCode = THUMB2_ADC_RRR;
937 break;
938 case OP_AND:
939 opCode = THUMB2_AND_RRR;
940 break;
941 case OP_BIC:
942 opCode = THUMB2_BIC_RRR;
943 break;
944 case OP_XOR:
945 opCode = THUMB2_EOR_RRR;
946 break;
947 case OP_MUL:
948 assert(shift == 0);
949 opCode = THUMB2_MUL_RRR;
950 break;
951 case OP_OR:
952 opCode = THUMB2_ORR_RRR;
953 break;
954 case OP_SBC:
955 opCode = THUMB2_SBC_RRR;
956 break;
957 case OP_LSL:
958 assert(shift == 0);
959 opCode = THUMB2_LSLV_RRR;
960 break;
961 case OP_LSR:
962 assert(shift == 0);
963 opCode = THUMB2_LSRV_RRR;
964 break;
965 case OP_ASR:
966 assert(shift == 0);
967 opCode = THUMB2_ASRV_RRR;
968 break;
969 case OP_ROR:
970 assert(shift == 0);
971 opCode = THUMB2_RORV_RRR;
972 break;
973 default:
974 assert(0);
975 break;
976 }
977 assert(opCode >= 0);
978 if (EncodingMap[opCode].flags & IS_QUAD_OP)
979 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
980 else {
981 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
982 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
983 }
984}
985
986static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
987 int rSrc1, int rSrc2)
988{
989 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
990}
991
992static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
993 int rSrc1, int value, int rScratch)
994{
995 ArmLIR *res;
996 bool neg = (value < 0);
997 int absValue = (neg) ? -value : value;
998 ArmOpCode opCode = THUMB_BKPT;
999 ArmOpCode altOpCode = THUMB_BKPT;
1000 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
1001 int modImm = modifiedImmediate(value);
1002 int modImmNeg = modifiedImmediate(-value);
1003
1004 switch(op) {
1005 case OP_LSL:
1006 if (allLowRegs)
1007 return newLIR3(cUnit, THUMB_LSL, rDest, rSrc1, value);
1008 else
1009 return newLIR3(cUnit, THUMB2_LSL_RRI5, rDest, rSrc1, value);
1010 case OP_LSR:
1011 if (allLowRegs)
1012 return newLIR3(cUnit, THUMB_LSR, rDest, rSrc1, value);
1013 else
1014 return newLIR3(cUnit, THUMB2_LSR_RRI5, rDest, rSrc1, value);
1015 case OP_ASR:
1016 if (allLowRegs)
1017 return newLIR3(cUnit, THUMB_ASR, rDest, rSrc1, value);
1018 else
1019 return newLIR3(cUnit, THUMB2_ASR_RRI5, rDest, rSrc1, value);
1020 case OP_ROR:
1021 return newLIR3(cUnit, THUMB2_ROR_RRI5, rDest, rSrc1, value);
1022 case OP_ADD:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001023 if (LOWREG(rDest) && (rSrc1 == 13) && (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001024 return newLIR3(cUnit, THUMB_ADD_SP_REL, rDest, rSrc1,
1025 value >> 2);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001026 } else if (LOWREG(rDest) && (rSrc1 == rpc) && (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001027 return newLIR3(cUnit, THUMB_ADD_PC_REL, rDest, rSrc1,
1028 value >> 2);
1029 }
1030 opCode = THUMB2_ADD_RRI8;
1031 altOpCode = THUMB2_ADD_RRR;
1032 // Note: intentional fallthrough
1033 case OP_SUB:
1034 if (allLowRegs && ((absValue & 0x7) == absValue)) {
1035 if (op == OP_ADD)
1036 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
1037 else
1038 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
1039 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1040 } else if ((absValue & 0xff) == absValue) {
1041 if (op == OP_ADD)
1042 opCode = (neg) ? THUMB2_SUB_RRI12 : THUMB2_ADD_RRI12;
1043 else
1044 opCode = (neg) ? THUMB2_ADD_RRI12 : THUMB2_SUB_RRI12;
1045 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1046 }
1047 if (modImmNeg >= 0) {
1048 op = (op == OP_ADD) ? OP_SUB : OP_ADD;
1049 modImm = modImmNeg;
1050 }
1051 if (op == OP_SUB) {
1052 opCode = THUMB2_SUB_RRI8;
1053 altOpCode = THUMB2_SUB_RRR;
1054 }
1055 break;
1056 case OP_ADC:
1057 opCode = THUMB2_ADC_RRI8;
1058 altOpCode = THUMB2_ADC_RRR;
1059 break;
1060 case OP_SBC:
1061 opCode = THUMB2_SBC_RRI8;
1062 altOpCode = THUMB2_SBC_RRR;
1063 break;
1064 case OP_OR:
1065 opCode = THUMB2_ORR_RRI8;
1066 altOpCode = THUMB2_ORR_RRR;
1067 break;
1068 case OP_AND:
1069 opCode = THUMB2_AND_RRI8;
1070 altOpCode = THUMB2_AND_RRR;
1071 break;
1072 case OP_XOR:
1073 opCode = THUMB2_EOR_RRI8;
1074 altOpCode = THUMB2_EOR_RRR;
1075 break;
1076 case OP_MUL:
1077 //TUNING: power of 2, shift & add
1078 modImm = -1;
1079 altOpCode = THUMB2_MUL_RRR;
1080 break;
1081 default:
1082 assert(0);
1083 }
1084
1085 if (modImm >= 0) {
1086 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
1087 } else {
1088 loadConstant(cUnit, rScratch, value);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001089 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001090 return newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
1091 else
1092 return newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
1093 }
1094}
1095
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001096/*
1097 * 64-bit 3way compare function.
1098 * mov r7, #-1
1099 * cmp op1hi, op2hi
1100 * blt done
1101 * bgt flip
1102 * sub r7, op1lo, op2lo (treat as unsigned)
1103 * beq done
1104 * ite hi
1105 * mov(hi) r7, #-1
1106 * mov(!hi) r7, #1
1107 * flip:
1108 * neg r7
1109 * done:
1110 */
1111static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
1112 int vDest, int vSrc1, int vSrc2)
1113{
1114 int op1lo = selectFirstRegister(cUnit, vSrc1, true);
1115 int op1hi = NEXT_REG(op1lo);
1116 int op2lo = NEXT_REG(op1hi);
1117 int op2hi = NEXT_REG(op2lo);
1118 loadValuePair(cUnit, vSrc1, op1lo, op1hi);
1119 loadValuePair(cUnit, vSrc2, op2lo, op2hi);
1120 /* Note: using hardcoded r7 & r4PC for now. revisit */
1121 loadConstant(cUnit, r7, -1);
1122 opRegReg(cUnit, OP_CMP, op1hi, op2hi);
1123 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_LT);
1124 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
1125 opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
1126 ArmLIR *branch3 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
1127
1128 // TODO: need assert mechanism to verify IT block size
1129 branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
1130 newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
1131 newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
1132
1133 branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
1134 branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
1135 branch3->generic.target = branch1->generic.target;
1136}
1137
Bill Buzbee270c1d62009-08-13 16:58:07 -07001138static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1139{
1140 DecodedInstruction *dInsn = &mir->dalvikInsn;
1141 int offset = offsetof(InterpState, retval);
1142 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1143 int reg1 = NEXT_REG(regObj);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001144 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001145 loadValue(cUnit, dInsn->arg[0], regObj);
1146 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
1147 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001148 if (vDest >= 0)
1149 storeValue(cUnit, reg1, vDest, regObj);
1150 else
1151 storeWordDisp(cUnit, rGLUE, offset, reg1, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001152 return false;
1153}
1154
1155static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
1156{
1157 DecodedInstruction *dInsn = &mir->dalvikInsn;
1158 int offset = offsetof(InterpState, retval);
1159 int contents = offsetof(ArrayObject, contents);
1160 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1161 int regIdx = NEXT_REG(regObj);
1162 int regMax = NEXT_REG(regIdx);
1163 int regOff = NEXT_REG(regMax);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001164 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001165 loadValue(cUnit, dInsn->arg[0], regObj);
1166 loadValue(cUnit, dInsn->arg[1], regIdx);
1167 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
1168 mir->offset, NULL);
1169 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
1170 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
1171 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
1172 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001173 opRegImm(cUnit, OP_ADD, regObj, contents, rNone);
1174 opRegReg(cUnit, OP_ADD, regIdx, regOff);
1175 loadBaseIndexed(cUnit, regObj, regIdx, regMax, 1, UNSIGNED_HALF);
1176 if (vDest >= 0)
1177 storeValue(cUnit, regMax, vDest, regObj);
1178 else
1179 storeWordDisp(cUnit, rGLUE, offset, regMax, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001180 return false;
1181}
1182
1183static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
1184{
1185 int offset = offsetof(InterpState, retval);
1186 DecodedInstruction *dInsn = &mir->dalvikInsn;
1187 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1188 int sign = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001189 int vDest = inlinedTarget(mir);
1190 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001191 loadValue(cUnit, dInsn->arg[0], reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001192 /*
1193 * Thumb2's IT block also yields 3 instructions, but imposes
1194 * scheduling constraints.
1195 */
1196 opRegRegImm(cUnit, OP_ASR, sign, reg0, 31, rNone);
1197 opRegReg(cUnit, OP_ADD, reg0, sign);
1198 opRegReg(cUnit, OP_XOR, reg0, sign);
1199 if (vDest >= 0)
1200 storeValue(cUnit, reg0, vDest, sign);
1201 else
1202 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001203 return false;
1204}
1205
1206static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
1207{
1208 int offset = offsetof(InterpState, retval);
1209 DecodedInstruction *dInsn = &mir->dalvikInsn;
1210 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1211 int signMask = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001212 int vDest = inlinedTarget(mir);
1213 // TUNING: handle case of src already in FP reg
Bill Buzbee270c1d62009-08-13 16:58:07 -07001214 loadValue(cUnit, dInsn->arg[0], reg0);
1215 loadConstant(cUnit, signMask, 0x7fffffff);
1216 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001217 if (vDest >= 0)
1218 storeValue(cUnit, reg0, vDest, signMask);
1219 else
1220 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001221 return false;
1222}
1223
1224static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
1225{
1226 int offset = offsetof(InterpState, retval);
1227 DecodedInstruction *dInsn = &mir->dalvikInsn;
1228 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1229 int ophi = NEXT_REG(oplo);
1230 int signMask = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001231 int vSrc = dInsn->arg[0];
1232 int vDest = inlinedTarget(mir);
1233 // TUNING: handle case of src already in FP reg
1234 if (vDest >= 0) {
Bill Buzbee7fb2edd2009-08-31 10:25:55 -07001235 /*
1236 * FIXME: disable this case to to work around bug until after
1237 * new schedule/ralloc mechanisms are done.
1238 */
1239 if (0 && (vDest == vSrc)) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001240 loadValue(cUnit, vSrc+1, ophi);
1241 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1242 storeValue(cUnit, ophi, vDest + 1, signMask);
1243 } else {
1244 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1245 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1246 storeValuePair(cUnit, oplo, ophi, vDest, signMask);
1247 }
1248 } else {
1249 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1250 loadConstant(cUnit, signMask, 0x7fffffff);
1251 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1252 opRegReg(cUnit, OP_AND, ophi, signMask);
1253 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1254 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001255 return false;
1256}
1257
Bill Buzbee270c1d62009-08-13 16:58:07 -07001258static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1259{
1260 int offset = offsetof(InterpState, retval);
1261 DecodedInstruction *dInsn = &mir->dalvikInsn;
1262 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1263 int reg1 = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001264 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001265 loadValue(cUnit, dInsn->arg[0], reg0);
1266 loadValue(cUnit, dInsn->arg[1], reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001267 opRegReg(cUnit, OP_CMP, reg0, reg1);
1268 //TODO: need assertion mechanism to validate IT region size
1269 genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
1270 opRegReg(cUnit, OP_MOV, reg0, reg1);
1271 if (vDest >= 0)
1272 storeValue(cUnit, reg0, vDest, reg1);
1273 else
1274 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001275 return false;
1276}
1277
1278static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1279{
1280 int offset = offsetof(InterpState, retval);
1281 DecodedInstruction *dInsn = &mir->dalvikInsn;
1282 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1283 int ophi = NEXT_REG(oplo);
1284 int sign = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001285 int vDest = inlinedTarget(mir);
1286 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001287 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001288 /*
1289 * Thumb2 IT block allows slightly shorter sequence,
1290 * but introduces a scheduling barrier. Stick with this
1291 * mechanism for now.
1292 */
1293 opRegRegImm(cUnit, OP_ASR, sign, ophi, 31, rNone);
1294 opRegReg(cUnit, OP_ADD, oplo, sign);
1295 opRegReg(cUnit, OP_ADC, ophi, sign);
1296 opRegReg(cUnit, OP_XOR, oplo, sign);
1297 opRegReg(cUnit, OP_XOR, ophi, sign);
1298 if (vDest >= 0) {
1299 storeValuePair(cUnit, oplo, ophi, vDest, sign);
1300 } else {
1301 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1302 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1303 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001304 return false;
1305}