blob: 9326faf08fa02669229452615b9a58ba4f08d1e2 [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
buzbeec5159d52012-03-03 11:48:39 -080031bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
32 RegLocation rlSrc)
33{
34 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,
42 zReg, rlSrc.lowReg);
43 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
44 zReg, tReg);
45 oatFreeTemp(cUnit, tReg);
46 } else {
47 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
48 zReg, rlSrc.lowReg);
49 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
50 zReg, rlSrc.highReg);
51 }
52 oatFreeTemp(cUnit, zReg);
53 storeValueWide(cUnit, rlDest, rlResult);
54 return false;
55}
56
buzbee31a4a6f2012-02-28 15:36:15 -080057int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -080058{
buzbee31a4a6f2012-02-28 15:36:15 -080059 loadWordDisp(cUnit, rSELF, offset, rLR);
60 return rLR;
buzbeee3acd072012-02-25 17:03:10 -080061}
62
buzbee31a4a6f2012-02-28 15:36:15 -080063void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -080064{
65 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
66 /*
67 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
68 * mechanism know so it doesn't try to use any of them when
69 * expanding the frame or flushing. This leaves the utility
70 * code with a single temp: r12. This should be enough.
71 */
72 oatLockTemp(cUnit, r0);
73 oatLockTemp(cUnit, r1);
74 oatLockTemp(cUnit, r2);
75 oatLockTemp(cUnit, r3);
76
77 /*
78 * We can safely skip the stack overflow check if we're
79 * a leaf *and* our frame size < fudge factor.
80 */
81 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
82 ((size_t)cUnit->frameSize <
83 Thread::kStackOverflowReservedBytes));
buzbee31a4a6f2012-02-28 15:36:15 -080084 newLIR0(cUnit, kPseudoMethodEntry);
buzbeee3acd072012-02-25 17:03:10 -080085 if (!skipOverflowCheck) {
86 /* Load stack limit */
87 loadWordDisp(cUnit, rSELF,
88 Thread::StackEndOffset().Int32Value(), r12);
89 }
90 /* Spill core callee saves */
91 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
92 /* Need to spill any FP regs? */
93 if (cUnit->numFPSpills) {
94 /*
95 * NOTE: fp spills are a little different from core spills in that
96 * they are pushed as a contiguous block. When promoting from
97 * the fp set, we must allocate all singles from s16..highest-promoted
98 */
99 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
100 }
101 if (!skipOverflowCheck) {
102 opRegRegImm(cUnit, kOpSub, rLR, rSP,
103 cUnit->frameSize - (spillCount * 4));
buzbee31a4a6f2012-02-28 15:36:15 -0800104 genRegRegCheck(cUnit, kCondCc, rLR, r12, NULL,
105 kThrowStackOverflow);
buzbee82488f52012-03-02 08:20:26 -0800106 opRegCopy(cUnit, rSP, rLR); // Establish stack
buzbeee3acd072012-02-25 17:03:10 -0800107 } else {
108 opRegImm(cUnit, kOpSub, rSP,
109 cUnit->frameSize - (spillCount * 4));
110 }
buzbeee1965672012-03-11 18:39:19 -0700111
buzbeee3acd072012-02-25 17:03:10 -0800112 flushIns(cUnit);
113
114 if (cUnit->genDebugger) {
115 // Refresh update debugger callout
116 loadWordDisp(cUnit, rSELF,
Ian Rogers57b86d42012-03-27 16:05:41 -0700117 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode), rSUSPEND);
buzbeee3acd072012-02-25 17:03:10 -0800118 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
119 }
120
121 oatFreeTemp(cUnit, r0);
122 oatFreeTemp(cUnit, r1);
123 oatFreeTemp(cUnit, r2);
124 oatFreeTemp(cUnit, r3);
125}
126
buzbee31a4a6f2012-02-28 15:36:15 -0800127void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -0800128{
129 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
130 /*
131 * In the exit path, r0/r1 are live - make sure they aren't
132 * allocated by the register utilities as temps.
133 */
134 oatLockTemp(cUnit, r0);
135 oatLockTemp(cUnit, r1);
136
buzbee31a4a6f2012-02-28 15:36:15 -0800137 newLIR0(cUnit, kPseudoMethodExit);
buzbeee3acd072012-02-25 17:03:10 -0800138 /* If we're compiling for the debugger, generate an update callout */
139 if (cUnit->genDebugger) {
140 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
141 }
142 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
143 /* Need to restore any FP callee saves? */
144 if (cUnit->numFPSpills) {
145 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
146 }
147 if (cUnit->coreSpillMask & (1 << rLR)) {
148 /* Unspill rLR to rPC */
149 cUnit->coreSpillMask &= ~(1 << rLR);
150 cUnit->coreSpillMask |= (1 << rPC);
151 }
152 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
153 if (!(cUnit->coreSpillMask & (1 << rPC))) {
154 /* We didn't pop to rPC, so must do a bv rLR */
155 newLIR1(cUnit, kThumbBx, rLR);
156 }
157}
158
159/*
160 * Nop any unconditional branches that go to the next instruction.
161 * Note: new redundant branches may be inserted later, and we'll
162 * use a check in final instruction assembly to nop those out.
163 */
164void removeRedundantBranches(CompilationUnit* cUnit)
165{
buzbee31a4a6f2012-02-28 15:36:15 -0800166 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800167
buzbee31a4a6f2012-02-28 15:36:15 -0800168 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
169 thisLIR != (LIR*) cUnit->lastLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800170 thisLIR = NEXT_LIR(thisLIR)) {
171
172 /* Branch to the next instruction */
173 if ((thisLIR->opcode == kThumbBUncond) ||
174 (thisLIR->opcode == kThumb2BUncond)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800175 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800176
177 while (true) {
178 nextLIR = NEXT_LIR(nextLIR);
179
180 /*
181 * Is the branch target the next instruction?
182 */
buzbee31a4a6f2012-02-28 15:36:15 -0800183 if (nextLIR == (LIR*) thisLIR->target) {
buzbeee3acd072012-02-25 17:03:10 -0800184 thisLIR->flags.isNop = true;
185 break;
186 }
187
188 /*
189 * Found real useful stuff between the branch and the target.
190 * Need to explicitly check the lastLIRInsn here because it
191 * might be the last real instruction.
192 */
193 if (!isPseudoOpcode(nextLIR->opcode) ||
buzbee31a4a6f2012-02-28 15:36:15 -0800194 (nextLIR = (LIR*) cUnit->lastLIRInsn))
buzbeee3acd072012-02-25 17:03:10 -0800195 break;
196 }
197 }
198 }
199}
200
buzbeee3acd072012-02-25 17:03:10 -0800201
202/* Common initialization routine for an architecture family */
203bool oatArchInit()
204{
205 int i;
206
207 for (i = 0; i < kArmLast; i++) {
208 if (EncodingMap[i].opcode != i) {
209 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
210 " is wrong: expecting " << i << ", seeing " <<
211 (int)EncodingMap[i].opcode;
212 }
213 }
214
215 return oatArchVariantInit();
216}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800217} // namespace art