blob: 9050cf973ca512dce1a205a28fe561a0f25125ab [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
buzbeee3acd072012-02-25 17:03:10 -080025namespace art {
26
buzbeec5159d52012-03-03 11:48:39 -080027bool genAddLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
28 RegLocation rlSrc1, RegLocation rlSrc2)
29{
30 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
31 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
32 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
33 /*
34 * [v1 v0] = [a1 a0] + [a3 a2];
35 * addu v0,a2,a0
36 * addu t1,a3,a1
37 * sltu v1,v0,a2
38 * addu v1,v1,t1
39 */
40
41 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg);
42 int tReg = oatAllocTemp(cUnit);
43 opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg);
44 newLIR3(cUnit, kMipsSltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg);
45 opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
46 oatFreeTemp(cUnit, tReg);
47 storeValueWide(cUnit, rlDest, rlResult);
48 return false;
49}
50
51bool genSubLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
52 RegLocation rlSrc1, RegLocation rlSrc2)
53{
54 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
55 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
56 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
57 /*
58 * [v1 v0] = [a1 a0] - [a3 a2];
59 * subu v0,a0,a2
60 * subu v1,a1,a3
61 * sltu t1,a0,v0
62 * subu v1,v1,t1
63 */
64
65 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
66 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
67 int tReg = oatAllocTemp(cUnit);
68 newLIR3(cUnit, kMipsSltu, tReg, rlSrc1.lowReg, rlResult.lowReg);
69 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
70 oatFreeTemp(cUnit, tReg);
71 storeValueWide(cUnit, rlDest, rlResult);
72 return false;
73}
74
75bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
76 RegLocation rlSrc)
77{
78 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
79 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
80 /*
81 * [v1 v0] = -[a1 a0]
82 * negu v0,a0
83 * negu v1,a1
84 * sltu t1,r_zero
85 * subu v1,v1,t1
86 */
87
88 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
89 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
90 int tReg = oatAllocTemp(cUnit);
91 newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg);
92 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
93 oatFreeTemp(cUnit, tReg);
94 storeValueWide(cUnit, rlDest, rlResult);
95 return false;
96}
97
buzbee5de34942012-03-01 14:51:57 -080098void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
buzbeee3acd072012-02-25 17:03:10 -080099
100/*
buzbee5de34942012-03-01 14:51:57 -0800101 * In the Arm code a it is typical to use the link register
102 * to hold the target address. However, for Mips we must
103 * ensure that all branch instructions can be restarted if
104 * there is a trap in the shadow. Allocate a temp register.
buzbeee3acd072012-02-25 17:03:10 -0800105 */
buzbee5de34942012-03-01 14:51:57 -0800106int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800107{
buzbee5de34942012-03-01 14:51:57 -0800108 int tReg = oatAllocTemp(cUnit);
109 loadWordDisp(cUnit, rSELF, offset, tReg);
110 return tReg;
buzbeee3acd072012-02-25 17:03:10 -0800111}
112
buzbee5de34942012-03-01 14:51:57 -0800113void spillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800114{
buzbee5de34942012-03-01 14:51:57 -0800115 if (cUnit->numCoreSpills == 0) {
buzbeee3acd072012-02-25 17:03:10 -0800116 return;
buzbee5de34942012-03-01 14:51:57 -0800117 }
118 uint32_t mask = cUnit->coreSpillMask;
119 int offset = cUnit->numCoreSpills * 4;
120 opRegImm(cUnit, kOpSub, rSP, offset);
121 for (int reg = 0; mask; mask >>= 1, reg++) {
122 if (mask & 0x1) {
123 offset -= 4;
124 storeWordDisp(cUnit, rSP, offset, reg);
buzbeee3acd072012-02-25 17:03:10 -0800125 }
126 }
buzbeee3acd072012-02-25 17:03:10 -0800127}
128
buzbee5de34942012-03-01 14:51:57 -0800129void unSpillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800130{
buzbee5de34942012-03-01 14:51:57 -0800131 if (cUnit->numCoreSpills == 0) {
132 return;
133 }
134 uint32_t mask = cUnit->coreSpillMask;
135 int offset = cUnit->frameSize;
136 for (int reg = 0; mask; mask >>= 1, reg++) {
137 if (mask & 0x1) {
138 offset -= 4;
139 loadWordDisp(cUnit, rSP, offset, reg);
140 }
141 }
142 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
143}
144
145void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
146{
buzbeee3acd072012-02-25 17:03:10 -0800147 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
148 /*
buzbee5de34942012-03-01 14:51:57 -0800149 * On entry, rARG0, rARG1, rARG2 & rARG3 are live. Let the register
150 * allocation mechanism know so it doesn't try to use any of them when
buzbeee3acd072012-02-25 17:03:10 -0800151 * expanding the frame or flushing. This leaves the utility
152 * code with a single temp: r12. This should be enough.
153 */
buzbee5de34942012-03-01 14:51:57 -0800154 oatLockTemp(cUnit, rARG0);
155 oatLockTemp(cUnit, rARG1);
156 oatLockTemp(cUnit, rARG2);
157 oatLockTemp(cUnit, rARG3);
buzbeee3acd072012-02-25 17:03:10 -0800158
159 /*
160 * We can safely skip the stack overflow check if we're
161 * a leaf *and* our frame size < fudge factor.
162 */
163 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
164 ((size_t)cUnit->frameSize <
165 Thread::kStackOverflowReservedBytes));
buzbee31a4a6f2012-02-28 15:36:15 -0800166 newLIR0(cUnit, kPseudoMethodEntry);
buzbee5de34942012-03-01 14:51:57 -0800167 int checkReg = oatAllocTemp(cUnit);
168 int newSP = oatAllocTemp(cUnit);
buzbeee3acd072012-02-25 17:03:10 -0800169 if (!skipOverflowCheck) {
170 /* Load stack limit */
171 loadWordDisp(cUnit, rSELF,
buzbee5de34942012-03-01 14:51:57 -0800172 Thread::StackEndOffset().Int32Value(), checkReg);
buzbeee3acd072012-02-25 17:03:10 -0800173 }
174 /* Spill core callee saves */
buzbee5de34942012-03-01 14:51:57 -0800175 spillCoreRegs(cUnit);
176 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
177 DCHECK_EQ(cUnit->numFPSpills, 0);
buzbeee3acd072012-02-25 17:03:10 -0800178 if (!skipOverflowCheck) {
buzbee5de34942012-03-01 14:51:57 -0800179 opRegRegImm(cUnit, kOpSub, newSP, rSP,
buzbeee3acd072012-02-25 17:03:10 -0800180 cUnit->frameSize - (spillCount * 4));
buzbee5de34942012-03-01 14:51:57 -0800181 genRegRegCheck(cUnit, kCondCc, newSP, checkReg, NULL,
182 kThrowStackOverflow);
buzbee82488f52012-03-02 08:20:26 -0800183 opRegCopy(cUnit, rSP, newSP); // Establish stack
buzbeee3acd072012-02-25 17:03:10 -0800184 } else {
185 opRegImm(cUnit, kOpSub, rSP,
186 cUnit->frameSize - (spillCount * 4));
187 }
buzbee5de34942012-03-01 14:51:57 -0800188 storeBaseDisp(cUnit, rSP, 0, rARG0, kWord);
buzbeee3acd072012-02-25 17:03:10 -0800189 flushIns(cUnit);
190
191 if (cUnit->genDebugger) {
192 // Refresh update debugger callout
193 loadWordDisp(cUnit, rSELF,
194 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
195 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
196 }
197
buzbee5de34942012-03-01 14:51:57 -0800198 oatFreeTemp(cUnit, rARG0);
199 oatFreeTemp(cUnit, rARG1);
200 oatFreeTemp(cUnit, rARG2);
201 oatFreeTemp(cUnit, rARG3);
buzbeee3acd072012-02-25 17:03:10 -0800202}
203
buzbee5de34942012-03-01 14:51:57 -0800204void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -0800205{
buzbeee3acd072012-02-25 17:03:10 -0800206 /*
buzbee5de34942012-03-01 14:51:57 -0800207 * In the exit path, rRET0/rRET1 are live - make sure they aren't
buzbeee3acd072012-02-25 17:03:10 -0800208 * allocated by the register utilities as temps.
209 */
buzbee5de34942012-03-01 14:51:57 -0800210 oatLockTemp(cUnit, rRET0);
211 oatLockTemp(cUnit, rRET1);
buzbeee3acd072012-02-25 17:03:10 -0800212
buzbee31a4a6f2012-02-28 15:36:15 -0800213 newLIR0(cUnit, kPseudoMethodExit);
buzbeee3acd072012-02-25 17:03:10 -0800214 /* If we're compiling for the debugger, generate an update callout */
215 if (cUnit->genDebugger) {
216 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
217 }
buzbee5de34942012-03-01 14:51:57 -0800218 unSpillCoreRegs(cUnit);
buzbee0398c422012-03-02 15:22:47 -0800219 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800220}
221
222/*
223 * Nop any unconditional branches that go to the next instruction.
224 * Note: new redundant branches may be inserted later, and we'll
225 * use a check in final instruction assembly to nop those out.
226 */
227void removeRedundantBranches(CompilationUnit* cUnit)
228{
buzbee5de34942012-03-01 14:51:57 -0800229 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800230
buzbee5de34942012-03-01 14:51:57 -0800231 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
232 thisLIR != (LIR*) cUnit->lastLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800233 thisLIR = NEXT_LIR(thisLIR)) {
234
235 /* Branch to the next instruction */
buzbee5de34942012-03-01 14:51:57 -0800236 if (thisLIR->opcode == kMipsB) {
237 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800238
239 while (true) {
240 nextLIR = NEXT_LIR(nextLIR);
241
242 /*
243 * Is the branch target the next instruction?
244 */
buzbee5de34942012-03-01 14:51:57 -0800245 if (nextLIR == (LIR*) thisLIR->target) {
buzbeee3acd072012-02-25 17:03:10 -0800246 thisLIR->flags.isNop = true;
247 break;
248 }
249
250 /*
251 * Found real useful stuff between the branch and the target.
252 * Need to explicitly check the lastLIRInsn here because it
253 * might be the last real instruction.
254 */
255 if (!isPseudoOpcode(nextLIR->opcode) ||
buzbee5de34942012-03-01 14:51:57 -0800256 (nextLIR = (LIR*) cUnit->lastLIRInsn))
buzbeee3acd072012-02-25 17:03:10 -0800257 break;
258 }
259 }
260 }
buzbeee3acd072012-02-25 17:03:10 -0800261}
262
buzbeee3acd072012-02-25 17:03:10 -0800263
264/* Common initialization routine for an architecture family */
265bool oatArchInit()
266{
267 int i;
268
269 for (i = 0; i < kMipsLast; i++) {
270 if (EncodingMap[i].opcode != i) {
271 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
272 " is wrong: expecting " << i << ", seeing " <<
273 (int)EncodingMap[i].opcode;
274 }
275 }
276
277 return oatArchVariantInit();
278}
279
buzbeee3acd072012-02-25 17:03:10 -0800280} // namespace art