blob: c0d91a454aec2092311d61e859afea6e9a5b90ad [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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 arm-specific codegen factory support.
19 * It is included by
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
Ian Rogers57b86d42012-03-27 16:05:41 -070025#include "oat/runtime/oat_support_entrypoints.h"
26
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080027namespace art {
28
buzbee31a4a6f2012-02-28 15:36:15 -080029void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
buzbeee3acd072012-02-25 17:03:10 -080030
buzbee408ad162012-06-06 16:45:18 -070031bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeec5159d52012-03-03 11:48:39 -080032 RegLocation rlSrc)
33{
Bill Buzbeea114add2012-05-03 15:00:40 -070034 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
35 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
36 int zReg = oatAllocTemp(cUnit);
37 loadConstantNoClobber(cUnit, zReg, 0);
38 // Check for destructive overlap
39 if (rlResult.lowReg == rlSrc.highReg) {
40 int tReg = oatAllocTemp(cUnit);
41 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg);
42 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, tReg);
43 oatFreeTemp(cUnit, tReg);
44 } else {
45 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg);
46 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, rlSrc.highReg);
47 }
48 oatFreeTemp(cUnit, zReg);
49 storeValueWide(cUnit, rlDest, rlResult);
50 return false;
buzbeec5159d52012-03-03 11:48:39 -080051}
52
buzbee31a4a6f2012-02-28 15:36:15 -080053int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -080054{
Bill Buzbeea114add2012-05-03 15:00:40 -070055 loadWordDisp(cUnit, rSELF, offset, rLR);
56 return rLR;
buzbeee3acd072012-02-25 17:03:10 -080057}
58
buzbee2cfc6392012-05-07 14:51:40 -070059void genEntrySequence(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -080060{
Bill Buzbeea114add2012-05-03 15:00:40 -070061 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
62 /*
63 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
64 * mechanism know so it doesn't try to use any of them when
65 * expanding the frame or flushing. This leaves the utility
66 * code with a single temp: r12. This should be enough.
67 */
68 oatLockTemp(cUnit, r0);
69 oatLockTemp(cUnit, r1);
70 oatLockTemp(cUnit, r2);
71 oatLockTemp(cUnit, r3);
72
73 /*
74 * We can safely skip the stack overflow check if we're
75 * a leaf *and* our frame size < fudge factor.
76 */
77 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
78 ((size_t)cUnit->frameSize <
79 Thread::kStackOverflowReservedBytes));
80 newLIR0(cUnit, kPseudoMethodEntry);
81 if (!skipOverflowCheck) {
82 /* Load stack limit */
83 loadWordDisp(cUnit, rSELF, Thread::StackEndOffset().Int32Value(), r12);
84 }
85 /* Spill core callee saves */
86 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
87 /* Need to spill any FP regs? */
88 if (cUnit->numFPSpills) {
buzbeee3acd072012-02-25 17:03:10 -080089 /*
Bill Buzbeea114add2012-05-03 15:00:40 -070090 * NOTE: fp spills are a little different from core spills in that
91 * they are pushed as a contiguous block. When promoting from
92 * the fp set, we must allocate all singles from s16..highest-promoted
buzbeee3acd072012-02-25 17:03:10 -080093 */
Bill Buzbeea114add2012-05-03 15:00:40 -070094 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
95 }
96 if (!skipOverflowCheck) {
97 opRegRegImm(cUnit, kOpSub, rLR, rSP, cUnit->frameSize - (spillCount * 4));
buzbee408ad162012-06-06 16:45:18 -070098 genRegRegCheck(cUnit, kCondCc, rLR, r12, kThrowStackOverflow);
Bill Buzbeea114add2012-05-03 15:00:40 -070099 opRegCopy(cUnit, rSP, rLR); // Establish stack
100 } else {
101 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (spillCount * 4));
102 }
buzbeee3acd072012-02-25 17:03:10 -0800103
Bill Buzbeea114add2012-05-03 15:00:40 -0700104 flushIns(cUnit);
buzbeee1965672012-03-11 18:39:19 -0700105
Bill Buzbeea114add2012-05-03 15:00:40 -0700106 if (cUnit->genDebugger) {
107 // Refresh update debugger callout
108 loadWordDisp(cUnit, rSELF,
109 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode), rSUSPEND);
110 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
111 }
buzbeee3acd072012-02-25 17:03:10 -0800112
Bill Buzbeea114add2012-05-03 15:00:40 -0700113 oatFreeTemp(cUnit, r0);
114 oatFreeTemp(cUnit, r1);
115 oatFreeTemp(cUnit, r2);
116 oatFreeTemp(cUnit, r3);
buzbeee3acd072012-02-25 17:03:10 -0800117}
118
buzbee2cfc6392012-05-07 14:51:40 -0700119void genExitSequence(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800120{
Bill Buzbeea114add2012-05-03 15:00:40 -0700121 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
122 /*
123 * In the exit path, r0/r1 are live - make sure they aren't
124 * allocated by the register utilities as temps.
125 */
126 oatLockTemp(cUnit, r0);
127 oatLockTemp(cUnit, r1);
buzbeee3acd072012-02-25 17:03:10 -0800128
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 newLIR0(cUnit, kPseudoMethodExit);
130 /* If we're compiling for the debugger, generate an update callout */
131 if (cUnit->genDebugger) {
132 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
133 }
134 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
135 /* Need to restore any FP callee saves? */
136 if (cUnit->numFPSpills) {
137 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
138 }
139 if (cUnit->coreSpillMask & (1 << rLR)) {
140 /* Unspill rLR to rPC */
141 cUnit->coreSpillMask &= ~(1 << rLR);
142 cUnit->coreSpillMask |= (1 << rPC);
143 }
144 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
145 if (!(cUnit->coreSpillMask & (1 << rPC))) {
146 /* We didn't pop to rPC, so must do a bv rLR */
147 newLIR1(cUnit, kThumbBx, rLR);
148 }
buzbeee3acd072012-02-25 17:03:10 -0800149}
150
151/*
152 * Nop any unconditional branches that go to the next instruction.
153 * Note: new redundant branches may be inserted later, and we'll
154 * use a check in final instruction assembly to nop those out.
155 */
156void removeRedundantBranches(CompilationUnit* cUnit)
157{
Bill Buzbeea114add2012-05-03 15:00:40 -0700158 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800159
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
161 thisLIR != (LIR*) cUnit->lastLIRInsn;
162 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee3acd072012-02-25 17:03:10 -0800163
Bill Buzbeea114add2012-05-03 15:00:40 -0700164 /* Branch to the next instruction */
165 if ((thisLIR->opcode == kThumbBUncond) ||
166 (thisLIR->opcode == kThumb2BUncond)) {
167 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800168
Bill Buzbeea114add2012-05-03 15:00:40 -0700169 while (true) {
170 nextLIR = NEXT_LIR(nextLIR);
buzbeee3acd072012-02-25 17:03:10 -0800171
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 /*
173 * Is the branch target the next instruction?
174 */
175 if (nextLIR == (LIR*) thisLIR->target) {
176 thisLIR->flags.isNop = true;
177 break;
buzbeee3acd072012-02-25 17:03:10 -0800178 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700179
180 /*
181 * Found real useful stuff between the branch and the target.
182 * Need to explicitly check the lastLIRInsn here because it
183 * might be the last real instruction.
184 */
185 if (!isPseudoOpcode(nextLIR->opcode) ||
186 (nextLIR = (LIR*) cUnit->lastLIRInsn))
187 break;
188 }
buzbeee3acd072012-02-25 17:03:10 -0800189 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700190 }
buzbeee3acd072012-02-25 17:03:10 -0800191}
192
buzbeee3acd072012-02-25 17:03:10 -0800193
194/* Common initialization routine for an architecture family */
195bool oatArchInit()
196{
Bill Buzbeea114add2012-05-03 15:00:40 -0700197 int i;
buzbeee3acd072012-02-25 17:03:10 -0800198
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 for (i = 0; i < kArmLast; i++) {
200 if (EncodingMap[i].opcode != i) {
201 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
202 << " is wrong: expecting " << i << ", seeing "
203 << (int)EncodingMap[i].opcode;
buzbeee3acd072012-02-25 17:03:10 -0800204 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700205 }
buzbeee3acd072012-02-25 17:03:10 -0800206
Bill Buzbeea114add2012-05-03 15:00:40 -0700207 return oatArchVariantInit();
buzbeee3acd072012-02-25 17:03:10 -0800208}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800209} // namespace art