blob: 8d3ce07cb6d5a17e5b196b948154649ea5593e56 [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 /*
642 * TODO: re-enable usage of THUMB2_CBZ & THUMB2_CBNZ once assembler is enhanced
643 * to allow us to replace code patterns when instructions don't reach. Currently,
644 * CB[N]Z is causing too many assembler aborts. What we want to do is emit
645 * the short forms, and then replace them with longer versions when needed.
646 */
647 if (0 && (LOWREG(reg)) && (checkValue == 0) &&
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700648 ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
649 branch = newLIR2(cUnit,
650 (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
651 reg, 0);
652 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700653 modImm = modifiedImmediate(checkValue);
654 if ((checkValue & 0xff) == checkValue) {
655 newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
656 } else if (modImm >= 0) {
657 newLIR2(cUnit, THUMB2_CMP_RI8, reg, modImm);
658 } else {
659 /* Note: direct use of hot temp r7 here. Revisit. */
660 loadConstant(cUnit, r7, checkValue);
661 newLIR2(cUnit, THUMB_CMP_RR, reg, r7);
662 }
Bill Buzbee7ea0f642009-08-10 17:06:51 -0700663 branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
664 }
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700665 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
666}
Bill Buzbee270c1d62009-08-13 16:58:07 -0700667
668static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
669{
670 ArmLIR *res;
671 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
672 res = newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
673 } else {
674 res = newLIR2(cUnit, THUMB2_LDMIA, rBase, rMask);
675 }
676 return res;
677}
678
679static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
680{
681 ArmLIR *res;
682 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
683 res = newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
684 } else {
685 res = newLIR2(cUnit, THUMB2_STMIA, rBase, rMask);
686 }
687 return res;
688}
689
690static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
691{
692 ArmOpCode opCode = THUMB_BKPT;
693 switch (op) {
694 case OP_UNCOND_BR:
695 opCode = THUMB_B_UNCOND;
696 break;
697 default:
698 assert(0);
699 }
700 return newLIR0(cUnit, opCode);
701}
702
703static ArmLIR *opImmImm(CompilationUnit *cUnit, OpKind op, int value1,
704 int value2)
705{
706 ArmOpCode opCode = THUMB_BKPT;
707 switch (op) {
708 case OP_COND_BR:
709 opCode = THUMB_B_COND;
710 break;
711 default:
712 assert(0);
713 }
714 return newLIR2(cUnit, opCode, value1, value2);
715}
716
717static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
718{
719 ArmOpCode opCode = THUMB_BKPT;
720 switch (op) {
721 case OP_PUSH:
722 opCode = ((value & 0xff00) != 0) ? THUMB2_PUSH : THUMB_PUSH;
723 break;
724 case OP_POP:
725 opCode = ((value & 0xff00) != 0) ? THUMB2_POP : THUMB_POP;
726 break;
727 default:
728 assert(0);
729 }
730 return newLIR1(cUnit, opCode, value);
731}
732
733static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
734{
735 ArmOpCode opCode = THUMB_BKPT;
736 switch (op) {
737 case OP_BLX:
738 opCode = THUMB_BLX_R;
739 break;
740 default:
741 assert(0);
742 }
743 return newLIR1(cUnit, opCode, rDestSrc);
744}
745
746static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
747 int rSrc2, int shift)
748{
749 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
750 ArmOpCode opCode = THUMB_BKPT;
751 switch (op) {
752 case OP_ADC:
753 opCode = (thumbForm) ? THUMB_ADC : THUMB2_ADC_RRR;
754 break;
755 case OP_AND:
756 opCode = (thumbForm) ? THUMB_AND_RR : THUMB2_AND_RRR;
757 break;
758 case OP_BIC:
759 opCode = (thumbForm) ? THUMB_BIC : THUMB2_BIC_RRR;
760 break;
761 case OP_CMN:
762 assert(shift == 0);
763 opCode = (thumbForm) ? THUMB_CMN : THUMB2_CMN_RR;
764 break;
765 case OP_CMP:
766 if (thumbForm)
767 opCode = THUMB_CMP_RR;
768 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
769 opCode = THUMB_CMP_HH;
770 else if ((shift == 0) && LOWREG(rDestSrc1))
771 opCode = THUMB_CMP_LH;
772 else if (shift == 0)
773 opCode = THUMB_CMP_HL;
774 if (shift == 0) {
775 rDestSrc1 &= THUMB_REG_MASK;
776 rSrc2 &= THUMB_REG_MASK;
777 } else {
778 opCode = THUMB2_CMP_RR;
779 }
780 break;
781 case OP_XOR:
782 opCode = (thumbForm) ? THUMB_EOR : THUMB2_EOR_RRR;
783 break;
784 case OP_MOV:
785 assert(shift == 0);
786 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
787 opCode = THUMB_MOV_RR;
788 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
789 opCode = THUMB_MOV_RR_H2H;
790 else if (LOWREG(rDestSrc1))
791 opCode = THUMB_MOV_RR_H2L;
792 else
793 opCode = THUMB_MOV_RR_L2H;
794 rDestSrc1 &= THUMB_REG_MASK;
795 rSrc2 &= THUMB_REG_MASK;
796 break;
797 case OP_MUL:
798 assert(shift == 0);
799 opCode = (thumbForm) ? THUMB_MUL : THUMB2_MUL_RRR;
800 break;
801 case OP_MVN:
802 opCode = (thumbForm) ? THUMB_MVN : THUMB2_MVN_RR;
803 break;
804 case OP_NEG:
805 assert(shift == 0);
806 opCode = (thumbForm) ? THUMB_NEG : THUMB2_NEG_RR;
807 break;
808 case OP_OR:
809 opCode = (thumbForm) ? THUMB_ORR : THUMB2_ORR_RRR;
810 break;
811 case OP_SBC:
812 opCode = (thumbForm) ? THUMB_SBC : THUMB2_SBC_RRR;
813 break;
814 case OP_TST:
815 opCode = (thumbForm) ? THUMB_TST : THUMB2_TST_RR;
816 break;
817 case OP_LSL:
818 assert(shift == 0);
819 opCode = (thumbForm) ? THUMB_LSLV : THUMB2_LSLV_RRR;
820 break;
821 case OP_LSR:
822 assert(shift == 0);
823 opCode = (thumbForm) ? THUMB_LSRV : THUMB2_LSRV_RRR;
824 break;
825 case OP_ASR:
826 assert(shift == 0);
827 opCode = (thumbForm) ? THUMB_ASRV : THUMB2_ASRV_RRR;
828 break;
829 case OP_ROR:
830 assert(shift == 0);
831 opCode = (thumbForm) ? THUMB_RORV : THUMB2_RORV_RRR;
832 break;
833 case OP_ADD:
834 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
835 break;
836 case OP_SUB:
837 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
838 break;
839 case OP_2BYTE:
840 assert(shift == 0);
841 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 8);
842 case OP_2SHORT:
843 assert(shift == 0);
844 return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 16);
845 case OP_2CHAR:
846 assert(shift == 0);
847 return newLIR4(cUnit, THUMB2_UBFX, rDestSrc1, rSrc2, 0, 16);
848 default:
849 assert(0);
850 break;
851 }
852 assert(opCode >= 0);
853 if (EncodingMap[opCode].flags & IS_BINARY_OP)
854 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
855 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
856 if (EncodingMap[opCode].fieldLoc[2].kind == SHIFT)
857 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
858 else
859 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
860 } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
861 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
862 else {
863 assert(0);
864 return NULL;
865 }
866}
867
868static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
869 int rSrc2)
870{
871 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
872}
873
874/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
875static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
876 int value, int rScratch)
877{
878 ArmLIR *res;
879 bool neg = (value < 0);
880 int absValue = (neg) ? -value : value;
881 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
882 ArmOpCode opCode = THUMB_BKPT;
883 switch (op) {
884 case OP_ADD:
885 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
886 assert((value & 0x3) == 0);
887 return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
888 } else if (shortForm) {
889 opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
890 }
891 break;
892 case OP_SUB:
893 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
894 assert((value & 0x3) == 0);
895 return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
896 } else if (shortForm) {
897 opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
898 }
899 break;
900 case OP_CMP:
901 if (LOWREG(rDestSrc1) && shortForm)
902 opCode = (shortForm) ? THUMB_CMP_RI8 : THUMB_CMP_RR;
903 else if (LOWREG(rDestSrc1))
904 opCode = THUMB_CMP_RR;
905 else {
906 shortForm = false;
907 opCode = THUMB_CMP_HL;
908 }
909 break;
910 default:
911 /* Punt to opRegRegImm - if bad case catch it there */
912 shortForm = false;
913 break;
914 }
915 if (shortForm)
916 return newLIR2(cUnit, opCode, rDestSrc1, absValue);
917 else
918 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value, rScratch);
919}
920
921static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
922 int rDest, int rSrc1, int rSrc2, int shift)
923{
924 ArmOpCode opCode = THUMB_BKPT;
925 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
926 LOWREG(rSrc2);
927 switch (op) {
928 case OP_ADD:
929 opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
930 break;
931 case OP_SUB:
932 opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
933 break;
934 case OP_ADC:
935 opCode = THUMB2_ADC_RRR;
936 break;
937 case OP_AND:
938 opCode = THUMB2_AND_RRR;
939 break;
940 case OP_BIC:
941 opCode = THUMB2_BIC_RRR;
942 break;
943 case OP_XOR:
944 opCode = THUMB2_EOR_RRR;
945 break;
946 case OP_MUL:
947 assert(shift == 0);
948 opCode = THUMB2_MUL_RRR;
949 break;
950 case OP_OR:
951 opCode = THUMB2_ORR_RRR;
952 break;
953 case OP_SBC:
954 opCode = THUMB2_SBC_RRR;
955 break;
956 case OP_LSL:
957 assert(shift == 0);
958 opCode = THUMB2_LSLV_RRR;
959 break;
960 case OP_LSR:
961 assert(shift == 0);
962 opCode = THUMB2_LSRV_RRR;
963 break;
964 case OP_ASR:
965 assert(shift == 0);
966 opCode = THUMB2_ASRV_RRR;
967 break;
968 case OP_ROR:
969 assert(shift == 0);
970 opCode = THUMB2_RORV_RRR;
971 break;
972 default:
973 assert(0);
974 break;
975 }
976 assert(opCode >= 0);
977 if (EncodingMap[opCode].flags & IS_QUAD_OP)
978 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
979 else {
980 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
981 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
982 }
983}
984
985static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
986 int rSrc1, int rSrc2)
987{
988 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
989}
990
991static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
992 int rSrc1, int value, int rScratch)
993{
994 ArmLIR *res;
995 bool neg = (value < 0);
996 int absValue = (neg) ? -value : value;
997 ArmOpCode opCode = THUMB_BKPT;
998 ArmOpCode altOpCode = THUMB_BKPT;
999 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
1000 int modImm = modifiedImmediate(value);
1001 int modImmNeg = modifiedImmediate(-value);
1002
1003 switch(op) {
1004 case OP_LSL:
1005 if (allLowRegs)
1006 return newLIR3(cUnit, THUMB_LSL, rDest, rSrc1, value);
1007 else
1008 return newLIR3(cUnit, THUMB2_LSL_RRI5, rDest, rSrc1, value);
1009 case OP_LSR:
1010 if (allLowRegs)
1011 return newLIR3(cUnit, THUMB_LSR, rDest, rSrc1, value);
1012 else
1013 return newLIR3(cUnit, THUMB2_LSR_RRI5, rDest, rSrc1, value);
1014 case OP_ASR:
1015 if (allLowRegs)
1016 return newLIR3(cUnit, THUMB_ASR, rDest, rSrc1, value);
1017 else
1018 return newLIR3(cUnit, THUMB2_ASR_RRI5, rDest, rSrc1, value);
1019 case OP_ROR:
1020 return newLIR3(cUnit, THUMB2_ROR_RRI5, rDest, rSrc1, value);
1021 case OP_ADD:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001022 if (LOWREG(rDest) && (rSrc1 == 13) && (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001023 return newLIR3(cUnit, THUMB_ADD_SP_REL, rDest, rSrc1,
1024 value >> 2);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001025 } else if (LOWREG(rDest) && (rSrc1 == rpc) && (value <= 1020) && ((value & 0x3)==0)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001026 return newLIR3(cUnit, THUMB_ADD_PC_REL, rDest, rSrc1,
1027 value >> 2);
1028 }
1029 opCode = THUMB2_ADD_RRI8;
1030 altOpCode = THUMB2_ADD_RRR;
1031 // Note: intentional fallthrough
1032 case OP_SUB:
1033 if (allLowRegs && ((absValue & 0x7) == absValue)) {
1034 if (op == OP_ADD)
1035 opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
1036 else
1037 opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
1038 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1039 } else if ((absValue & 0xff) == absValue) {
1040 if (op == OP_ADD)
1041 opCode = (neg) ? THUMB2_SUB_RRI12 : THUMB2_ADD_RRI12;
1042 else
1043 opCode = (neg) ? THUMB2_ADD_RRI12 : THUMB2_SUB_RRI12;
1044 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
1045 }
1046 if (modImmNeg >= 0) {
1047 op = (op == OP_ADD) ? OP_SUB : OP_ADD;
1048 modImm = modImmNeg;
1049 }
1050 if (op == OP_SUB) {
1051 opCode = THUMB2_SUB_RRI8;
1052 altOpCode = THUMB2_SUB_RRR;
1053 }
1054 break;
1055 case OP_ADC:
1056 opCode = THUMB2_ADC_RRI8;
1057 altOpCode = THUMB2_ADC_RRR;
1058 break;
1059 case OP_SBC:
1060 opCode = THUMB2_SBC_RRI8;
1061 altOpCode = THUMB2_SBC_RRR;
1062 break;
1063 case OP_OR:
1064 opCode = THUMB2_ORR_RRI8;
1065 altOpCode = THUMB2_ORR_RRR;
1066 break;
1067 case OP_AND:
1068 opCode = THUMB2_AND_RRI8;
1069 altOpCode = THUMB2_AND_RRR;
1070 break;
1071 case OP_XOR:
1072 opCode = THUMB2_EOR_RRI8;
1073 altOpCode = THUMB2_EOR_RRR;
1074 break;
1075 case OP_MUL:
1076 //TUNING: power of 2, shift & add
1077 modImm = -1;
1078 altOpCode = THUMB2_MUL_RRR;
1079 break;
1080 default:
1081 assert(0);
1082 }
1083
1084 if (modImm >= 0) {
1085 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
1086 } else {
1087 loadConstant(cUnit, rScratch, value);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001088 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001089 return newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
1090 else
1091 return newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
1092 }
1093}
1094
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001095/*
1096 * 64-bit 3way compare function.
1097 * mov r7, #-1
1098 * cmp op1hi, op2hi
1099 * blt done
1100 * bgt flip
1101 * sub r7, op1lo, op2lo (treat as unsigned)
1102 * beq done
1103 * ite hi
1104 * mov(hi) r7, #-1
1105 * mov(!hi) r7, #1
1106 * flip:
1107 * neg r7
1108 * done:
1109 */
1110static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
1111 int vDest, int vSrc1, int vSrc2)
1112{
1113 int op1lo = selectFirstRegister(cUnit, vSrc1, true);
1114 int op1hi = NEXT_REG(op1lo);
1115 int op2lo = NEXT_REG(op1hi);
1116 int op2hi = NEXT_REG(op2lo);
1117 loadValuePair(cUnit, vSrc1, op1lo, op1hi);
1118 loadValuePair(cUnit, vSrc2, op2lo, op2hi);
1119 /* Note: using hardcoded r7 & r4PC for now. revisit */
1120 loadConstant(cUnit, r7, -1);
1121 opRegReg(cUnit, OP_CMP, op1hi, op2hi);
1122 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_LT);
1123 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
1124 opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
1125 ArmLIR *branch3 = opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
1126
1127 // TODO: need assert mechanism to verify IT block size
1128 branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
1129 newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
1130 newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
1131
1132 branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
1133 branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
1134 branch3->generic.target = branch1->generic.target;
1135}
1136
Bill Buzbee270c1d62009-08-13 16:58:07 -07001137static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1138{
1139 DecodedInstruction *dInsn = &mir->dalvikInsn;
1140 int offset = offsetof(InterpState, retval);
1141 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1142 int reg1 = NEXT_REG(regObj);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001143 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001144 loadValue(cUnit, dInsn->arg[0], regObj);
1145 genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
1146 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001147 if (vDest >= 0)
1148 storeValue(cUnit, reg1, vDest, regObj);
1149 else
1150 storeWordDisp(cUnit, rGLUE, offset, reg1, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001151 return false;
1152}
1153
1154static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
1155{
1156 DecodedInstruction *dInsn = &mir->dalvikInsn;
1157 int offset = offsetof(InterpState, retval);
1158 int contents = offsetof(ArrayObject, contents);
1159 int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
1160 int regIdx = NEXT_REG(regObj);
1161 int regMax = NEXT_REG(regIdx);
1162 int regOff = NEXT_REG(regMax);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001163 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001164 loadValue(cUnit, dInsn->arg[0], regObj);
1165 loadValue(cUnit, dInsn->arg[1], regIdx);
1166 ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
1167 mir->offset, NULL);
1168 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
1169 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
1170 loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
1171 genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001172 opRegImm(cUnit, OP_ADD, regObj, contents, rNone);
1173 opRegReg(cUnit, OP_ADD, regIdx, regOff);
1174 loadBaseIndexed(cUnit, regObj, regIdx, regMax, 1, UNSIGNED_HALF);
1175 if (vDest >= 0)
1176 storeValue(cUnit, regMax, vDest, regObj);
1177 else
1178 storeWordDisp(cUnit, rGLUE, offset, regMax, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001179 return false;
1180}
1181
1182static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
1183{
1184 int offset = offsetof(InterpState, retval);
1185 DecodedInstruction *dInsn = &mir->dalvikInsn;
1186 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1187 int sign = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001188 int vDest = inlinedTarget(mir);
1189 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001190 loadValue(cUnit, dInsn->arg[0], reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001191 /*
1192 * Thumb2's IT block also yields 3 instructions, but imposes
1193 * scheduling constraints.
1194 */
1195 opRegRegImm(cUnit, OP_ASR, sign, reg0, 31, rNone);
1196 opRegReg(cUnit, OP_ADD, reg0, sign);
1197 opRegReg(cUnit, OP_XOR, reg0, sign);
1198 if (vDest >= 0)
1199 storeValue(cUnit, reg0, vDest, sign);
1200 else
1201 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001202 return false;
1203}
1204
1205static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
1206{
1207 int offset = offsetof(InterpState, retval);
1208 DecodedInstruction *dInsn = &mir->dalvikInsn;
1209 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1210 int signMask = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001211 int vDest = inlinedTarget(mir);
1212 // TUNING: handle case of src already in FP reg
Bill Buzbee270c1d62009-08-13 16:58:07 -07001213 loadValue(cUnit, dInsn->arg[0], reg0);
1214 loadConstant(cUnit, signMask, 0x7fffffff);
1215 newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001216 if (vDest >= 0)
1217 storeValue(cUnit, reg0, vDest, signMask);
1218 else
1219 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001220 return false;
1221}
1222
1223static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
1224{
1225 int offset = offsetof(InterpState, retval);
1226 DecodedInstruction *dInsn = &mir->dalvikInsn;
1227 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1228 int ophi = NEXT_REG(oplo);
1229 int signMask = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001230 int vSrc = dInsn->arg[0];
1231 int vDest = inlinedTarget(mir);
1232 // TUNING: handle case of src already in FP reg
1233 if (vDest >= 0) {
1234 if (vDest == vSrc) {
1235 loadValue(cUnit, vSrc+1, ophi);
1236 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1237 storeValue(cUnit, ophi, vDest + 1, signMask);
1238 } else {
1239 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1240 opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
1241 storeValuePair(cUnit, oplo, ophi, vDest, signMask);
1242 }
1243 } else {
1244 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
1245 loadConstant(cUnit, signMask, 0x7fffffff);
1246 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1247 opRegReg(cUnit, OP_AND, ophi, signMask);
1248 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1249 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001250 return false;
1251}
1252
Bill Buzbee270c1d62009-08-13 16:58:07 -07001253static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
1254{
1255 int offset = offsetof(InterpState, retval);
1256 DecodedInstruction *dInsn = &mir->dalvikInsn;
1257 int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
1258 int reg1 = NEXT_REG(reg0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001259 int vDest = inlinedTarget(mir);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001260 loadValue(cUnit, dInsn->arg[0], reg0);
1261 loadValue(cUnit, dInsn->arg[1], reg1);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001262 opRegReg(cUnit, OP_CMP, reg0, reg1);
1263 //TODO: need assertion mechanism to validate IT region size
1264 genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
1265 opRegReg(cUnit, OP_MOV, reg0, reg1);
1266 if (vDest >= 0)
1267 storeValue(cUnit, reg0, vDest, reg1);
1268 else
1269 storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001270 return false;
1271}
1272
1273static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
1274{
1275 int offset = offsetof(InterpState, retval);
1276 DecodedInstruction *dInsn = &mir->dalvikInsn;
1277 int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
1278 int ophi = NEXT_REG(oplo);
1279 int sign = NEXT_REG(ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001280 int vDest = inlinedTarget(mir);
1281 /* abs(x) = y<=x>>31, (x+y)^y. */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001282 loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
Bill Buzbeea4a7f072009-08-27 13:58:09 -07001283 /*
1284 * Thumb2 IT block allows slightly shorter sequence,
1285 * but introduces a scheduling barrier. Stick with this
1286 * mechanism for now.
1287 */
1288 opRegRegImm(cUnit, OP_ASR, sign, ophi, 31, rNone);
1289 opRegReg(cUnit, OP_ADD, oplo, sign);
1290 opRegReg(cUnit, OP_ADC, ophi, sign);
1291 opRegReg(cUnit, OP_XOR, oplo, sign);
1292 opRegReg(cUnit, OP_XOR, ophi, sign);
1293 if (vDest >= 0) {
1294 storeValuePair(cUnit, oplo, ophi, vDest, sign);
1295 } else {
1296 storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
1297 storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
1298 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001299 return false;
1300}