2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
21 * Codegen-$(TARGET_ARCH_VARIANT).c
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
27 #include "compiler/Loop.h"
29 /* Array holding the entry offset of each template relative to the first one */
30 static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
32 /* Track exercised opcodes */
33 static int opcodeCoverage[256];
35 static void setMemRefType(ArmLIR *lir, bool isLoad, int memType)
39 assert( EncodingMap[lir->opCode].flags & (IS_LOAD | IS_STORE));
41 maskPtr = &lir->useMask;
42 mask = ENCODE_MEM_USE;
44 maskPtr = &lir->defMask;
45 mask = ENCODE_MEM_DEF;
47 /* Clear out the memref flags */
49 /* ..and then add back the one we need */
53 *maskPtr |= (ENCODE_LITERAL | ENCODE_LITPOOL_REF);
56 *maskPtr |= (ENCODE_DALVIK_REG | ENCODE_FRAME_REF);
59 *maskPtr |= ENCODE_HEAP_REF;
62 LOGE("Jit: invalid memref kind - %d", memType);
68 * Mark load/store instructions that access Dalvik registers through rFP +
71 static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
73 setMemRefType(lir, isLoad, kDalvikReg);
76 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
79 lir->aliasInfo = regId;
80 if (DOUBLEREG(lir->operands[0])) {
81 lir->aliasInfo |= 0x80000000;
86 * Decode the register id and mark the corresponding bit(s).
88 static inline void setupRegMask(u8 *mask, int reg)
92 int regId = reg & 0x1f;
95 * Each double register is equal to a pair of single-precision FP registers
97 seed = DOUBLEREG(reg) ? 3 : 1;
98 /* FP register starts at bit position 16 */
99 shift = FPREG(reg) ? kFPReg0 : 0;
100 /* Expand the double register id into single offset */
102 *mask |= seed << shift;
106 * Set up the proper fields in the resource mask
108 static void setupResourceMasks(ArmLIR *lir)
110 int opCode = lir->opCode;
114 lir->useMask = lir->defMask = 0;
118 flags = EncodingMap[lir->opCode].flags;
120 /* Set up the mask for resources that are updated */
121 if (flags & (IS_LOAD | IS_STORE)) {
122 /* Default to heap - will catch specialized classes later */
123 setMemRefType(lir, flags & IS_LOAD, kHeapRef);
126 if (flags & IS_BRANCH) {
127 lir->defMask |= ENCODE_REG_PC;
128 lir->useMask |= ENCODE_REG_PC;
131 if (flags & REG_DEF0) {
132 setupRegMask(&lir->defMask, lir->operands[0]);
135 if (flags & REG_DEF1) {
136 setupRegMask(&lir->defMask, lir->operands[1]);
139 if (flags & REG_DEF_SP) {
140 lir->defMask |= ENCODE_REG_SP;
143 if (flags & REG_DEF_LR) {
144 lir->defMask |= ENCODE_REG_LR;
147 if (flags & REG_DEF_LIST0) {
148 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
151 if (flags & REG_DEF_LIST1) {
152 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
155 if (flags & SETS_CCODES) {
156 lir->defMask |= ENCODE_CCODE;
159 /* Conservatively treat the IT block */
161 lir->defMask = ENCODE_ALL;
164 /* Set up the mask for resources that are used */
165 if (flags & IS_BRANCH) {
166 lir->useMask |= ENCODE_REG_PC;
169 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
172 for (i = 0; i < 4; i++) {
173 if (flags & (1 << (kRegUse0 + i))) {
174 setupRegMask(&lir->useMask, lir->operands[i]);
179 if (flags & REG_USE_PC) {
180 lir->useMask |= ENCODE_REG_PC;
183 if (flags & REG_USE_SP) {
184 lir->useMask |= ENCODE_REG_SP;
187 if (flags & REG_USE_LIST0) {
188 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
191 if (flags & REG_USE_LIST1) {
192 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
195 if (flags & USES_CCODES) {
196 lir->useMask |= ENCODE_CCODE;
201 * The following are building blocks to construct low-level IRs with 0 - 4
204 static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
206 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
207 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
208 insn->opCode = opCode;
209 setupResourceMasks(insn);
210 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
214 static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
217 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
218 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
219 insn->opCode = opCode;
220 insn->operands[0] = dest;
221 setupResourceMasks(insn);
222 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
226 static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
229 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
230 assert(isPseudoOpCode(opCode) ||
231 (EncodingMap[opCode].flags & IS_BINARY_OP));
232 insn->opCode = opCode;
233 insn->operands[0] = dest;
234 insn->operands[1] = src1;
235 setupResourceMasks(insn);
236 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
240 static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
241 int dest, int src1, int src2)
243 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
244 if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
245 LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
247 assert(isPseudoOpCode(opCode) ||
248 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
249 insn->opCode = opCode;
250 insn->operands[0] = dest;
251 insn->operands[1] = src1;
252 insn->operands[2] = src2;
253 setupResourceMasks(insn);
254 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
258 static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
259 int dest, int src1, int src2, int info)
261 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
262 assert(isPseudoOpCode(opCode) ||
263 (EncodingMap[opCode].flags & IS_QUAD_OP));
264 insn->opCode = opCode;
265 insn->operands[0] = dest;
266 insn->operands[1] = src1;
267 insn->operands[2] = src2;
268 insn->operands[3] = info;
269 setupResourceMasks(insn);
270 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
275 * If the next instruction is a move-result or move-result-long,
276 * return the target Dalvik sReg[s] and convert the next to a
277 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
279 static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
283 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
284 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
285 mir->next->dalvikInsn.opCode = OP_NOP;
286 return dvmCompilerGetDest(cUnit, mir->next, 0);
288 RegLocation res = LOC_DALVIK_RETURN_VAL;
295 * Search the existing constants in the literal pool for an exact or close match
296 * within specified delta (greater or equal to 0).
298 static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
301 LIR *dataTarget = cUnit->wordList;
303 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
305 return (ArmLIR *) dataTarget;
306 dataTarget = dataTarget->next;
312 * The following are building blocks to insert constants into the pool or
313 * instruction streams.
316 /* Add a 32-bit constant either in the constant pool or mixed with code */
317 static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
319 /* Add the constant to the literal pool */
321 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
322 newValue->operands[0] = value;
323 newValue->generic.next = cUnit->wordList;
324 cUnit->wordList = (LIR *) newValue;
327 /* Add the constant in the middle of code stream */
328 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
329 newLIR1(cUnit, kArm16BitData, (value >> 16));
334 static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
338 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
339 mir->next->dalvikInsn.opCode = OP_NOP;
340 return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
342 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
350 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
353 static void genBarrier(CompilationUnit *cUnit)
355 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
356 /* Mark all resources as being clobbered */
357 barrier->defMask = -1;
360 /* Create the PC reconstruction slot if not already done */
361 extern ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
365 /* Forget all def info (because we might rollback here. Bug #2367397 */
366 dvmCompilerResetDefTracking(cUnit);
368 /* Set up the place holder to reconstruct this Dalvik PC */
369 if (pcrLabel == NULL) {
370 int dPC = (int) (cUnit->method->insns + dOffset);
371 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
372 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
373 pcrLabel->operands[0] = dPC;
374 pcrLabel->operands[1] = dOffset;
375 /* Insert the place holder to the growable list */
376 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
378 /* Branch to the PC reconstruction code */
379 branch->generic.target = (LIR *) pcrLabel;