blob: f4ca95c4a1ca12493341769c43d45277a65a992e [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;
38 u8 mask;
Dan Bornstein9a1f8162010-12-01 17:02:26 -080039 assert( EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
Bill Buzbee1f748632010-03-02 16:14:41 -080040 if (isLoad) {
41 maskPtr = &lir->useMask;
42 mask = ENCODE_MEM_USE;
43 } else {
44 maskPtr = &lir->defMask;
45 mask = ENCODE_MEM_DEF;
46 }
47 /* Clear out the memref flags */
48 *maskPtr &= ~mask;
49 /* ..and then add back the one we need */
50 switch(memType) {
51 case kLiteral:
52 assert(isLoad);
53 *maskPtr |= (ENCODE_LITERAL | ENCODE_LITPOOL_REF);
54 break;
55 case kDalvikReg:
56 *maskPtr |= (ENCODE_DALVIK_REG | ENCODE_FRAME_REF);
57 break;
58 case kHeapRef:
59 *maskPtr |= ENCODE_HEAP_REF;
60 break;
61 default:
62 LOGE("Jit: invalid memref kind - %d", memType);
Bill Buzbeefc519dc2010-03-06 23:30:57 -080063 assert(0); // Bail if debug build, set worst-case in the field
64 *maskPtr |= ENCODE_ALL;
Bill Buzbee1f748632010-03-02 16:14:41 -080065 }
66}
67
Ben Cheng5d90c202009-11-22 23:31:11 -080068/*
69 * Mark load/store instructions that access Dalvik registers through rFP +
70 * offset.
71 */
72static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
73{
Bill Buzbee1f748632010-03-02 16:14:41 -080074 setMemRefType(lir, isLoad, kDalvikReg);
Ben Cheng5d90c202009-11-22 23:31:11 -080075
76 /*
77 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
78 * access.
79 */
80 lir->aliasInfo = regId;
81 if (DOUBLEREG(lir->operands[0])) {
82 lir->aliasInfo |= 0x80000000;
83 }
84}
85
86/*
Ben Chengd72564c2011-02-08 17:09:25 -080087 * Decode the register id.
Ben Cheng5d90c202009-11-22 23:31:11 -080088 */
Ben Chengd72564c2011-02-08 17:09:25 -080089static inline u8 getRegMaskCommon(int reg)
Ben Cheng5d90c202009-11-22 23:31:11 -080090{
91 u8 seed;
92 int shift;
93 int regId = reg & 0x1f;
94
95 /*
96 * Each double register is equal to a pair of single-precision FP registers
97 */
98 seed = DOUBLEREG(reg) ? 3 : 1;
99 /* FP register starts at bit position 16 */
100 shift = FPREG(reg) ? kFPReg0 : 0;
101 /* Expand the double register id into single offset */
102 shift += regId;
Ben Chengd72564c2011-02-08 17:09:25 -0800103 return (seed << shift);
104}
105
106/* External version of getRegMaskCommon */
107u8 dvmGetRegResourceMask(int reg)
108{
109 return getRegMaskCommon(reg);
110}
111
112/*
113 * Mark the corresponding bit(s).
114 */
115static inline void setupRegMask(u8 *mask, int reg)
116{
117 *mask |= getRegMaskCommon(reg);
Ben Cheng5d90c202009-11-22 23:31:11 -0800118}
119
120/*
121 * Set up the proper fields in the resource mask
122 */
123static void setupResourceMasks(ArmLIR *lir)
124{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800125 int opcode = lir->opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800126 int flags;
127
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800128 if (opcode <= 0) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800129 lir->useMask = lir->defMask = 0;
130 return;
131 }
132
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800133 flags = EncodingMap[lir->opcode].flags;
Ben Cheng5d90c202009-11-22 23:31:11 -0800134
135 /* Set up the mask for resources that are updated */
Bill Buzbee1f748632010-03-02 16:14:41 -0800136 if (flags & (IS_LOAD | IS_STORE)) {
137 /* Default to heap - will catch specialized classes later */
138 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
139 }
140
Ben Cheng5d90c202009-11-22 23:31:11 -0800141 if (flags & IS_BRANCH) {
142 lir->defMask |= ENCODE_REG_PC;
143 lir->useMask |= ENCODE_REG_PC;
144 }
145
146 if (flags & REG_DEF0) {
147 setupRegMask(&lir->defMask, lir->operands[0]);
148 }
149
150 if (flags & REG_DEF1) {
151 setupRegMask(&lir->defMask, lir->operands[1]);
152 }
153
154 if (flags & REG_DEF_SP) {
155 lir->defMask |= ENCODE_REG_SP;
156 }
157
Bill Buzbeed867b232010-02-25 15:38:40 -0800158 if (flags & REG_DEF_LR) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800159 lir->defMask |= ENCODE_REG_LR;
160 }
161
162 if (flags & REG_DEF_LIST0) {
163 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
164 }
165
166 if (flags & REG_DEF_LIST1) {
167 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
168 }
169
170 if (flags & SETS_CCODES) {
171 lir->defMask |= ENCODE_CCODE;
172 }
173
174 /* Conservatively treat the IT block */
175 if (flags & IS_IT) {
176 lir->defMask = ENCODE_ALL;
177 }
178
179 /* Set up the mask for resources that are used */
180 if (flags & IS_BRANCH) {
181 lir->useMask |= ENCODE_REG_PC;
182 }
183
184 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
185 int i;
186
187 for (i = 0; i < 4; i++) {
188 if (flags & (1 << (kRegUse0 + i))) {
189 setupRegMask(&lir->useMask, lir->operands[i]);
190 }
191 }
192 }
193
194 if (flags & REG_USE_PC) {
195 lir->useMask |= ENCODE_REG_PC;
196 }
197
198 if (flags & REG_USE_SP) {
199 lir->useMask |= ENCODE_REG_SP;
200 }
201
202 if (flags & REG_USE_LIST0) {
203 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
204 }
205
206 if (flags & REG_USE_LIST1) {
207 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
208 }
209
210 if (flags & USES_CCODES) {
211 lir->useMask |= ENCODE_CCODE;
212 }
Ben Chengd72564c2011-02-08 17:09:25 -0800213
214 /* Fixup for kThumbPush/lr and kThumbPop/pc */
215 if (opcode == kThumbPush || opcode == kThumbPop) {
216 u8 r8Mask = getRegMaskCommon(r8);
217 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
218 lir->useMask &= ~r8Mask;
219 lir->useMask |= ENCODE_REG_LR;
220 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
221 lir->defMask &= ~r8Mask;
222 lir->defMask |= ENCODE_REG_PC;
223 }
224 }
Ben Cheng5d90c202009-11-22 23:31:11 -0800225}
226
227/*
228 * The following are building blocks to construct low-level IRs with 0 - 4
229 * operands.
230 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800231static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpcode opcode)
Ben Cheng5d90c202009-11-22 23:31:11 -0800232{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800233 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800234 assert(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
235 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800236 setupResourceMasks(insn);
237 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
238 return insn;
239}
240
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800241static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800242 int dest)
243{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800244 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800245 assert(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
246 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800247 insn->operands[0] = dest;
248 setupResourceMasks(insn);
249 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
250 return insn;
251}
252
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800253static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800254 int dest, int src1)
255{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800256 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800257 assert(isPseudoOpcode(opcode) ||
258 (EncodingMap[opcode].flags & IS_BINARY_OP));
259 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800260 insn->operands[0] = dest;
261 insn->operands[1] = src1;
262 setupResourceMasks(insn);
263 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
264 return insn;
265}
266
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800267static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800268 int dest, int src1, int src2)
269{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800270 ArmLIR *insn = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800271 if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
272 LOGE("Bad LIR3: %s[%d]",EncodingMap[opcode].name,opcode);
Ben Cheng5d90c202009-11-22 23:31:11 -0800273 }
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800274 assert(isPseudoOpcode(opcode) ||
275 (EncodingMap[opcode].flags & IS_TERTIARY_OP));
276 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800277 insn->operands[0] = dest;
278 insn->operands[1] = src1;
279 insn->operands[2] = src2;
280 setupResourceMasks(insn);
281 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
282 return insn;
283}
284
Ben Chengfc075c22010-05-28 15:20:08 -0700285#if defined(_ARMV7_A) || defined(_ARMV7_A_NEON)
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800286static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpcode opcode,
Ben Cheng5d90c202009-11-22 23:31:11 -0800287 int dest, int src1, int src2, int info)
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_QUAD_OP));
292 insn->opcode = opcode;
Ben Cheng5d90c202009-11-22 23:31:11 -0800293 insn->operands[0] = dest;
294 insn->operands[1] = src1;
295 insn->operands[2] = src2;
296 insn->operands[3] = info;
297 setupResourceMasks(insn);
298 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
299 return insn;
300}
Ben Chengfc075c22010-05-28 15:20:08 -0700301#endif
Ben Cheng5d90c202009-11-22 23:31:11 -0800302
303/*
304 * If the next instruction is a move-result or move-result-long,
305 * return the target Dalvik sReg[s] and convert the next to a
306 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
307 */
308static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
309 bool fpHint)
310{
311 if (mir->next &&
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800312 ((mir->next->dalvikInsn.opcode == OP_MOVE_RESULT) ||
313 (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_OBJECT))) {
314 mir->next->dalvikInsn.opcode = OP_NOP;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800315 return dvmCompilerGetDest(cUnit, mir->next, 0);
Ben Cheng5d90c202009-11-22 23:31:11 -0800316 } else {
317 RegLocation res = LOC_DALVIK_RETURN_VAL;
318 res.fp = fpHint;
319 return res;
320 }
321}
322
323/*
324 * Search the existing constants in the literal pool for an exact or close match
325 * within specified delta (greater or equal to 0).
326 */
327static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
328 unsigned int delta)
329{
330 LIR *dataTarget = cUnit->wordList;
331 while (dataTarget) {
332 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
333 delta)
334 return (ArmLIR *) dataTarget;
335 dataTarget = dataTarget->next;
336 }
337 return NULL;
338}
339
340/*
341 * The following are building blocks to insert constants into the pool or
342 * instruction streams.
343 */
344
345/* Add a 32-bit constant either in the constant pool or mixed with code */
346static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
347{
348 /* Add the constant to the literal pool */
349 if (!inPlace) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800350 ArmLIR *newValue = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Ben Cheng5d90c202009-11-22 23:31:11 -0800351 newValue->operands[0] = value;
352 newValue->generic.next = cUnit->wordList;
353 cUnit->wordList = (LIR *) newValue;
354 return newValue;
355 } else {
356 /* Add the constant in the middle of code stream */
357 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
358 newLIR1(cUnit, kArm16BitData, (value >> 16));
359 }
360 return NULL;
361}
362
363static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
364 bool fpHint)
365{
366 if (mir->next &&
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800367 (mir->next->dalvikInsn.opcode == OP_MOVE_RESULT_WIDE)) {
368 mir->next->dalvikInsn.opcode = OP_NOP;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800369 return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
Ben Cheng5d90c202009-11-22 23:31:11 -0800370 } else {
371 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
372 res.fp = fpHint;
373 return res;
374 }
375}
376
377
378/*
379 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
380 * blocks.
381 */
382static void genBarrier(CompilationUnit *cUnit)
383{
384 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
385 /* Mark all resources as being clobbered */
386 barrier->defMask = -1;
387}
388
389/* Create the PC reconstruction slot if not already done */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700390static ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
Ben Cheng5d90c202009-11-22 23:31:11 -0800391 ArmLIR *branch,
392 ArmLIR *pcrLabel)
393{
Bill Buzbee1f5cd6f2010-01-11 21:44:36 -0800394 /* Forget all def info (because we might rollback here. Bug #2367397 */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800395 dvmCompilerResetDefTracking(cUnit);
Bill Buzbee1f5cd6f2010-01-11 21:44:36 -0800396
Ben Cheng5d90c202009-11-22 23:31:11 -0800397 /* Set up the place holder to reconstruct this Dalvik PC */
398 if (pcrLabel == NULL) {
399 int dPC = (int) (cUnit->method->insns + dOffset);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800400 pcrLabel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800401 pcrLabel->opcode = kArmPseudoPCReconstructionCell;
Ben Cheng5d90c202009-11-22 23:31:11 -0800402 pcrLabel->operands[0] = dPC;
403 pcrLabel->operands[1] = dOffset;
404 /* Insert the place holder to the growable list */
Ben Cheng00603072010-10-28 11:13:58 -0700405 dvmInsertGrowableList(&cUnit->pcReconstructionList,
406 (intptr_t) pcrLabel);
Ben Cheng5d90c202009-11-22 23:31:11 -0800407 }
408 /* Branch to the PC reconstruction code */
409 branch->generic.target = (LIR *) pcrLabel;
410 return pcrLabel;
411}