blob: 4a61efb4a0101add71ca7318e8c475af62e282d1 [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -08001/*
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 mips-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
buzbeee3acd072012-02-25 17:03:10 -080027namespace art {
28
buzbee408ad162012-06-06 16:45:18 -070029bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeec5159d52012-03-03 11:48:39 -080030 RegLocation rlSrc1, RegLocation rlSrc2)
31{
Bill Buzbeea114add2012-05-03 15:00:40 -070032 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
33 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
34 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
35 /*
36 * [v1 v0] = [a1 a0] + [a3 a2];
37 * addu v0,a2,a0
38 * addu t1,a3,a1
39 * sltu v1,v0,a2
40 * addu v1,v1,t1
41 */
buzbeec5159d52012-03-03 11:48:39 -080042
Bill Buzbeea114add2012-05-03 15:00:40 -070043 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg);
44 int tReg = oatAllocTemp(cUnit);
45 opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg);
46 newLIR3(cUnit, kMipsSltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg);
47 opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
48 oatFreeTemp(cUnit, tReg);
49 storeValueWide(cUnit, rlDest, rlResult);
50 return false;
buzbeec5159d52012-03-03 11:48:39 -080051}
52
buzbee408ad162012-06-06 16:45:18 -070053bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -070054 RegLocation rlSrc1, RegLocation rlSrc2)
buzbeec5159d52012-03-03 11:48:39 -080055{
Bill Buzbeea114add2012-05-03 15:00:40 -070056 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
57 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
58 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
59 /*
60 * [v1 v0] = [a1 a0] - [a3 a2];
61 * subu v0,a0,a2
62 * subu v1,a1,a3
63 * sltu t1,a0,v0
64 * subu v1,v1,t1
65 */
buzbeec5159d52012-03-03 11:48:39 -080066
Bill Buzbeea114add2012-05-03 15:00:40 -070067 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
68 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
69 int tReg = oatAllocTemp(cUnit);
70 newLIR3(cUnit, kMipsSltu, tReg, rlSrc1.lowReg, rlResult.lowReg);
71 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
72 oatFreeTemp(cUnit, tReg);
73 storeValueWide(cUnit, rlDest, rlResult);
74 return false;
buzbeec5159d52012-03-03 11:48:39 -080075}
76
buzbee408ad162012-06-06 16:45:18 -070077bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeec5159d52012-03-03 11:48:39 -080078 RegLocation rlSrc)
79{
Bill Buzbeea114add2012-05-03 15:00:40 -070080 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
81 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
82 /*
83 * [v1 v0] = -[a1 a0]
84 * negu v0,a0
85 * negu v1,a1
86 * sltu t1,r_zero
87 * subu v1,v1,t1
88 */
buzbeec5159d52012-03-03 11:48:39 -080089
Bill Buzbeea114add2012-05-03 15:00:40 -070090 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
91 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
92 int tReg = oatAllocTemp(cUnit);
93 newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg);
94 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
95 oatFreeTemp(cUnit, tReg);
96 storeValueWide(cUnit, rlDest, rlResult);
97 return false;
buzbeec5159d52012-03-03 11:48:39 -080098}
99
buzbee5de34942012-03-01 14:51:57 -0800100void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
buzbeee3acd072012-02-25 17:03:10 -0800101
102/*
buzbee5de34942012-03-01 14:51:57 -0800103 * In the Arm code a it is typical to use the link register
104 * to hold the target address. However, for Mips we must
105 * ensure that all branch instructions can be restarted if
106 * there is a trap in the shadow. Allocate a temp register.
buzbeee3acd072012-02-25 17:03:10 -0800107 */
buzbee5de34942012-03-01 14:51:57 -0800108int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800109{
Bill Buzbeea114add2012-05-03 15:00:40 -0700110 int tReg = oatAllocTemp(cUnit);
111 loadWordDisp(cUnit, rSELF, offset, tReg);
112 return tReg;
buzbeee3acd072012-02-25 17:03:10 -0800113}
114
buzbee5de34942012-03-01 14:51:57 -0800115void spillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800116{
Bill Buzbeea114add2012-05-03 15:00:40 -0700117 if (cUnit->numCoreSpills == 0) {
118 return;
119 }
120 uint32_t mask = cUnit->coreSpillMask;
121 int offset = cUnit->numCoreSpills * 4;
122 opRegImm(cUnit, kOpSub, rSP, offset);
123 for (int reg = 0; mask; mask >>= 1, reg++) {
124 if (mask & 0x1) {
125 offset -= 4;
126 storeWordDisp(cUnit, rSP, offset, reg);
buzbee5de34942012-03-01 14:51:57 -0800127 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700128 }
buzbeee3acd072012-02-25 17:03:10 -0800129}
130
buzbee5de34942012-03-01 14:51:57 -0800131void unSpillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800132{
Bill Buzbeea114add2012-05-03 15:00:40 -0700133 if (cUnit->numCoreSpills == 0) {
134 return;
135 }
136 uint32_t mask = cUnit->coreSpillMask;
137 int offset = cUnit->frameSize;
138 for (int reg = 0; mask; mask >>= 1, reg++) {
139 if (mask & 0x1) {
140 offset -= 4;
141 loadWordDisp(cUnit, rSP, offset, reg);
buzbee5de34942012-03-01 14:51:57 -0800142 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 }
144 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
buzbee5de34942012-03-01 14:51:57 -0800145}
146
buzbeead8f15e2012-06-18 14:49:45 -0700147void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs,
148 RegLocation rlMethod)
buzbee5de34942012-03-01 14:51:57 -0800149{
Bill Buzbeea114add2012-05-03 15:00:40 -0700150 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
151 /*
152 * On entry, rARG0, rARG1, rARG2 & rARG3 are live. Let the register
153 * allocation mechanism know so it doesn't try to use any of them when
154 * expanding the frame or flushing. This leaves the utility
155 * code with a single temp: r12. This should be enough.
156 */
157 oatLockTemp(cUnit, rARG0);
158 oatLockTemp(cUnit, rARG1);
159 oatLockTemp(cUnit, rARG2);
160 oatLockTemp(cUnit, rARG3);
buzbeee3acd072012-02-25 17:03:10 -0800161
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 /*
163 * We can safely skip the stack overflow check if we're
164 * a leaf *and* our frame size < fudge factor.
165 */
166 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
167 ((size_t)cUnit->frameSize < Thread::kStackOverflowReservedBytes));
168 newLIR0(cUnit, kPseudoMethodEntry);
169 int checkReg = oatAllocTemp(cUnit);
170 int newSP = oatAllocTemp(cUnit);
171 if (!skipOverflowCheck) {
172 /* Load stack limit */
173 loadWordDisp(cUnit, rSELF, Thread::StackEndOffset().Int32Value(), checkReg);
174 }
175 /* Spill core callee saves */
176 spillCoreRegs(cUnit);
177 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
178 DCHECK_EQ(cUnit->numFPSpills, 0);
179 if (!skipOverflowCheck) {
180 opRegRegImm(cUnit, kOpSub, newSP, rSP, cUnit->frameSize - (spillCount * 4));
buzbee408ad162012-06-06 16:45:18 -0700181 genRegRegCheck(cUnit, kCondCc, newSP, checkReg, kThrowStackOverflow);
Bill Buzbeea114add2012-05-03 15:00:40 -0700182 opRegCopy(cUnit, rSP, newSP); // Establish stack
183 } else {
184 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (spillCount * 4));
185 }
buzbee9c044ce2012-03-18 13:24:07 -0700186
buzbeead8f15e2012-06-18 14:49:45 -0700187 flushIns(cUnit, argLocs, rlMethod);
buzbeee3acd072012-02-25 17:03:10 -0800188
Bill Buzbeea114add2012-05-03 15:00:40 -0700189 if (cUnit->genDebugger) {
190 // Refresh update debugger callout
191 loadWordDisp(cUnit, rSELF,
192 ENTRYPOINT_OFFSET(pUpdateDebuggerFromCode), rSUSPEND);
193 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
194 }
buzbeee3acd072012-02-25 17:03:10 -0800195
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 oatFreeTemp(cUnit, rARG0);
197 oatFreeTemp(cUnit, rARG1);
198 oatFreeTemp(cUnit, rARG2);
199 oatFreeTemp(cUnit, rARG3);
buzbeee3acd072012-02-25 17:03:10 -0800200}
201
buzbee2cfc6392012-05-07 14:51:40 -0700202void genExitSequence(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800203{
Bill Buzbeea114add2012-05-03 15:00:40 -0700204 /*
205 * In the exit path, rRET0/rRET1 are live - make sure they aren't
206 * allocated by the register utilities as temps.
207 */
208 oatLockTemp(cUnit, rRET0);
209 oatLockTemp(cUnit, rRET1);
buzbeee3acd072012-02-25 17:03:10 -0800210
Bill Buzbeea114add2012-05-03 15:00:40 -0700211 newLIR0(cUnit, kPseudoMethodExit);
212 /* If we're compiling for the debugger, generate an update callout */
213 if (cUnit->genDebugger) {
214 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
215 }
216 unSpillCoreRegs(cUnit);
217 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800218}
219
220/*
221 * Nop any unconditional branches that go to the next instruction.
222 * Note: new redundant branches may be inserted later, and we'll
223 * use a check in final instruction assembly to nop those out.
224 */
225void removeRedundantBranches(CompilationUnit* cUnit)
226{
Bill Buzbeea114add2012-05-03 15:00:40 -0700227 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800228
Bill Buzbeea114add2012-05-03 15:00:40 -0700229 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
230 thisLIR != (LIR*) cUnit->lastLIRInsn;
231 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee3acd072012-02-25 17:03:10 -0800232
Bill Buzbeea114add2012-05-03 15:00:40 -0700233 /* Branch to the next instruction */
234 if (thisLIR->opcode == kMipsB) {
235 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800236
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 while (true) {
238 nextLIR = NEXT_LIR(nextLIR);
buzbeee3acd072012-02-25 17:03:10 -0800239
Bill Buzbeea114add2012-05-03 15:00:40 -0700240 /*
241 * Is the branch target the next instruction?
242 */
243 if (nextLIR == (LIR*) thisLIR->target) {
244 thisLIR->flags.isNop = true;
245 break;
buzbeee3acd072012-02-25 17:03:10 -0800246 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700247
248 /*
249 * Found real useful stuff between the branch and the target.
250 * Need to explicitly check the lastLIRInsn here because it
251 * might be the last real instruction.
252 */
253 if (!isPseudoOpcode(nextLIR->opcode) ||
254 (nextLIR = (LIR*) cUnit->lastLIRInsn))
255 break;
256 }
buzbeee3acd072012-02-25 17:03:10 -0800257 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 }
buzbeee3acd072012-02-25 17:03:10 -0800259}
260
buzbeee3acd072012-02-25 17:03:10 -0800261
262/* Common initialization routine for an architecture family */
263bool oatArchInit()
264{
Bill Buzbeea114add2012-05-03 15:00:40 -0700265 int i;
buzbeee3acd072012-02-25 17:03:10 -0800266
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 for (i = 0; i < kMipsLast; i++) {
268 if (EncodingMap[i].opcode != i) {
269 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
270 " is wrong: expecting " << i << ", seeing " <<
271 (int)EncodingMap[i].opcode;
buzbeee3acd072012-02-25 17:03:10 -0800272 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700273 }
buzbeee3acd072012-02-25 17:03:10 -0800274
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 return oatArchVariantInit();
buzbeee3acd072012-02-25 17:03:10 -0800276}
277
buzbeee3acd072012-02-25 17:03:10 -0800278} // namespace art