blob: b272e48276922f0ff303007499bfc06f6938badd [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00: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#include "Dalvik.h"
18#include "interp/InterpDefs.h"
19#include "libdex/OpCode.h"
20#include "dexdump/OpCodeNames.h"
21#include "vm/compiler/CompilerInternals.h"
Bill Buzbeed45ba372009-06-15 17:00:57 -070022#include "FpCodegen.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070023#include "Armv5teLIR.h"
24#include "vm/mterp/common/FindInterface.h"
25
Ben Chengba4fc8b2009-06-01 13:00:29 -070026/* Array holding the entry offset of each template relative to the first one */
27static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
28
29/* Track exercised opcodes */
30static int opcodeCoverage[256];
31
Ben Chenge9695e52009-06-16 16:11:47 -070032/* non-existent register */
33#define vNone (-1)
34
35/* get the next register in r0..r3 in a round-robin fashion */
36#define NEXT_REG(reg) ((reg + 1) & 3)
37
Ben Chengba4fc8b2009-06-01 13:00:29 -070038/*****************************************************************************/
39
40/*
41 * The following are building blocks to construct low-level IRs with 0 - 3
42 * operands.
43 */
44static Armv5teLIR *newLIR0(CompilationUnit *cUnit, Armv5teOpCode opCode)
45{
46 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070047 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -070048 insn->opCode = opCode;
49 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
50 return insn;
51}
52
53static Armv5teLIR *newLIR1(CompilationUnit *cUnit, Armv5teOpCode opCode,
54 int dest)
55{
56 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070057 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070058 insn->opCode = opCode;
59 insn->operands[0] = dest;
60 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
61 return insn;
62}
63
64static Armv5teLIR *newLIR2(CompilationUnit *cUnit, Armv5teOpCode opCode,
65 int dest, int src1)
66{
67 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070068 assert(isPseudoOpCode(opCode) ||
69 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070070 insn->opCode = opCode;
71 insn->operands[0] = dest;
72 insn->operands[1] = src1;
73 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
74 return insn;
75}
76
77static Armv5teLIR *newLIR3(CompilationUnit *cUnit, Armv5teOpCode opCode,
78 int dest, int src1, int src2)
79{
80 Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -070081 assert(isPseudoOpCode(opCode) ||
82 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -070083 insn->opCode = opCode;
84 insn->operands[0] = dest;
85 insn->operands[1] = src1;
86 insn->operands[2] = src2;
87 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
88 return insn;
89}
90
91static Armv5teLIR *newLIR23(CompilationUnit *cUnit, Armv5teOpCode opCode,
92 int srcdest, int src2)
93{
94 assert(!isPseudoOpCode(opCode));
Ben Chenge9695e52009-06-16 16:11:47 -070095 if (EncodingMap[opCode].flags & IS_BINARY_OP)
Ben Chengba4fc8b2009-06-01 13:00:29 -070096 return newLIR2(cUnit, opCode, srcdest, src2);
97 else
98 return newLIR3(cUnit, opCode, srcdest, srcdest, src2);
99}
100
101/*****************************************************************************/
102
103/*
Ben Chenge9695e52009-06-16 16:11:47 -0700104 * The following are utility routines to help maintain the RegisterScoreboard
105 * state to facilitate register renaming.
106 */
107
108/* Reset the tracker to unknown state */
109static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
110{
111 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
112
113 dvmClearAllBits(registerScoreboard->nullCheckedRegs);
114 registerScoreboard->liveDalvikReg = vNone;
115 registerScoreboard->nativeReg = vNone;
116 registerScoreboard->nativeRegHi = vNone;
117}
118
119/* Kill the corresponding bit in the null-checked register list */
120static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
121{
122 dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
123}
124
125/* The Dalvik register pair held in native registers have changed */
126static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
127 int vReg, int mRegLo, int mRegHi)
128{
129 cUnit->registerScoreboard.liveDalvikReg = vReg;
130 cUnit->registerScoreboard.nativeReg = mRegLo;
131 cUnit->registerScoreboard.nativeRegHi = mRegHi;
132 cUnit->registerScoreboard.isWide = true;
133}
134
135/* The Dalvik register held in a native register has changed */
136static inline void updateLiveRegister(CompilationUnit *cUnit,
137 int vReg, int mReg)
138{
139 cUnit->registerScoreboard.liveDalvikReg = vReg;
140 cUnit->registerScoreboard.nativeReg = mReg;
141 cUnit->registerScoreboard.isWide = false;
142}
143
144/*
145 * Given a Dalvik register id vSrc, use a very simple algorithm to increase
146 * the lifetime of cached Dalvik value in a native register.
147 */
148static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
149 bool isWide)
150{
151 RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
152
153 /* No live value - suggest to use r0 */
154 if (registerScoreboard->liveDalvikReg == vNone)
155 return r0;
156
157 /* Reuse the previously used native reg */
158 if (registerScoreboard->liveDalvikReg == vSrc) {
159 if (isWide != true) {
160 return registerScoreboard->nativeReg;
161 } else {
162 /* Return either r0 or r2 */
163 return (registerScoreboard->nativeReg + 1) & 2;
164 }
165 }
166
167 /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
168 if (isWide) {
169 return (registerScoreboard->nativeReg + 2) & 2;
170 } else {
171 return (registerScoreboard->nativeReg + 1) & 3;
172 }
173
174}
175/*****************************************************************************/
176
177/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700178 * The following are building blocks to insert constants into the pool or
179 * instruction streams.
180 */
181
182/* Add a 32-bit constant either in the constant pool or mixed with code */
183static Armv5teLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
184{
185 /* Add the constant to the literal pool */
186 if (!inPlace) {
187 Armv5teLIR *newValue = dvmCompilerNew(sizeof(Armv5teLIR), true);
188 newValue->operands[0] = value;
189 newValue->generic.next = cUnit->wordList;
190 cUnit->wordList = (LIR *) newValue;
191 return newValue;
192 } else {
193 /* Add the constant in the middle of code stream */
194 newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value & 0xffff));
195 newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value >> 16));
196 }
197 return NULL;
198}
199
200/*
201 * Search the existing constants in the literal pool for an exact or close match
202 * within specified delta (greater or equal to 0).
203 */
204static Armv5teLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
205 unsigned int delta)
206{
207 LIR *dataTarget = cUnit->wordList;
208 while (dataTarget) {
209 if (((unsigned) (value - ((Armv5teLIR *) dataTarget)->operands[0])) <=
210 delta)
211 return (Armv5teLIR *) dataTarget;
212 dataTarget = dataTarget->next;
213 }
214 return NULL;
215}
216
217/*
218 * Load a immediate using a shortcut if possible; otherwise
219 * grab from the per-translation literal pool
220 */
221void loadConstant(CompilationUnit *cUnit, int rDest, int value)
222{
223 /* See if the value can be constructed cheaply */
224 if ((value >= 0) && (value <= 255)) {
225 newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, value);
226 return;
227 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
228 newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, ~value);
229 newLIR2(cUnit, ARMV5TE_MVN, rDest, rDest);
230 return;
231 }
232 /* No shortcut - go ahead and use literal pool */
233 Armv5teLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
234 if (dataTarget == NULL) {
235 dataTarget = addWordData(cUnit, value, false);
236 }
237 Armv5teLIR *loadPcRel = dvmCompilerNew(sizeof(Armv5teLIR), true);
238 loadPcRel->opCode = ARMV5TE_LDR_PC_REL;
239 loadPcRel->generic.target = (LIR *) dataTarget;
240 loadPcRel->operands[0] = rDest;
241 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
242
243 /*
244 * To save space in the constant pool, we use the ADD_RRI8 instruction to
245 * add up to 255 to an existing constant value.
246 */
247 if (dataTarget->operands[0] != value) {
248 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, value - dataTarget->operands[0]);
249 }
250}
251
252/* Export the Dalvik PC assicated with an instruction to the StackSave area */
253static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
254{
255 int offset = offsetof(StackSaveArea, xtra.currentPc);
256 loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
257 newLIR2(cUnit, ARMV5TE_MOV_RR, rAddr, rFP);
258 newLIR2(cUnit, ARMV5TE_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
259 newLIR3(cUnit, ARMV5TE_STR_RRI5, rDPC, rAddr, 0);
260}
261
262/* Generate conditional branch instructions */
263static void genConditionalBranch(CompilationUnit *cUnit,
264 Armv5teConditionCode cond,
265 Armv5teLIR *target)
266{
267 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
268 branch->generic.target = (LIR *) target;
269}
270
271/* Generate unconditional branch instructions */
272static void genUnconditionalBranch(CompilationUnit *cUnit, Armv5teLIR *target)
273{
274 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
275 branch->generic.target = (LIR *) target;
276}
277
278#define USE_IN_CACHE_HANDLER 1
279
280/*
281 * Jump to the out-of-line handler in ARM mode to finish executing the
282 * remaining of more complex instructions.
283 */
284static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
285{
286#if USE_IN_CACHE_HANDLER
287 /*
288 * NOTE - In practice BLX only needs one operand, but since the assembler
289 * may abort itself and retry due to other out-of-range conditions we
290 * cannot really use operand[0] to store the absolute target address since
291 * it may get clobbered by the final relative offset. Therefore,
292 * we fake BLX_1 is a two operand instruction and the absolute target
293 * address is stored in operand[1].
294 */
295 newLIR2(cUnit, ARMV5TE_BLX_1,
296 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
297 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
298 newLIR2(cUnit, ARMV5TE_BLX_2,
299 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
300 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
301#else
302 /*
303 * In case we want to access the statically compiled handlers for
304 * debugging purposes, define USE_IN_CACHE_HANDLER to 0
305 */
306 void *templatePtr;
307
308#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
309#include "../../template/armv5te/TemplateOpList.h"
310#undef JIT_TEMPLATE
311 switch (opCode) {
312#define JIT_TEMPLATE(X) \
313 case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
314#include "../../template/armv5te/TemplateOpList.h"
315#undef JIT_TEMPLATE
316 default: templatePtr = NULL;
317 }
318 loadConstant(cUnit, r7, (int) templatePtr);
319 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
320#endif
321}
322
323/* Perform the actual operation for OP_RETURN_* */
324static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
325{
326 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
327#if defined(INVOKE_STATS)
328 gDvmJit.jitReturn++;
329#endif
330 int dPC = (int) (cUnit->method->insns + mir->offset);
331 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
332 /* Set up the place holder to reconstruct this Dalvik PC */
333 Armv5teLIR *pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
334 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
335 pcrLabel->operands[0] = dPC;
336 pcrLabel->operands[1] = mir->offset;
337 /* Insert the place holder to the growable list */
338 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
339 /* Branch to the PC reconstruction code */
340 branch->generic.target = (LIR *) pcrLabel;
341}
342
343/*
344 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
345 * rDestHi
346 */
347static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
348 int rDestHi)
349{
350 /* Use reg + imm5*4 to load the values if possible */
351 if (vSrc <= 30) {
352 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestLo, rFP, vSrc);
353 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestHi, rFP, vSrc+1);
354 } else {
355 if (vSrc <= 64) {
356 /* Sneak 4 into the base address first */
357 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDestLo, rFP, 4);
358 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDestHi, (vSrc-1)*4);
359 } else {
360 /* Offset too far from rFP */
361 loadConstant(cUnit, rDestLo, vSrc*4);
362 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDestLo, rFP, rDestLo);
363 }
Ben Chenge9695e52009-06-16 16:11:47 -0700364 assert(rDestLo < rDestHi);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700365 newLIR2(cUnit, ARMV5TE_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
366 }
367}
368
369/*
370 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
371 * vDest+1
372 */
373static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
374 int vDest, int rScratch)
375{
Ben Chenge9695e52009-06-16 16:11:47 -0700376 killNullCheckedRegister(cUnit, vDest);
377 killNullCheckedRegister(cUnit, vDest+1);
378 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
379
Ben Chengba4fc8b2009-06-01 13:00:29 -0700380 /* Use reg + imm5*4 to store the values if possible */
381 if (vDest <= 30) {
382 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcLo, rFP, vDest);
383 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcHi, rFP, vDest+1);
384 } else {
385 if (vDest <= 64) {
386 /* Sneak 4 into the base address first */
387 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rScratch, rFP, 4);
388 newLIR2(cUnit, ARMV5TE_ADD_RI8, rScratch, (vDest-1)*4);
389 } else {
390 /* Offset too far from rFP */
391 loadConstant(cUnit, rScratch, vDest*4);
392 newLIR3(cUnit, ARMV5TE_ADD_RRR, rScratch, rFP, rScratch);
393 }
Ben Chenge9695e52009-06-16 16:11:47 -0700394 assert(rSrcLo < rSrcHi);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700395 newLIR2(cUnit, ARMV5TE_STMIA, rScratch, (1<<rSrcLo) | (1 << (rSrcHi)));
396 }
397}
398
399/* Load the address of a Dalvik register on the frame */
400static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
401{
402 /* RRI3 can add up to 7 */
403 if (vSrc <= 1) {
404 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, vSrc*4);
405 } else if (vSrc <= 64) {
406 /* Sneak 4 into the base address first */
407 newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, 4);
408 newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, (vSrc-1)*4);
409 } else {
410 loadConstant(cUnit, rDest, vSrc*4);
411 newLIR3(cUnit, ARMV5TE_ADD_RRR, rDest, rFP, rDest);
412 }
413}
414
Ben Chengba4fc8b2009-06-01 13:00:29 -0700415/* Load a single value from rFP[src] and store them into rDest */
416static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
417{
418 /* Use reg + imm5*4 to load the value if possible */
419 if (vSrc <= 31) {
420 newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDest, rFP, vSrc);
421 } else {
422 loadConstant(cUnit, rDest, vSrc*4);
423 newLIR3(cUnit, ARMV5TE_LDR_RRR, rDest, rFP, rDest);
424 }
425}
426
427/* Store a value from rSrc to vDest */
428static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
429 int rScratch)
430{
Ben Chenge9695e52009-06-16 16:11:47 -0700431 killNullCheckedRegister(cUnit, vDest);
432 updateLiveRegister(cUnit, vDest, rSrc);
433
Ben Chengba4fc8b2009-06-01 13:00:29 -0700434 /* Use reg + imm5*4 to store the value if possible */
435 if (vDest <= 31) {
436 newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrc, rFP, vDest);
437 } else {
438 loadConstant(cUnit, rScratch, vDest*4);
439 newLIR3(cUnit, ARMV5TE_STR_RRR, rSrc, rFP, rScratch);
440 }
441}
442
Ben Chengba4fc8b2009-06-01 13:00:29 -0700443/*
444 * Perform a binary operation on 64-bit operands and leave the results in the
445 * r0/r1 pair.
446 */
447static void genBinaryOpWide(CompilationUnit *cUnit, int vDest,
Ben Chenge9695e52009-06-16 16:11:47 -0700448 Armv5teOpCode preinst, Armv5teOpCode inst,
449 int reg0, int reg2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700450{
Ben Chenge9695e52009-06-16 16:11:47 -0700451 int reg1 = NEXT_REG(reg0);
452 int reg3 = NEXT_REG(reg2);
453 newLIR23(cUnit, preinst, reg0, reg2);
454 newLIR23(cUnit, inst, reg1, reg3);
455 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700456}
457
458/* Perform a binary operation on 32-bit operands and leave the results in r0. */
Ben Chenge9695e52009-06-16 16:11:47 -0700459static void genBinaryOp(CompilationUnit *cUnit, int vDest, Armv5teOpCode inst,
460 int reg0, int reg1, int regDest)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700461{
Ben Chenge9695e52009-06-16 16:11:47 -0700462 if (EncodingMap[inst].flags & IS_BINARY_OP) {
463 newLIR2(cUnit, inst, reg0, reg1);
464 storeValue(cUnit, reg0, vDest, reg1);
465 } else {
466 newLIR3(cUnit, inst, regDest, reg0, reg1);
467 storeValue(cUnit, regDest, vDest, reg1);
468 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700469}
470
471/* Create the PC reconstruction slot if not already done */
472static inline Armv5teLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
473 Armv5teLIR *branch,
474 Armv5teLIR *pcrLabel)
475{
476 /* Set up the place holder to reconstruct this Dalvik PC */
477 if (pcrLabel == NULL) {
478 int dPC = (int) (cUnit->method->insns + dOffset);
479 pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
480 pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
481 pcrLabel->operands[0] = dPC;
482 pcrLabel->operands[1] = dOffset;
483 /* Insert the place holder to the growable list */
484 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
485 }
486 /* Branch to the PC reconstruction code */
487 branch->generic.target = (LIR *) pcrLabel;
488 return pcrLabel;
489}
490
491/*
492 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
493 * satisfies.
494 */
495static inline Armv5teLIR *genRegImmCheck(CompilationUnit *cUnit,
496 Armv5teConditionCode cond, int reg,
497 int checkValue, int dOffset,
498 Armv5teLIR *pcrLabel)
499{
500 newLIR2(cUnit, ARMV5TE_CMP_RI8, reg, checkValue);
501 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
502 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
503}
504
505/*
506 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
507 * satisfies.
508 */
509static inline Armv5teLIR *inertRegRegCheck(CompilationUnit *cUnit,
510 Armv5teConditionCode cond,
511 int reg1, int reg2, int dOffset,
512 Armv5teLIR *pcrLabel)
513{
514 newLIR2(cUnit, ARMV5TE_CMP_RR, reg1, reg2);
515 Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
516 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
517}
518
Ben Chenge9695e52009-06-16 16:11:47 -0700519/*
520 * Perform null-check on a register. vReg is the Dalvik register being checked,
521 * and mReg is the machine register holding the actual value. If internal state
522 * indicates that vReg has been checked before the check request is ignored.
523 */
524static Armv5teLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
525 int dOffset, Armv5teLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700526{
Ben Chenge9695e52009-06-16 16:11:47 -0700527 /* This particular Dalvik register has been null-checked */
528 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
529 return pcrLabel;
530 }
531 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
532 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
533}
534
535/*
536 * Perform zero-check on a register. Similar to genNullCheck but the value being
537 * checked does not have a corresponding Dalvik register.
538 */
539static Armv5teLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
540 int dOffset, Armv5teLIR *pcrLabel)
541{
542 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700543}
544
545/* Perform bound check on two registers */
546static Armv5teLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
547 int rBound, int dOffset, Armv5teLIR *pcrLabel)
548{
549 return inertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
550 pcrLabel);
551}
552
553/* Generate a unconditional branch to go to the interpreter */
554static inline Armv5teLIR *genTrap(CompilationUnit *cUnit, int dOffset,
555 Armv5teLIR *pcrLabel)
556{
557 Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
558 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
559}
560
561/* Load a wide field from an object instance */
562static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
563{
564 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700565 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700566
Ben Chenge9695e52009-06-16 16:11:47 -0700567 /* Allocate reg0..reg3 into physical registers r0..r3 */
568
569 /* See if vB is in a native register. If so, reuse it. */
570 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
571 /* Ping reg3 to the other register of the same pair containing reg2 */
572 reg3 = reg2 ^ 0x1;
573 /*
574 * Ping reg0 to the first register of the alternate register pair
575 */
576 reg0 = (reg2 + 2) & 0x2;
577 reg1 = NEXT_REG(reg0);
578
579 loadValue(cUnit, dInsn->vB, reg2);
580 loadConstant(cUnit, reg3, fieldOffset);
581 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
582 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg2, reg2, reg3);
583 newLIR2(cUnit, ARMV5TE_LDMIA, reg2, (1<<reg0 | 1<<reg1));
584 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700585}
586
587/* Store a wide field to an object instance */
588static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
589{
590 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700591 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700592
Ben Chenge9695e52009-06-16 16:11:47 -0700593 /* Allocate reg0..reg3 into physical registers r0..r3 */
594
595 /* See if vB is in a native register. If so, reuse it. */
596 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
597 /* Ping reg3 to the other register of the same pair containing reg2 */
598 reg3 = reg2 ^ 0x1;
599 /*
600 * Ping reg0 to the first register of the alternate register pair
601 */
602 reg0 = (reg2 + 2) & 0x2;
603 reg1 = NEXT_REG(reg0);
604
605
606 loadValue(cUnit, dInsn->vB, reg2);
607 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
608 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
609 loadConstant(cUnit, reg3, fieldOffset);
610 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
611 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg2, reg2, reg3);
612 newLIR2(cUnit, ARMV5TE_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700613}
614
615/*
616 * Load a field from an object instance
617 *
618 * Inst should be one of:
619 * ARMV5TE_LDR_RRR
620 * ARMV5TE_LDRB_RRR
621 * ARMV5TE_LDRH_RRR
622 * ARMV5TE_LDRSB_RRR
623 * ARMV5TE_LDRSH_RRR
624 */
625static void genIGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
626 int fieldOffset)
627{
628 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700629 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700630
Ben Chenge9695e52009-06-16 16:11:47 -0700631 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
632 reg1 = NEXT_REG(reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700633 /* TUNING: write a utility routine to load via base + constant offset */
Ben Chenge9695e52009-06-16 16:11:47 -0700634 loadValue(cUnit, dInsn->vB, reg0);
635 loadConstant(cUnit, reg1, fieldOffset);
636 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
637 newLIR3(cUnit, inst, reg0, reg0, reg1);
638 storeValue(cUnit, reg0, dInsn->vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700639}
640
641/*
642 * Store a field to an object instance
643 *
644 * Inst should be one of:
645 * ARMV5TE_STR_RRR
646 * ARMV5TE_STRB_RRR
647 * ARMV5TE_STRH_RRR
648 */
649static void genIPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
650 int fieldOffset)
651{
652 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700653 int reg0, reg1, reg2;
654
655 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
656 reg1 = NEXT_REG(reg0);
657 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700658
659 /* TUNING: write a utility routine to load via base + constant offset */
Ben Chenge9695e52009-06-16 16:11:47 -0700660 loadValue(cUnit, dInsn->vB, reg0);
661 loadConstant(cUnit, reg1, fieldOffset);
662 loadValue(cUnit, dInsn->vA, reg2);
663 updateLiveRegister(cUnit, dInsn->vA, reg2);
664 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
665 newLIR3(cUnit, inst, reg2, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700666}
667
668
669/* TODO: This should probably be done as an out-of-line instruction handler. */
670
671/*
672 * Generate array load
673 *
674 * Inst should be one of:
675 * ARMV5TE_LDR_RRR
676 * ARMV5TE_LDRB_RRR
677 * ARMV5TE_LDRH_RRR
678 * ARMV5TE_LDRSB_RRR
679 * ARMV5TE_LDRSH_RRR
680 */
681static void genArrayGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
682 int vArray, int vIndex, int vDest, int scale)
683{
684 int lenOffset = offsetof(ArrayObject, length);
685 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700686 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700687
Ben Chenge9695e52009-06-16 16:11:47 -0700688 reg0 = selectFirstRegister(cUnit, vArray, false);
689 reg1 = NEXT_REG(reg0);
690 reg2 = NEXT_REG(reg1);
691 reg3 = NEXT_REG(reg2);
692
693 loadValue(cUnit, vArray, reg2);
694 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700695
696 /* null object? */
Ben Chenge9695e52009-06-16 16:11:47 -0700697 Armv5teLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
698 NULL);
699 newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
700 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
701 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700702 if (scale) {
Ben Chenge9695e52009-06-16 16:11:47 -0700703 newLIR3(cUnit, ARMV5TE_LSL, reg3, reg3, scale);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700704 }
705 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700706 newLIR3(cUnit, inst, reg0, reg2, reg3);
707 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, 4);
708 newLIR3(cUnit, inst, reg1, reg2, reg3);
709 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700710 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700711 newLIR3(cUnit, inst, reg0, reg2, reg3);
712 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700713 }
714}
715
716/* TODO: This should probably be done as an out-of-line instruction handler. */
717
718/*
719 * Generate array store
720 *
721 * Inst should be one of:
722 * ARMV5TE_STR_RRR
723 * ARMV5TE_STRB_RRR
724 * ARMV5TE_STRH_RRR
725 */
726static void genArrayPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
727 int vArray, int vIndex, int vSrc, int scale)
728{
729 int lenOffset = offsetof(ArrayObject, length);
730 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700731 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700732
Ben Chenge9695e52009-06-16 16:11:47 -0700733 reg0 = selectFirstRegister(cUnit, vArray, false);
734 reg1 = NEXT_REG(reg0);
735 reg2 = NEXT_REG(reg1);
736 reg3 = NEXT_REG(reg2);
737
738 loadValue(cUnit, vArray, reg2);
739 loadValue(cUnit, vIndex, reg3);
740
Ben Cheng1efc9c52009-06-08 18:25:27 -0700741 /* null object? */
Ben Chenge9695e52009-06-16 16:11:47 -0700742 Armv5teLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
743 NULL);
744 newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
745 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
746 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
747 /* at this point, reg2 points to array, reg3 is unscaled index */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700748 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700749 loadValuePair(cUnit, vSrc, reg0, reg1);
750 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700751 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700752 loadValue(cUnit, vSrc, reg0);
753 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700754 }
755 if (scale) {
Ben Chenge9695e52009-06-16 16:11:47 -0700756 newLIR3(cUnit, ARMV5TE_LSL, reg3, reg3, scale);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700757 }
758 /*
Ben Chenge9695e52009-06-16 16:11:47 -0700759 * at this point, reg2 points to array, reg3 is scaled index, and
760 * reg0[reg1] is data
Ben Chengba4fc8b2009-06-01 13:00:29 -0700761 */
762 if (scale==3) {
Ben Chenge9695e52009-06-16 16:11:47 -0700763 newLIR3(cUnit, inst, reg0, reg2, reg3);
764 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, 4);
765 newLIR3(cUnit, inst, reg1, reg2, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700766 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700767 newLIR3(cUnit, inst, reg0, reg2, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700768 }
769}
770
771static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
772 int vSrc1, int vShift)
773{
Ben Chenge9695e52009-06-16 16:11:47 -0700774 /*
775 * Don't mess with the regsiters here as there is a particular calling
776 * convention to the out-of-line handler.
777 */
778 loadValue(cUnit, vShift, r2);
779 loadValuePair(cUnit, vSrc1, r0, r1);
780 switch( mir->dalvikInsn.opCode) {
781 case OP_SHL_LONG:
782 case OP_SHL_LONG_2ADDR:
783 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
784 break;
785 case OP_SHR_LONG:
786 case OP_SHR_LONG_2ADDR:
787 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
788 break;
789 case OP_USHR_LONG:
790 case OP_USHR_LONG_2ADDR:
791 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
792 break;
793 default:
794 return true;
795 }
796 storeValuePair(cUnit, r0, r1, vDest, r2);
797 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700798}
Bill Buzbeed45ba372009-06-15 17:00:57 -0700799bool dvmCompilerGenArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
800 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700801{
Ben Chenge9695e52009-06-16 16:11:47 -0700802 /*
803 * Don't optimize the regsiter usage here as they are governed by the EABI
804 * calling convention.
805 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700806 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -0700807 int reg0, reg1;
808
Ben Chengba4fc8b2009-06-01 13:00:29 -0700809 /* TODO: use a proper include file to define these */
810 float __aeabi_fadd(float a, float b);
811 float __aeabi_fsub(float a, float b);
812 float __aeabi_fdiv(float a, float b);
813 float __aeabi_fmul(float a, float b);
814 float fmodf(float a, float b);
815
Ben Chenge9695e52009-06-16 16:11:47 -0700816 reg0 = selectFirstRegister(cUnit, vSrc2, false);
817 reg1 = NEXT_REG(reg0);
818
Ben Chengba4fc8b2009-06-01 13:00:29 -0700819 switch (mir->dalvikInsn.opCode) {
820 case OP_ADD_FLOAT_2ADDR:
821 case OP_ADD_FLOAT:
822 funct = (void*) __aeabi_fadd;
823 break;
824 case OP_SUB_FLOAT_2ADDR:
825 case OP_SUB_FLOAT:
826 funct = (void*) __aeabi_fsub;
827 break;
828 case OP_DIV_FLOAT_2ADDR:
829 case OP_DIV_FLOAT:
830 funct = (void*) __aeabi_fdiv;
831 break;
832 case OP_MUL_FLOAT_2ADDR:
833 case OP_MUL_FLOAT:
834 funct = (void*) __aeabi_fmul;
835 break;
836 case OP_REM_FLOAT_2ADDR:
837 case OP_REM_FLOAT:
838 funct = (void*) fmodf;
839 break;
840 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -0700841 loadValue(cUnit, vSrc2, reg0);
842 loadConstant(cUnit, reg1, 0x80000000);
843 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg0, reg0, reg1);
844 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700845 return false;
846 }
847 default:
848 return true;
849 }
850 loadConstant(cUnit, r2, (int)funct);
851 loadValue(cUnit, vSrc1, r0);
852 loadValue(cUnit, vSrc2, r1);
853 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
854 storeValue(cUnit, r0, vDest, r1);
855 return false;
856}
857
Bill Buzbeed45ba372009-06-15 17:00:57 -0700858bool dvmCompilerGenArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
859 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700860{
861 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -0700862 int reg0, reg1, reg2;
863
Ben Chengba4fc8b2009-06-01 13:00:29 -0700864 /* TODO: use a proper include file to define these */
865 double __aeabi_dadd(double a, double b);
866 double __aeabi_dsub(double a, double b);
867 double __aeabi_ddiv(double a, double b);
868 double __aeabi_dmul(double a, double b);
869 double fmod(double a, double b);
870
Ben Chenge9695e52009-06-16 16:11:47 -0700871 reg0 = selectFirstRegister(cUnit, vSrc2, true);
872 reg1 = NEXT_REG(reg0);
873 reg2 = NEXT_REG(reg1);
874
Ben Chengba4fc8b2009-06-01 13:00:29 -0700875 switch (mir->dalvikInsn.opCode) {
876 case OP_ADD_DOUBLE_2ADDR:
877 case OP_ADD_DOUBLE:
878 funct = (void*) __aeabi_dadd;
879 break;
880 case OP_SUB_DOUBLE_2ADDR:
881 case OP_SUB_DOUBLE:
882 funct = (void*) __aeabi_dsub;
883 break;
884 case OP_DIV_DOUBLE_2ADDR:
885 case OP_DIV_DOUBLE:
886 funct = (void*) __aeabi_ddiv;
887 break;
888 case OP_MUL_DOUBLE_2ADDR:
889 case OP_MUL_DOUBLE:
890 funct = (void*) __aeabi_dmul;
891 break;
892 case OP_REM_DOUBLE_2ADDR:
893 case OP_REM_DOUBLE:
894 funct = (void*) fmod;
895 break;
896 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -0700897 loadValuePair(cUnit, vSrc2, reg0, reg1);
898 loadConstant(cUnit, reg2, 0x80000000);
899 newLIR3(cUnit, ARMV5TE_ADD_RRR, reg1, reg1, reg2);
900 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700901 return false;
902 }
903 default:
904 return true;
905 }
Ben Chenge9695e52009-06-16 16:11:47 -0700906 /*
907 * Don't optimize the regsiter usage here as they are governed by the EABI
908 * calling convention.
909 */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700910 loadConstant(cUnit, r4PC, (int)funct);
911 loadValuePair(cUnit, vSrc1, r0, r1);
912 loadValuePair(cUnit, vSrc2, r2, r3);
913 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
914 storeValuePair(cUnit, r0, r1, vDest, r2);
915 return false;
916}
917
918static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
919 int vSrc1, int vSrc2)
920{
921 int firstOp = ARMV5TE_BKPT;
922 int secondOp = ARMV5TE_BKPT;
923 bool callOut = false;
924 void *callTgt;
925 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -0700926 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700927 /* TODO - find proper .h file to declare these */
928 long long __aeabi_ldivmod(long long op1, long long op2);
929
930 switch (mir->dalvikInsn.opCode) {
931 case OP_NOT_LONG:
932 firstOp = ARMV5TE_MVN;
933 secondOp = ARMV5TE_MVN;
934 break;
935 case OP_ADD_LONG:
936 case OP_ADD_LONG_2ADDR:
937 firstOp = ARMV5TE_ADD_RRR;
938 secondOp = ARMV5TE_ADC;
939 break;
940 case OP_SUB_LONG:
941 case OP_SUB_LONG_2ADDR:
942 firstOp = ARMV5TE_SUB_RRR;
943 secondOp = ARMV5TE_SBC;
944 break;
945 case OP_MUL_LONG:
946 case OP_MUL_LONG_2ADDR:
947 loadValuePair(cUnit, vSrc1, r0, r1);
948 loadValuePair(cUnit, vSrc2, r2, r3);
949 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
950 storeValuePair(cUnit, r0, r1, vDest, r2);
951 return false;
952 break;
953 case OP_DIV_LONG:
954 case OP_DIV_LONG_2ADDR:
955 callOut = true;
956 retReg = r0;
957 callTgt = (void*)__aeabi_ldivmod;
958 break;
959 /* NOTE - result is in r2/r3 instead of r0/r1 */
960 case OP_REM_LONG:
961 case OP_REM_LONG_2ADDR:
962 callOut = true;
963 callTgt = (void*)__aeabi_ldivmod;
964 retReg = r2;
965 break;
966 case OP_AND_LONG:
967 case OP_AND_LONG_2ADDR:
968 firstOp = ARMV5TE_AND_RR;
969 secondOp = ARMV5TE_AND_RR;
970 break;
971 case OP_OR_LONG:
972 case OP_OR_LONG_2ADDR:
973 firstOp = ARMV5TE_ORR;
974 secondOp = ARMV5TE_ORR;
975 break;
976 case OP_XOR_LONG:
977 case OP_XOR_LONG_2ADDR:
978 firstOp = ARMV5TE_EOR;
979 secondOp = ARMV5TE_EOR;
980 break;
Ben Chenge9695e52009-06-16 16:11:47 -0700981 case OP_NEG_LONG: {
982 reg0 = selectFirstRegister(cUnit, vSrc2, true);
983 reg1 = NEXT_REG(reg0);
984 reg2 = NEXT_REG(reg1);
985 reg3 = NEXT_REG(reg2);
986
987 loadValuePair(cUnit, vSrc2, reg0, reg1);
988 loadConstant(cUnit, reg3, 0);
989 newLIR3(cUnit, ARMV5TE_SUB_RRR, reg2, reg3, reg0);
990 newLIR2(cUnit, ARMV5TE_SBC, reg3, reg1);
991 storeValuePair(cUnit, r0, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700992 return false;
Ben Chenge9695e52009-06-16 16:11:47 -0700993 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700994 default:
995 LOGE("Invalid long arith op");
996 dvmAbort();
997 }
998 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -0700999 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1000 reg1 = NEXT_REG(reg0);
1001 reg2 = NEXT_REG(reg1);
1002 reg3 = NEXT_REG(reg2);
1003
1004 loadValuePair(cUnit, vSrc1, reg0, reg1);
1005 loadValuePair(cUnit, vSrc2, reg2, reg3);
1006 genBinaryOpWide(cUnit, vDest, firstOp, secondOp, reg0, reg2);
1007 /*
1008 * Don't optimize the regsiter usage here as they are governed by the EABI
1009 * calling convention.
1010 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001011 } else {
1012 loadValuePair(cUnit, vSrc2, r2, r3);
1013 loadConstant(cUnit, r4PC, (int) callTgt);
1014 loadValuePair(cUnit, vSrc1, r0, r1);
1015 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1016 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1017 }
1018 return false;
1019}
1020
1021static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1022 int vSrc1, int vSrc2)
1023{
1024 int armOp = ARMV5TE_BKPT;
1025 bool callOut = false;
1026 bool checkZero = false;
1027 int retReg = r0;
1028 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001029 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001030
1031 /* TODO - find proper .h file to declare these */
1032 int __aeabi_idivmod(int op1, int op2);
1033 int __aeabi_idiv(int op1, int op2);
1034
1035 switch (mir->dalvikInsn.opCode) {
1036 case OP_NEG_INT:
1037 armOp = ARMV5TE_NEG;
1038 break;
1039 case OP_NOT_INT:
1040 armOp = ARMV5TE_MVN;
1041 break;
1042 case OP_ADD_INT:
1043 case OP_ADD_INT_2ADDR:
1044 armOp = ARMV5TE_ADD_RRR;
1045 break;
1046 case OP_SUB_INT:
1047 case OP_SUB_INT_2ADDR:
1048 armOp = ARMV5TE_SUB_RRR;
1049 break;
1050 case OP_MUL_INT:
1051 case OP_MUL_INT_2ADDR:
1052 armOp = ARMV5TE_MUL;
1053 break;
1054 case OP_DIV_INT:
1055 case OP_DIV_INT_2ADDR:
1056 callOut = true;
1057 checkZero = true;
1058 callTgt = __aeabi_idiv;
1059 retReg = r0;
1060 break;
1061 /* NOTE: returns in r1 */
1062 case OP_REM_INT:
1063 case OP_REM_INT_2ADDR:
1064 callOut = true;
1065 checkZero = true;
1066 callTgt = __aeabi_idivmod;
1067 retReg = r1;
1068 break;
1069 case OP_AND_INT:
1070 case OP_AND_INT_2ADDR:
1071 armOp = ARMV5TE_AND_RR;
1072 break;
1073 case OP_OR_INT:
1074 case OP_OR_INT_2ADDR:
1075 armOp = ARMV5TE_ORR;
1076 break;
1077 case OP_XOR_INT:
1078 case OP_XOR_INT_2ADDR:
1079 armOp = ARMV5TE_EOR;
1080 break;
1081 case OP_SHL_INT:
1082 case OP_SHL_INT_2ADDR:
1083 armOp = ARMV5TE_LSLV;
1084 break;
1085 case OP_SHR_INT:
1086 case OP_SHR_INT_2ADDR:
1087 armOp = ARMV5TE_ASRV;
1088 break;
1089 case OP_USHR_INT:
1090 case OP_USHR_INT_2ADDR:
1091 armOp = ARMV5TE_LSRV;
1092 break;
1093 default:
1094 LOGE("Invalid word arith op: 0x%x(%d)",
1095 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1096 dvmAbort();
1097 }
1098 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001099 /* Try to allocate reg0 to the currently cached source operand */
1100 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1101 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1102 reg1 = NEXT_REG(reg0);
1103 regDest = NEXT_REG(reg1);
1104
1105 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1106 loadValue(cUnit, vSrc2, reg1);
1107 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
1108 } else {
1109 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1110 reg1 = NEXT_REG(reg0);
1111 regDest = NEXT_REG(reg1);
1112
1113 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1114 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
1115 genBinaryOp(cUnit, vDest, armOp, reg1, reg0, regDest);
1116 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001117 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001118 /*
1119 * Load the callout target first since it will never be eliminated
1120 * and its value will be used first.
1121 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001122 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001123 /*
1124 * Load vSrc2 first if it is not cached in a native register or it
1125 * is in r0 which will be clobbered if vSrc1 is loaded first.
1126 */
1127 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1128 cUnit->registerScoreboard.nativeReg == r0) {
1129 /* Cannot be optimized and won't clobber r0 */
1130 loadValue(cUnit, vSrc2, r1);
1131 /* May be optimized if vSrc1 is cached */
1132 loadValue(cUnit, vSrc1, r0);
1133 } else {
1134 loadValue(cUnit, vSrc1, r0);
1135 loadValue(cUnit, vSrc2, r1);
1136 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001137 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001138 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001139 }
1140 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1141 storeValue(cUnit, retReg, vDest, r2);
1142 }
1143 return false;
1144}
1145
1146static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1147{
1148 OpCode opCode = mir->dalvikInsn.opCode;
1149 int vA = mir->dalvikInsn.vA;
1150 int vB = mir->dalvikInsn.vB;
1151 int vC = mir->dalvikInsn.vC;
1152
1153 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1154 return genArithOpLong(cUnit,mir, vA, vA, vB);
1155 }
1156 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1157 return genArithOpLong(cUnit,mir, vA, vB, vC);
1158 }
1159 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1160 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1161 }
1162 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1163 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1164 }
1165 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1166 return genArithOpInt(cUnit,mir, vA, vA, vB);
1167 }
1168 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1169 return genArithOpInt(cUnit,mir, vA, vB, vC);
1170 }
1171 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001172 return dvmCompilerGenArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001173 }
1174 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001175 return dvmCompilerGenArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001176 }
1177 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001178 return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001179 }
1180 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07001181 return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001182 }
1183 return true;
1184}
1185
Bill Buzbeed45ba372009-06-15 17:00:57 -07001186static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1187 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001188{
Ben Chenge9695e52009-06-16 16:11:47 -07001189 /*
1190 * Don't optimize the register usage since it calls out to template
1191 * functions
1192 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001193 loadConstant(cUnit, r2, (int)funct);
1194 if (srcSize == 1) {
1195 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1196 } else {
1197 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1198 }
1199 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1200 if (tgtSize == 1) {
1201 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1202 } else {
1203 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1204 }
1205 return false;
1206}
1207
1208/* Experimental example of completely inlining a native replacement */
1209static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
1210{
Ben Chenge9695e52009-06-16 16:11:47 -07001211 /* Don't optimize the register usage */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001212 int offset = (int) &((InterpState *) NULL)->retval;
1213 DecodedInstruction *dInsn = &mir->dalvikInsn;
1214 assert(dInsn->vA == 1);
1215 loadValue(cUnit, dInsn->arg[0], r0);
1216 loadConstant(cUnit, r1, gDvm.offJavaLangString_count);
Ben Chenge9695e52009-06-16 16:11:47 -07001217 genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001218 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r1);
1219 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1220 return false;
1221}
1222
1223static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1224 DecodedInstruction *dInsn,
1225 Armv5teLIR **pcrLabel)
1226{
1227 unsigned int i;
1228 unsigned int regMask = 0;
1229
1230 /* Load arguments to r0..r4 */
1231 for (i = 0; i < dInsn->vA; i++) {
1232 regMask |= 1 << i;
1233 loadValue(cUnit, dInsn->arg[i], i);
1234 }
1235 if (regMask) {
1236 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
1237 newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
1238 newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
1239 sizeof(StackSaveArea) + (dInsn->vA << 2));
1240 /* generate null check */
1241 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001242 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1243 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001244 }
1245 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1246 }
1247}
1248
1249static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1250 DecodedInstruction *dInsn,
1251 Armv5teLIR **pcrLabel)
1252{
1253 int srcOffset = dInsn->vC << 2;
1254 int numArgs = dInsn->vA;
1255 int regMask;
1256 /*
1257 * r4PC : &rFP[vC]
1258 * r7: &newFP[0]
1259 */
1260 if (srcOffset < 8) {
1261 newLIR3(cUnit, ARMV5TE_ADD_RRI3, r4PC, rFP, srcOffset);
1262 } else {
1263 loadConstant(cUnit, r4PC, srcOffset);
1264 newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, rFP, r4PC);
1265 }
1266 /* load [r0 .. min(numArgs,4)] */
1267 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
1268 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1269
1270 if (sizeof(StackSaveArea) + (numArgs << 2) < 256) {
1271 newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
1272 newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
1273 sizeof(StackSaveArea) + (numArgs << 2));
1274 } else {
1275 loadConstant(cUnit, r7, sizeof(StackSaveArea) + (numArgs << 2));
1276 newLIR3(cUnit, ARMV5TE_SUB_RRR, r7, rFP, r7);
1277 }
1278
1279 /* generate null check */
1280 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001281 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001282 }
1283
1284 /*
1285 * Handle remaining 4n arguments:
1286 * store previously loaded 4 values and load the next 4 values
1287 */
1288 if (numArgs >= 8) {
1289 Armv5teLIR *loopLabel = NULL;
1290 /*
1291 * r0 contains "this" and it will be used later, so push it to the stack
1292 * first. Pushing r5 is just for stack alignment purposes.
1293 */
1294 newLIR1(cUnit, ARMV5TE_PUSH, 1 << r0 | 1 << 5);
1295 /* No need to generate the loop structure if numArgs <= 11 */
1296 if (numArgs > 11) {
1297 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
1298 loopLabel = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1299 }
1300 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1301 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1302 /* No need to generate the loop structure if numArgs <= 11 */
1303 if (numArgs > 11) {
1304 newLIR2(cUnit, ARMV5TE_SUB_RI8, 5, 4);
1305 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1306 }
1307 }
1308
1309 /* Save the last batch of loaded values */
1310 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1311
1312 /* Generate the loop epilogue - don't use r0 */
1313 if ((numArgs > 4) && (numArgs % 4)) {
1314 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
1315 newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
1316 }
1317 if (numArgs >= 8)
1318 newLIR1(cUnit, ARMV5TE_POP, 1 << r0 | 1 << 5);
1319
1320 /* Save the modulo 4 arguments */
1321 if ((numArgs > 4) && (numArgs % 4)) {
1322 newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
1323 }
1324}
1325
1326static void genInvokeCommon(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1327 Armv5teLIR *labelList, Armv5teLIR *pcrLabel,
1328 const Method *calleeMethod)
1329{
1330 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
1331
1332 /* r1 = &retChainingCell */
1333 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
1334 r1, 0);
1335 /* r4PC = dalvikCallsite */
1336 loadConstant(cUnit, r4PC,
1337 (int) (cUnit->method->insns + mir->offset));
1338 addrRetChain->generic.target = (LIR *) retChainingCell;
1339 /*
1340 * r0 = calleeMethod (loaded upon calling genInvokeCommon)
1341 * r1 = &ChainingCell
1342 * r4PC = callsiteDPC
1343 */
1344 if (dvmIsNativeMethod(calleeMethod)) {
1345 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1346#if defined(INVOKE_STATS)
1347 gDvmJit.invokeNoOpt++;
1348#endif
1349 } else {
1350 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1351#if defined(INVOKE_STATS)
1352 gDvmJit.invokeChain++;
1353#endif
1354 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1355 }
1356 /* Handle exceptions using the interpreter */
1357 genTrap(cUnit, mir->offset, pcrLabel);
1358}
1359
1360/* Geneate a branch to go back to the interpreter */
1361static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1362{
1363 /* r0 = dalvik pc */
1364 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
1365 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
1366 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
1367 newLIR1(cUnit, ARMV5TE_BLX_R, r1);
1368}
1369
1370/*
1371 * Attempt to single step one instruction using the interpreter and return
1372 * to the compiled code for the next Dalvik instruction
1373 */
1374static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1375{
1376 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1377 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1378 kInstrCanThrow;
1379 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1380 genPuntToInterp(cUnit, mir->offset);
1381 return;
1382 }
1383 int entryAddr = offsetof(InterpState,
1384 jitToInterpEntries.dvmJitToInterpSingleStep);
1385 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
1386 /* r0 = dalvik pc */
1387 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1388 /* r1 = dalvik pc of following instruction */
1389 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
1390 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1391}
1392
1393
1394/*****************************************************************************/
1395/*
1396 * The following are the first-level codegen routines that analyze the format
1397 * of each bytecode then either dispatch special purpose codegen routines
1398 * or produce corresponding Thumb instructions directly.
1399 */
1400
1401static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
1402 BasicBlock *bb, Armv5teLIR *labelList)
1403{
1404 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1405 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1406 return false;
1407}
1408
1409static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1410{
1411 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1412 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1413 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1414 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1415 return true;
1416 }
1417 switch (dalvikOpCode) {
1418 case OP_RETURN_VOID:
1419 genReturnCommon(cUnit,mir);
1420 break;
1421 case OP_UNUSED_73:
1422 case OP_UNUSED_79:
1423 case OP_UNUSED_7A:
1424 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1425 return true;
1426 case OP_NOP:
1427 break;
1428 default:
1429 return true;
1430 }
1431 return false;
1432}
1433
1434static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1435{
Ben Chenge9695e52009-06-16 16:11:47 -07001436 int reg0, reg1, reg2;
1437
Ben Chengba4fc8b2009-06-01 13:00:29 -07001438 switch (mir->dalvikInsn.opCode) {
1439 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001440 case OP_CONST_4: {
1441 /* Avoid using the previously used register */
1442 reg0 = selectFirstRegister(cUnit, vNone, false);
1443 reg1 = NEXT_REG(reg0);
1444 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1445 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001446 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001447 }
1448 case OP_CONST_WIDE_32: {
1449 /* Avoid using the previously used register */
1450 reg0 = selectFirstRegister(cUnit, vNone, true);
1451 reg1 = NEXT_REG(reg0);
1452 reg2 = NEXT_REG(reg1);
1453 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1454 newLIR3(cUnit, ARMV5TE_ASR, reg1, reg0, 31);
1455 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001456 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001457 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001458 default:
1459 return true;
1460 }
1461 return false;
1462}
1463
1464static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1465{
Ben Chenge9695e52009-06-16 16:11:47 -07001466 int reg0, reg1, reg2;
1467
1468 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001469 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001470 case OP_CONST_HIGH16: {
1471 reg0 = selectFirstRegister(cUnit, vNone, false);
1472 reg1 = NEXT_REG(reg0);
1473 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1474 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001475 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001476 }
1477 case OP_CONST_WIDE_HIGH16: {
1478 reg0 = selectFirstRegister(cUnit, vNone, true);
1479 reg1 = NEXT_REG(reg0);
1480 reg2 = NEXT_REG(reg1);
1481 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1482 loadConstant(cUnit, reg0, 0);
1483 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001484 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001485 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001486 default:
1487 return true;
1488 }
1489 return false;
1490}
1491
1492static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1493{
1494 /* For OP_THROW_VERIFICATION_ERROR */
1495 genInterpSingleStep(cUnit, mir);
1496 return false;
1497}
1498
1499static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1500{
Ben Chenge9695e52009-06-16 16:11:47 -07001501 /* Native register to use if the interested value is vA */
1502 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1503 /* Native register to use if source is not from Dalvik registers */
1504 int regvNone = selectFirstRegister(cUnit, vNone, false);
1505 /* Similar to regvA but for 64-bit values */
1506 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1507 /* Similar to regvNone but for 64-bit values */
1508 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1509
Ben Chengba4fc8b2009-06-01 13:00:29 -07001510 switch (mir->dalvikInsn.opCode) {
1511 /*
1512 * TODO: Verify that we can ignore the resolution check here because
1513 * it will have already successfully been interpreted once
1514 */
1515 case OP_CONST_STRING_JUMBO:
1516 case OP_CONST_STRING: {
1517 void *strPtr = (void*)
1518 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1519 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001520 loadConstant(cUnit, regvNone, (int) strPtr );
1521 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001522 break;
1523 }
1524 /*
1525 * TODO: Verify that we can ignore the resolution check here because
1526 * it will have already successfully been interpreted once
1527 */
1528 case OP_CONST_CLASS: {
1529 void *classPtr = (void*)
1530 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1531 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001532 loadConstant(cUnit, regvNone, (int) classPtr );
1533 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001534 break;
1535 }
1536 case OP_SGET_OBJECT:
1537 case OP_SGET_BOOLEAN:
1538 case OP_SGET_CHAR:
1539 case OP_SGET_BYTE:
1540 case OP_SGET_SHORT:
1541 case OP_SGET: {
1542 int valOffset = (int)&((struct StaticField*)NULL)->value;
1543 void *fieldPtr = (void*)
1544 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1545 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001546 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
1547 newLIR3(cUnit, ARMV5TE_LDR_RRI5, regvNone, regvNone, 0);
1548 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001549 break;
1550 }
1551 case OP_SGET_WIDE: {
1552 int valOffset = (int)&((struct StaticField*)NULL)->value;
1553 void *fieldPtr = (void*)
1554 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001555 int reg0, reg1, reg2;
1556
Ben Chengba4fc8b2009-06-01 13:00:29 -07001557 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001558 reg0 = regvNoneWide;
1559 reg1 = NEXT_REG(reg0);
1560 reg2 = NEXT_REG(reg1);
1561 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
1562 newLIR2(cUnit, ARMV5TE_LDMIA, reg2, (1<<reg0 | 1<<reg1));
1563 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001564 break;
1565 }
1566 case OP_SPUT_OBJECT:
1567 case OP_SPUT_BOOLEAN:
1568 case OP_SPUT_CHAR:
1569 case OP_SPUT_BYTE:
1570 case OP_SPUT_SHORT:
1571 case OP_SPUT: {
1572 int valOffset = (int)&((struct StaticField*)NULL)->value;
1573 void *fieldPtr = (void*)
1574 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001575
Ben Chengba4fc8b2009-06-01 13:00:29 -07001576 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001577 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
1578 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
1579 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
1580 newLIR3(cUnit, ARMV5TE_STR_RRI5, regvA, NEXT_REG(regvA), 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001581 break;
1582 }
1583 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001584 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001585 int valOffset = (int)&((struct StaticField*)NULL)->value;
1586 void *fieldPtr = (void*)
1587 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001588
Ben Chengba4fc8b2009-06-01 13:00:29 -07001589 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001590 reg0 = regvAWide;
1591 reg1 = NEXT_REG(reg0);
1592 reg2 = NEXT_REG(reg1);
1593 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1594 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
1595 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
1596 newLIR2(cUnit, ARMV5TE_STMIA, reg2, (1<<reg0 | 1<<reg1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001597 break;
1598 }
1599 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001600 /*
1601 * Obey the calling convention and don't mess with the register
1602 * usage.
1603 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001604 ClassObject *classPtr = (void*)
1605 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1606 assert(classPtr != NULL);
1607 assert(classPtr->status & CLASS_INITIALIZED);
1608 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
1609 /* It's going to throw, just let the interp. deal with it. */
1610 genInterpSingleStep(cUnit, mir);
1611 return false;
1612 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001613 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07001614 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001615 genExportPC(cUnit, mir, r2, r3 );
1616 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
1617 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1618 /*
1619 * TODO: As coded, we'll bail and reinterpret on alloc failure.
1620 * Need a general mechanism to bail to thrown exception code.
1621 */
Ben Chenge9695e52009-06-16 16:11:47 -07001622 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001623 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1624 break;
1625 }
1626 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07001627 /*
1628 * Obey the calling convention and don't mess with the register
1629 * usage.
1630 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001631 ClassObject *classPtr =
1632 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1633 loadConstant(cUnit, r1, (int) classPtr );
1634 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
1635 /*
1636 * TODO - in theory classPtr should be resoved by the time this
1637 * instruction made into a trace, but we are seeing NULL at runtime
1638 * so this check is temporarily used as a workaround.
1639 */
Ben Chenge9695e52009-06-16 16:11:47 -07001640 Armv5teLIR * pcrLabel = genZeroCheck(cUnit, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001641 newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
1642 Armv5teLIR *branch1 =
1643 newLIR2(cUnit, ARMV5TE_B_COND, 4, ARM_COND_EQ);
1644 /* r0 now contains object->clazz */
1645 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
1646 offsetof(Object, clazz) >> 2);
1647 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
1648 newLIR2(cUnit, ARMV5TE_CMP_RR, r0, r1);
1649 Armv5teLIR *branch2 =
1650 newLIR2(cUnit, ARMV5TE_B_COND, 2, ARM_COND_EQ);
1651 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
1652 /* check cast failed - punt to the interpreter */
Ben Chenge9695e52009-06-16 16:11:47 -07001653 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001654 /* check cast passed - branch target here */
1655 Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
1656 branch1->generic.target = (LIR *)target;
1657 branch2->generic.target = (LIR *)target;
1658 break;
1659 }
1660 default:
1661 return true;
1662 }
1663 return false;
1664}
1665
1666static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1667{
1668 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1669 switch (dalvikOpCode) {
1670 case OP_MOVE_EXCEPTION: {
1671 int offset = offsetof(InterpState, self);
1672 int exOffset = offsetof(Thread, exception);
Ben Chenge9695e52009-06-16 16:11:47 -07001673 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, offset >> 2);
1674 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r1, exOffset >> 2);
1675 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001676 break;
1677 }
1678 case OP_MOVE_RESULT:
1679 case OP_MOVE_RESULT_OBJECT: {
1680 int offset = offsetof(InterpState, retval);
1681 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1682 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1683 break;
1684 }
1685 case OP_MOVE_RESULT_WIDE: {
1686 int offset = offsetof(InterpState, retval);
1687 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1688 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
1689 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1690 break;
1691 }
1692 case OP_RETURN_WIDE: {
1693 loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
1694 int offset = offsetof(InterpState, retval);
1695 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1696 newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
1697 genReturnCommon(cUnit,mir);
1698 break;
1699 }
1700 case OP_RETURN:
1701 case OP_RETURN_OBJECT: {
1702 loadValue(cUnit, mir->dalvikInsn.vA, r0);
1703 int offset = offsetof(InterpState, retval);
1704 newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
1705 genReturnCommon(cUnit,mir);
1706 break;
1707 }
1708 /*
1709 * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
1710 * a failure on lock/unlock will cause us to revert to the interpeter
1711 * to try again. This means we essentially ignore the first failure on
1712 * the assumption that the interpreter will correctly handle the 2nd.
1713 */
1714 case OP_MONITOR_ENTER:
1715 case OP_MONITOR_EXIT: {
1716 int offset = offsetof(InterpState, self);
1717 loadValue(cUnit, mir->dalvikInsn.vA, r1);
1718 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
1719 if (dalvikOpCode == OP_MONITOR_ENTER) {
1720 loadConstant(cUnit, r2, (int)dvmLockObject);
1721 } else {
1722 loadConstant(cUnit, r2, (int)dvmUnlockObject);
1723 }
1724 /*
1725 * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
1726 * Lock/unlock won't throw, and this code does not support
1727 * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
1728 */
Ben Chenge9695e52009-06-16 16:11:47 -07001729 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001730 /* Do the call */
1731 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
1732 break;
1733 }
1734 case OP_THROW: {
1735 genInterpSingleStep(cUnit, mir);
1736 break;
1737 }
1738 default:
1739 return true;
1740 }
1741 return false;
1742}
1743
Bill Buzbeed45ba372009-06-15 17:00:57 -07001744bool dvmCompilerGenConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001745{
1746 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001747
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748 float __aeabi_i2f( int op1 );
1749 int __aeabi_f2iz( float op1 );
1750 float __aeabi_d2f( double op1 );
1751 double __aeabi_f2d( float op1 );
1752 double __aeabi_i2d( int op1 );
1753 int __aeabi_d2iz( double op1 );
1754 long __aeabi_f2lz( float op1 );
1755 float __aeabi_l2f( long op1 );
1756 long __aeabi_d2lz( double op1 );
1757 double __aeabi_l2d( long op1 );
1758
Bill Buzbeed45ba372009-06-15 17:00:57 -07001759 switch (opCode) {
1760 case OP_INT_TO_FLOAT:
1761 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
1762 case OP_FLOAT_TO_INT:
1763 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
1764 case OP_DOUBLE_TO_FLOAT:
1765 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
1766 case OP_FLOAT_TO_DOUBLE:
1767 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
1768 case OP_INT_TO_DOUBLE:
1769 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
1770 case OP_DOUBLE_TO_INT:
1771 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
1772 case OP_FLOAT_TO_LONG:
1773 return genConversionCall(cUnit, mir, (void*)__aeabi_f2lz, 1, 2);
1774 case OP_LONG_TO_FLOAT:
1775 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
1776 case OP_DOUBLE_TO_LONG:
1777 return genConversionCall(cUnit, mir, (void*)__aeabi_d2lz, 2, 2);
1778 case OP_LONG_TO_DOUBLE:
1779 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
1780 default:
1781 return true;
1782 }
1783 return false;
1784}
1785
1786static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1787{
1788 OpCode opCode = mir->dalvikInsn.opCode;
1789 int vSrc1Dest = mir->dalvikInsn.vA;
1790 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001791 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07001792
1793 /* TODO - find the proper include file to declare these */
1794
Ben Chengba4fc8b2009-06-01 13:00:29 -07001795 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
1796 return genArithOp( cUnit, mir );
1797 }
1798
Ben Chenge9695e52009-06-16 16:11:47 -07001799 /*
1800 * If data type is 64-bit, re-calculate the register numbers in the
1801 * corresponding cases.
1802 */
1803 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1804 reg1 = NEXT_REG(reg0);
1805 reg2 = NEXT_REG(reg1);
1806
Ben Chengba4fc8b2009-06-01 13:00:29 -07001807 switch (opCode) {
1808 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001809 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001810 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001811 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001812 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001813 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001814 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001815 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001816 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001817 case OP_LONG_TO_DOUBLE:
Bill Buzbeed45ba372009-06-15 17:00:57 -07001818 return dvmCompilerGenConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001819 case OP_NEG_INT:
1820 case OP_NOT_INT:
1821 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
1822 case OP_NEG_LONG:
1823 case OP_NOT_LONG:
1824 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
1825 case OP_NEG_FLOAT:
Bill Buzbeed45ba372009-06-15 17:00:57 -07001826 return dvmCompilerGenArithOpFloat(cUnit, mir, vSrc1Dest,
1827 vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001828 case OP_NEG_DOUBLE:
Bill Buzbeed45ba372009-06-15 17:00:57 -07001829 return dvmCompilerGenArithOpDouble(cUnit, mir, vSrc1Dest,
1830 vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07001831 case OP_MOVE_WIDE: {
1832 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1833 reg1 = NEXT_REG(reg0);
1834 reg2 = NEXT_REG(reg1);
1835
1836 loadValuePair(cUnit, vSrc2, reg0, reg1);
1837 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001838 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001839 }
1840 case OP_INT_TO_LONG: {
1841 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1842 reg1 = NEXT_REG(reg0);
1843 reg2 = NEXT_REG(reg1);
1844
1845 loadValue(cUnit, mir->dalvikInsn.vB, reg0);
1846 newLIR3(cUnit, ARMV5TE_ASR, reg1, reg0, 31);
1847 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001848 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001849 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001850 case OP_MOVE:
1851 case OP_MOVE_OBJECT:
1852 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07001853 loadValue(cUnit, vSrc2, reg0);
1854 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001855 break;
1856 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07001857 loadValue(cUnit, vSrc2, reg0);
1858 newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 24);
1859 newLIR3(cUnit, ARMV5TE_ASR, reg0, reg0, 24);
1860 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001861 break;
1862 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07001863 loadValue(cUnit, vSrc2, reg0);
1864 newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 16);
1865 newLIR3(cUnit, ARMV5TE_ASR, reg0, reg0, 16);
1866 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001867 break;
1868 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07001869 loadValue(cUnit, vSrc2, reg0);
1870 newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 16);
1871 newLIR3(cUnit, ARMV5TE_LSR, reg0, reg0, 16);
1872 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001873 break;
1874 case OP_ARRAY_LENGTH: {
1875 int lenOffset = offsetof(ArrayObject, length);
Ben Chenge9695e52009-06-16 16:11:47 -07001876 loadValue(cUnit, vSrc2, reg0);
1877 genNullCheck(cUnit, vSrc2, reg0, mir->offset, NULL);
1878 newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg0, lenOffset >> 2);
1879 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001880 break;
1881 }
1882 default:
1883 return true;
1884 }
1885 return false;
1886}
1887
1888static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1889{
1890 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07001891 int reg0, reg1, reg2;
1892
Ben Chengba4fc8b2009-06-01 13:00:29 -07001893 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
1894 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07001895 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001896 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07001897
1898 reg0 = selectFirstRegister(cUnit, vNone, true);
1899 reg1 = NEXT_REG(reg0);
1900 reg2 = NEXT_REG(reg1);
1901
1902 loadConstant(cUnit, reg0, BBBB);
1903 loadConstant(cUnit, reg1, 0);
1904 if (BBBB < 0) {
1905 newLIR2(cUnit, ARMV5TE_SUB_RI8, reg1, -1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001906 }
1907
1908 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07001909 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001910 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07001911 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001912 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001913
Ben Chenge9695e52009-06-16 16:11:47 -07001914 reg0 = selectFirstRegister(cUnit, vNone, false);
1915 reg1 = NEXT_REG(reg0);
1916
1917 loadConstant(cUnit, reg0, BBBB);
1918 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001919 } else {
1920 return true;
1921 }
1922 return false;
1923}
1924
1925/* Compare agaist zero */
1926static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
1927 Armv5teLIR *labelList)
1928{
1929 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1930 Armv5teConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07001931 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001932
Ben Chenge9695e52009-06-16 16:11:47 -07001933 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
1934 newLIR2(cUnit, ARMV5TE_CMP_RI8, reg0, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001935
1936 switch (dalvikOpCode) {
1937 case OP_IF_EQZ:
1938 cond = ARM_COND_EQ;
1939 break;
1940 case OP_IF_NEZ:
1941 cond = ARM_COND_NE;
1942 break;
1943 case OP_IF_LTZ:
1944 cond = ARM_COND_LT;
1945 break;
1946 case OP_IF_GEZ:
1947 cond = ARM_COND_GE;
1948 break;
1949 case OP_IF_GTZ:
1950 cond = ARM_COND_GT;
1951 break;
1952 case OP_IF_LEZ:
1953 cond = ARM_COND_LE;
1954 break;
1955 default:
1956 cond = 0;
1957 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1958 dvmAbort();
1959 }
1960 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1961 /* This mostly likely will be optimized away in a later phase */
1962 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1963 return false;
1964}
1965
1966static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1967{
1968 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1969 int vSrc = mir->dalvikInsn.vB;
1970 int vDest = mir->dalvikInsn.vA;
1971 int lit = mir->dalvikInsn.vC;
1972 int armOp;
Ben Chenge9695e52009-06-16 16:11:47 -07001973 int reg0, reg1, regDest;
1974
1975 reg0 = selectFirstRegister(cUnit, vSrc, false);
1976 reg1 = NEXT_REG(reg0);
1977 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001978
1979 /* TODO: find the proper .h file to declare these */
1980 int __aeabi_idivmod(int op1, int op2);
1981 int __aeabi_idiv(int op1, int op2);
1982
1983 switch (dalvikOpCode) {
1984 case OP_ADD_INT_LIT8:
1985 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07001986 loadValue(cUnit, vSrc, reg0);
1987 if (lit <= 7 && lit >= 0) {
1988 newLIR3(cUnit, ARMV5TE_ADD_RRI3, regDest, reg0, lit);
1989 storeValue(cUnit, regDest, vDest, reg1);
1990 } else if (lit <= 255 && lit >= 0) {
1991 newLIR2(cUnit, ARMV5TE_ADD_RI8, reg0, lit);
1992 storeValue(cUnit, reg0, vDest, reg1);
1993 } else if (lit >= -7 && lit <= 0) {
1994 /* Convert to a small constant subtraction */
1995 newLIR3(cUnit, ARMV5TE_SUB_RRI3, regDest, reg0, -lit);
1996 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001997 } else if (lit >= -255 && lit <= 0) {
1998 /* Convert to a small constant subtraction */
Ben Chenge9695e52009-06-16 16:11:47 -07001999 newLIR2(cUnit, ARMV5TE_SUB_RI8, reg0, -lit);
2000 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002001 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07002002 loadConstant(cUnit, reg1, lit);
2003 genBinaryOp(cUnit, vDest, ARMV5TE_ADD_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002004 }
2005 break;
2006
2007 case OP_RSUB_INT_LIT8:
2008 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002009 loadValue(cUnit, vSrc, reg1);
2010 loadConstant(cUnit, reg0, lit);
2011 genBinaryOp(cUnit, vDest, ARMV5TE_SUB_RRR, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002012 break;
2013
2014 case OP_MUL_INT_LIT8:
2015 case OP_MUL_INT_LIT16:
2016 case OP_AND_INT_LIT8:
2017 case OP_AND_INT_LIT16:
2018 case OP_OR_INT_LIT8:
2019 case OP_OR_INT_LIT16:
2020 case OP_XOR_INT_LIT8:
2021 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002022 loadValue(cUnit, vSrc, reg0);
2023 loadConstant(cUnit, reg1, lit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002024 switch (dalvikOpCode) {
2025 case OP_MUL_INT_LIT8:
2026 case OP_MUL_INT_LIT16:
2027 armOp = ARMV5TE_MUL;
2028 break;
2029 case OP_AND_INT_LIT8:
2030 case OP_AND_INT_LIT16:
2031 armOp = ARMV5TE_AND_RR;
2032 break;
2033 case OP_OR_INT_LIT8:
2034 case OP_OR_INT_LIT16:
2035 armOp = ARMV5TE_ORR;
2036 break;
2037 case OP_XOR_INT_LIT8:
2038 case OP_XOR_INT_LIT16:
2039 armOp = ARMV5TE_EOR;
2040 break;
2041 default:
2042 dvmAbort();
2043 }
Ben Chenge9695e52009-06-16 16:11:47 -07002044 genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002045 break;
2046
2047 case OP_SHL_INT_LIT8:
2048 case OP_SHR_INT_LIT8:
2049 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002050 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002051 switch (dalvikOpCode) {
2052 case OP_SHL_INT_LIT8:
2053 armOp = ARMV5TE_LSL;
2054 break;
2055 case OP_SHR_INT_LIT8:
2056 armOp = ARMV5TE_ASR;
2057 break;
2058 case OP_USHR_INT_LIT8:
2059 armOp = ARMV5TE_LSR;
2060 break;
2061 default: dvmAbort();
2062 }
Ben Chenge9695e52009-06-16 16:11:47 -07002063 newLIR3(cUnit, armOp, reg0, reg0, lit);
2064 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002065 break;
2066
2067 case OP_DIV_INT_LIT8:
2068 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002069 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002070 if (lit == 0) {
2071 /* Let the interpreter deal with div by 0 */
2072 genInterpSingleStep(cUnit, mir);
2073 return false;
2074 }
2075 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2076 loadConstant(cUnit, r1, lit);
2077 loadValue(cUnit, vSrc, r0);
2078 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2079 storeValue(cUnit, r0, vDest, r2);
2080 break;
2081
2082 case OP_REM_INT_LIT8:
2083 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002084 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002085 if (lit == 0) {
2086 /* Let the interpreter deal with div by 0 */
2087 genInterpSingleStep(cUnit, mir);
2088 return false;
2089 }
2090 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2091 loadConstant(cUnit, r1, lit);
2092 loadValue(cUnit, vSrc, r0);
2093 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2094 storeValue(cUnit, r1, vDest, r2);
2095 break;
2096 default:
2097 return true;
2098 }
2099 return false;
2100}
2101
2102static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2103{
2104 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2105 int fieldOffset;
2106
2107 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2108 InstField *pInstField = (InstField *)
2109 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2110 int fieldOffset;
2111
2112 assert(pInstField != NULL);
2113 fieldOffset = pInstField->byteOffset;
2114 } else {
2115 /* To make the compiler happy */
2116 fieldOffset = 0;
2117 }
2118 switch (dalvikOpCode) {
2119 /*
2120 * TODO: I may be assuming too much here.
2121 * Verify what is known at JIT time.
2122 */
2123 case OP_NEW_ARRAY: {
2124 void *classPtr = (void*)
2125 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2126 assert(classPtr != NULL);
2127 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2128 loadConstant(cUnit, r0, (int) classPtr );
2129 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
2130 Armv5teLIR *pcrLabel =
2131 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2132 genExportPC(cUnit, mir, r2, r3 );
2133 newLIR2(cUnit, ARMV5TE_MOV_IMM,r2,ALLOC_DONT_TRACK);
2134 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2135 /*
2136 * TODO: As coded, we'll bail and reinterpret on alloc failure.
2137 * Need a general mechanism to bail to thrown exception code.
2138 */
Ben Chenge9695e52009-06-16 16:11:47 -07002139 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002140 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2141 break;
2142 }
2143 /*
2144 * TODO: I may be assuming too much here.
2145 * Verify what is known at JIT time.
2146 */
2147 case OP_INSTANCE_OF: {
2148 ClassObject *classPtr =
2149 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2150 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002151 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002152 loadConstant(cUnit, r2, (int) classPtr );
Ben Cheng752c7942009-06-22 10:50:07 -07002153 newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
2154 /* When taken r0 has NULL which can be used for store directly */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002155 Armv5teLIR *branch1 = newLIR2(cUnit, ARMV5TE_B_COND, 4,
2156 ARM_COND_EQ);
2157 /* r1 now contains object->clazz */
Ben Cheng752c7942009-06-22 10:50:07 -07002158 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0,
Ben Chengba4fc8b2009-06-01 13:00:29 -07002159 offsetof(Object, clazz) >> 2);
2160 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002161 loadConstant(cUnit, r0, 1); /* Assume true */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002162 newLIR2(cUnit, ARMV5TE_CMP_RR, r1, r2);
2163 Armv5teLIR *branch2 = newLIR2(cUnit, ARMV5TE_B_COND, 2,
2164 ARM_COND_EQ);
2165 newLIR2(cUnit, ARMV5TE_MOV_RR, r0, r1);
2166 newLIR2(cUnit, ARMV5TE_MOV_RR, r1, r2);
2167 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2168 /* branch target here */
2169 Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
2170 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2171 branch1->generic.target = (LIR *)target;
2172 branch2->generic.target = (LIR *)target;
2173 break;
2174 }
2175 case OP_IGET_WIDE:
2176 genIGetWide(cUnit, mir, fieldOffset);
2177 break;
2178 case OP_IGET:
2179 case OP_IGET_OBJECT:
2180 genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
2181 break;
2182 case OP_IGET_BOOLEAN:
2183 genIGet(cUnit, mir, ARMV5TE_LDRB_RRR, fieldOffset);
2184 break;
2185 case OP_IGET_BYTE:
2186 genIGet(cUnit, mir, ARMV5TE_LDRSB_RRR, fieldOffset);
2187 break;
2188 case OP_IGET_CHAR:
2189 genIGet(cUnit, mir, ARMV5TE_LDRH_RRR, fieldOffset);
2190 break;
2191 case OP_IGET_SHORT:
2192 genIGet(cUnit, mir, ARMV5TE_LDRSH_RRR, fieldOffset);
2193 break;
2194 case OP_IPUT_WIDE:
2195 genIPutWide(cUnit, mir, fieldOffset);
2196 break;
2197 case OP_IPUT:
2198 case OP_IPUT_OBJECT:
2199 genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
2200 break;
2201 case OP_IPUT_SHORT:
2202 case OP_IPUT_CHAR:
2203 genIPut(cUnit, mir, ARMV5TE_STRH_RRR, fieldOffset);
2204 break;
2205 case OP_IPUT_BYTE:
2206 case OP_IPUT_BOOLEAN:
2207 genIPut(cUnit, mir, ARMV5TE_STRB_RRR, fieldOffset);
2208 break;
2209 default:
2210 return true;
2211 }
2212 return false;
2213}
2214
2215static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2216{
2217 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2218 int fieldOffset = mir->dalvikInsn.vC;
2219 switch (dalvikOpCode) {
2220 case OP_IGET_QUICK:
2221 case OP_IGET_OBJECT_QUICK:
2222 genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
2223 break;
2224 case OP_IPUT_QUICK:
2225 case OP_IPUT_OBJECT_QUICK:
2226 genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
2227 break;
2228 case OP_IGET_WIDE_QUICK:
2229 genIGetWide(cUnit, mir, fieldOffset);
2230 break;
2231 case OP_IPUT_WIDE_QUICK:
2232 genIPutWide(cUnit, mir, fieldOffset);
2233 break;
2234 default:
2235 return true;
2236 }
2237 return false;
2238
2239}
2240
2241/* Compare agaist zero */
2242static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2243 Armv5teLIR *labelList)
2244{
2245 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2246 Armv5teConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002247 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002248
Ben Chenge9695e52009-06-16 16:11:47 -07002249 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2250 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2251 reg1 = NEXT_REG(reg0);
2252 /* Load vB first since vA can be fetched via a move */
2253 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2254 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2255 } else {
2256 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2257 reg1 = NEXT_REG(reg0);
2258 /* Load vA first since vB can be fetched via a move */
2259 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2260 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2261 }
2262 newLIR2(cUnit, ARMV5TE_CMP_RR, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002263
2264 switch (dalvikOpCode) {
2265 case OP_IF_EQ:
2266 cond = ARM_COND_EQ;
2267 break;
2268 case OP_IF_NE:
2269 cond = ARM_COND_NE;
2270 break;
2271 case OP_IF_LT:
2272 cond = ARM_COND_LT;
2273 break;
2274 case OP_IF_GE:
2275 cond = ARM_COND_GE;
2276 break;
2277 case OP_IF_GT:
2278 cond = ARM_COND_GT;
2279 break;
2280 case OP_IF_LE:
2281 cond = ARM_COND_LE;
2282 break;
2283 default:
2284 cond = 0;
2285 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2286 dvmAbort();
2287 }
2288 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2289 /* This mostly likely will be optimized away in a later phase */
2290 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2291 return false;
2292}
2293
2294static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2295{
2296 OpCode opCode = mir->dalvikInsn.opCode;
2297 int vSrc1Dest = mir->dalvikInsn.vA;
2298 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002299 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002300
2301 switch (opCode) {
2302 case OP_MOVE_16:
2303 case OP_MOVE_OBJECT_16:
2304 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002305 case OP_MOVE_OBJECT_FROM16: {
2306 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2307 reg1 = NEXT_REG(reg0);
2308 loadValue(cUnit, vSrc2, reg0);
2309 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002310 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002311 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002312 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002313 case OP_MOVE_WIDE_FROM16: {
2314 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2315 reg1 = NEXT_REG(reg0);
2316 reg2 = NEXT_REG(reg1);
2317 loadValuePair(cUnit, vSrc2, reg0, reg1);
2318 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002319 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002320 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002321 default:
2322 return true;
2323 }
2324 return false;
2325}
2326
2327static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2328{
2329 OpCode opCode = mir->dalvikInsn.opCode;
2330 int vA = mir->dalvikInsn.vA;
2331 int vB = mir->dalvikInsn.vB;
2332 int vC = mir->dalvikInsn.vC;
2333
Ben Chenge9695e52009-06-16 16:11:47 -07002334 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002335 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2336 return genArithOp( cUnit, mir );
2337 }
2338
2339 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002340 case OP_CMPL_FLOAT:
2341 case OP_CMPG_FLOAT:
2342 case OP_CMPL_DOUBLE:
2343 case OP_CMPG_DOUBLE:
2344 return dvmCompilerGenCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002345 case OP_CMP_LONG:
2346 loadValuePair(cUnit,vB, r0, r1);
2347 loadValuePair(cUnit, vC, r2, r3);
2348 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2349 storeValue(cUnit, r0, vA, r1);
2350 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002351 case OP_AGET_WIDE:
2352 genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 3);
2353 break;
2354 case OP_AGET:
2355 case OP_AGET_OBJECT:
2356 genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 2);
2357 break;
2358 case OP_AGET_BOOLEAN:
2359 genArrayGet(cUnit, mir, ARMV5TE_LDRB_RRR, vB, vC, vA, 0);
2360 break;
2361 case OP_AGET_BYTE:
2362 genArrayGet(cUnit, mir, ARMV5TE_LDRSB_RRR, vB, vC, vA, 0);
2363 break;
2364 case OP_AGET_CHAR:
2365 genArrayGet(cUnit, mir, ARMV5TE_LDRH_RRR, vB, vC, vA, 1);
2366 break;
2367 case OP_AGET_SHORT:
2368 genArrayGet(cUnit, mir, ARMV5TE_LDRSH_RRR, vB, vC, vA, 1);
2369 break;
2370 case OP_APUT_WIDE:
2371 genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 3);
2372 break;
2373 case OP_APUT:
2374 case OP_APUT_OBJECT:
2375 genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 2);
2376 break;
2377 case OP_APUT_SHORT:
2378 case OP_APUT_CHAR:
2379 genArrayPut(cUnit, mir, ARMV5TE_STRH_RRR, vB, vC, vA, 1);
2380 break;
2381 case OP_APUT_BYTE:
2382 case OP_APUT_BOOLEAN:
2383 genArrayPut(cUnit, mir, ARMV5TE_STRB_RRR, vB, vC, vA, 0);
2384 break;
2385 default:
2386 return true;
2387 }
2388 return false;
2389}
2390
2391static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2392{
2393 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2394 switch (dalvikOpCode) {
2395 case OP_FILL_ARRAY_DATA: {
2396 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2397 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2398 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2399 (int) (cUnit->method->insns + mir->offset));
2400 genExportPC(cUnit, mir, r2, r3 );
2401 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002402 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002403 break;
2404 }
2405 /*
2406 * TODO
2407 * - Add a 1 to 3-entry per-location cache here to completely
2408 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2409 * - Use out-of-line handlers for both of these
2410 */
2411 case OP_PACKED_SWITCH:
2412 case OP_SPARSE_SWITCH: {
2413 if (dalvikOpCode == OP_PACKED_SWITCH) {
2414 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2415 } else {
2416 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2417 }
2418 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2419 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2420 (int) (cUnit->method->insns + mir->offset));
2421 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2422 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
2423 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE,
2424 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
2425 >> 2);
2426 newLIR3(cUnit, ARMV5TE_ADD_RRR, r0, r0, r0);
2427 newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, r0, r1);
2428 newLIR1(cUnit, ARMV5TE_BLX_R, r2);
2429 break;
2430 }
2431 default:
2432 return true;
2433 }
2434 return false;
2435}
2436
2437static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
2438 Armv5teLIR *labelList)
2439{
2440 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
2441 Armv5teLIR *pcrLabel = NULL;
2442
2443 DecodedInstruction *dInsn = &mir->dalvikInsn;
2444 switch (mir->dalvikInsn.opCode) {
2445 /*
2446 * calleeMethod = this->clazz->vtable[
2447 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2448 * ]
2449 */
2450 case OP_INVOKE_VIRTUAL:
2451 case OP_INVOKE_VIRTUAL_RANGE: {
2452 int methodIndex =
2453 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2454 methodIndex;
2455
2456 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2457 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2458 else
2459 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2460
2461 /* r0 now contains this->clazz */
2462 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2463 offsetof(Object, clazz) >> 2);
2464 /* r1 = &retChainingCell */
2465 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2466 r1, 0);
2467 /* r4PC = dalvikCallsite */
2468 loadConstant(cUnit, r4PC,
2469 (int) (cUnit->method->insns + mir->offset));
2470
2471 /* r0 now contains this->clazz->vtable */
2472 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2473 offsetof(ClassObject, vtable) >> 2);
2474 addrRetChain->generic.target = (LIR *) retChainingCell;
2475
2476 if (methodIndex < 32) {
2477 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, methodIndex);
2478 } else {
2479 loadConstant(cUnit, r7, methodIndex<<2);
2480 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r7);
2481 }
2482
2483 /*
2484 * r0 = calleeMethod,
2485 * r1 = &ChainingCell,
2486 * r4PC = callsiteDPC,
2487 */
2488 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2489#if defined(INVOKE_STATS)
2490 gDvmJit.invokeNoOpt++;
2491#endif
2492 /* Handle exceptions using the interpreter */
2493 genTrap(cUnit, mir->offset, pcrLabel);
2494 break;
2495 }
2496 /*
2497 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2498 * ->pResMethods[BBBB]->methodIndex]
2499 */
2500 /* TODO - not excersized in RunPerf.jar */
2501 case OP_INVOKE_SUPER:
2502 case OP_INVOKE_SUPER_RANGE: {
2503 int mIndex = cUnit->method->clazz->pDvmDex->
2504 pResMethods[dInsn->vB]->methodIndex;
2505 const Method *calleeMethod =
2506 cUnit->method->clazz->super->vtable[mIndex];
2507
2508 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2509 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2510 else
2511 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2512
2513 /* r0 = calleeMethod */
2514 loadConstant(cUnit, r0, (int) calleeMethod);
2515
2516 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2517 calleeMethod);
2518 break;
2519 }
2520 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2521 case OP_INVOKE_DIRECT:
2522 case OP_INVOKE_DIRECT_RANGE: {
2523 const Method *calleeMethod =
2524 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2525
2526 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2527 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2528 else
2529 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2530
2531 /* r0 = calleeMethod */
2532 loadConstant(cUnit, r0, (int) calleeMethod);
2533
2534 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2535 calleeMethod);
2536 break;
2537 }
2538 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2539 case OP_INVOKE_STATIC:
2540 case OP_INVOKE_STATIC_RANGE: {
2541 const Method *calleeMethod =
2542 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2543
2544 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2545 genProcessArgsNoRange(cUnit, mir, dInsn,
2546 NULL /* no null check */);
2547 else
2548 genProcessArgsRange(cUnit, mir, dInsn,
2549 NULL /* no null check */);
2550
2551 /* r0 = calleeMethod */
2552 loadConstant(cUnit, r0, (int) calleeMethod);
2553
2554 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2555 calleeMethod);
2556 break;
2557 }
2558 /*
2559 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2560 * BBBB, method, method->clazz->pDvmDex)
2561 */
2562 case OP_INVOKE_INTERFACE:
2563 case OP_INVOKE_INTERFACE_RANGE: {
2564 int methodIndex = dInsn->vB;
2565
2566 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2567 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2568 else
2569 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2570
2571 /* r0 now contains this->clazz */
2572 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2573 offsetof(Object, clazz) >> 2);
2574
2575 /* r1 = BBBB */
2576 loadConstant(cUnit, r1, dInsn->vB);
2577
2578 /* r2 = method (caller) */
2579 loadConstant(cUnit, r2, (int) cUnit->method);
2580
2581 /* r3 = pDvmDex */
2582 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2583
2584 loadConstant(cUnit, r7,
2585 (intptr_t) dvmFindInterfaceMethodInCache);
2586 newLIR1(cUnit, ARMV5TE_BLX_R, r7);
2587
2588 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2589
2590 /* r1 = &retChainingCell */
2591 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2592 r1, 0);
2593 /* r4PC = dalvikCallsite */
2594 loadConstant(cUnit, r4PC,
2595 (int) (cUnit->method->insns + mir->offset));
2596
2597 addrRetChain->generic.target = (LIR *) retChainingCell;
2598 /*
2599 * r0 = this, r1 = calleeMethod,
2600 * r1 = &ChainingCell,
2601 * r4PC = callsiteDPC,
2602 */
2603 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2604#if defined(INVOKE_STATS)
2605 gDvmJit.invokeNoOpt++;
2606#endif
2607 /* Handle exceptions using the interpreter */
2608 genTrap(cUnit, mir->offset, pcrLabel);
2609 break;
2610 }
2611 /* NOP */
2612 case OP_INVOKE_DIRECT_EMPTY: {
2613 return false;
2614 }
2615 case OP_FILLED_NEW_ARRAY:
2616 case OP_FILLED_NEW_ARRAY_RANGE: {
2617 /* Just let the interpreter deal with these */
2618 genInterpSingleStep(cUnit, mir);
2619 break;
2620 }
2621 default:
2622 return true;
2623 }
2624 return false;
2625}
2626
2627static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
2628 BasicBlock *bb, Armv5teLIR *labelList)
2629{
2630 Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
2631 Armv5teLIR *pcrLabel = NULL;
2632
2633 DecodedInstruction *dInsn = &mir->dalvikInsn;
2634 switch (mir->dalvikInsn.opCode) {
2635 /* calleeMethod = this->clazz->vtable[BBBB] */
2636 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2637 case OP_INVOKE_VIRTUAL_QUICK: {
2638 int methodIndex = dInsn->vB;
2639 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2640 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2641 else
2642 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2643
2644 /* r0 now contains this->clazz */
2645 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2646 offsetof(Object, clazz) >> 2);
2647 /* r1 = &retChainingCell */
2648 Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
2649 r1, 0);
2650 /* r4PC = dalvikCallsite */
2651 loadConstant(cUnit, r4PC,
2652 (int) (cUnit->method->insns + mir->offset));
2653
2654 /* r0 now contains this->clazz->vtable */
2655 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
2656 offsetof(ClassObject, vtable) >> 2);
2657 addrRetChain->generic.target = (LIR *) retChainingCell;
2658
2659 if (methodIndex < 32) {
2660 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, methodIndex);
2661 } else {
2662 loadConstant(cUnit, r7, methodIndex<<2);
2663 newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r7);
2664 }
2665
2666 /*
2667 * r0 = calleeMethod,
2668 * r1 = &ChainingCell,
2669 * r4PC = callsiteDPC,
2670 */
2671 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2672#if defined(INVOKE_STATS)
2673 gDvmJit.invokeNoOpt++;
2674#endif
2675 break;
2676 }
2677 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2678 case OP_INVOKE_SUPER_QUICK:
2679 case OP_INVOKE_SUPER_QUICK_RANGE: {
2680 const Method *calleeMethod =
2681 cUnit->method->clazz->super->vtable[dInsn->vB];
2682
2683 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2684 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2685 else
2686 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2687
2688 /* r0 = calleeMethod */
2689 loadConstant(cUnit, r0, (int) calleeMethod);
2690
2691 genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
2692 calleeMethod);
2693 break;
2694 }
2695 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2696 default:
2697 return true;
2698 }
2699 /* Handle exceptions using the interpreter */
2700 genTrap(cUnit, mir->offset, pcrLabel);
2701 return false;
2702}
2703
2704/*
2705 * NOTE: We assume here that the special native inline routines
2706 * are side-effect free. By making this assumption, we can safely
2707 * re-execute the routine from the interpreter if it decides it
2708 * wants to throw an exception. We still need to EXPORT_PC(), though.
2709 */
2710static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
2711{
2712 DecodedInstruction *dInsn = &mir->dalvikInsn;
2713 switch( mir->dalvikInsn.opCode) {
2714 case OP_EXECUTE_INLINE: {
2715 unsigned int i;
2716 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
2717 int offset = (int) &((InterpState *) NULL)->retval;
2718 int operation = dInsn->vB;
2719
2720 if (!strcmp(inLineTable[operation].classDescriptor,
2721 "Ljava/lang/String;") &&
2722 !strcmp(inLineTable[operation].methodName,
2723 "length") &&
2724 !strcmp(inLineTable[operation].methodSignature,
2725 "()I")) {
2726 return genInlinedStringLength(cUnit,mir);
2727 }
2728
2729 /* Materialize pointer to retval & push */
2730 newLIR2(cUnit, ARMV5TE_MOV_RR, r4PC, rGLUE);
2731 newLIR2(cUnit, ARMV5TE_ADD_RI8, r4PC, offset);
2732 /* Push r4 and (just to take up space) r5) */
2733 newLIR1(cUnit, ARMV5TE_PUSH, (1<<r4PC | 1<<rFP));
2734
2735 /* Get code pointer to inline routine */
2736 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
2737
2738 /* Export PC */
2739 genExportPC(cUnit, mir, r0, r1 );
2740
2741 /* Load arguments to r0 through r3 as applicable */
2742 for (i=0; i < dInsn->vA; i++) {
2743 loadValue(cUnit, dInsn->arg[i], i);
2744 }
2745 /* Call inline routine */
2746 newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
2747
2748 /* Strip frame */
2749 newLIR1(cUnit, ARMV5TE_ADD_SPI7, 2);
2750
2751 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07002752 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002753
Ben Chenge9695e52009-06-16 16:11:47 -07002754 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002755 break;
2756 }
2757 default:
2758 return true;
2759 }
2760 return false;
2761}
2762
2763static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
2764{
2765 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
2766 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
2767 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2768 return false;
2769}
2770
2771/*****************************************************************************/
2772/*
2773 * The following are special processing routines that handle transfer of
2774 * controls between compiled code and the interpreter. Certain VM states like
2775 * Dalvik PC and special-purpose registers are reconstructed here.
2776 */
2777
Ben Cheng1efc9c52009-06-08 18:25:27 -07002778/* Chaining cell for code that may need warmup. */
2779static void handleNormalChainingCell(CompilationUnit *cUnit,
2780 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002781{
2782 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
2783 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
2784 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
2785 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2786}
2787
2788/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07002789 * Chaining cell for instructions that immediately following already translated
2790 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002791 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07002792static void handleHotChainingCell(CompilationUnit *cUnit,
2793 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002794{
2795 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
2796 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
2797 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
2798 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
2799}
2800
2801/* Chaining cell for monomorphic method invocations. */
2802static void handleInvokeChainingCell(CompilationUnit *cUnit,
2803 const Method *callee)
2804{
2805 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
2806 offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
2807 newLIR1(cUnit, ARMV5TE_BLX_R, r0);
2808 addWordData(cUnit, (int) (callee->insns), true);
2809}
2810
2811/* Load the Dalvik PC into r0 and jump to the specified target */
2812static void handlePCReconstruction(CompilationUnit *cUnit,
2813 Armv5teLIR *targetLabel)
2814{
2815 Armv5teLIR **pcrLabel =
2816 (Armv5teLIR **) cUnit->pcReconstructionList.elemList;
2817 int numElems = cUnit->pcReconstructionList.numUsed;
2818 int i;
2819 for (i = 0; i < numElems; i++) {
2820 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
2821 /* r0 = dalvik PC */
2822 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
2823 genUnconditionalBranch(cUnit, targetLabel);
2824 }
2825}
2826
2827/* Entry function to invoke the backend of the JIT compiler */
2828void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
2829{
2830 /* Used to hold the labels of each block */
2831 Armv5teLIR *labelList =
2832 dvmCompilerNew(sizeof(Armv5teLIR) * cUnit->numBlocks, true);
2833 GrowableList chainingListByType[CHAINING_CELL_LAST];
2834 int i;
2835
2836 /*
2837 * Initialize the three chaining lists for generic, post-invoke, and invoke
2838 * chains.
2839 */
2840 for (i = 0; i < CHAINING_CELL_LAST; i++) {
2841 dvmInitGrowableList(&chainingListByType[i], 2);
2842 }
2843
2844 BasicBlock **blockList = cUnit->blockList;
2845
Bill Buzbee6e963e12009-06-17 16:56:19 -07002846 if (cUnit->executionCount) {
2847 /*
2848 * Reserve 6 bytes at the beginning of the trace
2849 * +----------------------------+
2850 * | execution count (4 bytes) |
2851 * +----------------------------+
2852 * | chain cell offset (2 bytes)|
2853 * +----------------------------+
2854 * ...and then code to increment the execution
2855 * count:
2856 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
2857 * sub r0, #10 @ back up to addr of executionCount
2858 * ldr r1, [r0]
2859 * add r1, #1
2860 * str r1, [r0]
2861 */
2862 newLIR1(cUnit, ARMV5TE_16BIT_DATA, 0);
2863 newLIR1(cUnit, ARMV5TE_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07002864 cUnit->chainCellOffsetLIR =
2865 (LIR *) newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07002866 cUnit->headerSize = 6;
2867 newLIR2(cUnit, ARMV5TE_MOV_RR_HL, r0, rpc & THUMB_REG_MASK);
2868 newLIR2(cUnit, ARMV5TE_SUB_RI8, r0, 10);
2869 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0, 0);
2870 newLIR2(cUnit, ARMV5TE_ADD_RI8, r1, 1);
2871 newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, r0, 0);
2872 } else {
2873 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07002874 cUnit->chainCellOffsetLIR =
2875 (LIR *) newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07002876 cUnit->headerSize = 2;
2877 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07002878
Ben Chengba4fc8b2009-06-01 13:00:29 -07002879 /* Handle the content in each basic block */
2880 for (i = 0; i < cUnit->numBlocks; i++) {
2881 blockList[i]->visited = true;
2882 MIR *mir;
2883
2884 labelList[i].operands[0] = blockList[i]->startOffset;
2885
2886 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
2887 /*
2888 * Append the label pseudo LIR first. Chaining cells will be handled
2889 * separately afterwards.
2890 */
2891 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
2892 }
2893
2894 if (blockList[i]->blockType == DALVIK_BYTECODE) {
2895 labelList[i].opCode = ARMV5TE_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07002896 /* Reset the register state */
2897 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002898 } else {
2899 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07002900 case CHAINING_CELL_NORMAL:
2901 labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 /* handle the codegen later */
2903 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07002904 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002905 break;
2906 case CHAINING_CELL_INVOKE:
2907 labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE;
2908 labelList[i].operands[0] =
2909 (int) blockList[i]->containingMethod;
2910 /* handle the codegen later */
2911 dvmInsertGrowableList(
2912 &chainingListByType[CHAINING_CELL_INVOKE], (void *) i);
2913 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07002914 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002915 labelList[i].opCode =
Ben Cheng1efc9c52009-06-08 18:25:27 -07002916 ARMV5TE_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002917 /* handle the codegen later */
2918 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07002919 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07002920 (void *) i);
2921 break;
2922 case PC_RECONSTRUCTION:
2923 /* Make sure exception handling block is next */
2924 labelList[i].opCode =
2925 ARMV5TE_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
2926 assert (i == cUnit->numBlocks - 2);
2927 handlePCReconstruction(cUnit, &labelList[i+1]);
2928 break;
2929 case EXCEPTION_HANDLING:
2930 labelList[i].opCode = ARMV5TE_PSEUDO_EH_BLOCK_LABEL;
2931 if (cUnit->pcReconstructionList.numUsed) {
2932 newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
2933 offsetof(InterpState,
2934 jitToInterpEntries.dvmJitToInterpPunt)
2935 >> 2);
2936 newLIR1(cUnit, ARMV5TE_BLX_R, r1);
2937 }
2938 break;
2939 default:
2940 break;
2941 }
2942 continue;
2943 }
Ben Chenge9695e52009-06-16 16:11:47 -07002944
2945 Armv5teLIR *headLIR = NULL;
2946
Ben Chengba4fc8b2009-06-01 13:00:29 -07002947 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
2948 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2949 InstructionFormat dalvikFormat =
2950 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Ben Chenge9695e52009-06-16 16:11:47 -07002951 Armv5teLIR *boundaryLIR =
2952 newLIR2(cUnit, ARMV5TE_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
2953 mir->offset,dalvikOpCode);
2954 /* Remember the first LIR for this block */
2955 if (headLIR == NULL) {
2956 headLIR = boundaryLIR;
2957 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002958 bool notHandled;
2959 /*
2960 * Debugging: screen the opcode first to see if it is in the
2961 * do[-not]-compile list
2962 */
2963 bool singleStepMe =
2964 gDvmJit.includeSelectedOp !=
2965 ((gDvmJit.opList[dalvikOpCode >> 3] &
2966 (1 << (dalvikOpCode & 0x7))) !=
2967 0);
2968 if (singleStepMe || cUnit->allSingleStep) {
2969 notHandled = false;
2970 genInterpSingleStep(cUnit, mir);
2971 } else {
2972 opcodeCoverage[dalvikOpCode]++;
2973 switch (dalvikFormat) {
2974 case kFmt10t:
2975 case kFmt20t:
2976 case kFmt30t:
2977 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
2978 mir, blockList[i], labelList);
2979 break;
2980 case kFmt10x:
2981 notHandled = handleFmt10x(cUnit, mir);
2982 break;
2983 case kFmt11n:
2984 case kFmt31i:
2985 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
2986 break;
2987 case kFmt11x:
2988 notHandled = handleFmt11x(cUnit, mir);
2989 break;
2990 case kFmt12x:
2991 notHandled = handleFmt12x(cUnit, mir);
2992 break;
2993 case kFmt20bc:
2994 notHandled = handleFmt20bc(cUnit, mir);
2995 break;
2996 case kFmt21c:
2997 case kFmt31c:
2998 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
2999 break;
3000 case kFmt21h:
3001 notHandled = handleFmt21h(cUnit, mir);
3002 break;
3003 case kFmt21s:
3004 notHandled = handleFmt21s(cUnit, mir);
3005 break;
3006 case kFmt21t:
3007 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3008 labelList);
3009 break;
3010 case kFmt22b:
3011 case kFmt22s:
3012 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3013 break;
3014 case kFmt22c:
3015 notHandled = handleFmt22c(cUnit, mir);
3016 break;
3017 case kFmt22cs:
3018 notHandled = handleFmt22cs(cUnit, mir);
3019 break;
3020 case kFmt22t:
3021 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3022 labelList);
3023 break;
3024 case kFmt22x:
3025 case kFmt32x:
3026 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3027 break;
3028 case kFmt23x:
3029 notHandled = handleFmt23x(cUnit, mir);
3030 break;
3031 case kFmt31t:
3032 notHandled = handleFmt31t(cUnit, mir);
3033 break;
3034 case kFmt3rc:
3035 case kFmt35c:
3036 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3037 labelList);
3038 break;
3039 case kFmt3rms:
3040 case kFmt35ms:
3041 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3042 labelList);
3043 break;
3044 case kFmt3inline:
3045 notHandled = handleFmt3inline(cUnit, mir);
3046 break;
3047 case kFmt51l:
3048 notHandled = handleFmt51l(cUnit, mir);
3049 break;
3050 default:
3051 notHandled = true;
3052 break;
3053 }
3054 }
3055 if (notHandled) {
3056 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3057 mir->offset,
3058 dalvikOpCode, getOpcodeName(dalvikOpCode),
3059 dalvikFormat);
3060 dvmAbort();
3061 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003062 }
3063 }
Ben Chenge9695e52009-06-16 16:11:47 -07003064
3065 /* Eliminate redundant loads/stores and delay stores into later slots */
3066 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3067 cUnit->lastLIRInsn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07003068 /*
3069 * Check if the block is terminated due to trace length constraint -
3070 * insert an unconditional branch to the chaining cell.
3071 */
3072 if (blockList[i]->needFallThroughBranch) {
3073 genUnconditionalBranch(cUnit,
3074 &labelList[blockList[i]->fallThrough->id]);
3075 }
3076
Ben Chengba4fc8b2009-06-01 13:00:29 -07003077 }
3078
Ben Chenge9695e52009-06-16 16:11:47 -07003079 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003080 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3081 size_t j;
3082 int *blockIdList = (int *) chainingListByType[i].elemList;
3083
3084 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3085
3086 /* No chaining cells of this type */
3087 if (cUnit->numChainingCells[i] == 0)
3088 continue;
3089
3090 /* Record the first LIR for a new type of chaining cell */
3091 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3092
3093 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3094 int blockId = blockIdList[j];
3095
3096 /* Align this chaining cell first */
3097 newLIR0(cUnit, ARMV5TE_PSEUDO_ALIGN4);
3098
3099 /* Insert the pseudo chaining instruction */
3100 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3101
3102
3103 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003104 case CHAINING_CELL_NORMAL:
3105 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003106 blockList[blockId]->startOffset);
3107 break;
3108 case CHAINING_CELL_INVOKE:
3109 handleInvokeChainingCell(cUnit,
3110 blockList[blockId]->containingMethod);
3111 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003112 case CHAINING_CELL_HOT:
3113 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003114 blockList[blockId]->startOffset);
3115 break;
3116 default:
3117 dvmAbort();
3118 break;
3119 }
3120 }
3121 }
Ben Chenge9695e52009-06-16 16:11:47 -07003122
3123 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003124}
3125
3126/* Accept the work and start compiling */
3127void *dvmCompilerDoWork(CompilerWorkOrder *work)
3128{
3129 void *res;
3130
3131 if (gDvmJit.codeCacheFull) {
3132 return NULL;
3133 }
3134
3135 switch (work->kind) {
3136 case kWorkOrderMethod:
3137 res = dvmCompileMethod(work->info);
3138 break;
3139 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003140 /* Start compilation with maximally allowed trace length */
3141 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003142 break;
3143 default:
3144 res = NULL;
3145 dvmAbort();
3146 }
3147 return res;
3148}
3149
3150/* Architecture-specific initializations and checks go here */
3151bool dvmCompilerArchInit(void)
3152{
3153 /* First, declare dvmCompiler_TEMPLATE_XXX for each template */
3154#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
3155#include "../../template/armv5te/TemplateOpList.h"
3156#undef JIT_TEMPLATE
3157
3158 int i = 0;
3159 extern void dvmCompilerTemplateStart(void);
3160
3161 /*
3162 * Then, populate the templateEntryOffsets array with the offsets from the
3163 * the dvmCompilerTemplateStart symbol for each template.
3164 */
3165#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
3166 (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
3167#include "../../template/armv5te/TemplateOpList.h"
3168#undef JIT_TEMPLATE
3169
3170 /* Codegen-specific assumptions */
3171 assert(offsetof(ClassObject, vtable) < 128 &&
3172 (offsetof(ClassObject, vtable) & 0x3) == 0);
3173 assert(offsetof(ArrayObject, length) < 128 &&
3174 (offsetof(ArrayObject, length) & 0x3) == 0);
3175 assert(offsetof(ArrayObject, contents) < 256);
3176
3177 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
3178 assert(sizeof(StackSaveArea) < 236);
3179
3180 /*
3181 * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points
3182 * that codegen may access, make sure that the offset from the top of the
3183 * struct is less than 108.
3184 */
3185 assert(offsetof(InterpState, jitToInterpEntries) < 108);
3186 return true;
3187}
3188
3189/* Architectural-specific debugging helpers go here */
3190void dvmCompilerArchDump(void)
3191{
3192 /* Print compiled opcode in this VM instance */
3193 int i, start, streak;
3194 char buf[1024];
3195
3196 streak = i = 0;
3197 buf[0] = 0;
3198 while (opcodeCoverage[i] == 0 && i < 256) {
3199 i++;
3200 }
3201 if (i == 256) {
3202 return;
3203 }
3204 for (start = i++, streak = 1; i < 256; i++) {
3205 if (opcodeCoverage[i]) {
3206 streak++;
3207 } else {
3208 if (streak == 1) {
3209 sprintf(buf+strlen(buf), "%x,", start);
3210 } else {
3211 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3212 }
3213 streak = 0;
3214 while (opcodeCoverage[i] == 0 && i < 256) {
3215 i++;
3216 }
3217 if (i < 256) {
3218 streak = 1;
3219 start = i;
3220 }
3221 }
3222 }
3223 if (streak) {
3224 if (streak == 1) {
3225 sprintf(buf+strlen(buf), "%x", start);
3226 } else {
3227 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3228 }
3229 }
3230 if (strlen(buf)) {
3231 LOGD("dalvik.vm.jitop = %s", buf);
3232 }
3233}
Bill Buzbeed45ba372009-06-15 17:00:57 -07003234
3235/*
3236 * Exported version of loadValueAddress
3237 * TODO: revisit source file structure
3238 */
3239void dvmCompilerLoadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
3240{
3241 loadValueAddress(cUnit, vSrc, rDest);
3242}
3243
3244/*
3245 * Exported version of genDispatchToHandler
3246 * TODO: revisit source file structure
3247 */
Ben Chenge9695e52009-06-16 16:11:47 -07003248void dvmCompilerGenDispatchToHandler(CompilationUnit *cUnit,
Bill Buzbeed45ba372009-06-15 17:00:57 -07003249 TemplateOpCode opCode)
3250{
3251 genDispatchToHandler(cUnit, opCode);
3252}
3253
3254/*
3255 * Exported version of loadValue
3256 * TODO: revisit source file structure
3257 */
3258void dvmCompilerLoadValue(CompilationUnit *cUnit, int vSrc, int rDest)
3259{
3260 loadValue(cUnit, vSrc, rDest);
3261}
3262
3263/*
3264 * Exported version of storeValue
3265 * TODO: revisit source file structure
3266 */
3267void dvmCompilerStoreValue(CompilationUnit *cUnit, int rSrc, int vDest,
3268 int rScratch)
3269{
3270 storeValue(cUnit, rSrc, vDest, rScratch);
3271}