blob: f75d8e358061620054d8877f8a50024e7a0e91f6 [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{
buzbeef0504cd2012-11-13 16:31:10 -080047 loadWordDisp(cUnit, rARM_SELF, offset, rARM_LR);
48 return rARM_LR;
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 */
buzbeef0504cd2012-11-13 16:31:10 -080076 loadWordDisp(cUnit, rARM_SELF, Thread::StackEndOffset().Int32Value(), r12);
Bill Buzbeea114add2012-05-03 15:00:40 -070077 }
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) {
buzbeef0504cd2012-11-13 16:31:10 -080090 opRegRegImm(cUnit, kOpSub, rARM_LR, rARM_SP, cUnit->frameSize - (spillCount * 4));
91 genRegRegCheck(cUnit, kCondCc, rARM_LR, r12, kThrowStackOverflow);
92 opRegCopy(cUnit, rARM_SP, rARM_LR); // Establish stack
Bill Buzbeea114add2012-05-03 15:00:40 -070093 } else {
buzbeef0504cd2012-11-13 16:31:10 -080094 opRegImm(cUnit, kOpSub, rARM_SP, cUnit->frameSize - (spillCount * 4));
Bill Buzbeea114add2012-05-03 15:00:40 -070095 }
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);
buzbeef0504cd2012-11-13 16:31:10 -0800116 opRegImm(cUnit, kOpAdd, rARM_SP, cUnit->frameSize - (spillCount * 4));
Bill Buzbeea114add2012-05-03 15:00:40 -0700117 /* Need to restore any FP callee saves? */
118 if (cUnit->numFPSpills) {
119 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
120 }
buzbeef0504cd2012-11-13 16:31:10 -0800121 if (cUnit->coreSpillMask & (1 << rARM_LR)) {
122 /* Unspill rARM_LR to rARM_PC */
123 cUnit->coreSpillMask &= ~(1 << rARM_LR);
124 cUnit->coreSpillMask |= (1 << rARM_PC);
Bill Buzbeea114add2012-05-03 15:00:40 -0700125 }
126 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
buzbeef0504cd2012-11-13 16:31:10 -0800127 if (!(cUnit->coreSpillMask & (1 << rARM_PC))) {
128 /* We didn't pop to rARM_PC, so must do a bv rARM_LR */
129 newLIR1(cUnit, kThumbBx, rARM_LR);
Bill Buzbeea114add2012-05-03 15:00:40 -0700130 }
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