blob: 8a23d5c2e1bb709e227ad35ff442a5cf4e7deb0c [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
17/*
18 * This file contains arm-specific codegen factory support.
19 * It is included by
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080025namespace art {
26
buzbee31a4a6f2012-02-28 15:36:15 -080027void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
buzbeee3acd072012-02-25 17:03:10 -080028
buzbeec5159d52012-03-03 11:48:39 -080029bool genNegLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
30 RegLocation rlSrc)
31{
32 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
33 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
34 int zReg = oatAllocTemp(cUnit);
35 loadConstantNoClobber(cUnit, zReg, 0);
36 // Check for destructive overlap
37 if (rlResult.lowReg == rlSrc.highReg) {
38 int tReg = oatAllocTemp(cUnit);
39 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
40 zReg, rlSrc.lowReg);
41 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
42 zReg, tReg);
43 oatFreeTemp(cUnit, tReg);
44 } else {
45 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
46 zReg, rlSrc.lowReg);
47 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
48 zReg, rlSrc.highReg);
49 }
50 oatFreeTemp(cUnit, zReg);
51 storeValueWide(cUnit, rlDest, rlResult);
52 return false;
53}
54
buzbee31a4a6f2012-02-28 15:36:15 -080055int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -080056{
buzbee31a4a6f2012-02-28 15:36:15 -080057 loadWordDisp(cUnit, rSELF, offset, rLR);
58 return rLR;
buzbeee3acd072012-02-25 17:03:10 -080059}
60
buzbee31a4a6f2012-02-28 15:36:15 -080061void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -080062{
63 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
64 /*
65 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
66 * mechanism know so it doesn't try to use any of them when
67 * expanding the frame or flushing. This leaves the utility
68 * code with a single temp: r12. This should be enough.
69 */
70 oatLockTemp(cUnit, r0);
71 oatLockTemp(cUnit, r1);
72 oatLockTemp(cUnit, r2);
73 oatLockTemp(cUnit, r3);
74
75 /*
76 * We can safely skip the stack overflow check if we're
77 * a leaf *and* our frame size < fudge factor.
78 */
79 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
80 ((size_t)cUnit->frameSize <
81 Thread::kStackOverflowReservedBytes));
buzbee31a4a6f2012-02-28 15:36:15 -080082 newLIR0(cUnit, kPseudoMethodEntry);
buzbeee3acd072012-02-25 17:03:10 -080083 if (!skipOverflowCheck) {
84 /* Load stack limit */
85 loadWordDisp(cUnit, rSELF,
86 Thread::StackEndOffset().Int32Value(), r12);
87 }
88 /* Spill core callee saves */
89 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
90 /* Need to spill any FP regs? */
91 if (cUnit->numFPSpills) {
92 /*
93 * NOTE: fp spills are a little different from core spills in that
94 * they are pushed as a contiguous block. When promoting from
95 * the fp set, we must allocate all singles from s16..highest-promoted
96 */
97 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
98 }
99 if (!skipOverflowCheck) {
100 opRegRegImm(cUnit, kOpSub, rLR, rSP,
101 cUnit->frameSize - (spillCount * 4));
buzbee31a4a6f2012-02-28 15:36:15 -0800102 genRegRegCheck(cUnit, kCondCc, rLR, r12, NULL,
103 kThrowStackOverflow);
buzbee82488f52012-03-02 08:20:26 -0800104 opRegCopy(cUnit, rSP, rLR); // Establish stack
buzbeee3acd072012-02-25 17:03:10 -0800105 } else {
106 opRegImm(cUnit, kOpSub, rSP,
107 cUnit->frameSize - (spillCount * 4));
108 }
109 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
110 flushIns(cUnit);
111
112 if (cUnit->genDebugger) {
113 // Refresh update debugger callout
114 loadWordDisp(cUnit, rSELF,
115 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
116 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
117 }
118
119 oatFreeTemp(cUnit, r0);
120 oatFreeTemp(cUnit, r1);
121 oatFreeTemp(cUnit, r2);
122 oatFreeTemp(cUnit, r3);
123}
124
buzbee31a4a6f2012-02-28 15:36:15 -0800125void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -0800126{
127 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
128 /*
129 * In the exit path, r0/r1 are live - make sure they aren't
130 * allocated by the register utilities as temps.
131 */
132 oatLockTemp(cUnit, r0);
133 oatLockTemp(cUnit, r1);
134
buzbee31a4a6f2012-02-28 15:36:15 -0800135 newLIR0(cUnit, kPseudoMethodExit);
buzbeee3acd072012-02-25 17:03:10 -0800136 /* If we're compiling for the debugger, generate an update callout */
137 if (cUnit->genDebugger) {
138 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
139 }
140 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
141 /* Need to restore any FP callee saves? */
142 if (cUnit->numFPSpills) {
143 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
144 }
145 if (cUnit->coreSpillMask & (1 << rLR)) {
146 /* Unspill rLR to rPC */
147 cUnit->coreSpillMask &= ~(1 << rLR);
148 cUnit->coreSpillMask |= (1 << rPC);
149 }
150 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
151 if (!(cUnit->coreSpillMask & (1 << rPC))) {
152 /* We didn't pop to rPC, so must do a bv rLR */
153 newLIR1(cUnit, kThumbBx, rLR);
154 }
155}
156
157/*
158 * Nop any unconditional branches that go to the next instruction.
159 * Note: new redundant branches may be inserted later, and we'll
160 * use a check in final instruction assembly to nop those out.
161 */
162void removeRedundantBranches(CompilationUnit* cUnit)
163{
buzbee31a4a6f2012-02-28 15:36:15 -0800164 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800165
buzbee31a4a6f2012-02-28 15:36:15 -0800166 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
167 thisLIR != (LIR*) cUnit->lastLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800168 thisLIR = NEXT_LIR(thisLIR)) {
169
170 /* Branch to the next instruction */
171 if ((thisLIR->opcode == kThumbBUncond) ||
172 (thisLIR->opcode == kThumb2BUncond)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800173 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800174
175 while (true) {
176 nextLIR = NEXT_LIR(nextLIR);
177
178 /*
179 * Is the branch target the next instruction?
180 */
buzbee31a4a6f2012-02-28 15:36:15 -0800181 if (nextLIR == (LIR*) thisLIR->target) {
buzbeee3acd072012-02-25 17:03:10 -0800182 thisLIR->flags.isNop = true;
183 break;
184 }
185
186 /*
187 * Found real useful stuff between the branch and the target.
188 * Need to explicitly check the lastLIRInsn here because it
189 * might be the last real instruction.
190 */
191 if (!isPseudoOpcode(nextLIR->opcode) ||
buzbee31a4a6f2012-02-28 15:36:15 -0800192 (nextLIR = (LIR*) cUnit->lastLIRInsn))
buzbeee3acd072012-02-25 17:03:10 -0800193 break;
194 }
195 }
196 }
197}
198
buzbeee3acd072012-02-25 17:03:10 -0800199
200/* Common initialization routine for an architecture family */
201bool oatArchInit()
202{
203 int i;
204
205 for (i = 0; i < kArmLast; i++) {
206 if (EncodingMap[i].opcode != i) {
207 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
208 " is wrong: expecting " << i << ", seeing " <<
209 (int)EncodingMap[i].opcode;
210 }
211 }
212
213 return oatArchVariantInit();
214}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800215} // namespace art