blob: ba49277a3fb58069a748c4f420cd082a89face0a [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
buzbeead8f15e2012-06-18 14:49:45 -070059void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs,
60 RegLocation rlMethod)
buzbeee3acd072012-02-25 17:03:10 -080061{
Bill Buzbeea114add2012-05-03 15:00:40 -070062 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
63 /*
64 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
65 * mechanism know so it doesn't try to use any of them when
66 * expanding the frame or flushing. This leaves the utility
67 * code with a single temp: r12. This should be enough.
68 */
69 oatLockTemp(cUnit, r0);
70 oatLockTemp(cUnit, r1);
71 oatLockTemp(cUnit, r2);
72 oatLockTemp(cUnit, r3);
73
74 /*
75 * We can safely skip the stack overflow check if we're
76 * a leaf *and* our frame size < fudge factor.
77 */
78 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
79 ((size_t)cUnit->frameSize <
80 Thread::kStackOverflowReservedBytes));
81 newLIR0(cUnit, kPseudoMethodEntry);
82 if (!skipOverflowCheck) {
83 /* Load stack limit */
84 loadWordDisp(cUnit, rSELF, Thread::StackEndOffset().Int32Value(), r12);
85 }
86 /* Spill core callee saves */
87 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
88 /* Need to spill any FP regs? */
89 if (cUnit->numFPSpills) {
buzbeee3acd072012-02-25 17:03:10 -080090 /*
Bill Buzbeea114add2012-05-03 15:00:40 -070091 * NOTE: fp spills are a little different from core spills in that
92 * they are pushed as a contiguous block. When promoting from
93 * the fp set, we must allocate all singles from s16..highest-promoted
buzbeee3acd072012-02-25 17:03:10 -080094 */
Bill Buzbeea114add2012-05-03 15:00:40 -070095 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
96 }
97 if (!skipOverflowCheck) {
98 opRegRegImm(cUnit, kOpSub, rLR, rSP, cUnit->frameSize - (spillCount * 4));
buzbee408ad162012-06-06 16:45:18 -070099 genRegRegCheck(cUnit, kCondCc, rLR, r12, kThrowStackOverflow);
Bill Buzbeea114add2012-05-03 15:00:40 -0700100 opRegCopy(cUnit, rSP, rLR); // Establish stack
101 } else {
102 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (spillCount * 4));
103 }
buzbeee3acd072012-02-25 17:03:10 -0800104
buzbeead8f15e2012-06-18 14:49:45 -0700105 flushIns(cUnit, argLocs, rlMethod);
buzbeee1965672012-03-11 18:39:19 -0700106
Bill Buzbeea114add2012-05-03 15:00:40 -0700107 if (cUnit->genDebugger) {
108 // Refresh update debugger callout
109 loadWordDisp(cUnit, rSELF,
110 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode), rSUSPEND);
111 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
112 }
buzbeee3acd072012-02-25 17:03:10 -0800113
Bill Buzbeea114add2012-05-03 15:00:40 -0700114 oatFreeTemp(cUnit, r0);
115 oatFreeTemp(cUnit, r1);
116 oatFreeTemp(cUnit, r2);
117 oatFreeTemp(cUnit, r3);
buzbeee3acd072012-02-25 17:03:10 -0800118}
119
buzbee2cfc6392012-05-07 14:51:40 -0700120void genExitSequence(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800121{
Bill Buzbeea114add2012-05-03 15:00:40 -0700122 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
123 /*
124 * In the exit path, r0/r1 are live - make sure they aren't
125 * allocated by the register utilities as temps.
126 */
127 oatLockTemp(cUnit, r0);
128 oatLockTemp(cUnit, r1);
buzbeee3acd072012-02-25 17:03:10 -0800129
Bill Buzbeea114add2012-05-03 15:00:40 -0700130 newLIR0(cUnit, kPseudoMethodExit);
131 /* If we're compiling for the debugger, generate an update callout */
132 if (cUnit->genDebugger) {
133 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
134 }
135 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
136 /* Need to restore any FP callee saves? */
137 if (cUnit->numFPSpills) {
138 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
139 }
140 if (cUnit->coreSpillMask & (1 << rLR)) {
141 /* Unspill rLR to rPC */
142 cUnit->coreSpillMask &= ~(1 << rLR);
143 cUnit->coreSpillMask |= (1 << rPC);
144 }
145 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
146 if (!(cUnit->coreSpillMask & (1 << rPC))) {
147 /* We didn't pop to rPC, so must do a bv rLR */
148 newLIR1(cUnit, kThumbBx, rLR);
149 }
buzbeee3acd072012-02-25 17:03:10 -0800150}
151
152/*
153 * Nop any unconditional branches that go to the next instruction.
154 * Note: new redundant branches may be inserted later, and we'll
155 * use a check in final instruction assembly to nop those out.
156 */
157void removeRedundantBranches(CompilationUnit* cUnit)
158{
Bill Buzbeea114add2012-05-03 15:00:40 -0700159 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800160
Bill Buzbeea114add2012-05-03 15:00:40 -0700161 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
162 thisLIR != (LIR*) cUnit->lastLIRInsn;
163 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee3acd072012-02-25 17:03:10 -0800164
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 /* Branch to the next instruction */
166 if ((thisLIR->opcode == kThumbBUncond) ||
167 (thisLIR->opcode == kThumb2BUncond)) {
168 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800169
Bill Buzbeea114add2012-05-03 15:00:40 -0700170 while (true) {
171 nextLIR = NEXT_LIR(nextLIR);
buzbeee3acd072012-02-25 17:03:10 -0800172
Bill Buzbeea114add2012-05-03 15:00:40 -0700173 /*
174 * Is the branch target the next instruction?
175 */
176 if (nextLIR == (LIR*) thisLIR->target) {
177 thisLIR->flags.isNop = true;
178 break;
buzbeee3acd072012-02-25 17:03:10 -0800179 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700180
181 /*
182 * Found real useful stuff between the branch and the target.
183 * Need to explicitly check the lastLIRInsn here because it
184 * might be the last real instruction.
185 */
186 if (!isPseudoOpcode(nextLIR->opcode) ||
187 (nextLIR = (LIR*) cUnit->lastLIRInsn))
188 break;
189 }
buzbeee3acd072012-02-25 17:03:10 -0800190 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700191 }
buzbeee3acd072012-02-25 17:03:10 -0800192}
193
buzbeee3acd072012-02-25 17:03:10 -0800194
195/* Common initialization routine for an architecture family */
196bool oatArchInit()
197{
Bill Buzbeea114add2012-05-03 15:00:40 -0700198 int i;
buzbeee3acd072012-02-25 17:03:10 -0800199
Bill Buzbeea114add2012-05-03 15:00:40 -0700200 for (i = 0; i < kArmLast; i++) {
201 if (EncodingMap[i].opcode != i) {
202 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
203 << " is wrong: expecting " << i << ", seeing "
204 << (int)EncodingMap[i].opcode;
buzbeee3acd072012-02-25 17:03:10 -0800205 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700206 }
buzbeee3acd072012-02-25 17:03:10 -0800207
Bill Buzbeea114add2012-05-03 15:00:40 -0700208 return oatArchVariantInit();
buzbeee3acd072012-02-25 17:03:10 -0800209}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800210} // namespace art