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];
36 * Mark load/store instructions that access Dalvik registers through rFP +
39 static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
42 lir->useMask |= ENCODE_DALVIK_REG;
44 lir->defMask |= ENCODE_DALVIK_REG;
48 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
51 lir->aliasInfo = regId;
52 if (DOUBLEREG(lir->operands[0])) {
53 lir->aliasInfo |= 0x80000000;
58 * Decode the register id and mark the corresponding bit(s).
60 static inline void setupRegMask(u8 *mask, int reg)
64 int regId = reg & 0x1f;
67 * Each double register is equal to a pair of single-precision FP registers
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 */
74 *mask |= seed << shift;
78 * Set up the proper fields in the resource mask
80 static void setupResourceMasks(ArmLIR *lir)
82 int opCode = lir->opCode;
86 lir->useMask = lir->defMask = 0;
90 flags = EncodingMap[lir->opCode].flags;
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;
98 if (flags & REG_DEF0) {
99 setupRegMask(&lir->defMask, lir->operands[0]);
102 if (flags & REG_DEF1) {
103 setupRegMask(&lir->defMask, lir->operands[1]);
106 if (flags & REG_DEF_SP) {
107 lir->defMask |= ENCODE_REG_SP;
110 if (flags & REG_DEF_LR) {
111 lir->defMask |= ENCODE_REG_LR;
114 if (flags & REG_DEF_LIST0) {
115 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
118 if (flags & REG_DEF_LIST1) {
119 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
122 if (flags & SETS_CCODES) {
123 lir->defMask |= ENCODE_CCODE;
126 /* Conservatively treat the IT block */
128 lir->defMask = ENCODE_ALL;
131 /* Set up the mask for resources that are used */
132 if (flags & IS_BRANCH) {
133 lir->useMask |= ENCODE_REG_PC;
136 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
139 for (i = 0; i < 4; i++) {
140 if (flags & (1 << (kRegUse0 + i))) {
141 setupRegMask(&lir->useMask, lir->operands[i]);
146 if (flags & REG_USE_PC) {
147 lir->useMask |= ENCODE_REG_PC;
150 if (flags & REG_USE_SP) {
151 lir->useMask |= ENCODE_REG_SP;
154 if (flags & REG_USE_LIST0) {
155 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
158 if (flags & REG_USE_LIST1) {
159 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
162 if (flags & USES_CCODES) {
163 lir->useMask |= ENCODE_CCODE;
168 * The following are building blocks to construct low-level IRs with 0 - 4
171 static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
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);
181 static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
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);
193 static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
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);
207 static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
208 int dest, int src1, int src2)
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);
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);
225 static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
226 int dest, int src1, int src2, int info)
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);
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.
246 static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
250 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
251 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
252 mir->next->dalvikInsn.opCode = OP_NOP;
253 return dvmCompilerGetDest(cUnit, mir->next, 0);
255 RegLocation res = LOC_DALVIK_RETURN_VAL;
262 * Search the existing constants in the literal pool for an exact or close match
263 * within specified delta (greater or equal to 0).
265 static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
268 LIR *dataTarget = cUnit->wordList;
270 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
272 return (ArmLIR *) dataTarget;
273 dataTarget = dataTarget->next;
279 * The following are building blocks to insert constants into the pool or
280 * instruction streams.
283 /* Add a 32-bit constant either in the constant pool or mixed with code */
284 static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
286 /* Add the constant to the literal pool */
288 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
289 newValue->operands[0] = value;
290 newValue->generic.next = cUnit->wordList;
291 cUnit->wordList = (LIR *) newValue;
294 /* Add the constant in the middle of code stream */
295 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
296 newLIR1(cUnit, kArm16BitData, (value >> 16));
301 static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
305 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
306 mir->next->dalvikInsn.opCode = OP_NOP;
307 return dvmCompilerGetDestWide(cUnit, mir->next, 0, 1);
309 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
317 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
320 static void genBarrier(CompilationUnit *cUnit)
322 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
323 /* Mark all resources as being clobbered */
324 barrier->defMask = -1;
327 /* Create the PC reconstruction slot if not already done */
328 extern ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
332 /* Forget all def info (because we might rollback here. Bug #2367397 */
333 dvmCompilerResetDefTracking(cUnit);
335 /* 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);
345 /* Branch to the PC reconstruction code */
346 branch->generic.target = (LIR *) pcrLabel;