blob: 5f75ef8782a4d74a29ed3a371ca84e1955d29207 [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
buzbee31a4a6f2012-02-28 15:36:15 -080029int loadHelper(CompilationUnit* cUnit, int offset)
buzbeee3acd072012-02-25 17:03:10 -080030{
buzbee31a4a6f2012-02-28 15:36:15 -080031 loadWordDisp(cUnit, rSELF, offset, rLR);
32 return rLR;
buzbeee3acd072012-02-25 17:03:10 -080033}
34
buzbee31a4a6f2012-02-28 15:36:15 -080035void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -080036{
37 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
38 /*
39 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
40 * mechanism know so it doesn't try to use any of them when
41 * expanding the frame or flushing. This leaves the utility
42 * code with a single temp: r12. This should be enough.
43 */
44 oatLockTemp(cUnit, r0);
45 oatLockTemp(cUnit, r1);
46 oatLockTemp(cUnit, r2);
47 oatLockTemp(cUnit, r3);
48
49 /*
50 * We can safely skip the stack overflow check if we're
51 * a leaf *and* our frame size < fudge factor.
52 */
53 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
54 ((size_t)cUnit->frameSize <
55 Thread::kStackOverflowReservedBytes));
buzbee31a4a6f2012-02-28 15:36:15 -080056 newLIR0(cUnit, kPseudoMethodEntry);
buzbeee3acd072012-02-25 17:03:10 -080057 if (!skipOverflowCheck) {
58 /* Load stack limit */
59 loadWordDisp(cUnit, rSELF,
60 Thread::StackEndOffset().Int32Value(), r12);
61 }
62 /* Spill core callee saves */
63 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
64 /* Need to spill any FP regs? */
65 if (cUnit->numFPSpills) {
66 /*
67 * NOTE: fp spills are a little different from core spills in that
68 * they are pushed as a contiguous block. When promoting from
69 * the fp set, we must allocate all singles from s16..highest-promoted
70 */
71 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
72 }
73 if (!skipOverflowCheck) {
74 opRegRegImm(cUnit, kOpSub, rLR, rSP,
75 cUnit->frameSize - (spillCount * 4));
buzbee31a4a6f2012-02-28 15:36:15 -080076 genRegRegCheck(cUnit, kCondCc, rLR, r12, NULL,
77 kThrowStackOverflow);
buzbeee3acd072012-02-25 17:03:10 -080078 genRegCopy(cUnit, rSP, rLR); // Establish stack
79 } else {
80 opRegImm(cUnit, kOpSub, rSP,
81 cUnit->frameSize - (spillCount * 4));
82 }
83 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
84 flushIns(cUnit);
85
86 if (cUnit->genDebugger) {
87 // Refresh update debugger callout
88 loadWordDisp(cUnit, rSELF,
89 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
90 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
91 }
92
93 oatFreeTemp(cUnit, r0);
94 oatFreeTemp(cUnit, r1);
95 oatFreeTemp(cUnit, r2);
96 oatFreeTemp(cUnit, r3);
97}
98
buzbee31a4a6f2012-02-28 15:36:15 -080099void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
buzbeee3acd072012-02-25 17:03:10 -0800100{
101 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
102 /*
103 * In the exit path, r0/r1 are live - make sure they aren't
104 * allocated by the register utilities as temps.
105 */
106 oatLockTemp(cUnit, r0);
107 oatLockTemp(cUnit, r1);
108
buzbee31a4a6f2012-02-28 15:36:15 -0800109 newLIR0(cUnit, kPseudoMethodExit);
buzbeee3acd072012-02-25 17:03:10 -0800110 /* If we're compiling for the debugger, generate an update callout */
111 if (cUnit->genDebugger) {
112 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
113 }
114 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
115 /* Need to restore any FP callee saves? */
116 if (cUnit->numFPSpills) {
117 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
118 }
119 if (cUnit->coreSpillMask & (1 << rLR)) {
120 /* Unspill rLR to rPC */
121 cUnit->coreSpillMask &= ~(1 << rLR);
122 cUnit->coreSpillMask |= (1 << rPC);
123 }
124 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
125 if (!(cUnit->coreSpillMask & (1 << rPC))) {
126 /* We didn't pop to rPC, so must do a bv rLR */
127 newLIR1(cUnit, kThumbBx, rLR);
128 }
129}
130
131/*
132 * Nop any unconditional branches that go to the next instruction.
133 * Note: new redundant branches may be inserted later, and we'll
134 * use a check in final instruction assembly to nop those out.
135 */
136void removeRedundantBranches(CompilationUnit* cUnit)
137{
buzbee31a4a6f2012-02-28 15:36:15 -0800138 LIR* thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800139
buzbee31a4a6f2012-02-28 15:36:15 -0800140 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
141 thisLIR != (LIR*) cUnit->lastLIRInsn;
buzbeee3acd072012-02-25 17:03:10 -0800142 thisLIR = NEXT_LIR(thisLIR)) {
143
144 /* Branch to the next instruction */
145 if ((thisLIR->opcode == kThumbBUncond) ||
146 (thisLIR->opcode == kThumb2BUncond)) {
buzbee31a4a6f2012-02-28 15:36:15 -0800147 LIR* nextLIR = thisLIR;
buzbeee3acd072012-02-25 17:03:10 -0800148
149 while (true) {
150 nextLIR = NEXT_LIR(nextLIR);
151
152 /*
153 * Is the branch target the next instruction?
154 */
buzbee31a4a6f2012-02-28 15:36:15 -0800155 if (nextLIR == (LIR*) thisLIR->target) {
buzbeee3acd072012-02-25 17:03:10 -0800156 thisLIR->flags.isNop = true;
157 break;
158 }
159
160 /*
161 * Found real useful stuff between the branch and the target.
162 * Need to explicitly check the lastLIRInsn here because it
163 * might be the last real instruction.
164 */
165 if (!isPseudoOpcode(nextLIR->opcode) ||
buzbee31a4a6f2012-02-28 15:36:15 -0800166 (nextLIR = (LIR*) cUnit->lastLIRInsn))
buzbeee3acd072012-02-25 17:03:10 -0800167 break;
168 }
169 }
170 }
171}
172
buzbeee3acd072012-02-25 17:03:10 -0800173
174/* Common initialization routine for an architecture family */
175bool oatArchInit()
176{
177 int i;
178
179 for (i = 0; i < kArmLast; i++) {
180 if (EncodingMap[i].opcode != i) {
181 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
182 " is wrong: expecting " << i << ", seeing " <<
183 (int)EncodingMap[i].opcode;
184 }
185 }
186
187 return oatArchVariantInit();
188}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800189} // namespace art