blob: f85bd2fff5f1612f29084a4d061c09bda46d9f16 [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
buzbeeb046e162012-10-30 15:48:42 -070017/* This file contains arm-specific codegen factory support. */
buzbee67bf8852011-08-17 17:51:35 -070018
Ian Rogers57b86d42012-03-27 16:05:41 -070019#include "oat/runtime/oat_support_entrypoints.h"
20
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080021namespace art {
22
buzbee408ad162012-06-06 16:45:18 -070023bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeec5159d52012-03-03 11:48:39 -080024 RegLocation rlSrc)
25{
Bill Buzbeea114add2012-05-03 15:00:40 -070026 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
27 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
28 int zReg = oatAllocTemp(cUnit);
29 loadConstantNoClobber(cUnit, zReg, 0);
30 // Check for destructive overlap
31 if (rlResult.lowReg == rlSrc.highReg) {
32 int tReg = oatAllocTemp(cUnit);
33 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg);
34 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, tReg);
35 oatFreeTemp(cUnit, tReg);
36 } else {
37 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, zReg, rlSrc.lowReg);
38 opRegRegReg(cUnit, kOpSbc, rlResult.highReg, zReg, rlSrc.highReg);
39 }
40 oatFreeTemp(cUnit, zReg);
41 storeValueWide(cUnit, rlDest, rlResult);
42 return false;
buzbeec5159d52012-03-03 11:48:39 -080043}
44
buzbee31a4a6f2012-02-28 15:36:15 -080045int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -080046{
Bill Buzbeea114add2012-05-03 15:00:40 -070047 loadWordDisp(cUnit, rSELF, offset, rLR);
48 return rLR;
buzbeee3acd072012-02-25 17:03:10 -080049}
50
buzbeead8f15e2012-06-18 14:49:45 -070051void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs,
52 RegLocation rlMethod)
buzbeee3acd072012-02-25 17:03:10 -080053{
Bill Buzbeea114add2012-05-03 15:00:40 -070054 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
55 /*
56 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
57 * mechanism know so it doesn't try to use any of them when
58 * expanding the frame or flushing. This leaves the utility
59 * code with a single temp: r12. This should be enough.
60 */
61 oatLockTemp(cUnit, r0);
62 oatLockTemp(cUnit, r1);
63 oatLockTemp(cUnit, r2);
64 oatLockTemp(cUnit, r3);
65
66 /*
67 * We can safely skip the stack overflow check if we're
68 * a leaf *and* our frame size < fudge factor.
69 */
70 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
71 ((size_t)cUnit->frameSize <
72 Thread::kStackOverflowReservedBytes));
73 newLIR0(cUnit, kPseudoMethodEntry);
74 if (!skipOverflowCheck) {
75 /* Load stack limit */
76 loadWordDisp(cUnit, rSELF, Thread::StackEndOffset().Int32Value(), r12);
77 }
78 /* Spill core callee saves */
79 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
80 /* Need to spill any FP regs? */
81 if (cUnit->numFPSpills) {
buzbeee3acd072012-02-25 17:03:10 -080082 /*
Bill Buzbeea114add2012-05-03 15:00:40 -070083 * NOTE: fp spills are a little different from core spills in that
84 * they are pushed as a contiguous block. When promoting from
85 * the fp set, we must allocate all singles from s16..highest-promoted
buzbeee3acd072012-02-25 17:03:10 -080086 */
Bill Buzbeea114add2012-05-03 15:00:40 -070087 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
88 }
89 if (!skipOverflowCheck) {
90 opRegRegImm(cUnit, kOpSub, rLR, rSP, cUnit->frameSize - (spillCount * 4));
buzbee408ad162012-06-06 16:45:18 -070091 genRegRegCheck(cUnit, kCondCc, rLR, r12, kThrowStackOverflow);
Bill Buzbeea114add2012-05-03 15:00:40 -070092 opRegCopy(cUnit, rSP, rLR); // Establish stack
93 } else {
94 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (spillCount * 4));
95 }
buzbeee3acd072012-02-25 17:03:10 -080096
buzbeead8f15e2012-06-18 14:49:45 -070097 flushIns(cUnit, argLocs, rlMethod);
buzbeee1965672012-03-11 18:39:19 -070098
Bill Buzbeea114add2012-05-03 15:00:40 -070099 oatFreeTemp(cUnit, r0);
100 oatFreeTemp(cUnit, r1);
101 oatFreeTemp(cUnit, r2);
102 oatFreeTemp(cUnit, r3);
buzbeee3acd072012-02-25 17:03:10 -0800103}
104
buzbee2cfc6392012-05-07 14:51:40 -0700105void genExitSequence(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800106{
Bill Buzbeea114add2012-05-03 15:00:40 -0700107 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
108 /*
109 * In the exit path, r0/r1 are live - make sure they aren't
110 * allocated by the register utilities as temps.
111 */
112 oatLockTemp(cUnit, r0);
113 oatLockTemp(cUnit, r1);
buzbeee3acd072012-02-25 17:03:10 -0800114
Bill Buzbeea114add2012-05-03 15:00:40 -0700115 newLIR0(cUnit, kPseudoMethodExit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700116 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
117 /* Need to restore any FP callee saves? */
118 if (cUnit->numFPSpills) {
119 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
120 }
121 if (cUnit->coreSpillMask & (1 << rLR)) {
122 /* Unspill rLR to rPC */
123 cUnit->coreSpillMask &= ~(1 << rLR);
124 cUnit->coreSpillMask |= (1 << rPC);
125 }
126 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
127 if (!(cUnit->coreSpillMask & (1 << rPC))) {
128 /* We didn't pop to rPC, so must do a bv rLR */
129 newLIR1(cUnit, kThumbBx, rLR);
130 }
buzbeee3acd072012-02-25 17:03:10 -0800131}
132
133/*
134 * Nop any unconditional branches that go to the next instruction.
135 * Note: new redundant branches may be inserted later, and we'll
136 * use a check in final instruction assembly to nop those out.
137 */
138void removeRedundantBranches(CompilationUnit* cUnit)
139{
Bill Buzbeea114add2012-05-03 15:00:40 -0700140 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800141
Bill Buzbeea114add2012-05-03 15:00:40 -0700142 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
143 thisLIR != (LIR*) cUnit->lastLIRInsn;
144 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee3acd072012-02-25 17:03:10 -0800145
Bill Buzbeea114add2012-05-03 15:00:40 -0700146 /* Branch to the next instruction */
147 if ((thisLIR->opcode == kThumbBUncond) ||
148 (thisLIR->opcode == kThumb2BUncond)) {
149 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800150
Bill Buzbeea114add2012-05-03 15:00:40 -0700151 while (true) {
152 nextLIR = NEXT_LIR(nextLIR);
buzbeee3acd072012-02-25 17:03:10 -0800153
Bill Buzbeea114add2012-05-03 15:00:40 -0700154 /*
155 * Is the branch target the next instruction?
156 */
157 if (nextLIR == (LIR*) thisLIR->target) {
158 thisLIR->flags.isNop = true;
159 break;
buzbeee3acd072012-02-25 17:03:10 -0800160 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700161
162 /*
163 * Found real useful stuff between the branch and the target.
164 * Need to explicitly check the lastLIRInsn here because it
165 * might be the last real instruction.
166 */
167 if (!isPseudoOpcode(nextLIR->opcode) ||
168 (nextLIR = (LIR*) cUnit->lastLIRInsn))
169 break;
170 }
buzbeee3acd072012-02-25 17:03:10 -0800171 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700172 }
buzbeee3acd072012-02-25 17:03:10 -0800173}
174
buzbeee3acd072012-02-25 17:03:10 -0800175
176/* Common initialization routine for an architecture family */
177bool oatArchInit()
178{
Bill Buzbeea114add2012-05-03 15:00:40 -0700179 int i;
buzbeee3acd072012-02-25 17:03:10 -0800180
Bill Buzbeea114add2012-05-03 15:00:40 -0700181 for (i = 0; i < kArmLast; i++) {
182 if (EncodingMap[i].opcode != i) {
183 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
184 << " is wrong: expecting " << i << ", seeing "
185 << (int)EncodingMap[i].opcode;
buzbeee3acd072012-02-25 17:03:10 -0800186 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700187 }
buzbeee3acd072012-02-25 17:03:10 -0800188
Bill Buzbeea114add2012-05-03 15:00:40 -0700189 return oatArchVariantInit();
buzbeee3acd072012-02-25 17:03:10 -0800190}
buzbeeb046e162012-10-30 15:48:42 -0700191
192bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
193 RegLocation rlSrc1, RegLocation rlSrc2)
194{
195 LOG(FATAL) << "Unexpected use of genAddLong for Arm";
196 return false;
197}
198
199bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
200 RegLocation rlSrc1, RegLocation rlSrc2)
201{
202 LOG(FATAL) << "Unexpected use of genSubLong for Arm";
203 return false;
204}
205
206bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
207 RegLocation rlSrc1, RegLocation rlSrc2)
208{
209 LOG(FATAL) << "Unexpected use of genAndLong for Arm";
210 return false;
211}
212
213bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
214 RegLocation rlSrc1, RegLocation rlSrc2)
215{
216 LOG(FATAL) << "Unexpected use of genOrLong for Arm";
217 return false;
218}
219
220bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
221 RegLocation rlSrc1, RegLocation rlSrc2)
222{
223 LOG(FATAL) << "Unexpected use of genXoLong for Arm";
224 return false;
225}
226
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800227} // namespace art