blob: 90c0ede67bbc234c99927f7ef19222c4d582f5a8 [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
buzbeeb046e162012-10-30 15:48:42 -070017/* This file contains mips-specific codegen factory support. */
buzbeee3acd072012-02-25 17:03:10 -080018
Ian Rogers57b86d42012-03-27 16:05:41 -070019#include "oat/runtime/oat_support_entrypoints.h"
20
buzbeee3acd072012-02-25 17:03:10 -080021namespace art {
22
buzbee408ad162012-06-06 16:45:18 -070023bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeec5159d52012-03-03 11:48:39 -080024 RegLocation rlSrc1, RegLocation rlSrc2)
25{
Bill Buzbeea114add2012-05-03 15:00:40 -070026 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
27 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
28 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
29 /*
30 * [v1 v0] = [a1 a0] + [a3 a2];
31 * addu v0,a2,a0
32 * addu t1,a3,a1
33 * sltu v1,v0,a2
34 * addu v1,v1,t1
35 */
buzbeec5159d52012-03-03 11:48:39 -080036
Bill Buzbeea114add2012-05-03 15:00:40 -070037 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg);
38 int tReg = oatAllocTemp(cUnit);
39 opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg);
40 newLIR3(cUnit, kMipsSltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg);
41 opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
42 oatFreeTemp(cUnit, tReg);
43 storeValueWide(cUnit, rlDest, rlResult);
44 return false;
buzbeec5159d52012-03-03 11:48:39 -080045}
46
buzbee408ad162012-06-06 16:45:18 -070047bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -070048 RegLocation rlSrc1, RegLocation rlSrc2)
buzbeec5159d52012-03-03 11:48:39 -080049{
Bill Buzbeea114add2012-05-03 15:00:40 -070050 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
51 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
52 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
53 /*
54 * [v1 v0] = [a1 a0] - [a3 a2];
jeffhao09cd7272012-10-29 16:37:01 -070055 * sltu t1,a0,a2
Bill Buzbeea114add2012-05-03 15:00:40 -070056 * subu v0,a0,a2
57 * subu v1,a1,a3
Bill Buzbeea114add2012-05-03 15:00:40 -070058 * subu v1,v1,t1
59 */
buzbeec5159d52012-03-03 11:48:39 -080060
jeffhao09cd7272012-10-29 16:37:01 -070061 int tReg = oatAllocTemp(cUnit);
62 newLIR3(cUnit, kMipsSltu, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -070063 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
64 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -070065 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
66 oatFreeTemp(cUnit, tReg);
67 storeValueWide(cUnit, rlDest, rlResult);
68 return false;
buzbeec5159d52012-03-03 11:48:39 -080069}
70
buzbee408ad162012-06-06 16:45:18 -070071bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeec5159d52012-03-03 11:48:39 -080072 RegLocation rlSrc)
73{
Bill Buzbeea114add2012-05-03 15:00:40 -070074 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
75 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
76 /*
77 * [v1 v0] = -[a1 a0]
78 * negu v0,a0
79 * negu v1,a1
80 * sltu t1,r_zero
81 * subu v1,v1,t1
82 */
buzbeec5159d52012-03-03 11:48:39 -080083
Bill Buzbeea114add2012-05-03 15:00:40 -070084 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
85 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
86 int tReg = oatAllocTemp(cUnit);
87 newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg);
88 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
89 oatFreeTemp(cUnit, tReg);
90 storeValueWide(cUnit, rlDest, rlResult);
91 return false;
buzbeec5159d52012-03-03 11:48:39 -080092}
93
buzbeee3acd072012-02-25 17:03:10 -080094/*
buzbee5de34942012-03-01 14:51:57 -080095 * In the Arm code a it is typical to use the link register
96 * to hold the target address. However, for Mips we must
97 * ensure that all branch instructions can be restarted if
98 * there is a trap in the shadow. Allocate a temp register.
buzbeee3acd072012-02-25 17:03:10 -080099 */
buzbee5de34942012-03-01 14:51:57 -0800100int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -0800101{
buzbeef0504cd2012-11-13 16:31:10 -0800102 loadWordDisp(cUnit, rMIPS_SELF, offset, r_T9);
jeffhaofa147e22012-10-12 17:03:32 -0700103 return r_T9;
buzbeee3acd072012-02-25 17:03:10 -0800104}
105
buzbee5de34942012-03-01 14:51:57 -0800106void spillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800107{
Bill Buzbeea114add2012-05-03 15:00:40 -0700108 if (cUnit->numCoreSpills == 0) {
109 return;
110 }
111 uint32_t mask = cUnit->coreSpillMask;
112 int offset = cUnit->numCoreSpills * 4;
buzbeef0504cd2012-11-13 16:31:10 -0800113 opRegImm(cUnit, kOpSub, rMIPS_SP, offset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700114 for (int reg = 0; mask; mask >>= 1, reg++) {
115 if (mask & 0x1) {
116 offset -= 4;
buzbeef0504cd2012-11-13 16:31:10 -0800117 storeWordDisp(cUnit, rMIPS_SP, offset, reg);
buzbee5de34942012-03-01 14:51:57 -0800118 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700119 }
buzbeee3acd072012-02-25 17:03:10 -0800120}
121
buzbee5de34942012-03-01 14:51:57 -0800122void unSpillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800123{
Bill Buzbeea114add2012-05-03 15:00:40 -0700124 if (cUnit->numCoreSpills == 0) {
125 return;
126 }
127 uint32_t mask = cUnit->coreSpillMask;
128 int offset = cUnit->frameSize;
129 for (int reg = 0; mask; mask >>= 1, reg++) {
130 if (mask & 0x1) {
131 offset -= 4;
buzbeef0504cd2012-11-13 16:31:10 -0800132 loadWordDisp(cUnit, rMIPS_SP, offset, reg);
buzbee5de34942012-03-01 14:51:57 -0800133 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700134 }
buzbeef0504cd2012-11-13 16:31:10 -0800135 opRegImm(cUnit, kOpAdd, rMIPS_SP, cUnit->frameSize);
buzbee5de34942012-03-01 14:51:57 -0800136}
137
buzbeead8f15e2012-06-18 14:49:45 -0700138void genEntrySequence(CompilationUnit* cUnit, RegLocation* argLocs,
139 RegLocation rlMethod)
buzbee5de34942012-03-01 14:51:57 -0800140{
Bill Buzbeea114add2012-05-03 15:00:40 -0700141 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
142 /*
buzbeef0504cd2012-11-13 16:31:10 -0800143 * On entry, rMIPS_ARG0, rMIPS_ARG1, rMIPS_ARG2 & rMIPS_ARG3 are live. Let the register
Bill Buzbeea114add2012-05-03 15:00:40 -0700144 * allocation mechanism know so it doesn't try to use any of them when
145 * expanding the frame or flushing. This leaves the utility
146 * code with a single temp: r12. This should be enough.
147 */
buzbeef0504cd2012-11-13 16:31:10 -0800148 oatLockTemp(cUnit, rMIPS_ARG0);
149 oatLockTemp(cUnit, rMIPS_ARG1);
150 oatLockTemp(cUnit, rMIPS_ARG2);
151 oatLockTemp(cUnit, rMIPS_ARG3);
buzbeee3acd072012-02-25 17:03:10 -0800152
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 /*
154 * We can safely skip the stack overflow check if we're
155 * a leaf *and* our frame size < fudge factor.
156 */
157 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
158 ((size_t)cUnit->frameSize < Thread::kStackOverflowReservedBytes));
159 newLIR0(cUnit, kPseudoMethodEntry);
160 int checkReg = oatAllocTemp(cUnit);
161 int newSP = oatAllocTemp(cUnit);
162 if (!skipOverflowCheck) {
163 /* Load stack limit */
buzbeef0504cd2012-11-13 16:31:10 -0800164 loadWordDisp(cUnit, rMIPS_SELF, Thread::StackEndOffset().Int32Value(), checkReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 }
166 /* Spill core callee saves */
167 spillCoreRegs(cUnit);
168 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
169 DCHECK_EQ(cUnit->numFPSpills, 0);
170 if (!skipOverflowCheck) {
buzbeef0504cd2012-11-13 16:31:10 -0800171 opRegRegImm(cUnit, kOpSub, newSP, rMIPS_SP, cUnit->frameSize - (spillCount * 4));
buzbee408ad162012-06-06 16:45:18 -0700172 genRegRegCheck(cUnit, kCondCc, newSP, checkReg, kThrowStackOverflow);
buzbeef0504cd2012-11-13 16:31:10 -0800173 opRegCopy(cUnit, rMIPS_SP, newSP); // Establish stack
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800175 opRegImm(cUnit, kOpSub, rMIPS_SP, cUnit->frameSize - (spillCount * 4));
Bill Buzbeea114add2012-05-03 15:00:40 -0700176 }
buzbee9c044ce2012-03-18 13:24:07 -0700177
buzbeead8f15e2012-06-18 14:49:45 -0700178 flushIns(cUnit, argLocs, rlMethod);
buzbeee3acd072012-02-25 17:03:10 -0800179
buzbeef0504cd2012-11-13 16:31:10 -0800180 oatFreeTemp(cUnit, rMIPS_ARG0);
181 oatFreeTemp(cUnit, rMIPS_ARG1);
182 oatFreeTemp(cUnit, rMIPS_ARG2);
183 oatFreeTemp(cUnit, rMIPS_ARG3);
buzbeee3acd072012-02-25 17:03:10 -0800184}
185
buzbee2cfc6392012-05-07 14:51:40 -0700186void genExitSequence(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -0800187{
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 /*
buzbeef0504cd2012-11-13 16:31:10 -0800189 * In the exit path, rMIPS_RET0/rMIPS_RET1 are live - make sure they aren't
Bill Buzbeea114add2012-05-03 15:00:40 -0700190 * allocated by the register utilities as temps.
191 */
buzbeef0504cd2012-11-13 16:31:10 -0800192 oatLockTemp(cUnit, rMIPS_RET0);
193 oatLockTemp(cUnit, rMIPS_RET1);
buzbeee3acd072012-02-25 17:03:10 -0800194
Bill Buzbeea114add2012-05-03 15:00:40 -0700195 newLIR0(cUnit, kPseudoMethodExit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 unSpillCoreRegs(cUnit);
197 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800198}
199
200/*
201 * Nop any unconditional branches that go to the next instruction.
202 * Note: new redundant branches may be inserted later, and we'll
203 * use a check in final instruction assembly to nop those out.
204 */
205void removeRedundantBranches(CompilationUnit* cUnit)
206{
Bill Buzbeea114add2012-05-03 15:00:40 -0700207 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800208
Bill Buzbeea114add2012-05-03 15:00:40 -0700209 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
210 thisLIR != (LIR*) cUnit->lastLIRInsn;
211 thisLIR = NEXT_LIR(thisLIR)) {
buzbeee3acd072012-02-25 17:03:10 -0800212
Bill Buzbeea114add2012-05-03 15:00:40 -0700213 /* Branch to the next instruction */
214 if (thisLIR->opcode == kMipsB) {
215 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800216
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 while (true) {
218 nextLIR = NEXT_LIR(nextLIR);
buzbeee3acd072012-02-25 17:03:10 -0800219
Bill Buzbeea114add2012-05-03 15:00:40 -0700220 /*
221 * Is the branch target the next instruction?
222 */
223 if (nextLIR == (LIR*) thisLIR->target) {
224 thisLIR->flags.isNop = true;
225 break;
buzbeee3acd072012-02-25 17:03:10 -0800226 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700227
228 /*
229 * Found real useful stuff between the branch and the target.
230 * Need to explicitly check the lastLIRInsn here because it
231 * might be the last real instruction.
232 */
233 if (!isPseudoOpcode(nextLIR->opcode) ||
234 (nextLIR = (LIR*) cUnit->lastLIRInsn))
235 break;
236 }
buzbeee3acd072012-02-25 17:03:10 -0800237 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700238 }
buzbeee3acd072012-02-25 17:03:10 -0800239}
240
buzbeee3acd072012-02-25 17:03:10 -0800241
242/* Common initialization routine for an architecture family */
243bool oatArchInit()
244{
Bill Buzbeea114add2012-05-03 15:00:40 -0700245 int i;
buzbeee3acd072012-02-25 17:03:10 -0800246
Bill Buzbeea114add2012-05-03 15:00:40 -0700247 for (i = 0; i < kMipsLast; i++) {
248 if (EncodingMap[i].opcode != i) {
249 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
250 " is wrong: expecting " << i << ", seeing " <<
251 (int)EncodingMap[i].opcode;
buzbeee3acd072012-02-25 17:03:10 -0800252 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 }
buzbeee3acd072012-02-25 17:03:10 -0800254
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 return oatArchVariantInit();
buzbeee3acd072012-02-25 17:03:10 -0800256}
257
buzbeeb046e162012-10-30 15:48:42 -0700258bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
259 RegLocation rlSrc1, RegLocation rlSrc2)
260{
261 LOG(FATAL) << "Unexpected use of genAndLong for Mips";
262 return false;
263}
264
265bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
266 RegLocation rlSrc1, RegLocation rlSrc2)
267{
268 LOG(FATAL) << "Unexpected use of genOrLong for Mips";
269 return false;
270}
271
272bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
273 RegLocation rlSrc1, RegLocation rlSrc2)
274{
275 LOG(FATAL) << "Unexpected use of genXorLong for Mips";
276 return false;
277}
278
279
280
buzbeee3acd072012-02-25 17:03:10 -0800281} // namespace art