blob: 963427ddcee44d32b94621d85b0b5b8204b02733 [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
buzbee5de34942012-03-01 14:51:57 -080027void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
buzbeee3acd072012-02-25 17:03:10 -080028
29/*
buzbee5de34942012-03-01 14:51:57 -080030 * In the Arm code a it is typical to use the link register
31 * to hold the target address. However, for Mips we must
32 * ensure that all branch instructions can be restarted if
33 * there is a trap in the shadow. Allocate a temp register.
buzbeee3acd072012-02-25 17:03:10 -080034 */
buzbee5de34942012-03-01 14:51:57 -080035int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -080036{
buzbee5de34942012-03-01 14:51:57 -080037 int tReg = oatAllocTemp(cUnit);
38 loadWordDisp(cUnit, rSELF, offset, tReg);
39 return tReg;
buzbeee3acd072012-02-25 17:03:10 -080040}
41
buzbee5de34942012-03-01 14:51:57 -080042void spillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -080043{
buzbee5de34942012-03-01 14:51:57 -080044 if (cUnit->numCoreSpills == 0) {
buzbeee3acd072012-02-25 17:03:10 -080045 return;
buzbee5de34942012-03-01 14:51:57 -080046 }
47 uint32_t mask = cUnit->coreSpillMask;
48 int offset = cUnit->numCoreSpills * 4;
49 opRegImm(cUnit, kOpSub, rSP, offset);
50 for (int reg = 0; mask; mask >>= 1, reg++) {
51 if (mask & 0x1) {
52 offset -= 4;
53 storeWordDisp(cUnit, rSP, offset, reg);
buzbeee3acd072012-02-25 17:03:10 -080054 }
55 }
buzbeee3acd072012-02-25 17:03:10 -080056}
57
buzbee5de34942012-03-01 14:51:57 -080058void unSpillCoreRegs(CompilationUnit* cUnit)
buzbeee3acd072012-02-25 17:03:10 -080059{
buzbee5de34942012-03-01 14:51:57 -080060 if (cUnit->numCoreSpills == 0) {
61 return;
62 }
63 uint32_t mask = cUnit->coreSpillMask;
64 int offset = cUnit->frameSize;
65 for (int reg = 0; mask; mask >>= 1, reg++) {
66 if (mask & 0x1) {
67 offset -= 4;
68 loadWordDisp(cUnit, rSP, offset, reg);
69 }
70 }
71 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize);
72}
73
74void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
75{
buzbeee3acd072012-02-25 17:03:10 -080076 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
77 /*
buzbee5de34942012-03-01 14:51:57 -080078 * On entry, rARG0, rARG1, rARG2 & rARG3 are live. Let the register
79 * allocation mechanism know so it doesn't try to use any of them when
buzbeee3acd072012-02-25 17:03:10 -080080 * expanding the frame or flushing. This leaves the utility
81 * code with a single temp: r12. This should be enough.
82 */
buzbee5de34942012-03-01 14:51:57 -080083 oatLockTemp(cUnit, rARG0);
84 oatLockTemp(cUnit, rARG1);
85 oatLockTemp(cUnit, rARG2);
86 oatLockTemp(cUnit, rARG3);
buzbeee3acd072012-02-25 17:03:10 -080087
88 /*
89 * We can safely skip the stack overflow check if we're
90 * a leaf *and* our frame size < fudge factor.
91 */
92 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
93 ((size_t)cUnit->frameSize <
94 Thread::kStackOverflowReservedBytes));
buzbee31a4a6f2012-02-28 15:36:15 -080095 newLIR0(cUnit, kPseudoMethodEntry);
buzbee5de34942012-03-01 14:51:57 -080096 int checkReg = oatAllocTemp(cUnit);
97 int newSP = oatAllocTemp(cUnit);
buzbeee3acd072012-02-25 17:03:10 -080098 if (!skipOverflowCheck) {
99 /* Load stack limit */
100 loadWordDisp(cUnit, rSELF,
buzbee5de34942012-03-01 14:51:57 -0800101 Thread::StackEndOffset().Int32Value(), checkReg);
buzbeee3acd072012-02-25 17:03:10 -0800102 }
103 /* Spill core callee saves */
buzbee5de34942012-03-01 14:51:57 -0800104 spillCoreRegs(cUnit);
105 /* NOTE: promotion of FP regs currently unsupported, thus no FP spill */
106 DCHECK_EQ(cUnit->numFPSpills, 0);
buzbeee3acd072012-02-25 17:03:10 -0800107 if (!skipOverflowCheck) {
buzbee5de34942012-03-01 14:51:57 -0800108 opRegRegImm(cUnit, kOpSub, newSP, rSP,
buzbeee3acd072012-02-25 17:03:10 -0800109 cUnit->frameSize - (spillCount * 4));
buzbee5de34942012-03-01 14:51:57 -0800110 genRegRegCheck(cUnit, kCondCc, newSP, checkReg, NULL,
111 kThrowStackOverflow);
buzbee82488f52012-03-02 08:20:26 -0800112 opRegCopy(cUnit, rSP, newSP); // Establish stack
buzbeee3acd072012-02-25 17:03:10 -0800113 } else {
114 opRegImm(cUnit, kOpSub, rSP,
115 cUnit->frameSize - (spillCount * 4));
116 }
buzbee5de34942012-03-01 14:51:57 -0800117 storeBaseDisp(cUnit, rSP, 0, rARG0, kWord);
buzbeee3acd072012-02-25 17:03:10 -0800118 flushIns(cUnit);
119
120 if (cUnit->genDebugger) {
121 // Refresh update debugger callout
122 loadWordDisp(cUnit, rSELF,
123 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
124 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
125 }
126
buzbee5de34942012-03-01 14:51:57 -0800127 oatFreeTemp(cUnit, rARG0);
128 oatFreeTemp(cUnit, rARG1);
129 oatFreeTemp(cUnit, rARG2);
130 oatFreeTemp(cUnit, rARG3);
buzbeee3acd072012-02-25 17:03:10 -0800131}
132
buzbee5de34942012-03-01 14:51:57 -0800133void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -0800134{
buzbeee3acd072012-02-25 17:03:10 -0800135 /*
buzbee5de34942012-03-01 14:51:57 -0800136 * In the exit path, rRET0/rRET1 are live - make sure they aren't
buzbeee3acd072012-02-25 17:03:10 -0800137 * allocated by the register utilities as temps.
138 */
buzbee5de34942012-03-01 14:51:57 -0800139 oatLockTemp(cUnit, rRET0);
140 oatLockTemp(cUnit, rRET1);
buzbeee3acd072012-02-25 17:03:10 -0800141
buzbee31a4a6f2012-02-28 15:36:15 -0800142 newLIR0(cUnit, kPseudoMethodExit);
buzbeee3acd072012-02-25 17:03:10 -0800143 /* If we're compiling for the debugger, generate an update callout */
144 if (cUnit->genDebugger) {
145 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
146 }
buzbee5de34942012-03-01 14:51:57 -0800147 unSpillCoreRegs(cUnit);
buzbee0398c422012-03-02 15:22:47 -0800148 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800149}
150
151/*
152 * Nop any unconditional branches that go to the next instruction.
153 * Note: new redundant branches may be inserted later, and we'll
154 * use a check in final instruction assembly to nop those out.
155 */
156void removeRedundantBranches(CompilationUnit* cUnit)
157{
buzbee5de34942012-03-01 14:51:57 -0800158 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800159
buzbee5de34942012-03-01 14:51:57 -0800160 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
161 thisLIR != (LIR*) cUnit->lastLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800162 thisLIR = NEXT_LIR(thisLIR)) {
163
164 /* Branch to the next instruction */
buzbee5de34942012-03-01 14:51:57 -0800165 if (thisLIR->opcode == kMipsB) {
166 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800167
168 while (true) {
169 nextLIR = NEXT_LIR(nextLIR);
170
171 /*
172 * Is the branch target the next instruction?
173 */
buzbee5de34942012-03-01 14:51:57 -0800174 if (nextLIR == (LIR*) thisLIR->target) {
buzbeee3acd072012-02-25 17:03:10 -0800175 thisLIR->flags.isNop = true;
176 break;
177 }
178
179 /*
180 * Found real useful stuff between the branch and the target.
181 * Need to explicitly check the lastLIRInsn here because it
182 * might be the last real instruction.
183 */
184 if (!isPseudoOpcode(nextLIR->opcode) ||
buzbee5de34942012-03-01 14:51:57 -0800185 (nextLIR = (LIR*) cUnit->lastLIRInsn))
buzbeee3acd072012-02-25 17:03:10 -0800186 break;
187 }
188 }
189 }
buzbeee3acd072012-02-25 17:03:10 -0800190}
191
buzbeee3acd072012-02-25 17:03:10 -0800192
193/* Common initialization routine for an architecture family */
194bool oatArchInit()
195{
196 int i;
197
198 for (i = 0; i < kMipsLast; i++) {
199 if (EncodingMap[i].opcode != i) {
200 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
201 " is wrong: expecting " << i << ", seeing " <<
202 (int)EncodingMap[i].opcode;
203 }
204 }
205
206 return oatArchVariantInit();
207}
208
buzbeee3acd072012-02-25 17:03:10 -0800209} // namespace art