blob: 2555a8dbc0451430204f1eb4bf25f45e0615b6a5 [file] [log] [blame]
Ben Cheng5d90c202009-11-22 23:31:11 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
27#include "compiler/Loop.h"
28
29/* Array holding the entry offset of each template relative to the first one */
30static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
31
32/* Track exercised opcodes */
Dan Bornsteinccaab182010-12-03 15:32:40 -080033static int opcodeCoverage[kNumPackedOpcodes];
Ben Cheng5d90c202009-11-22 23:31:11 -080034
Bill Buzbee1f748632010-03-02 16:14:41 -080035static void setMemRefType(ArmLIR *lir, bool isLoad, int memType)
36{
37 u8 *maskPtr;
Ben Cheng7ab74e12011-02-03 14:02:06 -080038 u8 mask = ENCODE_MEM;;
39 assert(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
Bill Buzbee1f748632010-03-02 16:14:41 -080040 if (isLoad) {
41 maskPtr = &lir->useMask;
Bill Buzbee1f748632010-03-02 16:14:41 -080042 } else {
43 maskPtr = &lir->defMask;
Bill Buzbee1f748632010-03-02 16:14:41 -080044 }
45 /* Clear out the memref flags */
46 *maskPtr &= ~mask;
47 /* ..and then add back the one we need */
48 switch(memType) {
49 case kLiteral:
50 assert(isLoad);
Ben Cheng7ab74e12011-02-03 14:02:06 -080051 *maskPtr |= ENCODE_LITERAL;
Bill Buzbee1f748632010-03-02 16:14:41 -080052 break;
53 case kDalvikReg:
Ben Cheng7ab74e12011-02-03 14:02:06 -080054 *maskPtr |= ENCODE_DALVIK_REG;
Bill Buzbee1f748632010-03-02 16:14:41 -080055 break;
56 case kHeapRef:
57 *maskPtr |= ENCODE_HEAP_REF;
58 break;
Ben Cheng7ab74e12011-02-03 14:02:06 -080059 case kMustNotAlias:
60 /* Currently only loads can be marked as kMustNotAlias */
61 assert(!(EncodingMap[lir->opcode].flags & IS_STORE));
62 *maskPtr |= ENCODE_MUST_NOT_ALIAS;
63 break;
Bill Buzbee1f748632010-03-02 16:14:41 -080064 default:
65 LOGE("Jit: invalid memref kind - %d", memType);
Bill Buzbeefc519dc2010-03-06 23:30:57 -080066 assert(0); // Bail if debug build, set worst-case in the field
67 *maskPtr |= ENCODE_ALL;
Bill Buzbee1f748632010-03-02 16:14:41 -080068 }
69}
70
Ben Cheng5d90c202009-11-22 23:31:11 -080071/*
Ben Cheng20d7e6c2011-02-18 17:12:42 -080072 * Mark load/store instructions that access Dalvik registers through r5FP +
Ben Cheng5d90c202009-11-22 23:31:11 -080073 * offset.
74 */
75static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
76{
Bill Buzbee1f748632010-03-02 16:14:41 -080077 setMemRefType(lir, isLoad, kDalvikReg);
Ben Cheng5d90c202009-11-22 23:31:11 -080078
79 /*
80 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
81 * access.
82 */
83 lir->aliasInfo = regId;
84 if (DOUBLEREG(lir->operands[0])) {
85 lir->aliasInfo |= 0x80000000;
86 }
87}
88
89/*
Ben Chengd72564c2011-02-08 17:09:25 -080090 * Decode the register id.
Ben Cheng5d90c202009-11-22 23:31:11 -080091 */
Ben Chengd72564c2011-02-08 17:09:25 -080092static inline u8 getRegMaskCommon(int reg)
Ben Cheng5d90c202009-11-22 23:31:11 -080093{
94 u8 seed;
95 int shift;
96 int regId = reg & 0x1f;
97
98 /*
99 * Each double register is equal to a pair of single-precision FP registers
100 */
101 seed = DOUBLEREG(reg) ? 3 : 1;
102 /* FP register starts at bit position 16 */
103 shift = FPREG(reg) ? kFPReg0 : 0;
104 /* Expand the double register id into single offset */
105 shift += regId;
Ben Chengd72564c2011-02-08 17:09:25 -0800106 return (seed << shift);
107}
108
109/* External version of getRegMaskCommon */
110u8 dvmGetRegResourceMask(int reg)
111{
112 return getRegMaskCommon(reg);
113}
114
115/*
116 * Mark the corresponding bit(s).
117 */
118static inline void setupRegMask(u8 *mask, int reg)
119{
120 *mask |= getRegMaskCommon(reg);
Ben Cheng5d90c202009-11-22 23:31:11 -0800121}
122
123/*
124 * Set up the proper fields in the resource mask
125 */
126static void setupResourceMasks(ArmLIR *lir)
127{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800128 int opcode = lir->opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800129 int flags;
130
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800131 if (opcode <= 0) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800132 lir->useMask = lir->defMask = 0;
133 return;
134 }
135
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800136 flags = EncodingMap[lir->opcode].flags;
Ben Cheng5d90c202009-11-22 23:31:11 -0800137
138 /* Set up the mask for resources that are updated */
Bill Buzbee1f748632010-03-02 16:14:41 -0800139 if (flags & (IS_LOAD | IS_STORE)) {
140 /* Default to heap - will catch specialized classes later */
141 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
142 }
143
Ben Cheng7ab74e12011-02-03 14:02:06 -0800144 /*
145 * Conservatively assume the branch here will call out a function that in
146 * turn will trash everything.
147 */
Ben Cheng5d90c202009-11-22 23:31:11 -0800148 if (flags & IS_BRANCH) {
Ben Cheng7ab74e12011-02-03 14:02:06 -0800149 lir->defMask = lir->useMask = ENCODE_ALL;
150 return;
Ben Cheng5d90c202009-11-22 23:31:11 -0800151 }
152
153 if (flags & REG_DEF0) {
154 setupRegMask(&lir->defMask, lir->operands[0]);
155 }
156
157 if (flags & REG_DEF1) {
158 setupRegMask(&lir->defMask, lir->operands[1]);
159 }
160
161 if (flags & REG_DEF_SP) {
162 lir->defMask |= ENCODE_REG_SP;
163 }
164
Bill Buzbeed867b232010-02-25 15:38:40 -0800165 if (flags & REG_DEF_LR) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800166 lir->defMask |= ENCODE_REG_LR;
167 }
168
169 if (flags & REG_DEF_LIST0) {
170 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
171 }
172
173 if (flags & REG_DEF_LIST1) {
174 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
175 }
176
177 if (flags & SETS_CCODES) {
178 lir->defMask |= ENCODE_CCODE;
179 }
180
181 /* Conservatively treat the IT block */
182 if (flags & IS_IT) {
183 lir->defMask = ENCODE_ALL;
184 }
185
Ben Cheng5d90c202009-11-22 23:31:11 -0800186 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
187 int i;
188
189 for (i = 0; i < 4; i++) {
190 if (flags & (1 << (kRegUse0 + i))) {
191 setupRegMask(&lir->useMask, lir->operands[i]);
192 }
193 }
194 }
195
196 if (flags & REG_USE_PC) {
197 lir->useMask |= ENCODE_REG_PC;
198 }
199
200 if (flags & REG_USE_SP) {
201 lir->useMask |= ENCODE_REG_SP;
202 }
203
204 if (flags & REG_USE_LIST0) {
205 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
206 }
207
208 if (flags & REG_USE_LIST1) {
209 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
210 }
211
212 if (flags & USES_CCODES) {
213 lir->useMask |= ENCODE_CCODE;
214 }
Ben Chengd72564c2011-02-08 17:09:25 -0800215
216 /* Fixup for kThumbPush/lr and kThumbPop/pc */
217 if (opcode == kThumbPush || opcode == kThumbPop) {
218 u8 r8Mask = getRegMaskCommon(r8);
219 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
220 lir->useMask &= ~r8Mask;
221 lir->useMask |= ENCODE_REG_LR;
222 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
223 lir->defMask &= ~r8Mask;
224 lir->defMask |= ENCODE_REG_PC;
225 }
226 }
Ben Cheng5d90c202009-11-22 23:31:11 -0800227}
228
229/*
Ben Cheng7ab74e12011-02-03 14:02:06 -0800230 * Set up the accurate resource mask for branch instructions
231 */
232static void relaxBranchMasks(ArmLIR *lir)
233{
234 int flags = EncodingMap[lir->opcode].flags;
235
236 /* Make sure only branch instructions are passed here */
237 assert(flags & IS_BRANCH);
238
239 lir->useMask = lir->defMask = ENCODE_REG_PC;
240
241 if (flags & REG_DEF_LR) {
242 lir->defMask |= ENCODE_REG_LR;
243 }
244
245 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
246 int i;
247
248 for (i = 0; i < 4; i++) {
249 if (flags & (1 << (kRegUse0 + i))) {
250 setupRegMask(&lir->useMask, lir->operands[i]);
251 }
252 }
253 }
254
255 if (flags & USES_CCODES) {
256 lir->useMask |= ENCODE_CCODE;
257 }
258}
259
260/*
Ben Cheng5d90c202009-11-22 23:31:11 -0800261 * The following are building blocks to construct low-level IRs with 0 - 4
262 * operands.
263 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800264static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpcode opcode)
Ben Cheng5d90c202009-11-22 23:31:11 -0800265{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800266 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800267 assert(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
268 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800269 setupResourceMasks(insn);
270 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
271 return insn;
272}
273
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800274static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800275 int dest)
276{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800277 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800278 assert(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
279 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800280 insn->operands[0] = dest;
281 setupResourceMasks(insn);
282 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
283 return insn;
284}
285
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800286static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800287 int dest, int src1)
288{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800289 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800290 assert(isPseudoOpcode(opcode) ||
291 (EncodingMap[opcode].flags & IS_BINARY_OP));
292 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800293 insn->operands[0] = dest;
294 insn->operands[1] = src1;
295 setupResourceMasks(insn);
296 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
297 return insn;
298}
299
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800300static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800301 int dest, int src1, int src2)
302{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800303 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800304 if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
305 LOGE("Bad LIR3: %s[%d]",EncodingMap[opcode].name,opcode);
Ben Cheng5d90c202009-11-22 23:31:11 -0800306 }
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800307 assert(isPseudoOpcode(opcode) ||
308 (EncodingMap[opcode].flags & IS_TERTIARY_OP));
309 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800310 insn->operands[0] = dest;
311 insn->operands[1] = src1;
312 insn->operands[2] = src2;
313 setupResourceMasks(insn);
314 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
315 return insn;
316}
317
Ben Chengfc075c22010-05-28 15:20:08 -0700318#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800319static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800320 int dest, int src1, int src2, int info)
321{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800322 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800323 assert(isPseudoOpcode(opcode) ||
324 (EncodingMap[opcode].flags & IS_QUAD_OP));
325 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800326 insn->operands[0] = dest;
327 insn->operands[1] = src1;
328 insn->operands[2] = src2;
329 insn->operands[3] = info;
330 setupResourceMasks(insn);
331 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
332 return insn;
333}
Ben Chengfc075c22010-05-28 15:20:08 -0700334#endif
Ben Cheng5d90c202009-11-22 23:31:11 -0800335
336/*
337 * If the next instruction is a move-result or move-result-long,
338 * return the target Dalvik sReg[s] and convert the next to a
339 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
340 */
341static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
342 bool fpHint)
343{
344 if (mir->next &&
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800345 ((mir->next->dalvikInsn.opcode == OP_MOVE_RESULT) ||
346 (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_OBJECT))) {
347 mir->next->dalvikInsn.opcode = OP_NOP;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800348 return dvmCompilerGetDest(cUnit, mir->next, 0);
Ben Cheng5d90c202009-11-22 23:31:11 -0800349 } else {
350 RegLocation res = LOC_DALVIK_RETURN_VAL;
351 res.fp = fpHint;
352 return res;
353 }
354}
355
356/*
357 * Search the existing constants in the literal pool for an exact or close match
358 * within specified delta (greater or equal to 0).
359 */
360static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
361 unsigned int delta)
362{
363 LIR *dataTarget = cUnit->wordList;
364 while (dataTarget) {
365 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
366 delta)
367 return (ArmLIR *) dataTarget;
368 dataTarget = dataTarget->next;
369 }
370 return NULL;
371}
372
373/*
374 * The following are building blocks to insert constants into the pool or
375 * instruction streams.
376 */
377
378/* Add a 32-bit constant either in the constant pool or mixed with code */
379static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
380{
381 /* Add the constant to the literal pool */
382 if (!inPlace) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800383 ArmLIR *newValue = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Ben Cheng5d90c202009-11-22 23:31:11 -0800384 newValue->operands[0] = value;
385 newValue->generic.next = cUnit->wordList;
386 cUnit->wordList = (LIR *) newValue;
387 return newValue;
388 } else {
389 /* Add the constant in the middle of code stream */
390 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
391 newLIR1(cUnit, kArm16BitData, (value >> 16));
392 }
393 return NULL;
394}
395
396static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
397 bool fpHint)
398{
399 if (mir->next &&
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800400 (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_WIDE)) {
401 mir->next->dalvikInsn.opcode = OP_NOP;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800402 return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
Ben Cheng5d90c202009-11-22 23:31:11 -0800403 } else {
404 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
405 res.fp = fpHint;
406 return res;
407 }
408}
409
410
411/*
412 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
413 * blocks.
414 */
415static void genBarrier(CompilationUnit *cUnit)
416{
417 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
418 /* Mark all resources as being clobbered */
419 barrier->defMask = -1;
420}
421
422/* Create the PC reconstruction slot if not already done */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700423static ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
Ben Cheng5d90c202009-11-22 23:31:11 -0800424 ArmLIR *branch,
425 ArmLIR *pcrLabel)
426{
Bill Buzbee1f5cd6f2010-01-11 21:44:36 -0800427 /* Forget all def info (because we might rollback here. Bug #2367397 */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800428 dvmCompilerResetDefTracking(cUnit);
Bill Buzbee1f5cd6f2010-01-11 21:44:36 -0800429
Ben Cheng5d90c202009-11-22 23:31:11 -0800430 /* Set up the place holder to reconstruct this Dalvik PC */
431 if (pcrLabel == NULL) {
432 int dPC = (int) (cUnit->method->insns + dOffset);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800433 pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800434 pcrLabel->opcode = kArmPseudoPCReconstructionCell;
Ben Cheng5d90c202009-11-22 23:31:11 -0800435 pcrLabel->operands[0] = dPC;
436 pcrLabel->operands[1] = dOffset;
437 /* Insert the place holder to the growable list */
Ben Cheng00603072010-10-28 11:13:58 -0700438 dvmInsertGrowableList(&cUnit->pcReconstructionList,
439 (intptr_t) pcrLabel);
Ben Cheng5d90c202009-11-22 23:31:11 -0800440 }
441 /* Branch to the PC reconstruction code */
442 branch->generic.target = (LIR *) pcrLabel;
Ben Cheng7ab74e12011-02-03 14:02:06 -0800443
444 /* Clear the conservative flags for branches that punt to the interpreter */
445 relaxBranchMasks(branch);
446
Ben Cheng5d90c202009-11-22 23:31:11 -0800447 return pcrLabel;
448}