blob: ee4c877841961a12c98fc57246ff7384c8e9e665 [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 */
33static int opcodeCoverage[256];
34
35/*
36 * Mark load/store instructions that access Dalvik registers through rFP +
37 * offset.
38 */
39static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
40{
41 if (isLoad) {
42 lir->useMask |= ENCODE_DALVIK_REG;
43 } else {
44 lir->defMask |= ENCODE_DALVIK_REG;
45 }
46
47 /*
48 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
49 * access.
50 */
51 lir->aliasInfo = regId;
52 if (DOUBLEREG(lir->operands[0])) {
53 lir->aliasInfo |= 0x80000000;
54 }
55}
56
57/*
58 * Decode the register id and mark the corresponding bit(s).
59 */
60static inline void setupRegMask(u8 *mask, int reg)
61{
62 u8 seed;
63 int shift;
64 int regId = reg & 0x1f;
65
66 /*
67 * Each double register is equal to a pair of single-precision FP registers
68 */
69 seed = DOUBLEREG(reg) ? 3 : 1;
70 /* FP register starts at bit position 16 */
71 shift = FPREG(reg) ? kFPReg0 : 0;
72 /* Expand the double register id into single offset */
73 shift += regId;
74 *mask |= seed << shift;
75}
76
77/*
78 * Set up the proper fields in the resource mask
79 */
80static void setupResourceMasks(ArmLIR *lir)
81{
82 int opCode = lir->opCode;
83 int flags;
84
85 if (opCode <= 0) {
86 lir->useMask = lir->defMask = 0;
87 return;
88 }
89
90 flags = EncodingMap[lir->opCode].flags;
91
92 /* Set up the mask for resources that are updated */
93 if (flags & IS_BRANCH) {
94 lir->defMask |= ENCODE_REG_PC;
95 lir->useMask |= ENCODE_REG_PC;
96 }
97
98 if (flags & REG_DEF0) {
99 setupRegMask(&lir->defMask, lir->operands[0]);
100 }
101
102 if (flags & REG_DEF1) {
103 setupRegMask(&lir->defMask, lir->operands[1]);
104 }
105
106 if (flags & REG_DEF_SP) {
107 lir->defMask |= ENCODE_REG_SP;
108 }
109
110 if (flags & REG_DEF_SP) {
111 lir->defMask |= ENCODE_REG_LR;
112 }
113
114 if (flags & REG_DEF_LIST0) {
115 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
116 }
117
118 if (flags & REG_DEF_LIST1) {
119 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
120 }
121
122 if (flags & SETS_CCODES) {
123 lir->defMask |= ENCODE_CCODE;
124 }
125
126 /* Conservatively treat the IT block */
127 if (flags & IS_IT) {
128 lir->defMask = ENCODE_ALL;
129 }
130
131 /* Set up the mask for resources that are used */
132 if (flags & IS_BRANCH) {
133 lir->useMask |= ENCODE_REG_PC;
134 }
135
136 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
137 int i;
138
139 for (i = 0; i < 4; i++) {
140 if (flags & (1 << (kRegUse0 + i))) {
141 setupRegMask(&lir->useMask, lir->operands[i]);
142 }
143 }
144 }
145
146 if (flags & REG_USE_PC) {
147 lir->useMask |= ENCODE_REG_PC;
148 }
149
150 if (flags & REG_USE_SP) {
151 lir->useMask |= ENCODE_REG_SP;
152 }
153
154 if (flags & REG_USE_LIST0) {
155 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
156 }
157
158 if (flags & REG_USE_LIST1) {
159 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
160 }
161
162 if (flags & USES_CCODES) {
163 lir->useMask |= ENCODE_CCODE;
164 }
165}
166
167/*
168 * The following are building blocks to construct low-level IRs with 0 - 4
169 * operands.
170 */
171static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
172{
173 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
174 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
175 insn->opCode = opCode;
176 setupResourceMasks(insn);
177 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
178 return insn;
179}
180
181static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
182 int dest)
183{
184 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
185 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
186 insn->opCode = opCode;
187 insn->operands[0] = dest;
188 setupResourceMasks(insn);
189 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
190 return insn;
191}
192
193static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
194 int dest, int src1)
195{
196 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
197 assert(isPseudoOpCode(opCode) ||
198 (EncodingMap[opCode].flags & IS_BINARY_OP));
199 insn->opCode = opCode;
200 insn->operands[0] = dest;
201 insn->operands[1] = src1;
202 setupResourceMasks(insn);
203 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
204 return insn;
205}
206
207static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
208 int dest, int src1, int src2)
209{
210 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
211 if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
212 LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
213 }
214 assert(isPseudoOpCode(opCode) ||
215 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
216 insn->opCode = opCode;
217 insn->operands[0] = dest;
218 insn->operands[1] = src1;
219 insn->operands[2] = src2;
220 setupResourceMasks(insn);
221 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
222 return insn;
223}
224
225static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
226 int dest, int src1, int src2, int info)
227{
228 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
229 assert(isPseudoOpCode(opCode) ||
230 (EncodingMap[opCode].flags & IS_QUAD_OP));
231 insn->opCode = opCode;
232 insn->operands[0] = dest;
233 insn->operands[1] = src1;
234 insn->operands[2] = src2;
235 insn->operands[3] = info;
236 setupResourceMasks(insn);
237 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
238 return insn;
239}
240
241/*
242 * If the next instruction is a move-result or move-result-long,
243 * return the target Dalvik sReg[s] and convert the next to a
244 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
245 */
246static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
247 bool fpHint)
248{
249 if (mir->next &&
250 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
251 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
252 mir->next->dalvikInsn.opCode = OP_NOP;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800253 return dvmCompilerGetDest(cUnit, mir->next, 0);
Ben Cheng5d90c202009-11-22 23:31:11 -0800254 } else {
255 RegLocation res = LOC_DALVIK_RETURN_VAL;
256 res.fp = fpHint;
257 return res;
258 }
259}
260
261/*
262 * Search the existing constants in the literal pool for an exact or close match
263 * within specified delta (greater or equal to 0).
264 */
265static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
266 unsigned int delta)
267{
268 LIR *dataTarget = cUnit->wordList;
269 while (dataTarget) {
270 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
271 delta)
272 return (ArmLIR *) dataTarget;
273 dataTarget = dataTarget->next;
274 }
275 return NULL;
276}
277
278/*
279 * The following are building blocks to insert constants into the pool or
280 * instruction streams.
281 */
282
283/* Add a 32-bit constant either in the constant pool or mixed with code */
284static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
285{
286 /* Add the constant to the literal pool */
287 if (!inPlace) {
288 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
289 newValue->operands[0] = value;
290 newValue->generic.next = cUnit->wordList;
291 cUnit->wordList = (LIR *) newValue;
292 return newValue;
293 } else {
294 /* Add the constant in the middle of code stream */
295 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
296 newLIR1(cUnit, kArm16BitData, (value >> 16));
297 }
298 return NULL;
299}
300
301static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
302 bool fpHint)
303{
304 if (mir->next &&
305 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
306 mir->next->dalvikInsn.opCode = OP_NOP;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800307 return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
Ben Cheng5d90c202009-11-22 23:31:11 -0800308 } else {
309 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
310 res.fp = fpHint;
311 return res;
312 }
313}
314
315
316/*
317 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
318 * blocks.
319 */
320static void genBarrier(CompilationUnit *cUnit)
321{
322 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
323 /* Mark all resources as being clobbered */
324 barrier->defMask = -1;
325}
326
327/* Create the PC reconstruction slot if not already done */
328extern ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
329 ArmLIR *branch,
330 ArmLIR *pcrLabel)
331{
Bill Buzbee1f5cd6f2010-01-11 21:44:36 -0800332 /* Forget all def info (because we might rollback here. Bug #2367397 */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800333 dvmCompilerResetDefTracking(cUnit);
Bill Buzbee1f5cd6f2010-01-11 21:44:36 -0800334
Ben Cheng5d90c202009-11-22 23:31:11 -0800335 /* Set up the place holder to reconstruct this Dalvik PC */
336 if (pcrLabel == NULL) {
337 int dPC = (int) (cUnit->method->insns + dOffset);
338 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
339 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
340 pcrLabel->operands[0] = dPC;
341 pcrLabel->operands[1] = dOffset;
342 /* Insert the place holder to the growable list */
343 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
344 }
345 /* Branch to the PC reconstruction code */
346 branch->generic.target = (LIR *) pcrLabel;
347 return pcrLabel;
348}